@unbrained/pm-cli 2026.5.18 → 2026.5.24

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 (225) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +2 -1
  3. package/dist/cli/commander-usage.js +16 -2
  4. package/dist/cli/commander-usage.js.map +1 -1
  5. package/dist/cli/commands/annotation-command.d.ts +49 -0
  6. package/dist/cli/commands/annotation-command.js +135 -0
  7. package/dist/cli/commands/annotation-command.js.map +1 -0
  8. package/dist/cli/commands/append.js +3 -7
  9. package/dist/cli/commands/append.js.map +1 -1
  10. package/dist/cli/commands/calendar.js +3 -6
  11. package/dist/cli/commands/calendar.js.map +1 -1
  12. package/dist/cli/commands/claim.js +12 -22
  13. package/dist/cli/commands/claim.js.map +1 -1
  14. package/dist/cli/commands/close.js +61 -9
  15. package/dist/cli/commands/close.js.map +1 -1
  16. package/dist/cli/commands/comments.d.ts +5 -0
  17. package/dist/cli/commands/comments.js +27 -117
  18. package/dist/cli/commands/comments.js.map +1 -1
  19. package/dist/cli/commands/completion.js +102 -15
  20. package/dist/cli/commands/completion.js.map +1 -1
  21. package/dist/cli/commands/context.js +4 -10
  22. package/dist/cli/commands/context.js.map +1 -1
  23. package/dist/cli/commands/contracts.js +168 -36
  24. package/dist/cli/commands/contracts.js.map +1 -1
  25. package/dist/cli/commands/create.js +49 -44
  26. package/dist/cli/commands/create.js.map +1 -1
  27. package/dist/cli/commands/dedupe-audit.js +7 -4
  28. package/dist/cli/commands/dedupe-audit.js.map +1 -1
  29. package/dist/cli/commands/delete.d.ts +3 -0
  30. package/dist/cli/commands/delete.js +9 -8
  31. package/dist/cli/commands/delete.js.map +1 -1
  32. package/dist/cli/commands/docs.d.ts +1 -0
  33. package/dist/cli/commands/docs.js +4 -8
  34. package/dist/cli/commands/docs.js.map +1 -1
  35. package/dist/cli/commands/event-validation-messages.d.ts +3 -0
  36. package/dist/cli/commands/event-validation-messages.js +44 -0
  37. package/dist/cli/commands/event-validation-messages.js.map +1 -0
  38. package/dist/cli/commands/extension.d.ts +1 -0
  39. package/dist/cli/commands/extension.js +138 -21
  40. package/dist/cli/commands/extension.js.map +1 -1
  41. package/dist/cli/commands/files.js +6 -13
  42. package/dist/cli/commands/files.js.map +1 -1
  43. package/dist/cli/commands/gc.js +17 -4
  44. package/dist/cli/commands/gc.js.map +1 -1
  45. package/dist/cli/commands/get.d.ts +3 -2
  46. package/dist/cli/commands/get.js +50 -8
  47. package/dist/cli/commands/get.js.map +1 -1
  48. package/dist/cli/commands/health.d.ts +10 -0
  49. package/dist/cli/commands/health.js +254 -75
  50. package/dist/cli/commands/health.js.map +1 -1
  51. package/dist/cli/commands/history-redact.d.ts +8 -0
  52. package/dist/cli/commands/history-redact.js +14 -97
  53. package/dist/cli/commands/history-redact.js.map +1 -1
  54. package/dist/cli/commands/history-repair.d.ts +33 -0
  55. package/dist/cli/commands/history-repair.js +166 -0
  56. package/dist/cli/commands/history-repair.js.map +1 -0
  57. package/dist/cli/commands/history.d.ts +4 -4
  58. package/dist/cli/commands/history.js +10 -88
  59. package/dist/cli/commands/history.js.map +1 -1
  60. package/dist/cli/commands/index.d.ts +3 -1
  61. package/dist/cli/commands/index.js +5 -3
  62. package/dist/cli/commands/index.js.map +1 -1
  63. package/dist/cli/commands/init.d.ts +28 -0
  64. package/dist/cli/commands/init.js +23 -2
  65. package/dist/cli/commands/init.js.map +1 -1
  66. package/dist/cli/commands/learnings.js +20 -119
  67. package/dist/cli/commands/learnings.js.map +1 -1
  68. package/dist/cli/commands/linked-test-entry.d.ts +3 -0
  69. package/dist/cli/commands/linked-test-entry.js +62 -0
  70. package/dist/cli/commands/linked-test-entry.js.map +1 -0
  71. package/dist/cli/commands/list.js +32 -22
  72. package/dist/cli/commands/list.js.map +1 -1
  73. package/dist/cli/commands/notes.js +20 -119
  74. package/dist/cli/commands/notes.js.map +1 -1
  75. package/dist/cli/commands/plan.d.ts +3 -0
  76. package/dist/cli/commands/plan.js +184 -22
  77. package/dist/cli/commands/plan.js.map +1 -1
  78. package/dist/cli/commands/restore.js +7 -50
  79. package/dist/cli/commands/restore.js.map +1 -1
  80. package/dist/cli/commands/schema.d.ts +31 -0
  81. package/dist/cli/commands/schema.js +98 -0
  82. package/dist/cli/commands/schema.js.map +1 -0
  83. package/dist/cli/commands/search.js +151 -40
  84. package/dist/cli/commands/search.js.map +1 -1
  85. package/dist/cli/commands/templates.d.ts +4 -0
  86. package/dist/cli/commands/templates.js +89 -17
  87. package/dist/cli/commands/templates.js.map +1 -1
  88. package/dist/cli/commands/test-all.js +4 -8
  89. package/dist/cli/commands/test-all.js.map +1 -1
  90. package/dist/cli/commands/test.d.ts +1 -0
  91. package/dist/cli/commands/test.js +7 -10
  92. package/dist/cli/commands/test.js.map +1 -1
  93. package/dist/cli/commands/update-many.js +4 -8
  94. package/dist/cli/commands/update-many.js.map +1 -1
  95. package/dist/cli/commands/update.js +109 -51
  96. package/dist/cli/commands/update.js.map +1 -1
  97. package/dist/cli/commands/validate.d.ts +3 -1
  98. package/dist/cli/commands/validate.js +23 -71
  99. package/dist/cli/commands/validate.js.map +1 -1
  100. package/dist/cli/error-guidance.js +96 -6
  101. package/dist/cli/error-guidance.js.map +1 -1
  102. package/dist/cli/extension-command-help.d.ts +0 -1
  103. package/dist/cli/extension-command-help.js +2 -13
  104. package/dist/cli/extension-command-help.js.map +1 -1
  105. package/dist/cli/extension-command-options.d.ts +1 -0
  106. package/dist/cli/extension-command-options.js +106 -7
  107. package/dist/cli/extension-command-options.js.map +1 -1
  108. package/dist/cli/help-content.d.ts +0 -1
  109. package/dist/cli/help-content.js +13 -9
  110. package/dist/cli/help-content.js.map +1 -1
  111. package/dist/cli/help-json-payload.d.ts +1 -0
  112. package/dist/cli/help-json-payload.js +33 -3
  113. package/dist/cli/help-json-payload.js.map +1 -1
  114. package/dist/cli/main.js +35 -29
  115. package/dist/cli/main.js.map +1 -1
  116. package/dist/cli/register-list-query.d.ts +1 -1
  117. package/dist/cli/register-list-query.js +40 -17
  118. package/dist/cli/register-list-query.js.map +1 -1
  119. package/dist/cli/register-mutation.d.ts +1 -1
  120. package/dist/cli/register-mutation.js +232 -64
  121. package/dist/cli/register-mutation.js.map +1 -1
  122. package/dist/cli/register-operations.js +16 -11
  123. package/dist/cli/register-operations.js.map +1 -1
  124. package/dist/cli/register-setup.js +26 -14
  125. package/dist/cli/register-setup.js.map +1 -1
  126. package/dist/cli/registration-helpers.d.ts +0 -2
  127. package/dist/cli/registration-helpers.js +13 -40
  128. package/dist/cli/registration-helpers.js.map +1 -1
  129. package/dist/cli.js +23 -3
  130. package/dist/cli.js.map +1 -1
  131. package/dist/core/extensions/index.d.ts +0 -1
  132. package/dist/core/extensions/index.js +2 -14
  133. package/dist/core/extensions/index.js.map +1 -1
  134. package/dist/core/extensions/loader.js +3 -9
  135. package/dist/core/extensions/loader.js.map +1 -1
  136. package/dist/core/fs/path-utils.d.ts +1 -0
  137. package/dist/core/fs/path-utils.js +12 -0
  138. package/dist/core/fs/path-utils.js.map +1 -0
  139. package/dist/core/history/drift-scan.d.ts +11 -0
  140. package/dist/core/history/drift-scan.js +67 -0
  141. package/dist/core/history/drift-scan.js.map +1 -0
  142. package/dist/core/history/replay.d.ts +82 -0
  143. package/dist/core/history/replay.js +249 -0
  144. package/dist/core/history/replay.js.map +1 -0
  145. package/dist/core/item/item-format.js +11 -8
  146. package/dist/core/item/item-format.js.map +1 -1
  147. package/dist/core/item/item-type-definition.d.ts +52 -0
  148. package/dist/core/item/item-type-definition.js +123 -0
  149. package/dist/core/item/item-type-definition.js.map +1 -0
  150. package/dist/core/item/parse.js +3 -2
  151. package/dist/core/item/parse.js.map +1 -1
  152. package/dist/core/item/priority.d.ts +23 -0
  153. package/dist/core/item/priority.js +55 -0
  154. package/dist/core/item/priority.js.map +1 -0
  155. package/dist/core/item/status.d.ts +14 -1
  156. package/dist/core/item/status.js +22 -2
  157. package/dist/core/item/status.js.map +1 -1
  158. package/dist/core/item/toon-decode.d.ts +19 -0
  159. package/dist/core/item/toon-decode.js +69 -0
  160. package/dist/core/item/toon-decode.js.map +1 -0
  161. package/dist/core/item/type-registry.js +13 -84
  162. package/dist/core/item/type-registry.js.map +1 -1
  163. package/dist/core/packages/manifest.js +3 -9
  164. package/dist/core/packages/manifest.js.map +1 -1
  165. package/dist/core/schema/item-types-file.d.ts +85 -0
  166. package/dist/core/schema/item-types-file.js +243 -0
  167. package/dist/core/schema/item-types-file.js.map +1 -0
  168. package/dist/core/schema/runtime-schema.d.ts +2 -1
  169. package/dist/core/schema/runtime-schema.js +11 -9
  170. package/dist/core/schema/runtime-schema.js.map +1 -1
  171. package/dist/core/search/semantic-defaults.js +3 -3
  172. package/dist/core/search/semantic-defaults.js.map +1 -1
  173. package/dist/core/shared/author.d.ts +1 -0
  174. package/dist/core/shared/author.js +9 -0
  175. package/dist/core/shared/author.js.map +1 -0
  176. package/dist/core/shared/lazy-module.d.ts +1 -0
  177. package/dist/core/shared/lazy-module.js +11 -0
  178. package/dist/core/shared/lazy-module.js.map +1 -0
  179. package/dist/core/shared/option-alias-visibility.d.ts +44 -0
  180. package/dist/core/shared/option-alias-visibility.js +76 -0
  181. package/dist/core/shared/option-alias-visibility.js.map +1 -0
  182. package/dist/core/shared/text-normalization.d.ts +0 -1
  183. package/dist/core/shared/text-normalization.js +2 -5
  184. package/dist/core/shared/text-normalization.js.map +1 -1
  185. package/dist/core/store/item-store.d.ts +2 -0
  186. package/dist/core/store/item-store.js +70 -39
  187. package/dist/core/store/item-store.js.map +1 -1
  188. package/dist/core/store/settings-validator.d.ts +106 -0
  189. package/dist/core/store/settings-validator.js +279 -0
  190. package/dist/core/store/settings-validator.js.map +1 -0
  191. package/dist/core/store/settings.js +6 -343
  192. package/dist/core/store/settings.js.map +1 -1
  193. package/dist/core/telemetry/runtime.js +5 -3
  194. package/dist/core/telemetry/runtime.js.map +1 -1
  195. package/dist/mcp/server.js +64 -13
  196. package/dist/mcp/server.js.map +1 -1
  197. package/dist/sdk/cli-contracts.d.ts +9 -2
  198. package/dist/sdk/cli-contracts.js +204 -13
  199. package/dist/sdk/cli-contracts.js.map +1 -1
  200. package/dist/sdk/runtime.d.ts +25 -1
  201. package/dist/sdk/runtime.js +46 -3
  202. package/dist/sdk/runtime.js.map +1 -1
  203. package/dist/types.d.ts +6 -0
  204. package/dist/types.js +10 -2
  205. package/dist/types.js.map +1 -1
  206. package/docs/AGENT_GUIDE.md +7 -1
  207. package/docs/ARCHITECTURE.md +1 -1
  208. package/docs/COMMANDS.md +39 -6
  209. package/docs/CONFIGURATION.md +1 -1
  210. package/docs/RELEASING.md +11 -7
  211. package/docs/SDK.md +11 -2
  212. package/package.json +12 -11
  213. package/packages/pm-calendar/README.md +3 -1
  214. package/packages/pm-calendar/extensions/calendar/index.js +21 -2
  215. package/packages/pm-calendar/extensions/calendar/index.ts +21 -2
  216. package/packages/pm-search-advanced/README.md +8 -0
  217. package/packages/pm-search-advanced/extensions/search-advanced/index.js +74 -0
  218. package/packages/pm-search-advanced/extensions/search-advanced/index.ts +74 -0
  219. package/packages/pm-search-advanced/extensions/search-advanced/runtime.js +67 -9
  220. package/packages/pm-search-advanced/extensions/search-advanced/runtime.ts +67 -9
  221. package/packages/pm-templates/extensions/templates/runtime.js +11 -202
  222. package/packages/pm-templates/extensions/templates/runtime.ts +38 -230
  223. package/dist/core/output/command-aware.d.ts +0 -1
  224. package/dist/core/output/command-aware.js +0 -397
  225. package/dist/core/output/command-aware.js.map +0 -1
