@unbrained/pm-cli 2026.5.24 → 2026.5.28

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 (246) hide show
  1. package/CHANGELOG.md +953 -522
  2. package/README.md +2 -10
  3. package/dist/cli/bootstrap-args.d.ts +18 -1
  4. package/dist/cli/bootstrap-args.js +143 -3
  5. package/dist/cli/bootstrap-args.js.map +1 -1
  6. package/dist/cli/commander-usage.js +134 -11
  7. package/dist/cli/commander-usage.js.map +1 -1
  8. package/dist/cli/commands/append.js +4 -3
  9. package/dist/cli/commands/append.js.map +1 -1
  10. package/dist/cli/commands/claim.js +5 -4
  11. package/dist/cli/commands/claim.js.map +1 -1
  12. package/dist/cli/commands/close.d.ts +3 -0
  13. package/dist/cli/commands/close.js +26 -3
  14. package/dist/cli/commands/close.js.map +1 -1
  15. package/dist/cli/commands/completion.d.ts +2 -2
  16. package/dist/cli/commands/completion.js +109 -56
  17. package/dist/cli/commands/completion.js.map +1 -1
  18. package/dist/cli/commands/config.d.ts +1 -1
  19. package/dist/cli/commands/config.js +82 -4
  20. package/dist/cli/commands/config.js.map +1 -1
  21. package/dist/cli/commands/create.js +7 -272
  22. package/dist/cli/commands/create.js.map +1 -1
  23. package/dist/cli/commands/delete.js +4 -3
  24. package/dist/cli/commands/delete.js.map +1 -1
  25. package/dist/cli/commands/docs.d.ts +1 -12
  26. package/dist/cli/commands/docs.js +8 -312
  27. package/dist/cli/commands/docs.js.map +1 -1
  28. package/dist/cli/commands/extension/bundled-catalog.d.ts +14 -0
  29. package/dist/cli/commands/extension/bundled-catalog.js +268 -0
  30. package/dist/cli/commands/extension/bundled-catalog.js.map +1 -0
  31. package/dist/cli/commands/extension/doctor.d.ts +31 -0
  32. package/dist/cli/commands/extension/doctor.js +345 -0
  33. package/dist/cli/commands/extension/doctor.js.map +1 -0
  34. package/dist/cli/commands/extension/install-sources.d.ts +37 -0
  35. package/dist/cli/commands/extension/install-sources.js +384 -0
  36. package/dist/cli/commands/extension/install-sources.js.map +1 -0
  37. package/dist/cli/commands/extension/managed-state.d.ts +48 -0
  38. package/dist/cli/commands/extension/managed-state.js +172 -0
  39. package/dist/cli/commands/extension/managed-state.js.map +1 -0
  40. package/dist/cli/commands/extension/scaffold.d.ts +14 -0
  41. package/dist/cli/commands/extension/scaffold.js +202 -0
  42. package/dist/cli/commands/extension/scaffold.js.map +1 -0
  43. package/dist/cli/commands/extension/shared.d.ts +14 -0
  44. package/dist/cli/commands/extension/shared.js +106 -0
  45. package/dist/cli/commands/extension/shared.js.map +1 -0
  46. package/dist/cli/commands/extension.d.ts +36 -68
  47. package/dist/cli/commands/extension.js +143 -1422
  48. package/dist/cli/commands/extension.js.map +1 -1
  49. package/dist/cli/commands/files.d.ts +1 -12
  50. package/dist/cli/commands/files.js +11 -308
  51. package/dist/cli/commands/files.js.map +1 -1
  52. package/dist/cli/commands/get.js +4 -3
  53. package/dist/cli/commands/get.js.map +1 -1
  54. package/dist/cli/commands/health.js +17 -3
  55. package/dist/cli/commands/health.js.map +1 -1
  56. package/dist/cli/commands/history-redact.js +23 -18
  57. package/dist/cli/commands/history-redact.js.map +1 -1
  58. package/dist/cli/commands/history-repair.js +24 -18
  59. package/dist/cli/commands/history-repair.js.map +1 -1
  60. package/dist/cli/commands/legacy-none-tokens.d.ts +3 -0
  61. package/dist/cli/commands/legacy-none-tokens.js +39 -0
  62. package/dist/cli/commands/legacy-none-tokens.js.map +1 -0
  63. package/dist/cli/commands/linked-artifacts.d.ts +96 -0
  64. package/dist/cli/commands/linked-artifacts.js +335 -0
  65. package/dist/cli/commands/linked-artifacts.js.map +1 -0
  66. package/dist/cli/commands/linked-test-parsers.d.ts +28 -0
  67. package/dist/cli/commands/linked-test-parsers.js +192 -0
  68. package/dist/cli/commands/linked-test-parsers.js.map +1 -0
  69. package/dist/cli/commands/list.js +19 -5
  70. package/dist/cli/commands/list.js.map +1 -1
  71. package/dist/cli/commands/normalize.js +4 -3
  72. package/dist/cli/commands/normalize.js.map +1 -1
  73. package/dist/cli/commands/plan.d.ts +5 -0
  74. package/dist/cli/commands/plan.js +56 -8
  75. package/dist/cli/commands/plan.js.map +1 -1
  76. package/dist/cli/commands/recurrence-parsers.d.ts +26 -0
  77. package/dist/cli/commands/recurrence-parsers.js +98 -0
  78. package/dist/cli/commands/recurrence-parsers.js.map +1 -0
  79. package/dist/cli/commands/restore.js +19 -8
  80. package/dist/cli/commands/restore.js.map +1 -1
  81. package/dist/cli/commands/search.js +5 -8
  82. package/dist/cli/commands/search.js.map +1 -1
  83. package/dist/cli/commands/test/linked-command-detection.d.ts +37 -0
  84. package/dist/cli/commands/test/linked-command-detection.js +200 -0
  85. package/dist/cli/commands/test/linked-command-detection.js.map +1 -0
  86. package/dist/cli/commands/test.d.ts +1 -2
  87. package/dist/cli/commands/test.js +8 -350
  88. package/dist/cli/commands/test.js.map +1 -1
  89. package/dist/cli/commands/update-many.js +4 -3
  90. package/dist/cli/commands/update-many.js.map +1 -1
  91. package/dist/cli/commands/update.js +83 -356
  92. package/dist/cli/commands/update.js.map +1 -1
  93. package/dist/cli/commands/validate.js +32 -12
  94. package/dist/cli/commands/validate.js.map +1 -1
  95. package/dist/cli/error-guidance.d.ts +1 -0
  96. package/dist/cli/error-guidance.js +6 -2
  97. package/dist/cli/error-guidance.js.map +1 -1
  98. package/dist/cli/main.d.ts +11 -0
  99. package/dist/cli/main.js +76 -28
  100. package/dist/cli/main.js.map +1 -1
  101. package/dist/cli/register-list-query.d.ts +4 -1
  102. package/dist/cli/register-list-query.js +242 -203
  103. package/dist/cli/register-list-query.js.map +1 -1
  104. package/dist/cli/register-mutation.js +73 -11
  105. package/dist/cli/register-mutation.js.map +1 -1
  106. package/dist/cli/register-operations.js +3 -3
  107. package/dist/cli/register-operations.js.map +1 -1
  108. package/dist/cli/register-setup.js +12 -7
  109. package/dist/cli/register-setup.js.map +1 -1
  110. package/dist/cli/registration-helpers.js +3 -2
  111. package/dist/cli/registration-helpers.js.map +1 -1
  112. package/dist/cli.js +4 -3
  113. package/dist/cli.js.map +1 -1
  114. package/dist/core/config/positional-value.d.ts +44 -0
  115. package/dist/core/config/positional-value.js +109 -0
  116. package/dist/core/config/positional-value.js.map +1 -0
  117. package/dist/core/extensions/extension-capability-aliases.d.ts +14 -0
  118. package/dist/core/extensions/extension-capability-aliases.js +159 -0
  119. package/dist/core/extensions/extension-capability-aliases.js.map +1 -0
  120. package/dist/core/extensions/extension-hook-runtime.d.ts +13 -0
  121. package/dist/core/extensions/extension-hook-runtime.js +414 -0
  122. package/dist/core/extensions/extension-hook-runtime.js.map +1 -0
  123. package/dist/core/extensions/extension-policy.d.ts +69 -0
  124. package/dist/core/extensions/extension-policy.js +481 -0
  125. package/dist/core/extensions/extension-policy.js.map +1 -0
  126. package/dist/core/extensions/extension-registries.d.ts +8 -0
  127. package/dist/core/extensions/extension-registries.js +52 -0
  128. package/dist/core/extensions/extension-registries.js.map +1 -0
  129. package/dist/core/extensions/extension-runtime-helpers.d.ts +6 -0
  130. package/dist/core/extensions/extension-runtime-helpers.js +29 -0
  131. package/dist/core/extensions/extension-runtime-helpers.js.map +1 -0
  132. package/dist/core/extensions/extension-types.d.ts +13 -39
  133. package/dist/core/extensions/extension-types.js +34 -2
  134. package/dist/core/extensions/extension-types.js.map +1 -1
  135. package/dist/core/extensions/index.d.ts +7 -0
  136. package/dist/core/extensions/index.js +11 -2
  137. package/dist/core/extensions/index.js.map +1 -1
  138. package/dist/core/extensions/loader.d.ts +4 -22
  139. package/dist/core/extensions/loader.js +22 -1139
  140. package/dist/core/extensions/loader.js.map +1 -1
  141. package/dist/core/history/drift-scan.d.ts +11 -0
  142. package/dist/core/history/drift-scan.js +114 -32
  143. package/dist/core/history/drift-scan.js.map +1 -1
  144. package/dist/core/history/history-rewrite.d.ts +43 -0
  145. package/dist/core/history/history-rewrite.js +48 -0
  146. package/dist/core/history/history-rewrite.js.map +1 -0
  147. package/dist/core/history/history.js +5 -4
  148. package/dist/core/history/history.js.map +1 -1
  149. package/dist/core/history/replay.js +4 -3
  150. package/dist/core/history/replay.js.map +1 -1
  151. package/dist/core/item/item-record.d.ts +19 -0
  152. package/dist/core/item/item-record.js +24 -0
  153. package/dist/core/item/item-record.js.map +1 -0
  154. package/dist/core/output/mutation-projection.d.ts +31 -0
  155. package/dist/core/output/mutation-projection.js +103 -0
  156. package/dist/core/output/mutation-projection.js.map +1 -0
  157. package/dist/core/output/output.d.ts +2 -0
  158. package/dist/core/output/output.js +5 -3
  159. package/dist/core/output/output.js.map +1 -1
  160. package/dist/core/schema/runtime-schema.js +8 -38
  161. package/dist/core/schema/runtime-schema.js.map +1 -1
  162. package/dist/core/search/vector-stores.js +46 -9
  163. package/dist/core/search/vector-stores.js.map +1 -1
  164. package/dist/core/sentry/helpers.d.ts +1 -1
  165. package/dist/core/sentry/helpers.js +20 -3
  166. package/dist/core/sentry/helpers.js.map +1 -1
  167. package/dist/core/shared/command-types.d.ts +1 -0
  168. package/dist/core/shared/command-types.js +2 -2
  169. package/dist/core/shared/command-types.js.map +1 -1
  170. package/dist/core/shared/constants.d.ts +10 -1
  171. package/dist/core/shared/constants.js +56 -58
  172. package/dist/core/shared/constants.js.map +1 -1
  173. package/dist/core/shared/levenshtein.js +23 -7
  174. package/dist/core/shared/levenshtein.js.map +1 -1
  175. package/dist/core/shared/primitives.d.ts +23 -0
  176. package/dist/core/shared/primitives.js +39 -2
  177. package/dist/core/shared/primitives.js.map +1 -1
  178. package/dist/core/store/front-matter-cache.d.ts +16 -2
  179. package/dist/core/store/front-matter-cache.js +99 -33
  180. package/dist/core/store/front-matter-cache.js.map +1 -1
  181. package/dist/core/store/item-store.js +8 -73
  182. package/dist/core/store/item-store.js.map +1 -1
  183. package/dist/mcp/server.js +76 -28
  184. package/dist/mcp/server.js.map +1 -1
  185. package/dist/sdk/cli-contracts/enum-contracts.d.ts +20 -0
  186. package/dist/sdk/cli-contracts/enum-contracts.js +156 -0
  187. package/dist/sdk/cli-contracts/enum-contracts.js.map +1 -0
  188. package/dist/sdk/cli-contracts/tool-option-contracts.d.ts +14 -0
  189. package/dist/sdk/cli-contracts/tool-option-contracts.js +243 -0
  190. package/dist/sdk/cli-contracts/tool-option-contracts.js.map +1 -0
  191. package/dist/sdk/cli-contracts/tool-parameter-tables.d.ts +11 -0
  192. package/dist/sdk/cli-contracts/tool-parameter-tables.js +901 -0
  193. package/dist/sdk/cli-contracts/tool-parameter-tables.js.map +1 -0
  194. package/dist/sdk/cli-contracts.d.ts +11 -33
  195. package/dist/sdk/cli-contracts.js +30 -1356
  196. package/dist/sdk/cli-contracts.js.map +1 -1
  197. package/dist/sdk/package-import-adapters.d.ts +74 -0
  198. package/dist/sdk/package-import-adapters.js +186 -0
  199. package/dist/sdk/package-import-adapters.js.map +1 -0
  200. package/dist/sdk/package-runtime-options.d.ts +26 -0
  201. package/dist/sdk/package-runtime-options.js +71 -0
  202. package/dist/sdk/package-runtime-options.js.map +1 -0
  203. package/dist/sdk/runtime.d.ts +2 -0
  204. package/dist/sdk/runtime.js +4 -2
  205. package/dist/sdk/runtime.js.map +1 -1
  206. package/docs/AGENT_GUIDE.md +6 -10
  207. package/docs/CLAUDE_CODE_PLUGIN.md +5 -28
  208. package/docs/CODEX_PLUGIN.md +5 -5
  209. package/docs/COMMANDS.md +19 -3
  210. package/docs/CONFIGURATION.md +15 -0
  211. package/docs/EXTENSIONS.md +4 -63
  212. package/docs/RELEASING.md +4 -4
  213. package/marketplace.json +7 -3
  214. package/package.json +9 -6
  215. package/packages/pm-beads/extensions/beads/index.js +2 -49
  216. package/packages/pm-beads/extensions/beads/index.ts +2 -54
  217. package/packages/pm-beads/extensions/beads/runtime-loader.js +86 -0
  218. package/packages/pm-beads/extensions/beads/runtime-loader.ts +88 -0
  219. package/packages/pm-beads/extensions/beads/runtime.js +26 -115
  220. package/packages/pm-beads/extensions/beads/runtime.ts +33 -132
  221. package/packages/pm-calendar/extensions/calendar/index.js +47 -2
  222. package/packages/pm-calendar/extensions/calendar/index.ts +52 -2
  223. package/packages/pm-calendar/extensions/calendar/runtime.js +1 -0
  224. package/packages/pm-calendar/extensions/calendar/runtime.ts +1 -0
  225. package/packages/pm-governance-audit/extensions/governance-audit/runtime.js +14 -41
  226. package/packages/pm-governance-audit/extensions/governance-audit/runtime.ts +25 -41
  227. package/packages/pm-guide-shell/extensions/guide-shell/runtime.js +10 -50
  228. package/packages/pm-guide-shell/extensions/guide-shell/runtime.ts +17 -50
  229. package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/runtime.js +8 -40
  230. package/packages/pm-linked-test-adapters/extensions/linked-test-adapters/runtime.ts +10 -40
  231. package/packages/pm-search-advanced/extensions/search-advanced/index.js +1 -1
  232. package/packages/pm-search-advanced/extensions/search-advanced/runtime.js +4 -37
  233. package/packages/pm-search-advanced/extensions/search-advanced/runtime.ts +6 -37
  234. package/packages/pm-todos/extensions/todos/index.js +3 -50
  235. package/packages/pm-todos/extensions/todos/index.ts +3 -55
  236. package/packages/pm-todos/extensions/todos/runtime-loader.js +86 -0
  237. package/packages/pm-todos/extensions/todos/runtime-loader.ts +88 -0
  238. package/packages/pm-todos/extensions/todos/runtime.js +24 -117
  239. package/packages/pm-todos/extensions/todos/runtime.ts +32 -129
  240. package/plugins/pm-claude/README.md +2 -2
  241. package/plugins/pm-claude/commands/pm-planner.md +1 -15
  242. package/plugins/pm-claude/scripts/pm-mcp-server.mjs +5 -2
  243. package/plugins/pm-claude/skills/pm-planner/SKILL.md +3 -21
  244. package/plugins/pm-codex/scripts/pm-mcp-server.mjs +15 -6
  245. package/plugins/pm-codex/skills/pm-native/SKILL.md +1 -13
  246. package/PRD.md +0 -1734