@@ -1,13 +1,26 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="df6717c1-afaf-5933-945b-32b84cacd324")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="634fa316-811c-5a12-a391-225313b2c754")}catch(e){}}();
3
+ import { Option } from "commander";
3
4
  import { EXIT_CODE } from "../core/shared/constants.js";
4
5
  import { PmCliError } from "../core/shared/errors.js";
6
+ import { isPureSnakeCaseAlias } from "../core/shared/option-alias-visibility.js";
5
7
  import { CREATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS, UPDATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS, } from "../sdk/cli-contracts.js";
6
- import { collect, extractUpdateManyMutationOptionSource, getGlobalOptions, invalidateSearchCachesForMutation, normalizeCreateOptions, normalizeUpdateOptions, printError, printResult, } from "./registration-helpers.js";
7
- let mutationCommandsModulePromise = null;
8
- async function loadMutationCommandsModule() {
9
- mutationCommandsModulePromise ??= import("./commands/index.js");
10
- return mutationCommandsModulePromise;
8
+ import { collect, extractUpdateManyMutationOptionSource, formatHookWarnings, getGlobalOptions, invalidateSearchCachesForMutation, normalizeCreateOptions, normalizeUpdateOptions, printError, printResult, writeStdout, } from "./registration-helpers.js";
9
+ import { createLazyModule } from "../core/shared/lazy-module.js";
10
+ const loadMutationCommandsModule = createLazyModule(() => import("./commands/index.js"));
11
+ /**
12
+ * Register a flag and hide it from `--help` text while keeping it fully
13
+ * functional as a parse-time alias. The option still appears in
14
+ * `command.options`, so the JSON help payload and shell completion (which read
15
+ * from the contracts/commander option list, not the rendered text) are
16
+ * unchanged — only commander's text `--help` omits it.
17
+ */
18
+ function addHiddenOption(command, flags, description, repeatable) {
19
+ const option = new Option(flags, description).hideHelp();
20
+ if (repeatable) {
21
+ option.argParser(collect);
22
+ }
23
+ command.addOption(option);
11
24
  }
12
25
  function registerCommanderOptionContracts(command, contracts) {
13
26
  for (const contract of contracts) {
@@ -21,7 +34,13 @@ function registerCommanderOptionContracts(command, contracts) {
21
34
  command.option(contract.option, contract.description);
22
35
  }
23
36
  for (const aliasContract of contract.aliasOptions ?? []) {
24
- if (contract.repeatable) {
37
+ // Hide pure snake_case underscore-duplicate aliases (e.g. --create_mode
38
+ // for --create-mode) from --help, but keep semantically-distinct aliases
39
+ // (e.g. --ac for --acceptance-criteria) visible.
40
+ if (isPureSnakeCaseAlias(contract.option, aliasContract.option)) {
41
+ addHiddenOption(command, aliasContract.option, aliasContract.description, contract.repeatable === true);
42
+ }
43
+ else if (contract.repeatable) {
25
44
  command.option(aliasContract.option, aliasContract.description, collect);
26
45
  }
27
46
  else {
@@ -33,7 +52,8 @@ function registerCommanderOptionContracts(command, contracts) {
33
52
  export function registerMutationCommands(program) {
34
53
  const createCommand = program
35
54
  .command("create")
36
- .argument("[title]", "Item title (positional shortcut for --title)")
55
+ .argument("[typeOrTitle]", "Item title, or item type when a title follows (e.g. `pm create task \"Fix bug\"`)")
56
+ .argument("[title]", "Item title when the first argument is an item type")
37
57
  .description("Create a new project management item.");
38
58
  registerCommanderOptionContracts(createCommand, CREATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS);
39
59
  createCommand
@@ -47,9 +67,24 @@ export function registerMutationCommands(program) {
47
67
  .option("--clear-reminders", "Clear reminders")
48
68
  .option("--clear-events", "Clear events")
49
69
  .option("--clear-type-options", "Clear type options")
50
- .action(async (positionalTitle, options, command) => {
70
+ .action(async (typeOrTitle, secondTitle, options, command) => {
51
71
  const globalOptions = getGlobalOptions(command);
52
72
  const startedAt = Date.now();
73
+ // Support both `pm create "<title>"` and the natural subcommand-style
74
+ // `pm create <type> "<title>"` so agents are never blocked by argument
75
+ // count. When two positionals are given, the first is the item type.
76
+ let positionalType;
77
+ let positionalTitle;
78
+ if (typeof secondTitle === "string" && secondTitle.length > 0) {
79
+ positionalType = typeOrTitle;
80
+ positionalTitle = secondTitle;
81
+ }
82
+ else if (typeof typeOrTitle === "string" && typeOrTitle.length > 0) {
83
+ positionalTitle = typeOrTitle;
84
+ }
85
+ if (typeof positionalType === "string" && positionalType.length > 0 && options.type === undefined) {
86
+ options.type = positionalType;
87
+ }
53
88
  if (typeof positionalTitle === "string" && positionalTitle.length > 0 && options.title === undefined) {
54
89
  options.title = positionalTitle;
55
90
  }
@@ -81,10 +116,11 @@ export function registerMutationCommands(program) {
81
116
  .option("--clear-events", "Clear events")
82
117
  .option("--clear-type-options", "Clear type options")
83
118
  .option("--allow-audit-update", "Allow non-owner metadata-only audit updates without requiring --force")
84
- .option("--allow_audit_update", "Alias for --allow-audit-update")
85
119
  .option("--allow-audit-dep-update", "Allow non-owner append-only dependency updates without requiring --force")
86
- .option("--allow_audit_dep_update", "Alias for --allow-audit-dep-update")
87
- .option("--force", "Force ownership override")
120
+ .option("--force", "Force ownership override");
121
+ addHiddenOption(updateCommand, "--allow_audit_update", "Alias for --allow-audit-update", false);
122
+ addHiddenOption(updateCommand, "--allow_audit_dep_update", "Alias for --allow-audit-dep-update", false);
123
+ updateCommand
88
124
  .action(async (id, options, command) => {
89
125
  const globalOptions = getGlobalOptions(command);
90
126
  const startedAt = Date.now();
@@ -96,7 +132,7 @@ export function registerMutationCommands(program) {
96
132
  printError(`profile:command=update took_ms=${Date.now() - startedAt}`);
97
133
  }
98
134
  });
99
- program
135
+ const updateManyCommand = program
100
136
  .command("update-many")
101
137
  .description("Bulk-update matched items with dry-run plans and rollback checkpoints.")
102
138
  .option("--filter-status <value>", "Filter by status before applying updates")
@@ -107,7 +143,6 @@ export function registerMutationCommands(program) {
107
143
  .option("--filter-deadline-after <value>", "Filter by deadline lower bound before applying updates")
108
144
  .option("--filter-assignee <value>", "Filter by assignee before applying updates")
109
145
  .option("--filter-assignee-filter <value>", "Filter assignee presence: assigned|unassigned before applying updates")
110
- .option("--filter-assignee_filter <value>", "Alias for --filter-assignee-filter")
111
146
  .option("--filter-parent <value>", "Filter by parent item ID before applying updates")
112
147
  .option("--filter-sprint <value>", "Filter by sprint before applying updates")
113
148
  .option("--filter-release <value>", "Filter by release before applying updates")
@@ -125,12 +160,9 @@ export function registerMutationCommands(program) {
125
160
  .option("--tags <value>", "Set comma-separated tags")
126
161
  .option("--deadline <value>", "Set deadline (ISO/date string or relative)")
127
162
  .option("--estimate, --estimated-minutes <value>", "Set estimated minutes")
128
- .option("--estimated_minutes <value>", "Alias for --estimated-minutes")
129
163
  .option("--acceptance-criteria <value>", "Set acceptance criteria")
130
- .option("--acceptance_criteria <value>", "Alias for --acceptance-criteria")
131
164
  .option("--ac <value>", "Alias for --acceptance-criteria")
132
165
  .option("--definition-of-ready <value>", "Set definition of ready")
133
- .option("--definition_of_ready <value>", "Alias for --definition-of-ready")
134
166
  .option("--order <value>", "Set planning order/rank integer")
135
167
  .option("--rank <value>", "Alias for --order")
136
168
  .option("--goal <value>", "Set goal identifier")
@@ -139,7 +171,6 @@ export function registerMutationCommands(program) {
139
171
  .option("--impact <value>", "Set business impact summary")
140
172
  .option("--outcome <value>", "Set expected outcome summary")
141
173
  .option("--why-now <value>", "Set why-now rationale")
142
- .option("--why_now <value>", "Alias for --why-now")
143
174
  .option("--assignee <value>", "Set assignee")
144
175
  .option("--parent <value>", "Set parent item ID")
145
176
  .option("--reviewer <value>", "Set reviewer")
@@ -148,32 +179,22 @@ export function registerMutationCommands(program) {
148
179
  .option("--sprint <value>", "Set sprint identifier")
149
180
  .option("--release <value>", "Set release identifier")
150
181
  .option("--blocked-by <value>", "Set blocked-by item ID or reason")
151
- .option("--blocked_by <value>", "Alias for --blocked-by")
152
182
  .option("--blocked-reason <value>", "Set blocked reason")
153
- .option("--blocked_reason <value>", "Alias for --blocked-reason")
154
183
  .option("--unblock-note <value>", "Set unblock rationale note")
155
- .option("--unblock_note <value>", "Alias for --unblock-note")
156
184
  .option("--reporter <value>", "Set issue reporter")
157
185
  .option("--severity <value>", "Set issue severity")
158
186
  .option("--environment <value>", "Set issue environment context")
159
187
  .option("--repro-steps <value>", "Set issue reproduction steps")
160
- .option("--repro_steps <value>", "Alias for --repro-steps")
161
188
  .option("--resolution <value>", "Set issue resolution summary")
162
189
  .option("--expected-result <value>", "Set issue expected behavior")
163
- .option("--expected_result <value>", "Alias for --expected-result")
164
190
  .option("--actual-result <value>", "Set issue observed behavior")
165
- .option("--actual_result <value>", "Alias for --actual-result")
166
191
  .option("--affected-version <value>", "Set affected version identifier")
167
- .option("--affected_version <value>", "Alias for --affected-version")
168
192
  .option("--fixed-version <value>", "Set fixed version identifier")
169
- .option("--fixed_version <value>", "Alias for --fixed-version")
170
193
  .option("--component <value>", "Set issue component ownership")
171
194
  .option("--regression <value>", "Set regression marker: true|false|1|0")
172
195
  .option("--customer-impact <value>", "Set customer impact summary")
173
- .option("--customer_impact <value>", "Alias for --customer-impact")
174
196
  .option("--dep <value>", "Add dependency entry id=<id>,kind=<kind>,author=<author>,created_at=<timestamp>", collect)
175
197
  .option("--dep-remove <value>", "Remove dependency entries by id/kind/author/timestamp signature", collect)
176
- .option("--dep_remove <value>", "Alias for --dep-remove", collect)
177
198
  .option("--replace-deps", "Atomically replace dependency entries with provided --dep values")
178
199
  .option("--replace-tests", "Atomically replace linked tests with provided --test values")
179
200
  .option("--comment <value>", "Add comment seed author=<value>,created_at=<iso|now>,text=<value>", collect)
@@ -182,10 +203,9 @@ export function registerMutationCommands(program) {
182
203
  .option("--file <value>", "Add linked file path=<value>,scope=<project|global>,note=<text>", collect)
183
204
  .option("--test <value>", "Add linked test command=<value>,path=<value>,scope=<project|global>", collect)
184
205
  .option("--doc <value>", "Add linked doc path=<value>,scope=<project|global>,note=<text>", collect)
185
- .option("--reminder <value>", "Add reminder entry at=<iso|relative>,text=<text>", collect)
206
+ .option("--reminder <value>", "Add reminder entry at=<iso|relative>|date=<iso|relative>,text=<text>|title=<text>", collect)
186
207
  .option("--event <value>", "Add event entry start=<iso|relative>,end=<iso|relative>,recur_*", collect)
187
208
  .option("--type-option <value>", "Set type options key=value (repeatable)", collect)
188
- .option("--type_option <value>", "Alias for --type-option", collect)
189
209
  .option("--unset <field>", "Clear scalar metadata field by name (repeatable)", collect)
190
210
  .option("--clear-deps", "Clear dependency entries")
191
211
  .option("--clear-comments", "Clear comments")
@@ -198,12 +218,39 @@ export function registerMutationCommands(program) {
198
218
  .option("--clear-events", "Clear events")
199
219
  .option("--clear-type-options", "Clear type options")
200
220
  .option("--allow-audit-update", "Allow non-owner metadata-only audit updates without requiring --force")
201
- .option("--allow_audit_update", "Alias for --allow-audit-update")
202
221
  .option("--allow-audit-dep-update", "Allow non-owner append-only dependency updates without requiring --force")
203
- .option("--allow_audit_dep_update", "Alias for --allow-audit-dep-update")
204
222
  .option("--author <value>", "Mutation author")
205
223
  .option("--message <value>", "Mutation message")
206
- .option("--force", "Force ownership override")
224
+ .option("--force", "Force ownership override");
225
+ // Hidden pure snake_case underscore-duplicate aliases (kept parse-functional,
226
+ // omitted from --help to save agent context).
227
+ for (const [flags, description] of [
228
+ ["--filter-assignee_filter <value>", "Alias for --filter-assignee-filter"],
229
+ ["--estimated_minutes <value>", "Alias for --estimated-minutes"],
230
+ ["--acceptance_criteria <value>", "Alias for --acceptance-criteria"],
231
+ ["--definition_of_ready <value>", "Alias for --definition-of-ready"],
232
+ ["--why_now <value>", "Alias for --why-now"],
233
+ ["--blocked_by <value>", "Alias for --blocked-by"],
234
+ ["--blocked_reason <value>", "Alias for --blocked-reason"],
235
+ ["--unblock_note <value>", "Alias for --unblock-note"],
236
+ ["--repro_steps <value>", "Alias for --repro-steps"],
237
+ ["--expected_result <value>", "Alias for --expected-result"],
238
+ ["--actual_result <value>", "Alias for --actual-result"],
239
+ ["--affected_version <value>", "Alias for --affected-version"],
240
+ ["--fixed_version <value>", "Alias for --fixed-version"],
241
+ ["--customer_impact <value>", "Alias for --customer-impact"],
242
+ ["--allow_audit_update", "Alias for --allow-audit-update"],
243
+ ["--allow_audit_dep_update", "Alias for --allow-audit-dep-update"],
244
+ ]) {
245
+ addHiddenOption(updateManyCommand, flags, description, false);
246
+ }
247
+ for (const [flags, description] of [
248
+ ["--dep_remove <value>", "Alias for --dep-remove"],
249
+ ["--type_option <value>", "Alias for --type-option"],
250
+ ]) {
251
+ addHiddenOption(updateManyCommand, flags, description, true);
252
+ }
253
+ updateManyCommand
207
254
  .action(async (options, command) => {
208
255
  const globalOptions = getGlobalOptions(command);
209
256
  const startedAt = Date.now();
@@ -294,6 +341,7 @@ export function registerMutationCommands(program) {
294
341
  .option("--author <value>", "Mutation author")
295
342
  .option("--message <value>", "History message")
296
343
  .option("--force", "Force ownership override")
344
+ .option("--dry-run", "Preview the item file that would be deleted without mutating")
297
345
  .description("Delete an item and record the change in history.")
298
346
  .action(async (id, options, command) => {
299
347
  const globalOptions = getGlobalOptions(command);
@@ -303,8 +351,11 @@ export function registerMutationCommands(program) {
303
351
  author: typeof options.author === "string" ? options.author : undefined,
304
352
  message: typeof options.message === "string" ? options.message : undefined,
305
353
  force: Boolean(options.force),
354
+ dryRun: options.dryRun === true,
306
355
  }, globalOptions);
307
- await invalidateSearchCachesForMutation(globalOptions, result);
356
+ if (result.dry_run !== true) {
357
+ await invalidateSearchCachesForMutation(globalOptions, result);
358
+ }
308
359
  printResult(result, globalOptions);
309
360
  if (globalOptions.profile) {
310
361
  printError(`profile:command=delete took_ms=${Date.now() - startedAt}`);
@@ -313,17 +364,30 @@ export function registerMutationCommands(program) {
313
364
  program
314
365
  .command("append")
315
366
  .argument("<id>", "Item id")
316
- .requiredOption("--body <value>", "Text to append to body (or - for stdin)")
367
+ .argument("[text]", "Optional body text shorthand (equivalent to --body; use - for stdin)")
368
+ .option("--body <value>", "Text to append to body (or - for stdin)")
369
+ .option("--text <value>", "Alias for --body")
317
370
  .option("--author <value>", "Mutation author")
318
371
  .option("--message <value>", "Mutation message")
319
372
  .option("--force", "Force ownership override")
320
373
  .description("Append text to an item's body.")
321
- .action(async (id, options, command) => {
374
+ .action(async (id, text, options, command) => {
322
375
  const globalOptions = getGlobalOptions(command);
323
376
  const startedAt = Date.now();
377
+ const bodyFromOption = typeof options.body === "string" ? options.body : undefined;
378
+ const bodyFromAlias = typeof options.text === "string" ? options.text : undefined;
379
+ const bodyFromPositional = typeof text === "string" ? text : undefined;
380
+ const bodySourceCount = [bodyFromOption, bodyFromAlias, bodyFromPositional].filter((value) => value !== undefined).length;
381
+ if (bodySourceCount > 1) {
382
+ throw new PmCliError("Specify append text with exactly one source: positional [text], --body, or --text", EXIT_CODE.USAGE);
383
+ }
384
+ const resolvedBody = bodyFromOption ?? bodyFromAlias ?? bodyFromPositional;
385
+ if (resolvedBody === undefined) {
386
+ throw new PmCliError("Missing append text. Provide it as positional [text], --body <value>, or --text <value> (use - for stdin).", EXIT_CODE.USAGE);
387
+ }
324
388
  const { runAppend } = await loadMutationCommandsModule();
325
389
  const result = await runAppend(id, {
326
- body: typeof options.body === "string" ? options.body : "",
390
+ body: resolvedBody,
327
391
  author: typeof options.author === "string" ? options.author : undefined,
328
392
  message: typeof options.message === "string" ? options.message : undefined,
329
393
  force: Boolean(options.force),
@@ -371,71 +435,86 @@ export function registerMutationCommands(program) {
371
435
  .option("--related <value>", "Related pm item ids (repeatable, csv-friendly)", collect)
372
436
  .option("--blocks <value>", "Pm item ids this plan blocks (repeatable, csv-friendly)", collect)
373
437
  .option("--blocked-by <value>", "Pm item ids that block this plan (repeatable, csv-friendly)", collect)
374
- .option("--blocked_by <value>", "Alias for --blocked-by", collect)
375
438
  .option("--harness <value>", "Plan harness provenance: codex|claude-code|cursor|generic")
376
439
  .option("--mode <value>", "Plan mode: draft|research|review|approved|executing|paused|completed|superseded")
377
440
  .option("--resume-context <value>", "Compact context summary for a future stateless agent")
378
- .option("--resume_context <value>", "Alias for --resume-context")
379
441
  .option("--tags <value>", "Comma-separated tags")
380
442
  .option("--priority <value>", "Priority 0-4")
381
443
  .option("--body <value>", "Plan item body")
382
444
  .option("--claim", "Claim the plan on create for the author")
383
445
  .option("--from-search <value>", "Record the search query that led to plan creation")
384
- .option("--from_search <value>", "Alias for --from-search")
385
446
  .option("--step-title <value>", "Step title for add-step / update-step")
386
- .option("--step_title <value>", "Alias for --step-title")
447
+ .option("--step <value>", "Alias for --step-title")
387
448
  .option("--step-body <value>", "Step body text")
388
- .option("--step_body <value>", "Alias for --step-body")
389
449
  .option("--step-owner <value>", "Step owner")
390
- .option("--step_owner <value>", "Alias for --step-owner")
391
450
  .option("--step-status <value>", "Step status: pending|in_progress|completed|blocked|skipped|superseded")
392
- .option("--step_status <value>", "Alias for --step-status")
393
451
  .option("--step-evidence <value>", "Step evidence text (used by update-step/complete-step)")
394
- .option("--step_evidence <value>", "Alias for --step-evidence")
395
452
  .option("--step-blocked-reason <value>", "Step blocked reason (required when blocking)")
396
- .option("--step_blocked_reason <value>", "Alias for --step-blocked-reason")
397
453
  .option("--step-replacement <value>", "Replacement reference for a superseded step")
398
- .option("--step_replacement <value>", "Alias for --step-replacement")
399
454
  .option("--depends-on <value>", "Pm item ids the step depends on (repeatable, csv-friendly)", collect)
400
- .option("--depends_on <value>", "Alias for --depends-on", collect)
401
455
  .option("--link <value>", "Pm item id to link (repeatable, csv-friendly)", collect)
402
456
  .option("--link-kind <value>", "Link kind: related|blocks|blocked_by|depends_on|discovered_from|implements|verifies|supersedes")
403
- .option("--link_kind <value>", "Alias for --link-kind")
404
457
  .option("--link-note <value>", "Optional note for the link")
405
- .option("--link_note <value>", "Alias for --link-note")
406
458
  .option("--promote-to-item-dep", "Also add the linked id as a top-level item dependency when linking")
407
- .option("--promote_to_item_dep", "Alias for --promote-to-item-dep")
408
459
  .option("--allow-multiple-active", "Allow multiple steps to be in_progress at once")
409
- .option("--allow_multiple_active", "Alias for --allow-multiple-active")
410
460
  .option("--file <value>", "Step linked file path=<value>[,scope=project|global,note=<text>] (repeatable)", collect)
411
461
  .option("--test <value>", "Step linked test command=<value>[,path=<value>,note=<text>] (repeatable)", collect)
412
462
  .option("--doc <value>", "Step linked doc path=<value>[,scope=project|global,note=<text>] (repeatable)", collect)
413
463
  .option("--decision-text <value>", "Decision log entry text")
414
- .option("--decision_text <value>", "Alias for --decision-text")
464
+ .option("--decision <value>", "Alias for --decision-text")
415
465
  .option("--decision-rationale <value>", "Decision log entry rationale")
416
- .option("--decision_rationale <value>", "Alias for --decision-rationale")
417
466
  .option("--decision-evidence <value>", "Decision log entry evidence")
418
- .option("--decision_evidence <value>", "Alias for --decision-evidence")
419
467
  .option("--discovery-text <value>", "Discovery log entry text")
420
- .option("--discovery_text <value>", "Alias for --discovery-text")
468
+ .option("--discovery <value>", "Alias for --discovery-text")
421
469
  .option("--validation-text <value>", "Validation log entry text")
422
- .option("--validation_text <value>", "Alias for --validation-text")
470
+ .option("--validation <value>", "Alias for --validation-text")
423
471
  .option("--validation-command <value>", "Validation log entry command")
424
- .option("--validation_command <value>", "Alias for --validation-command")
425
472
  .option("--validation-expected <value>", "Validation log entry expected outcome")
426
- .option("--validation_expected <value>", "Alias for --validation-expected")
427
473
  .option("--depth <value>", "Show depth: brief|standard|deep (default: brief)")
428
474
  .option("--fields <value>", "Comma-separated field projection for show output")
429
475
  .option("--steps <value>", "Comma-separated step ids/orders for materialize")
430
476
  .option("--materialize-type <value>", "Item type for materialized steps (default: Task)")
431
- .option("--materialize_type <value>", "Alias for --materialize-type")
432
477
  .option("--materialize-parent <value>", "Parent item id for materialized children (default: the plan)")
433
- .option("--materialize_parent <value>", "Alias for --materialize-parent")
434
478
  .option("--materialize-tags <value>", "Comma-separated tags for materialized children")
435
- .option("--materialize_tags <value>", "Alias for --materialize-tags")
436
479
  .option("--author <value>", "Mutation author")
437
480
  .option("--message <value>", "Mutation message")
438
- .option("--force", "Force ownership override")
481
+ .option("--force", "Force ownership override");
482
+ // Hidden pure snake_case underscore-duplicate aliases (kept parse-functional,
483
+ // omitted from --help to save agent context).
484
+ for (const [flags, description] of [
485
+ ["--resume_context <value>", "Alias for --resume-context"],
486
+ ["--from_search <value>", "Alias for --from-search"],
487
+ ["--step_title <value>", "Alias for --step-title"],
488
+ ["--step_body <value>", "Alias for --step-body"],
489
+ ["--step_owner <value>", "Alias for --step-owner"],
490
+ ["--step_status <value>", "Alias for --step-status"],
491
+ ["--step_evidence <value>", "Alias for --step-evidence"],
492
+ ["--step_blocked_reason <value>", "Alias for --step-blocked-reason"],
493
+ ["--step_replacement <value>", "Alias for --step-replacement"],
494
+ ["--link_kind <value>", "Alias for --link-kind"],
495
+ ["--link_note <value>", "Alias for --link-note"],
496
+ ["--promote_to_item_dep", "Alias for --promote-to-item-dep"],
497
+ ["--allow_multiple_active", "Alias for --allow-multiple-active"],
498
+ ["--decision_text <value>", "Alias for --decision-text"],
499
+ ["--decision_rationale <value>", "Alias for --decision-rationale"],
500
+ ["--decision_evidence <value>", "Alias for --decision-evidence"],
501
+ ["--discovery_text <value>", "Alias for --discovery-text"],
502
+ ["--validation_text <value>", "Alias for --validation-text"],
503
+ ["--validation_command <value>", "Alias for --validation-command"],
504
+ ["--validation_expected <value>", "Alias for --validation-expected"],
505
+ ["--materialize_type <value>", "Alias for --materialize-type"],
506
+ ["--materialize_parent <value>", "Alias for --materialize-parent"],
507
+ ["--materialize_tags <value>", "Alias for --materialize-tags"],
508
+ ]) {
509
+ addHiddenOption(planCommand, flags, description, false);
510
+ }
511
+ for (const [flags, description] of [
512
+ ["--blocked_by <value>", "Alias for --blocked-by"],
513
+ ["--depends_on <value>", "Alias for --depends-on"],
514
+ ]) {
515
+ addHiddenOption(planCommand, flags, description, true);
516
+ }
517
+ planCommand
439
518
  .action(async (subcommand, id, stepRef, reorderToken, options, command) => {
440
519
  const globalOptions = getGlobalOptions(command);
441
520
  const startedAt = Date.now();
@@ -463,6 +542,7 @@ export function registerMutationCommands(program) {
463
542
  ["blocked_by", "blockedBy"],
464
543
  ["resume_context", "resumeContext"],
465
544
  ["from_search", "fromSearch"],
545
+ ["step", "stepTitle"],
466
546
  ["step_title", "stepTitle"],
467
547
  ["step_body", "stepBody"],
468
548
  ["step_owner", "stepOwner"],
@@ -555,6 +635,92 @@ export function registerMutationCommands(program) {
555
635
  printError(`profile:command=history-redact took_ms=${Date.now() - startedAt}`);
556
636
  }
557
637
  });
638
+ program
639
+ .command("history-repair")
640
+ .argument("<id>", "Item id")
641
+ .option("--dry-run", "Preview the re-anchor impact without writing the history file")
642
+ .option("--author <value>", "Mutation author")
643
+ .option("--message <value>", "Audit history message for the repair marker entry")
644
+ .option("--force", "Force ownership/lock override")
645
+ .description("Re-anchor a drifted item history chain (recompute hashes, reconcile with the on-disk item) and record an audit marker.")
646
+ .action(async (id, options, command) => {
647
+ const globalOptions = getGlobalOptions(command);
648
+ const startedAt = Date.now();
649
+ const { runHistoryRepair } = await loadMutationCommandsModule();
650
+ const result = await runHistoryRepair(id, {
651
+ dryRun: options.dryRun === true,
652
+ author: typeof options.author === "string" ? options.author : undefined,
653
+ message: typeof options.message === "string" ? options.message : undefined,
654
+ force: Boolean(options.force),
655
+ }, globalOptions);
656
+ // history-repair only re-anchors the audit stream; item content is untouched,
657
+ // so search caches do not need invalidation.
658
+ printResult(result, globalOptions);
659
+ if (globalOptions.profile) {
660
+ printError(`profile:command=history-repair took_ms=${Date.now() - startedAt}`);
661
+ }
662
+ });
663
+ const schemaCommand = program
664
+ .command("schema")
665
+ .argument("[subcommand]", "Schema subcommand: add-type")
666
+ .argument("[name]", "Custom item type name (for add-type)")
667
+ .option("--description <text>", "Human description for the custom item type")
668
+ .option("--default-status <status>", "Default status hint recorded for the custom item type")
669
+ .option("--folder <dir>", "Storage folder for items of this custom type")
670
+ .option("--alias <name>", "Alias for the custom type (repeatable, csv-friendly)", collect)
671
+ .option("--author <value>", "Mutation author")
672
+ .option("--force", "Force ownership/lock override")
673
+ .description("Manage config-driven runtime schema: register custom item types into .agents/pm/schema/types.json.");
674
+ // Hidden pure snake_case underscore-duplicate alias.
675
+ addHiddenOption(schemaCommand, "--default_status <status>", "Alias for --default-status", false);
676
+ schemaCommand
677
+ .action(async (subcommand, name, options, command) => {
678
+ const globalOptions = getGlobalOptions(command);
679
+ const startedAt = Date.now();
680
+ const { runSchemaAddType, formatSchemaAddTypeHuman, SCHEMA_SUBCOMMANDS } = await loadMutationCommandsModule();
681
+ const normalizedSubcommand = (subcommand ?? "").trim().toLowerCase();
682
+ if (!normalizedSubcommand) {
683
+ throw new PmCliError(`pm schema requires a subcommand. Allowed: ${SCHEMA_SUBCOMMANDS.join(", ")}`, EXIT_CODE.USAGE, {
684
+ code: "missing_required_argument",
685
+ examples: [
686
+ 'pm schema add-type Spike --description "Time-boxed investigation" --default-status open',
687
+ 'pm schema add-type Spike --alias spike --alias research',
688
+ ],
689
+ });
690
+ }
691
+ if (!SCHEMA_SUBCOMMANDS.includes(normalizedSubcommand)) {
692
+ throw new PmCliError(`Unknown pm schema subcommand "${subcommand}". Allowed: ${SCHEMA_SUBCOMMANDS.join(", ")}`, EXIT_CODE.USAGE, { code: "unknown_subcommand" });
693
+ }
694
+ const aliases = Array.isArray(options.alias) ? options.alias : undefined;
695
+ const defaultStatus = typeof options.defaultStatus === "string"
696
+ ? options.defaultStatus
697
+ : typeof options.default_status === "string"
698
+ ? options.default_status
699
+ : undefined;
700
+ const result = await runSchemaAddType(name, {
701
+ description: typeof options.description === "string" ? options.description : undefined,
702
+ defaultStatus,
703
+ folder: typeof options.folder === "string" ? options.folder : undefined,
704
+ alias: aliases,
705
+ author: typeof options.author === "string" ? options.author : undefined,
706
+ force: Boolean(options.force),
707
+ }, globalOptions);
708
+ // Registering a type does not touch item content, so search caches stay valid.
709
+ if (globalOptions.json === true || globalOptions.defaultOutputFormat === "json") {
710
+ printResult(result, globalOptions);
711
+ }
712
+ else if (!globalOptions.quiet) {
713
+ writeStdout(`${formatSchemaAddTypeHuman(result)}\n`);
714
+ // Surface extension on-write hook diagnostics so policy/enforcement
715
+ // warnings are visible without forcing --json.
716
+ if (result.warnings.length > 0) {
717
+ printError(`schema add-type warnings: ${formatHookWarnings(result.warnings)}`);
718
+ }
719
+ }
720
+ if (globalOptions.profile) {
721
+ printError(`profile:command=schema took_ms=${Date.now() - startedAt}`);
722
+ }
723
+ });
558
724
  program
559
725
  .command("comments")
560
726
  .argument("<id>", "Item id")
@@ -763,6 +929,7 @@ export function registerMutationCommands(program) {
763
929
  .option("--add-glob <value>", "Add linked doc entries from a glob (plain glob or pattern=<glob>,scope=<scope>,note=<text>; repeatable)", collect)
764
930
  .option("--remove <value>", "Remove linked doc by path (path=<value>, path:<value>, plain path, or - for stdin)", collect)
765
931
  .option("--migrate <value>", "Migrate linked doc paths in-place (from=<prefix>,to=<prefix>; repeatable)", collect)
932
+ .option("--list", "List linked docs without mutating")
766
933
  .option("--validate-paths", "Validate linked doc paths for existence and file shape")
767
934
  .option("--audit", "Audit linked doc usage across all items for this item's linked paths")
768
935
  .option("--author <value>", "Mutation author")
@@ -782,6 +949,7 @@ export function registerMutationCommands(program) {
782
949
  addGlob: addGlobValues,
783
950
  remove: removeValues,
784
951
  migrate: migrateValues,
952
+ list: Boolean(options.list),
785
953
  validatePaths: Boolean(options.validatePaths),
786
954
  audit: Boolean(options.audit),
787
955
  author: typeof options.author === "string" ? options.author : undefined,
@@ -821,4 +989,4 @@ export function registerMutationCommands(program) {
821
989
  });
822
990
  }
823
991
  //# sourceMappingURL=register-mutation.js.map
824
- //# debugId=df6717c1-afaf-5933-945b-32b84cacd324
992
+ //# debugId=634fa316-811c-5a12-a391-225313b2c754