@@ -7,35 +7,32 @@ import {
7
7
  ISSUE_SEVERITY_VALUES,
8
8
  PmCliError,
9
9
  RISK_VALUES,
10
- acquireLock,
11
- appendHistoryEntry,
12
10
  canonicalDocument,
13
- createHistoryEntry,
11
+ commitImportedItem,
14
12
  generateItemId,
15
13
  getActiveExtensionRegistrations,
16
- getHistoryPath,
17
14
  getItemPath,
18
- getSettingsPath,
19
15
  listAllFrontMatter,
20
16
  locateItem,
21
17
  normalizeFrontMatter,
22
18
  normalizeItemId,
23
- normalizeStatusInput,
24
19
  nowIso,
25
- parseTags,
26
- pathExists,
27
20
  readLocatedItem,
28
21
  readSettings,
29
- removeFileIfExists,
30
22
  resolveItemTypeRegistry,
31
23
  resolvePmRoot,
32
24
  runActiveOnReadHooks,
33
25
  runActiveOnWriteHooks,
34
- serializeItemDocument,
26
+ selectImportAuthor,
35
27
  splitFrontMatter,
28
+ ensureTrackerInitialized,
29
+ toEstimatedMinutesValue,
30
+ toImportPriority,
31
+ toImportStatus,
32
+ toImportTags,
33
+ toNonEmptyImportString,
36
34
  writeFileAtomic,
37
35
  type GlobalOptions,
38
- type ItemDocument,
39
36
  type ItemMetadata,
40
37
  type ItemStatus,
41
38
  type ItemType,
@@ -92,18 +89,16 @@ interface TodosImportRuntime {
92
89
 
93
90
  type ImportCandidateResult = { id: string; writeWarnings: string[] } | { warning: string };
94
91
 
92
+ // Shared, behavior-identical value coercers are sourced from the SDK adapter
93
+ // surface; package-specific mappings (lenient timestamps, type-name resolution,
94
+ // confidence/enum coercion) stay local below.
95
+ const toNonEmptyString = toNonEmptyImportString;
96
+ const toEstimatedMinutes = toEstimatedMinutesValue;
97
+
95
98
  function isRecord(value: unknown): value is Record<string, unknown> {
96
99
  return typeof value === "object" && value !== null && !Array.isArray(value);
97
100
  }
98
101
 
99
- function toNonEmptyString(value: unknown): string | undefined {
100
- if (typeof value !== "string") {
101
- return undefined;
102
- }
103
- const trimmed = value.trim();
104
- return trimmed.length > 0 ? trimmed : undefined;
105
- }
106
-
107
102
  function toIsoString(value: unknown): string | undefined {
108
103
  const raw = toNonEmptyString(value);
109
104
  if (!raw) {
@@ -116,19 +111,6 @@ function toIsoString(value: unknown): string | undefined {
116
111
  return new Date(timestamp).toISOString();
117
112
  }
118
113
 
119
- function toEstimatedMinutes(value: unknown): number | undefined {
120
- if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
121
- return value;
122
- }
123
- if (typeof value === "string" && value.trim().length > 0) {
124
- const parsed = Number(value);
125
- if (Number.isFinite(parsed) && parsed >= 0) {
126
- return parsed;
127
- }
128
- }
129
- return undefined;
130
- }
131
-
132
114
  function toInteger(value: unknown): number | undefined {
133
115
  if (typeof value === "number" && Number.isInteger(value)) {
134
116
  return value;
@@ -142,18 +124,7 @@ function toInteger(value: unknown): number | undefined {
142
124
  return undefined;
143
125
  }
144
126
 
145
- function toPriority(value: unknown): PriorityValue {
146
- if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 4) {
147
- return value as PriorityValue;
148
- }
149
- if (typeof value === "string" && value.trim().length > 0) {
150
- const parsed = Number(value);
151
- if (Number.isInteger(parsed) && parsed >= 0 && parsed <= 4) {
152
- return parsed as PriorityValue;
153
- }
154
- }
155
- return 2;
156
- }
127
+ const toPriority: (value: unknown) => PriorityValue = toImportPriority;
157
128
 
158
129
  function toConfidence(value: unknown): ItemMetadata["confidence"] | undefined {
159
130
  if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 100) {
@@ -221,19 +192,7 @@ function toBoolean(value: unknown): boolean | undefined {
221
192
  return undefined;
222
193
  }
223
194
 
224
- function toTags(value: unknown): string[] {
225
- if (Array.isArray(value)) {
226
- const tags = value
227
- .filter((entry): entry is string => typeof entry === "string")
228
- .map((entry) => entry.trim().toLowerCase())
229
- .filter((entry) => entry.length > 0);
230
- return Array.from(new Set(tags)).sort((left, right) => left.localeCompare(right));
231
- }
232
- if (typeof value === "string") {
233
- return parseTags(value);
234
- }
235
- return [];
236
- }
195
+ const toTags = toImportTags;
237
196
 
238
197
  function toItemType(value: unknown, typeNames: string[]): ItemType {
239
198
  const normalized = toNonEmptyString(value)?.toLowerCase();
@@ -249,42 +208,14 @@ function toItemType(value: unknown, typeNames: string[]): ItemType {
249
208
  return fallbackType;
250
209
  }
251
210
 
252
- function toStatus(value: unknown): ItemStatus {
253
- const normalized = toNonEmptyString(value);
254
- if (normalized) {
255
- const canonical = normalizeStatusInput(normalized);
256
- if (canonical) {
257
- return canonical;
258
- }
259
- }
260
- return "open";
261
- }
262
-
263
- function selectAuthor(explicitAuthor: string | undefined, settingsAuthor: string): string {
264
- const candidate = explicitAuthor ?? process.env.PM_AUTHOR ?? settingsAuthor;
265
- const trimmed = candidate.trim();
266
- return trimmed.length > 0 ? trimmed : "unknown";
267
- }
268
-
269
- function ensureInitHasRun(pmRoot: string): Promise<void> {
270
- return pathExists(getSettingsPath(pmRoot)).then((exists) => {
271
- if (!exists) {
272
- throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
273
- }
274
- });
275
- }
211
+ const toStatus: (value: unknown) => ItemStatus = toImportStatus;
212
+ const selectAuthor = selectImportAuthor;
213
+ const ensureInitHasRun = ensureTrackerInitialized;
276
214
 
277
215
  function normalizeBody(body: string): string {
278
216
  return body.replace(/^\n+/, "").replace(/\s+$/, "");
279
217
  }
280
218
 
281
- function emptyDocument(): ItemDocument {
282
- return {
283
- metadata: {} as ItemMetadata,
284
- body: "",
285
- };
286
- }
287
-
288
219
  function resolveFolderPath(rawPath: string): string {
289
220
  return path.isAbsolute(rawPath) ? rawPath : path.resolve(process.cwd(), rawPath);
290
221
  }
@@ -417,49 +348,21 @@ async function importTodoCandidate(candidate: ParsedTodoCandidate, runtime: Todo
417
348
  body: candidate.body,
418
349
  });
419
350
 
420
- const historyPath = getHistoryPath(runtime.pmRoot, id);
421
- let writeWarnings: string[] = [];
422
- try {
423
- const releaseLock = await acquireLock(runtime.pmRoot, id, runtime.settings.locks.ttl_seconds, runtime.author);
424
- try {
425
- await writeFileAtomic(itemPath, serializeItemDocument(afterDocument, { format: "toon" }));
426
- try {
427
- const historyEntry = createHistoryEntry({
428
- nowIso: nowIso(),
429
- author: runtime.author,
430
- op: "import",
431
- before: emptyDocument(),
432
- after: afterDocument,
433
- message: runtime.message,
434
- });
435
- await appendHistoryEntry(historyPath, historyEntry);
436
- writeWarnings = [
437
- ...(await runActiveOnWriteHooks({
438
- path: itemPath,
439
- scope: "project",
440
- op: "import",
441
- })),
442
- ...(await runActiveOnWriteHooks({
443
- path: historyPath,
444
- scope: "project",
445
- op: "import:history",
446
- })),
447
- ];
448
- } catch (error: unknown) {
449
- await removeFileIfExists(itemPath);
450
- throw error;
451
- }
452
- } finally {
453
- await releaseLock();
454
- }
455
- } catch (error: unknown) {
456
- if (error instanceof PmCliError && error.exitCode === EXIT_CODE.CONFLICT) {
457
- return { warning: `todos_import_lock_conflict:${id}` };
458
- }
459
- throw error;
351
+ const commit = await commitImportedItem({
352
+ pmRoot: runtime.pmRoot,
353
+ id,
354
+ itemPath,
355
+ document: afterDocument,
356
+ author: runtime.author,
357
+ message: runtime.message,
358
+ settings: runtime.settings,
359
+ conflictWarningPrefix: "todos_import_lock_conflict",
360
+ });
361
+ if (!commit.committed) {
362
+ return { warning: commit.conflictWarning };
460
363
  }
461
364
 
462
- return { id, writeWarnings };
365
+ return { id, writeWarnings: commit.writeWarnings };
463
366
  }
464
367
 
465
368
  export async function runTodosImport(options: TodosImportOptions, global: GlobalOptions): Promise<TodosImportResult> {
@@ -9,7 +9,7 @@ Native pm CLI integration for Claude Code. Use pm project management tools direc
9
9
  | **18 MCP tools** | Full pm surface: context, search, list, get, create, update, claim, release, close, comments, files, docs, test, validate, health, contracts, plan + `pm_run` for everything else |
10
10
  | **5 skills** | `pm-workflow`, `pm-developer`, `pm-release`, `pm-audit`, `pm-planner` — auto-loaded as Claude Code skills |
11
11
  | **14 slash commands** | Full lifecycle coverage — status, start, close, triage, audit, search, new, list, calendar, developer, planner, release, workflow, init |
12
- | **3 subagents** | `pm-coordinator` (batch/multi-item), `pm-triage-agent` (duplicate-safe item creation), `pm-verification-agent` (evidence + close readiness), and a `pm-delivery-chain` orchestrator |
12
+ | **4 subagents** | `pm-coordinator` (batch/multi-item), `pm-triage-agent` (duplicate-safe item creation), `pm-verification-agent` (evidence + close readiness), and `pm-delivery-chain` (orchestrated delivery) |
13
13
  | **Hybrid TUI tracking** | pm items sync to Claude Code's task panel — pm is the persistent store, the task panel is the live session view |
14
14
  | **Session hook** | Injects active pm item summary at session start when pm is initialized (uses native modules, no CLI required) |
15
15
 
@@ -29,7 +29,7 @@ claude plugin marketplace add /path/to/pm-cli
29
29
  # claude plugin marketplace add unbraind/pm-cli
30
30
  ```
31
31
 
32
- This installs all 18 MCP tools, 5 skills, 14 slash commands, 3 subagents, hybrid TUI tracking, and the session hook in one step.
32
+ This installs all 18 MCP tools, 5 skills, 14 slash commands, 4 subagents, hybrid TUI tracking, and the session hook in one step.
33
33
 
34
34
  ### Option B: Legacy marketplace alias (also works)
35
35
 
@@ -52,18 +52,4 @@ Run the pm planning loop using native MCP tools. Argument: `$ARGUMENTS` (optiona
52
52
 
53
53
  ## Living plan mode (`pm_plan`)
54
54
 
55
- If the user wants a Codex-style ExecPlan / Claude Plan Mode / Cursor plan-and-edit flow rather than a flat backlog, use the built-in `Plan` item type via the `pm_plan` MCP tool. It records ordered steps, evidence, decisions, discoveries, validation, and supports materializing steps into real Tasks/Features.
56
-
57
- ```json
58
- { "tool": "pm_plan", "args": { "options": { "subcommand": "create", "title": "Plan title", "scope": "What this plan changes", "harness": "claude-code", "parent": "pm-epic1", "claim": true } } }
59
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "add-step", "stepTitle": "Read affected files", "dependsOn": "pm-task1" } } }
60
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "stepRef": "plan-step-001", "options": { "subcommand": "complete-step", "stepEvidence": "files reviewed" } } }
61
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "approve" } } }
62
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "materialize", "steps": "plan-step-002,plan-step-003", "materializeType": "Task" } } }
63
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "show", "depth": "deep" } } }
64
- ```
65
-
66
- Resume a plan after compaction:
67
- ```json
68
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "resume", "resumeContext": "step 2 in progress; tests still failing on retry path" } } }
69
- ```
55
+ If the user wants a Codex-style ExecPlan / Claude Plan Mode / Cursor plan-and-edit flow rather than a flat backlog, use the built-in `Plan` item type via the `pm_plan` MCP tool. The canonical lifecycle recipe lives in [Command Reference: Plan Workflow](../../../docs/COMMANDS.md#plan-workflow); this slash command should add only Claude-specific context such as `harness: "claude-code"` and concise `resumeContext` after compaction.
@@ -1,11 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * pm-cli native MCP server launcher for Claude Code.
3
+ * pm-cli native MCP server launcher (Claude Code / Codex plugin).
4
+ *
5
+ * GENERATED by scripts/gen-plugin-mcp-wrappers.mjs — do not edit directly.
6
+ * Edit the template in that generator and re-run it to update both plugins.
4
7
  *
5
8
  * Resolution order:
6
9
  * 1. PM_CLI_MCP_SERVER env var (explicit path)
7
10
  * 2. dist/mcp/server.js walking up from this file (repo checkout)
8
- * 3. npx -y @unbrained/pm-cli@latest pm-mcp (installed via npm)
11
+ * 3. npx -y --package=@unbrained/pm-cli@latest pm-mcp (installed via npm)
9
12
  */
10
13
  import { spawn } from "node:child_process";
11
14
  import { access } from "node:fs/promises";
@@ -113,34 +113,16 @@ Set via `pm_create` with `acceptanceCriteria` field or `pm_update` with `options
113
113
 
114
114
  ## Built-in Plan workflow (`pm_plan` / `pm plan`)
115
115
 
116
- For durable Codex-style ExecPlans, Claude-style Plan Mode, and Cursor-style editable checklists, pm exposes a first-class `Plan` item type plus a `pm plan` command family. Plans are stored as normal pm items under `.agents/pm/plans/`, get the full history hash chain, dependencies, search corpus, and lifecycle tooling.
116
+ For durable Codex-style ExecPlans, Claude-style Plan Mode, and Cursor-style editable checklists, pm exposes a first-class `Plan` item type plus a `pm plan` command family. Use [Command Reference: Plan Workflow](../../../../docs/COMMANDS.md#plan-workflow) as the canonical lifecycle recipe; this skill keeps only Claude-specific routing notes.
117
117
 
118
118
  ### When to use `pm plan` vs. `pm_create` + tasks
119
119
 
120
120
  - `pm plan` — when you need a **living, resumable plan** with ordered steps, evidence, decisions, discoveries, validation, and the option to later materialize selected steps as real Tasks. Best for plan-then-execute workflows.
121
121
  - `pm_create` (Epic/Feature/Task) — when the work is already decomposed and you just need persistent backlog items.
122
122
 
123
- ### Lifecycle (call via `pm_plan` MCP tool)
123
+ ### Claude MCP routing
124
124
 
125
- ```json
126
- { "tool": "pm_plan", "args": { "options": { "subcommand": "create", "title": "Refactor lock retry", "scope": "Improve retry semantics", "harness": "claude-code", "parent": "pm-epic1", "related": "pm-rel1,pm-rel2", "claim": true } } }
127
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "add-step", "stepTitle": "Read lock.ts", "stepBody": "Understand retry path", "dependsOn": "pm-task1" } } }
128
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "stepRef": "plan-step-001", "options": { "subcommand": "update-step", "stepStatus": "in_progress", "stepEvidence": "started reading lock.ts" } } }
129
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "stepRef": "plan-step-001", "options": { "subcommand": "complete-step", "stepEvidence": "lock.ts read; retry path captured" } } }
130
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "decision", "decisionText": "Use exponential backoff", "decisionRationale": "Avoid thundering herd" } } }
131
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "discovery", "discoveryText": "Found existing util in src/util/retry.ts" } } }
132
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "validation", "validationText": "Coverage gate stays at 100%", "validationCommand": "node scripts/run-tests.mjs coverage" } } }
133
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "approve" } } }
134
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "materialize", "steps": "plan-step-002", "materializeType": "Task", "materializeParent": "pm-epic1" } } }
135
- ```
136
-
137
- ### Progressive-disclosure reads
138
-
139
- ```json
140
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "show", "depth": "brief" } } }
141
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "show", "depth": "standard" } } }
142
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "show", "depth": "deep" } } }
143
- ```
125
+ Call the same lifecycle through the `pm_plan` MCP tool. Use `harness: "claude-code"` on creation, `subcommand: "show"` with `depth: "brief"` for low-token reads, and `subcommand: "resume"` after compaction or handoff.
144
126
 
145
127
  ### Harness mapping cheatsheet
146
128
 
@@ -1,4 +1,15 @@
1
1
  #!/usr/bin/env node
2
+ /**
3
+ * pm-cli native MCP server launcher (Claude Code / Codex plugin).
4
+ *
5
+ * GENERATED by scripts/gen-plugin-mcp-wrappers.mjs — do not edit directly.
6
+ * Edit the template in that generator and re-run it to update both plugins.
7
+ *
8
+ * Resolution order:
9
+ * 1. PM_CLI_MCP_SERVER env var (explicit path)
10
+ * 2. dist/mcp/server.js walking up from this file (repo checkout)
11
+ * 3. npx -y --package=@unbrained/pm-cli@latest pm-mcp (installed via npm)
12
+ */
2
13
  import { spawn } from "node:child_process";
3
14
  import { access } from "node:fs/promises";
4
15
  import path from "node:path";
@@ -17,22 +28,20 @@ async function exists(target) {
17
28
 
18
29
  async function findRepoServer() {
19
30
  let cursor = here;
20
- for (let depth = 0; depth < 8; depth += 1) {
31
+ for (let depth = 0; depth < 10; depth += 1) {
21
32
  const candidate = path.join(cursor, "dist", "mcp", "server.js");
22
33
  if (await exists(candidate)) {
23
34
  return candidate;
24
35
  }
25
36
  const parent = path.dirname(cursor);
26
- if (parent === cursor) {
27
- break;
28
- }
37
+ if (parent === cursor) break;
29
38
  cursor = parent;
30
39
  }
31
40
  return null;
32
41
  }
33
42
 
34
43
  const explicitServer = process.env.PM_CLI_MCP_SERVER;
35
- if (explicitServer && await exists(explicitServer)) {
44
+ if (explicitServer && (await exists(explicitServer))) {
36
45
  const server = await import(pathToFileURL(explicitServer).href);
37
46
  server.startMcpServer();
38
47
  } else {
@@ -41,7 +50,7 @@ if (explicitServer && await exists(explicitServer)) {
41
50
  const server = await import(pathToFileURL(repoServer).href);
42
51
  server.startMcpServer();
43
52
  } else {
44
- const child = spawn("npx", ["-y", "@unbrained/pm-cli@latest", "pm-mcp"], {
53
+ const child = spawn("npx", ["-y", "--package=@unbrained/pm-cli@latest", "pm-mcp"], {
45
54
  stdio: "inherit",
46
55
  env: process.env,
47
56
  });
@@ -58,22 +58,10 @@ Most tools accept:
58
58
 
59
59
  ## Plan workflow (`pm_plan`)
60
60
 
61
- Codex-style living ExecPlans are first-class via the `Plan` item type and the `pm_plan` MCP tool. Plans persist ordered steps, evidence, decisions, discoveries, validation, and resume context so a future stateless agent can pick up the work.
61
+ Codex-style living ExecPlans are first-class via the `Plan` item type and the `pm_plan` MCP tool. Use [Command Reference: Plan Workflow](../../../../docs/COMMANDS.md#plan-workflow) as the canonical lifecycle recipe; this skill keeps only Codex-specific routing notes.
62
62
 
63
63
  Use `pm_plan` for plan-then-execute workflows; use `pm_create` with type Task/Feature/Epic for already-decomposed backlog work.
64
64
 
65
- ```json
66
- { "tool": "pm_plan", "args": { "options": { "subcommand": "create", "title": "Refactor lock retry", "scope": "Improve retry semantics under load", "harness": "codex", "parent": "pm-epic1", "claim": true } } }
67
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "add-step", "stepTitle": "Read lock.ts", "dependsOn": "pm-task1" } } }
68
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "stepRef": "plan-step-001", "options": { "subcommand": "update-step", "stepStatus": "in_progress", "stepEvidence": "started reading lock.ts" } } }
69
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "stepRef": "plan-step-001", "options": { "subcommand": "complete-step", "stepEvidence": "lock.ts read; retry path captured" } } }
70
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "decision", "decisionText": "Use exponential backoff", "decisionRationale": "Avoid thundering herd" } } }
71
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "approve" } } }
72
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "materialize", "steps": "plan-step-002", "materializeType": "Task", "materializeParent": "pm-epic1" } } }
73
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "resume", "resumeContext": "step 2 pending, deps verified" } } }
74
- { "tool": "pm_plan", "args": { "id": "pm-plan1", "options": { "subcommand": "show", "depth": "deep" } } }
75
- ```
76
-
77
65
  Invariants:
78
66
 
79
67
  - One step `in_progress` at a time by default; pass `allowMultipleActive: true` for explicit parallel branches.