@unbrained/pm-cli 2026.5.14 → 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 (436) hide show
  1. package/.claude-plugin/marketplace.json +4 -4
  2. package/AGENTS.md +78 -457
  3. package/CHANGELOG.md +71 -0
  4. package/CONTRIBUTING.md +1 -0
  5. package/README.md +8 -6
  6. package/dist/cli/argv-utils.js +4 -1
  7. package/dist/cli/argv-utils.js.map +1 -1
  8. package/dist/cli/bootstrap-args.js +4 -1
  9. package/dist/cli/bootstrap-args.js.map +1 -1
  10. package/dist/cli/commander-usage.js +19 -1
  11. package/dist/cli/commander-usage.js.map +1 -1
  12. package/dist/cli/commands/activity.js +4 -1
  13. package/dist/cli/commands/activity.js.map +1 -1
  14. package/dist/cli/commands/aggregate.js +5 -2
  15. package/dist/cli/commands/aggregate.js.map +1 -1
  16. package/dist/cli/commands/annotation-command.d.ts +49 -0
  17. package/dist/cli/commands/annotation-command.js +135 -0
  18. package/dist/cli/commands/annotation-command.js.map +1 -0
  19. package/dist/cli/commands/append.js +5 -6
  20. package/dist/cli/commands/append.js.map +1 -1
  21. package/dist/cli/commands/calendar.js +5 -5
  22. package/dist/cli/commands/calendar.js.map +1 -1
  23. package/dist/cli/commands/claim.d.ts +3 -0
  24. package/dist/cli/commands/claim.js +29 -23
  25. package/dist/cli/commands/claim.js.map +1 -1
  26. package/dist/cli/commands/close.js +63 -8
  27. package/dist/cli/commands/close.js.map +1 -1
  28. package/dist/cli/commands/comments-audit.js +4 -1
  29. package/dist/cli/commands/comments-audit.js.map +1 -1
  30. package/dist/cli/commands/comments.d.ts +5 -0
  31. package/dist/cli/commands/comments.js +29 -116
  32. package/dist/cli/commands/comments.js.map +1 -1
  33. package/dist/cli/commands/completion.js +198 -15
  34. package/dist/cli/commands/completion.js.map +1 -1
  35. package/dist/cli/commands/config.js +4 -1
  36. package/dist/cli/commands/config.js.map +1 -1
  37. package/dist/cli/commands/context.js +21 -13
  38. package/dist/cli/commands/context.js.map +1 -1
  39. package/dist/cli/commands/contracts.d.ts +9 -0
  40. package/dist/cli/commands/contracts.js +314 -64
  41. package/dist/cli/commands/contracts.js.map +1 -1
  42. package/dist/cli/commands/create.js +77 -48
  43. package/dist/cli/commands/create.js.map +1 -1
  44. package/dist/cli/commands/dedupe-audit.js +9 -3
  45. package/dist/cli/commands/dedupe-audit.js.map +1 -1
  46. package/dist/cli/commands/delete.d.ts +3 -0
  47. package/dist/cli/commands/delete.js +11 -7
  48. package/dist/cli/commands/delete.js.map +1 -1
  49. package/dist/cli/commands/deps.js +4 -1
  50. package/dist/cli/commands/deps.js.map +1 -1
  51. package/dist/cli/commands/docs.d.ts +1 -0
  52. package/dist/cli/commands/docs.js +6 -7
  53. package/dist/cli/commands/docs.js.map +1 -1
  54. package/dist/cli/commands/event-validation-messages.d.ts +3 -0
  55. package/dist/cli/commands/event-validation-messages.js +44 -0
  56. package/dist/cli/commands/event-validation-messages.js.map +1 -0
  57. package/dist/cli/commands/extension.d.ts +3 -1
  58. package/dist/cli/commands/extension.js +259 -52
  59. package/dist/cli/commands/extension.js.map +1 -1
  60. package/dist/cli/commands/files.js +8 -12
  61. package/dist/cli/commands/files.js.map +1 -1
  62. package/dist/cli/commands/gc.js +19 -3
  63. package/dist/cli/commands/gc.js.map +1 -1
  64. package/dist/cli/commands/get.d.ts +10 -5
  65. package/dist/cli/commands/get.js +135 -20
  66. package/dist/cli/commands/get.js.map +1 -1
  67. package/dist/cli/commands/guide.js +6 -8
  68. package/dist/cli/commands/guide.js.map +1 -1
  69. package/dist/cli/commands/health.d.ts +14 -0
  70. package/dist/cli/commands/health.js +269 -67
  71. package/dist/cli/commands/health.js.map +1 -1
  72. package/dist/cli/commands/history-redact.d.ts +50 -0
  73. package/dist/cli/commands/history-redact.js +476 -0
  74. package/dist/cli/commands/history-redact.js.map +1 -0
  75. package/dist/cli/commands/history-repair.d.ts +33 -0
  76. package/dist/cli/commands/history-repair.js +166 -0
  77. package/dist/cli/commands/history-repair.js.map +1 -0
  78. package/dist/cli/commands/history.d.ts +4 -0
  79. package/dist/cli/commands/history.js +12 -79
  80. package/dist/cli/commands/history.js.map +1 -1
  81. package/dist/cli/commands/index.d.ts +5 -1
  82. package/dist/cli/commands/index.js +9 -2
  83. package/dist/cli/commands/index.js.map +1 -1
  84. package/dist/cli/commands/init-agent-guidance.d.ts +31 -0
  85. package/dist/cli/commands/init-agent-guidance.js +336 -0
  86. package/dist/cli/commands/init-agent-guidance.js.map +1 -0
  87. package/dist/cli/commands/init.d.ts +42 -0
  88. package/dist/cli/commands/init.js +96 -1
  89. package/dist/cli/commands/init.js.map +1 -1
  90. package/dist/cli/commands/learnings.js +22 -118
  91. package/dist/cli/commands/learnings.js.map +1 -1
  92. package/dist/cli/commands/linked-test-entry.d.ts +3 -0
  93. package/dist/cli/commands/linked-test-entry.js +62 -0
  94. package/dist/cli/commands/linked-test-entry.js.map +1 -0
  95. package/dist/cli/commands/list.d.ts +1 -0
  96. package/dist/cli/commands/list.js +72 -38
  97. package/dist/cli/commands/list.js.map +1 -1
  98. package/dist/cli/commands/metadata-normalizers.js +4 -1
  99. package/dist/cli/commands/metadata-normalizers.js.map +1 -1
  100. package/dist/cli/commands/normalize.js +4 -1
  101. package/dist/cli/commands/normalize.js.map +1 -1
  102. package/dist/cli/commands/notes.js +22 -118
  103. package/dist/cli/commands/notes.js.map +1 -1
  104. package/dist/cli/commands/plan.d.ts +121 -0
  105. package/dist/cli/commands/plan.js +1137 -0
  106. package/dist/cli/commands/plan.js.map +1 -0
  107. package/dist/cli/commands/reindex.js +4 -1
  108. package/dist/cli/commands/reindex.js.map +1 -1
  109. package/dist/cli/commands/restore.js +9 -49
  110. package/dist/cli/commands/restore.js.map +1 -1
  111. package/dist/cli/commands/schema.d.ts +31 -0
  112. package/dist/cli/commands/schema.js +98 -0
  113. package/dist/cli/commands/schema.js.map +1 -0
  114. package/dist/cli/commands/search.js +156 -40
  115. package/dist/cli/commands/search.js.map +1 -1
  116. package/dist/cli/commands/stats.js +4 -1
  117. package/dist/cli/commands/stats.js.map +1 -1
  118. package/dist/cli/commands/templates.d.ts +4 -0
  119. package/dist/cli/commands/templates.js +91 -16
  120. package/dist/cli/commands/templates.js.map +1 -1
  121. package/dist/cli/commands/test-all.js +6 -7
  122. package/dist/cli/commands/test-all.js.map +1 -1
  123. package/dist/cli/commands/test-runs.js +4 -1
  124. package/dist/cli/commands/test-runs.js.map +1 -1
  125. package/dist/cli/commands/test.d.ts +1 -0
  126. package/dist/cli/commands/test.js +9 -9
  127. package/dist/cli/commands/test.js.map +1 -1
  128. package/dist/cli/commands/update-many.js +6 -7
  129. package/dist/cli/commands/update-many.js.map +1 -1
  130. package/dist/cli/commands/update.js +204 -103
  131. package/dist/cli/commands/update.js.map +1 -1
  132. package/dist/cli/commands/upgrade.js +6 -3
  133. package/dist/cli/commands/upgrade.js.map +1 -1
  134. package/dist/cli/commands/validate.d.ts +3 -1
  135. package/dist/cli/commands/validate.js +44 -64
  136. package/dist/cli/commands/validate.js.map +1 -1
  137. package/dist/cli/error-guidance.js +99 -6
  138. package/dist/cli/error-guidance.js.map +1 -1
  139. package/dist/cli/extension-command-help.d.ts +0 -1
  140. package/dist/cli/extension-command-help.js +4 -12
  141. package/dist/cli/extension-command-help.js.map +1 -1
  142. package/dist/cli/extension-command-options.d.ts +1 -0
  143. package/dist/cli/extension-command-options.js +108 -6
  144. package/dist/cli/extension-command-options.js.map +1 -1
  145. package/dist/cli/guide-topics.js +4 -1
  146. package/dist/cli/guide-topics.js.map +1 -1
  147. package/dist/cli/help-content.d.ts +0 -1
  148. package/dist/cli/help-content.js +46 -22
  149. package/dist/cli/help-content.js.map +1 -1
  150. package/dist/cli/help-json-payload.d.ts +1 -0
  151. package/dist/cli/help-json-payload.js +35 -2
  152. package/dist/cli/help-json-payload.js.map +1 -1
  153. package/dist/cli/main.js +214 -30
  154. package/dist/cli/main.js.map +1 -1
  155. package/dist/cli/migration-gates.js +4 -1
  156. package/dist/cli/migration-gates.js.map +1 -1
  157. package/dist/cli/register-list-query.d.ts +1 -1
  158. package/dist/cli/register-list-query.js +75 -29
  159. package/dist/cli/register-list-query.js.map +1 -1
  160. package/dist/cli/register-mutation.d.ts +1 -1
  161. package/dist/cli/register-mutation.js +430 -38
  162. package/dist/cli/register-mutation.js.map +1 -1
  163. package/dist/cli/register-operations.js +47 -10
  164. package/dist/cli/register-operations.js.map +1 -1
  165. package/dist/cli/register-setup.js +47 -25
  166. package/dist/cli/register-setup.js.map +1 -1
  167. package/dist/cli/registration-helpers.d.ts +0 -2
  168. package/dist/cli/registration-helpers.js +21 -40
  169. package/dist/cli/registration-helpers.js.map +1 -1
  170. package/dist/cli/shared-parsers.js +4 -1
  171. package/dist/cli/shared-parsers.js.map +1 -1
  172. package/dist/cli/telemetry-flush.js +4 -1
  173. package/dist/cli/telemetry-flush.js.map +1 -1
  174. package/dist/cli.js +65 -3
  175. package/dist/cli.js.map +1 -1
  176. package/dist/core/extensions/extension-types.js +4 -1
  177. package/dist/core/extensions/extension-types.js.map +1 -1
  178. package/dist/core/extensions/index.d.ts +0 -1
  179. package/dist/core/extensions/index.js +4 -13
  180. package/dist/core/extensions/index.js.map +1 -1
  181. package/dist/core/extensions/item-fields.js +4 -1
  182. package/dist/core/extensions/item-fields.js.map +1 -1
  183. package/dist/core/extensions/loader.js +78 -60
  184. package/dist/core/extensions/loader.js.map +1 -1
  185. package/dist/core/extensions/runtime-registrations.js +4 -1
  186. package/dist/core/extensions/runtime-registrations.js.map +1 -1
  187. package/dist/core/fs/fs-utils.js +4 -1
  188. package/dist/core/fs/fs-utils.js.map +1 -1
  189. package/dist/core/fs/index.js +4 -1
  190. package/dist/core/fs/index.js.map +1 -1
  191. package/dist/core/fs/path-utils.d.ts +1 -0
  192. package/dist/core/fs/path-utils.js +12 -0
  193. package/dist/core/fs/path-utils.js.map +1 -0
  194. package/dist/core/history/drift-scan.d.ts +11 -0
  195. package/dist/core/history/drift-scan.js +67 -0
  196. package/dist/core/history/drift-scan.js.map +1 -0
  197. package/dist/core/history/history-stream-policy.js +4 -1
  198. package/dist/core/history/history-stream-policy.js.map +1 -1
  199. package/dist/core/history/history.js +4 -1
  200. package/dist/core/history/history.js.map +1 -1
  201. package/dist/core/history/index.js +4 -1
  202. package/dist/core/history/index.js.map +1 -1
  203. package/dist/core/history/replay.d.ts +82 -0
  204. package/dist/core/history/replay.js +249 -0
  205. package/dist/core/history/replay.js.map +1 -0
  206. package/dist/core/item/id.js +4 -1
  207. package/dist/core/item/id.js.map +1 -1
  208. package/dist/core/item/index.js +4 -1
  209. package/dist/core/item/index.js.map +1 -1
  210. package/dist/core/item/item-format.js +250 -8
  211. package/dist/core/item/item-format.js.map +1 -1
  212. package/dist/core/item/item-type-definition.d.ts +52 -0
  213. package/dist/core/item/item-type-definition.js +123 -0
  214. package/dist/core/item/item-type-definition.js.map +1 -0
  215. package/dist/core/item/parent-reference-policy.js +4 -1
  216. package/dist/core/item/parent-reference-policy.js.map +1 -1
  217. package/dist/core/item/parse.js +34 -3
  218. package/dist/core/item/parse.js.map +1 -1
  219. package/dist/core/item/priority.d.ts +23 -0
  220. package/dist/core/item/priority.js +55 -0
  221. package/dist/core/item/priority.js.map +1 -0
  222. package/dist/core/item/sprint-release-format.js +4 -1
  223. package/dist/core/item/sprint-release-format.js.map +1 -1
  224. package/dist/core/item/status.d.ts +14 -1
  225. package/dist/core/item/status.js +24 -1
  226. package/dist/core/item/status.js.map +1 -1
  227. package/dist/core/item/toon-decode.d.ts +19 -0
  228. package/dist/core/item/toon-decode.js +69 -0
  229. package/dist/core/item/toon-decode.js.map +1 -0
  230. package/dist/core/item/type-registry.js +15 -83
  231. package/dist/core/item/type-registry.js.map +1 -1
  232. package/dist/core/lock/index.js +4 -1
  233. package/dist/core/lock/index.js.map +1 -1
  234. package/dist/core/lock/lock.js +4 -1
  235. package/dist/core/lock/lock.js.map +1 -1
  236. package/dist/core/output/output.d.ts +4 -0
  237. package/dist/core/output/output.js +47 -6
  238. package/dist/core/output/output.js.map +1 -1
  239. package/dist/core/packages/manifest.d.ts +1 -0
  240. package/dist/core/packages/manifest.js +6 -8
  241. package/dist/core/packages/manifest.js.map +1 -1
  242. package/dist/core/packages/root.d.ts +3 -0
  243. package/dist/core/packages/root.js +51 -0
  244. package/dist/core/packages/root.js.map +1 -0
  245. package/dist/core/schema/item-types-file.d.ts +85 -0
  246. package/dist/core/schema/item-types-file.js +243 -0
  247. package/dist/core/schema/item-types-file.js.map +1 -0
  248. package/dist/core/schema/runtime-field-filters.js +4 -1
  249. package/dist/core/schema/runtime-field-filters.js.map +1 -1
  250. package/dist/core/schema/runtime-field-values.js +4 -1
  251. package/dist/core/schema/runtime-field-values.js.map +1 -1
  252. package/dist/core/schema/runtime-schema.d.ts +2 -1
  253. package/dist/core/schema/runtime-schema.js +13 -8
  254. package/dist/core/schema/runtime-schema.js.map +1 -1
  255. package/dist/core/search/cache.js +7 -2
  256. package/dist/core/search/cache.js.map +1 -1
  257. package/dist/core/search/corpus.d.ts +2 -0
  258. package/dist/core/search/corpus.js +77 -2
  259. package/dist/core/search/corpus.js.map +1 -1
  260. package/dist/core/search/embedding-batches.js +21 -7
  261. package/dist/core/search/embedding-batches.js.map +1 -1
  262. package/dist/core/search/http-client.js +4 -1
  263. package/dist/core/search/http-client.js.map +1 -1
  264. package/dist/core/search/providers.js +4 -1
  265. package/dist/core/search/providers.js.map +1 -1
  266. package/dist/core/search/semantic-defaults.js +12 -3
  267. package/dist/core/search/semantic-defaults.js.map +1 -1
  268. package/dist/core/search/vector-stores.js +4 -1
  269. package/dist/core/search/vector-stores.js.map +1 -1
  270. package/dist/core/sentry/helpers.js +4 -1
  271. package/dist/core/sentry/helpers.js.map +1 -1
  272. package/dist/core/sentry/instrument.js +10 -13
  273. package/dist/core/sentry/instrument.js.map +1 -1
  274. package/dist/core/shared/author.d.ts +1 -0
  275. package/dist/core/shared/author.js +9 -0
  276. package/dist/core/shared/author.js.map +1 -0
  277. package/dist/core/shared/command-types.js +4 -1
  278. package/dist/core/shared/command-types.js.map +1 -1
  279. package/dist/core/shared/conflict-markers.js +4 -1
  280. package/dist/core/shared/conflict-markers.js.map +1 -1
  281. package/dist/core/shared/constants.d.ts +2 -2
  282. package/dist/core/shared/constants.js +24 -1
  283. package/dist/core/shared/constants.js.map +1 -1
  284. package/dist/core/shared/errors.js +4 -1
  285. package/dist/core/shared/errors.js.map +1 -1
  286. package/dist/core/shared/index.js +4 -1
  287. package/dist/core/shared/index.js.map +1 -1
  288. package/dist/core/shared/lazy-module.d.ts +1 -0
  289. package/dist/core/shared/lazy-module.js +11 -0
  290. package/dist/core/shared/lazy-module.js.map +1 -0
  291. package/dist/core/shared/levenshtein.js +4 -1
  292. package/dist/core/shared/levenshtein.js.map +1 -1
  293. package/dist/core/shared/option-alias-visibility.d.ts +44 -0
  294. package/dist/core/shared/option-alias-visibility.js +76 -0
  295. package/dist/core/shared/option-alias-visibility.js.map +1 -0
  296. package/dist/core/shared/primitives.js +4 -1
  297. package/dist/core/shared/primitives.js.map +1 -1
  298. package/dist/core/shared/serialization.js +4 -1
  299. package/dist/core/shared/serialization.js.map +1 -1
  300. package/dist/core/shared/text-normalization.d.ts +0 -1
  301. package/dist/core/shared/text-normalization.js +4 -4
  302. package/dist/core/shared/text-normalization.js.map +1 -1
  303. package/dist/core/shared/time.js +4 -1
  304. package/dist/core/shared/time.js.map +1 -1
  305. package/dist/core/store/front-matter-cache.js +8 -3
  306. package/dist/core/store/front-matter-cache.js.map +1 -1
  307. package/dist/core/store/index.js +4 -1
  308. package/dist/core/store/index.js.map +1 -1
  309. package/dist/core/store/item-format-migration.js +4 -1
  310. package/dist/core/store/item-format-migration.js.map +1 -1
  311. package/dist/core/store/item-store.d.ts +4 -0
  312. package/dist/core/store/item-store.js +133 -39
  313. package/dist/core/store/item-store.js.map +1 -1
  314. package/dist/core/store/paths.js +4 -1
  315. package/dist/core/store/paths.js.map +1 -1
  316. package/dist/core/store/settings-validator.d.ts +106 -0
  317. package/dist/core/store/settings-validator.js +279 -0
  318. package/dist/core/store/settings-validator.js.map +1 -0
  319. package/dist/core/store/settings.js +32 -331
  320. package/dist/core/store/settings.js.map +1 -1
  321. package/dist/core/telemetry/consent.js +4 -1
  322. package/dist/core/telemetry/consent.js.map +1 -1
  323. package/dist/core/telemetry/observability.d.ts +1 -1
  324. package/dist/core/telemetry/observability.js +11 -2
  325. package/dist/core/telemetry/observability.js.map +1 -1
  326. package/dist/core/telemetry/runtime.js +34 -6
  327. package/dist/core/telemetry/runtime.js.map +1 -1
  328. package/dist/core/test/background-runs.js +4 -1
  329. package/dist/core/test/background-runs.js.map +1 -1
  330. package/dist/core/test/item-test-run-tracking.js +4 -1
  331. package/dist/core/test/item-test-run-tracking.js.map +1 -1
  332. package/dist/mcp/server.js +182 -22
  333. package/dist/mcp/server.js.map +1 -1
  334. package/dist/sdk/cli-contracts/commander-mutation-options.js +10 -3
  335. package/dist/sdk/cli-contracts/commander-mutation-options.js.map +1 -1
  336. package/dist/sdk/cli-contracts/commander-types.js +4 -1
  337. package/dist/sdk/cli-contracts/commander-types.js.map +1 -1
  338. package/dist/sdk/cli-contracts.d.ts +13 -2
  339. package/dist/sdk/cli-contracts.js +410 -26
  340. package/dist/sdk/cli-contracts.js.map +1 -1
  341. package/dist/sdk/index.js +4 -1
  342. package/dist/sdk/index.js.map +1 -1
  343. package/dist/sdk/runtime.d.ts +25 -1
  344. package/dist/sdk/runtime.js +48 -2
  345. package/dist/sdk/runtime.js.map +1 -1
  346. package/dist/types/index.js +4 -1
  347. package/dist/types/index.js.map +1 -1
  348. package/dist/types.d.ts +92 -2
  349. package/dist/types.js +42 -1
  350. package/dist/types.js.map +1 -1
  351. package/docs/AGENT_GUIDE.md +23 -7
  352. package/docs/ARCHITECTURE.md +1 -1
  353. package/docs/CLAUDE_CODE_PLUGIN.md +10 -10
  354. package/docs/CODEX_PLUGIN.md +2 -2
  355. package/docs/COMMANDS.md +117 -12
  356. package/docs/CONFIGURATION.md +5 -2
  357. package/docs/EXTENSIONS.md +158 -814
  358. package/docs/QUICKSTART.md +11 -5
  359. package/docs/README.md +7 -6
  360. package/docs/RELEASING.md +13 -9
  361. package/docs/SDK.md +11 -2
  362. package/docs/TESTING.md +2 -2
  363. package/marketplace.json +3 -3
  364. package/package.json +15 -12
  365. package/packages/pm-beads/package.json +1 -1
  366. package/packages/pm-calendar/README.md +4 -2
  367. package/packages/pm-calendar/extensions/calendar/index.js +22 -3
  368. package/packages/pm-calendar/extensions/calendar/index.ts +22 -3
  369. package/packages/pm-calendar/extensions/calendar/runtime.js +26 -7
  370. package/packages/pm-calendar/extensions/calendar/runtime.ts +26 -7
  371. package/packages/pm-calendar/package.json +1 -1
  372. package/packages/pm-governance-audit/package.json +1 -1
  373. package/packages/pm-guide-shell/extensions/guide-shell/index.js +1 -1
  374. package/packages/pm-guide-shell/extensions/guide-shell/index.ts +1 -1
  375. package/packages/pm-guide-shell/package.json +1 -1
  376. package/packages/pm-linked-test-adapters/package.json +1 -1
  377. package/packages/pm-search-advanced/README.md +8 -0
  378. package/packages/pm-search-advanced/extensions/search-advanced/index.js +74 -0
  379. package/packages/pm-search-advanced/extensions/search-advanced/index.ts +75 -1
  380. package/packages/pm-search-advanced/extensions/search-advanced/runtime.js +67 -9
  381. package/packages/pm-search-advanced/extensions/search-advanced/runtime.ts +67 -9
  382. package/packages/pm-search-advanced/package.json +1 -1
  383. package/packages/pm-templates/README.md +1 -1
  384. package/packages/pm-templates/extensions/templates/runtime.js +11 -202
  385. package/packages/pm-templates/extensions/templates/runtime.ts +38 -230
  386. package/packages/pm-templates/package.json +1 -1
  387. package/packages/pm-todos/package.json +1 -1
  388. package/plugins/{pm-cli-claude → pm-claude}/.claude-plugin/plugin.json +2 -2
  389. package/plugins/{pm-cli-claude → pm-claude}/.mcp.json +1 -1
  390. package/plugins/{pm-cli-claude → pm-claude}/README.md +4 -4
  391. package/plugins/{pm-cli-claude → pm-claude}/agents/pm-coordinator.md +1 -1
  392. package/plugins/{pm-cli-claude → pm-claude}/commands/pm-init.md +10 -1
  393. package/plugins/{pm-cli-claude → pm-claude}/commands/pm-planner.md +18 -0
  394. package/plugins/{pm-cli-claude → pm-claude}/skills/pm-planner/SKILL.md +46 -1
  395. package/plugins/{pm-cli-codex → pm-codex}/.codex-plugin/plugin.json +3 -3
  396. package/plugins/{pm-cli-codex → pm-codex}/.mcp.json +1 -1
  397. package/plugins/{pm-cli-codex → pm-codex}/README.md +7 -4
  398. package/plugins/pm-codex/skills/pm-native/SKILL.md +81 -0
  399. package/scripts/finalize-build.mjs +28 -0
  400. package/scripts/prepare-build-cache.mjs +37 -0
  401. package/dist/core/output/command-aware.d.ts +0 -1
  402. package/dist/core/output/command-aware.js +0 -394
  403. package/dist/core/output/command-aware.js.map +0 -1
  404. package/plugins/pm-cli-codex/skills/pm-native/SKILL.md +0 -57
  405. /package/plugins/{pm-cli-claude → pm-claude}/agents/pm-delivery-chain.md +0 -0
  406. /package/plugins/{pm-cli-claude → pm-claude}/agents/pm-triage-agent.md +0 -0
  407. /package/plugins/{pm-cli-claude → pm-claude}/agents/pm-verification-agent.md +0 -0
  408. /package/plugins/{pm-cli-claude → pm-claude}/commands/pm-audit.md +0 -0
  409. /package/plugins/{pm-cli-claude → pm-claude}/commands/pm-calendar.md +0 -0
  410. /package/plugins/{pm-cli-claude → pm-claude}/commands/pm-close-task.md +0 -0
  411. /package/plugins/{pm-cli-claude → pm-claude}/commands/pm-developer.md +0 -0
  412. /package/plugins/{pm-cli-claude → pm-claude}/commands/pm-list.md +0 -0
  413. /package/plugins/{pm-cli-claude → pm-claude}/commands/pm-new.md +0 -0
  414. /package/plugins/{pm-cli-claude → pm-claude}/commands/pm-release.md +0 -0
  415. /package/plugins/{pm-cli-claude → pm-claude}/commands/pm-search.md +0 -0
  416. /package/plugins/{pm-cli-claude → pm-claude}/commands/pm-start-task.md +0 -0
  417. /package/plugins/{pm-cli-claude → pm-claude}/commands/pm-status.md +0 -0
  418. /package/plugins/{pm-cli-claude → pm-claude}/commands/pm-triage.md +0 -0
  419. /package/plugins/{pm-cli-claude → pm-claude}/commands/pm-workflow.md +0 -0
  420. /package/plugins/{pm-cli-claude → pm-claude}/hooks/hooks.json +0 -0
  421. /package/plugins/{pm-cli-claude → pm-claude}/hooks/session-start.mjs +0 -0
  422. /package/plugins/{pm-cli-claude → pm-claude}/scripts/pm-mcp-server.mjs +0 -0
  423. /package/plugins/{pm-cli-claude → pm-claude}/skills/pm-audit/SKILL.md +0 -0
  424. /package/plugins/{pm-cli-claude → pm-claude}/skills/pm-developer/SKILL.md +0 -0
  425. /package/plugins/{pm-cli-claude → pm-claude}/skills/pm-release/SKILL.md +0 -0
  426. /package/plugins/{pm-cli-claude → pm-claude}/skills/pm-workflow/SKILL.md +0 -0
  427. /package/plugins/{pm-cli-codex → pm-codex}/assets/pm-cli-small.svg +0 -0
  428. /package/plugins/{pm-cli-codex → pm-codex}/commands/pm-audit.md +0 -0
  429. /package/plugins/{pm-cli-codex → pm-codex}/commands/pm-close-task.md +0 -0
  430. /package/plugins/{pm-cli-codex → pm-codex}/commands/pm-start-task.md +0 -0
  431. /package/plugins/{pm-cli-codex → pm-codex}/scripts/pm-mcp-server.mjs +0 -0
  432. /package/plugins/{pm-cli-codex → pm-codex}/skills/pm-auditor/SKILL.md +0 -0
  433. /package/plugins/{pm-cli-codex → pm-codex}/skills/pm-auditor/agents/openai.yaml +0 -0
  434. /package/plugins/{pm-cli-codex → pm-codex}/skills/pm-native/agents/openai.yaml +0 -0
  435. /package/plugins/{pm-cli-codex → pm-codex}/skills/pm-release/SKILL.md +0 -0
  436. /package/plugins/{pm-cli-codex → pm-codex}/skills/pm-release/agents/openai.yaml +0 -0
@@ -15,6 +15,16 @@ const searchAdvancedFlags = [
15
15
  value_type: "string",
16
16
  description: "Search mode override: keyword|semantic|hybrid.",
17
17
  },
18
+ {
19
+ long: "--semantic",
20
+ value_type: "boolean",
21
+ description: "Alias for --mode semantic.",
22
+ },
23
+ {
24
+ long: "--hybrid",
25
+ value_type: "boolean",
26
+ description: "Alias for --mode hybrid.",
27
+ },
18
28
  {
19
29
  long: "--include-linked",
20
30
  value_type: "boolean",
@@ -45,6 +55,70 @@ const searchAdvancedFlags = [
45
55
  value_type: "boolean",
46
56
  description: "Alias for --phrase-exact.",
47
57
  },
58
+ {
59
+ long: "--type",
60
+ value_name: "value",
61
+ value_type: "string",
62
+ description: "Filter by item type.",
63
+ },
64
+ {
65
+ long: "--tag",
66
+ value_name: "value",
67
+ value_type: "string",
68
+ description: "Filter by tag.",
69
+ },
70
+ {
71
+ long: "--priority",
72
+ value_name: "value",
73
+ value_type: "string",
74
+ description: "Filter by priority.",
75
+ },
76
+ {
77
+ long: "--deadline-before",
78
+ value_name: "date",
79
+ value_type: "string",
80
+ description: "Filter to items with deadlines before a date.",
81
+ },
82
+ {
83
+ long: "--deadline_before",
84
+ value_name: "date",
85
+ value_type: "string",
86
+ description: "Alias for --deadline-before.",
87
+ },
88
+ {
89
+ long: "--deadline-after",
90
+ value_name: "date",
91
+ value_type: "string",
92
+ description: "Filter to items with deadlines after a date.",
93
+ },
94
+ {
95
+ long: "--deadline_after",
96
+ value_name: "date",
97
+ value_type: "string",
98
+ description: "Alias for --deadline-after.",
99
+ },
100
+ {
101
+ long: "--limit",
102
+ value_name: "count",
103
+ value_type: "string",
104
+ description: "Limit the number of search results.",
105
+ },
106
+ {
107
+ long: "--fields",
108
+ value_name: "list",
109
+ value_type: "string",
110
+ description: "Return only selected result fields.",
111
+ },
112
+ {
113
+ long: "--compact",
114
+ value_type: "boolean",
115
+ description: "Return compact token-efficient search results.",
116
+ },
117
+ {
118
+ long: "--full",
119
+ value_type: "boolean",
120
+ description: "Return full search results.",
121
+ },
48
122
  ];
49
123
 
50
124
  const reindexFlags = [
@@ -6,7 +6,7 @@ export const manifest = {
6
6
  version: "0.1.0",
7
7
  entry: "./index.js",
8
8
  priority: 0,
9
- capabilities: ["commands"],
9
+ capabilities: ["commands", "schema"],
10
10
  };
11
11
 
12
12
  const searchAdvancedFlags = [
@@ -16,6 +16,16 @@ const searchAdvancedFlags = [
16
16
  value_type: "string",
17
17
  description: "Search mode override: keyword|semantic|hybrid.",
18
18
  },
19
+ {
20
+ long: "--semantic",
21
+ value_type: "boolean",
22
+ description: "Alias for --mode semantic.",
23
+ },
24
+ {
25
+ long: "--hybrid",
26
+ value_type: "boolean",
27
+ description: "Alias for --mode hybrid.",
28
+ },
19
29
  {
20
30
  long: "--include-linked",
21
31
  value_type: "boolean",
@@ -46,6 +56,70 @@ const searchAdvancedFlags = [
46
56
  value_type: "boolean",
47
57
  description: "Alias for --phrase-exact.",
48
58
  },
59
+ {
60
+ long: "--type",
61
+ value_name: "value",
62
+ value_type: "string",
63
+ description: "Filter by item type.",
64
+ },
65
+ {
66
+ long: "--tag",
67
+ value_name: "value",
68
+ value_type: "string",
69
+ description: "Filter by tag.",
70
+ },
71
+ {
72
+ long: "--priority",
73
+ value_name: "value",
74
+ value_type: "string",
75
+ description: "Filter by priority.",
76
+ },
77
+ {
78
+ long: "--deadline-before",
79
+ value_name: "date",
80
+ value_type: "string",
81
+ description: "Filter to items with deadlines before a date.",
82
+ },
83
+ {
84
+ long: "--deadline_before",
85
+ value_name: "date",
86
+ value_type: "string",
87
+ description: "Alias for --deadline-before.",
88
+ },
89
+ {
90
+ long: "--deadline-after",
91
+ value_name: "date",
92
+ value_type: "string",
93
+ description: "Filter to items with deadlines after a date.",
94
+ },
95
+ {
96
+ long: "--deadline_after",
97
+ value_name: "date",
98
+ value_type: "string",
99
+ description: "Alias for --deadline-after.",
100
+ },
101
+ {
102
+ long: "--limit",
103
+ value_name: "count",
104
+ value_type: "string",
105
+ description: "Limit the number of search results.",
106
+ },
107
+ {
108
+ long: "--fields",
109
+ value_name: "list",
110
+ value_type: "string",
111
+ description: "Return only selected result fields.",
112
+ },
113
+ {
114
+ long: "--compact",
115
+ value_type: "boolean",
116
+ description: "Return compact token-efficient search results.",
117
+ },
118
+ {
119
+ long: "--full",
120
+ value_type: "boolean",
121
+ description: "Return full search results.",
122
+ },
49
123
  ] as const;
50
124
 
51
125
  const reindexFlags = [
@@ -48,6 +48,9 @@ function readStringOption(options, key, aliases = []) {
48
48
  return undefined;
49
49
  }
50
50
 
51
+ const BOOLEAN_TRUE_VALUES = new Set(["true", "1", "yes", "on"]);
52
+ const BOOLEAN_FALSE_VALUES = new Set(["false", "0", "no", "off"]);
53
+
51
54
  function readBooleanOption(options, key, aliases = []) {
52
55
  const keys = [key, ...aliases];
53
56
  for (const candidate of keys) {
@@ -60,10 +63,10 @@ function readBooleanOption(options, key, aliases = []) {
60
63
  }
61
64
  if (typeof value === "string") {
62
65
  const normalized = value.trim().toLowerCase();
63
- if (normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on") {
66
+ if (BOOLEAN_TRUE_VALUES.has(normalized)) {
64
67
  return true;
65
68
  }
66
- if (normalized === "false" || normalized === "0" || normalized === "no" || normalized === "off") {
69
+ if (BOOLEAN_FALSE_VALUES.has(normalized)) {
67
70
  return false;
68
71
  }
69
72
  }
@@ -71,24 +74,79 @@ function readBooleanOption(options, key, aliases = []) {
71
74
  return undefined;
72
75
  }
73
76
 
77
+ const SEARCH_VALUE_FLAGS = new Set([
78
+ "--mode",
79
+ "--type",
80
+ "--tag",
81
+ "--priority",
82
+ "--deadline-before",
83
+ "--deadline_before",
84
+ "--deadline-after",
85
+ "--deadline_after",
86
+ "--limit",
87
+ "--fields",
88
+ ]);
89
+
90
+ const SEARCH_BOOLEAN_FLAGS = new Set([
91
+ "--semantic",
92
+ "--hybrid",
93
+ "--include-linked",
94
+ "--include_linked",
95
+ "--title-exact",
96
+ "--title_exact",
97
+ "--phrase-exact",
98
+ "--phrase_exact",
99
+ "--compact",
100
+ "--full",
101
+ "--json",
102
+ ]);
103
+
104
+ function stripSearchOptionTokens(args) {
105
+ const queryTokens = [];
106
+ for (let index = 0; index < args.length; index += 1) {
107
+ const token = args[index]?.trim() ?? "";
108
+ const equalsIndex = token.indexOf("=");
109
+ const flagName = equalsIndex > 0 ? token.slice(0, equalsIndex) : token;
110
+ if (SEARCH_VALUE_FLAGS.has(flagName)) {
111
+ if (equalsIndex < 0) {
112
+ index += 1;
113
+ }
114
+ continue;
115
+ }
116
+ if (SEARCH_BOOLEAN_FLAGS.has(flagName)) {
117
+ continue;
118
+ }
119
+ if (token.length > 0) {
120
+ queryTokens.push(token);
121
+ }
122
+ }
123
+ return queryTokens;
124
+ }
125
+
74
126
  function resolveSearchQuery(args) {
75
- const query = args
76
- .map((value) => value.trim())
77
- .filter((value) => value.length > 0)
78
- .join(" ");
127
+ const query = stripSearchOptionTokens(args).join(" ");
79
128
  if (query.length === 0) {
80
129
  throw new PmCliError("Search query must not be empty", EXIT_CODE.USAGE);
81
130
  }
82
131
  return query;
83
132
  }
84
133
 
85
- function normalizeAdvancedSearchOptions(rawOptions) {
134
+ function normalizeAdvancedSearchOptions(rawOptions, args) {
86
135
  const fields = readStringOption(rawOptions, "fields");
87
136
  const compactRequested = readBooleanOption(rawOptions, "compact") === true;
88
137
  const fullRequested = readBooleanOption(rawOptions, "full") === true;
89
138
  const defaultCompact = !compactRequested && !fullRequested && fields === undefined;
139
+ const explicitMode = readStringOption(rawOptions, "mode");
140
+ const argFlags = new Set(args.map((value) => value?.trim() ?? ""));
141
+ const mode =
142
+ explicitMode ??
143
+ (readBooleanOption(rawOptions, "semantic") === true || argFlags.has("--semantic")
144
+ ? "semantic"
145
+ : readBooleanOption(rawOptions, "hybrid") === true || argFlags.has("--hybrid")
146
+ ? "hybrid"
147
+ : "keyword");
90
148
  return {
91
- mode: readStringOption(rawOptions, "mode"),
149
+ mode,
92
150
  includeLinked: readBooleanOption(rawOptions, "includeLinked", ["include_linked"]) === true ? true : undefined,
93
151
  titleExact: readBooleanOption(rawOptions, "titleExact", ["title_exact"]) === true ? true : undefined,
94
152
  phraseExact: readBooleanOption(rawOptions, "phraseExact", ["phrase_exact"]) === true ? true : undefined,
@@ -112,7 +170,7 @@ function normalizeReindexOptions(rawOptions) {
112
170
  }
113
171
 
114
172
  export async function runAdvancedSearchPackage(args, rawOptions, global) {
115
- return runSearch(resolveSearchQuery(args), normalizeAdvancedSearchOptions(rawOptions), global);
173
+ return runSearch(resolveSearchQuery(args), normalizeAdvancedSearchOptions(rawOptions, args), global);
116
174
  }
117
175
 
118
176
  export async function runAdvancedReindexPackage(rawOptions, global) {
@@ -65,6 +65,9 @@ function readStringOption(options: Record<string, unknown>, key: string, aliases
65
65
  return undefined;
66
66
  }
67
67
 
68
+ const BOOLEAN_TRUE_VALUES = new Set(["true", "1", "yes", "on"]);
69
+ const BOOLEAN_FALSE_VALUES = new Set(["false", "0", "no", "off"]);
70
+
68
71
  function readBooleanOption(options: Record<string, unknown>, key: string, aliases: string[] = []): boolean | undefined {
69
72
  const keys = [key, ...aliases];
70
73
  for (const candidate of keys) {
@@ -77,10 +80,10 @@ function readBooleanOption(options: Record<string, unknown>, key: string, aliase
77
80
  }
78
81
  if (typeof value === "string") {
79
82
  const normalized = value.trim().toLowerCase();
80
- if (normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on") {
83
+ if (BOOLEAN_TRUE_VALUES.has(normalized)) {
81
84
  return true;
82
85
  }
83
- if (normalized === "false" || normalized === "0" || normalized === "no" || normalized === "off") {
86
+ if (BOOLEAN_FALSE_VALUES.has(normalized)) {
84
87
  return false;
85
88
  }
86
89
  }
@@ -88,24 +91,79 @@ function readBooleanOption(options: Record<string, unknown>, key: string, aliase
88
91
  return undefined;
89
92
  }
90
93
 
94
+ const SEARCH_VALUE_FLAGS = new Set([
95
+ "--mode",
96
+ "--type",
97
+ "--tag",
98
+ "--priority",
99
+ "--deadline-before",
100
+ "--deadline_before",
101
+ "--deadline-after",
102
+ "--deadline_after",
103
+ "--limit",
104
+ "--fields",
105
+ ]);
106
+
107
+ const SEARCH_BOOLEAN_FLAGS = new Set([
108
+ "--semantic",
109
+ "--hybrid",
110
+ "--include-linked",
111
+ "--include_linked",
112
+ "--title-exact",
113
+ "--title_exact",
114
+ "--phrase-exact",
115
+ "--phrase_exact",
116
+ "--compact",
117
+ "--full",
118
+ "--json",
119
+ ]);
120
+
121
+ function stripSearchOptionTokens(args: string[]): string[] {
122
+ const queryTokens: string[] = [];
123
+ for (let index = 0; index < args.length; index += 1) {
124
+ const token = args[index]?.trim() ?? "";
125
+ const equalsIndex = token.indexOf("=");
126
+ const flagName = equalsIndex > 0 ? token.slice(0, equalsIndex) : token;
127
+ if (SEARCH_VALUE_FLAGS.has(flagName)) {
128
+ if (equalsIndex < 0) {
129
+ index += 1;
130
+ }
131
+ continue;
132
+ }
133
+ if (SEARCH_BOOLEAN_FLAGS.has(flagName)) {
134
+ continue;
135
+ }
136
+ if (token.length > 0) {
137
+ queryTokens.push(token);
138
+ }
139
+ }
140
+ return queryTokens;
141
+ }
142
+
91
143
  function resolveSearchQuery(args: string[]): string {
92
- const query = args
93
- .map((value) => value.trim())
94
- .filter((value) => value.length > 0)
95
- .join(" ");
144
+ const query = stripSearchOptionTokens(args).join(" ");
96
145
  if (query.length === 0) {
97
146
  throw new PmCliError("Search query must not be empty", EXIT_CODE.USAGE);
98
147
  }
99
148
  return query;
100
149
  }
101
150
 
102
- function normalizeAdvancedSearchOptions(rawOptions: Record<string, unknown>): SearchOptions {
151
+ function normalizeAdvancedSearchOptions(rawOptions: Record<string, unknown>, args: string[]): SearchOptions {
103
152
  const fields = readStringOption(rawOptions, "fields");
104
153
  const compactRequested = readBooleanOption(rawOptions, "compact") === true;
105
154
  const fullRequested = readBooleanOption(rawOptions, "full") === true;
106
155
  const defaultCompact = !compactRequested && !fullRequested && fields === undefined;
156
+ const explicitMode = readStringOption(rawOptions, "mode");
157
+ const argFlags = new Set(args.map((value) => value?.trim() ?? ""));
158
+ const mode =
159
+ explicitMode ??
160
+ (readBooleanOption(rawOptions, "semantic") === true || argFlags.has("--semantic")
161
+ ? "semantic"
162
+ : readBooleanOption(rawOptions, "hybrid") === true || argFlags.has("--hybrid")
163
+ ? "hybrid"
164
+ : "keyword");
107
165
  return {
108
- mode: readStringOption(rawOptions, "mode"),
166
+ mode,
109
167
  includeLinked: readBooleanOption(rawOptions, "includeLinked", ["include_linked"]) === true ? true : undefined,
110
168
  titleExact: readBooleanOption(rawOptions, "titleExact", ["title_exact"]) === true ? true : undefined,
111
169
  phraseExact: readBooleanOption(rawOptions, "phraseExact", ["phrase_exact"]) === true ? true : undefined,
@@ -133,7 +191,7 @@ export async function runAdvancedSearchPackage(
133
191
  rawOptions: Record<string, unknown>,
134
192
  global: GlobalOptions,
135
193
  ): Promise<SearchResult> {
136
- return runSearch(resolveSearchQuery(args), normalizeAdvancedSearchOptions(rawOptions), global);
194
+ return runSearch(resolveSearchQuery(args), normalizeAdvancedSearchOptions(rawOptions, args), global);
137
195
  }
138
196
 
139
197
  export async function runAdvancedReindexPackage(
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "@unbrained/pm-package-search-advanced",
2
+ "name": "@unbrained/pm-search-advanced",
3
3
  "version": "0.1.0",
4
4
  "private": true,
5
5
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  # pm Templates Package
2
2
 
3
- `@unbrained/pm-package-templates` provides reusable `pm create` templates as an installable pm package.
3
+ `@unbrained/pm-templates` provides reusable `pm create` templates as an installable pm package.
4
4
 
5
5
  Install it with:
6
6
 
@@ -1,226 +1,35 @@
1
- import fs from "node:fs/promises";
2
1
  import path from "node:path";
3
2
  import { pathToFileURL } from "node:url";
4
-
5
3
  const PM_PACKAGE_ROOT_ENV = "PM_CLI_PACKAGE_ROOT";
6
4
  const sdk = await loadTemplatesSdkModule();
7
- const {
8
- CREATE_COMMANDER_REPEATABLE_OPTION_CONTRACTS,
9
- EXIT_CODE,
10
- PmCliError,
11
- getSettingsPath,
12
- nowIso,
13
- pathExists,
14
- readFileIfExists,
15
- resolvePmRoot,
16
- writeFileAtomic,
17
- } = sdk;
18
-
19
5
  async function loadTemplatesSdkModule() {
20
6
  const envRoot = process.env[PM_PACKAGE_ROOT_ENV];
21
7
  if (typeof envRoot !== "string" || envRoot.trim().length === 0) {
22
- throw new Error(
23
- `builtin-templates requires ${PM_PACKAGE_ROOT_ENV} to locate core SDK runtime exports.`,
24
- );
8
+ throw new Error(`builtin-templates requires ${PM_PACKAGE_ROOT_ENV} to locate core SDK runtime exports.`);
25
9
  }
26
10
  const modulePath = path.join(path.resolve(envRoot.trim()), "dist", "sdk", "index.js");
27
11
  try {
28
12
  const loaded = await import(pathToFileURL(modulePath).href);
29
- if (
30
- typeof loaded.resolvePmRoot === "function" &&
31
- typeof loaded.pathExists === "function" &&
32
- typeof loaded.PmCliError === "function" &&
33
- Array.isArray(loaded.CREATE_COMMANDER_REPEATABLE_OPTION_CONTRACTS)
34
- ) {
13
+ if (typeof loaded.loadCreateTemplateOptions === "function" &&
14
+ typeof loaded.runTemplatesList === "function" &&
15
+ typeof loaded.runTemplatesSave === "function" &&
16
+ typeof loaded.runTemplatesShow === "function") {
35
17
  return loaded;
36
18
  }
37
19
  } catch {
38
20
  // Fall through to deterministic failure message below.
39
21
  }
40
- throw new Error(
41
- `builtin-templates failed to load SDK runtime exports from ${modulePath}.`,
42
- );
22
+ throw new Error(`builtin-templates failed to load template runtime exports from ${modulePath}.`);
43
23
  }
44
-
45
- const TEMPLATE_DIRECTORY_NAME = "templates";
46
- const TEMPLATE_FILE_EXTENSION = ".json";
47
- const TEMPLATE_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
48
- const TEMPLATE_OPTION_REPEATABLE_KEY_SET = new Set(CREATE_COMMANDER_REPEATABLE_OPTION_CONTRACTS.map((entry) => entry.target));
49
-
50
- function normalizeTemplateName(rawName) {
51
- const name = rawName.trim();
52
- if (!TEMPLATE_NAME_PATTERN.test(name)) {
53
- throw new PmCliError(
54
- `Invalid template name "${rawName}". Expected 1-64 characters matching [A-Za-z0-9][A-Za-z0-9._-]*.`,
55
- EXIT_CODE.USAGE,
56
- );
57
- }
58
- return name;
59
- }
60
-
61
- function templatesDirectory(pmRoot) {
62
- return path.join(pmRoot, TEMPLATE_DIRECTORY_NAME);
63
- }
64
-
65
- function templatePath(pmRoot, normalizedName) {
66
- return path.join(templatesDirectory(pmRoot), `${normalizedName}${TEMPLATE_FILE_EXTENSION}`);
67
- }
68
-
69
- async function ensureTrackerInitialized(pmRoot) {
70
- if (!(await pathExists(getSettingsPath(pmRoot)))) {
71
- throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
72
- }
73
- }
74
-
75
- function sortTemplateOptions(options) {
76
- return Object.fromEntries(Object.entries(options).sort(([left], [right]) => left.localeCompare(right)));
77
- }
78
-
79
- function extractTemplateOptions(rawOptions) {
80
- const next = {};
81
- for (const [key, value] of Object.entries(rawOptions)) {
82
- if (value === undefined) {
83
- continue;
84
- }
85
- if (TEMPLATE_OPTION_REPEATABLE_KEY_SET.has(key)) {
86
- if (typeof value === "string") {
87
- next[key] = [value];
88
- continue;
89
- }
90
- if (!Array.isArray(value)) {
91
- continue;
92
- }
93
- const values = value.filter((entry) => typeof entry === "string");
94
- if (values.length > 0) {
95
- next[key] = values;
96
- }
97
- continue;
98
- }
99
- if (typeof value === "string") {
100
- next[key] = value;
101
- continue;
102
- }
103
- if (Array.isArray(value) && value.every((entry) => typeof entry === "string")) {
104
- next[key] = [...value];
105
- }
106
- }
107
- return sortTemplateOptions(next);
108
- }
109
-
110
- function parseStoredTemplateOptions(rawOptions, templateName) {
111
- if (typeof rawOptions !== "object" || rawOptions === null || Array.isArray(rawOptions)) {
112
- throw new PmCliError(`Template "${templateName}" has invalid options payload.`, EXIT_CODE.GENERIC_FAILURE);
113
- }
114
- const normalized = {};
115
- for (const [key, value] of Object.entries(rawOptions)) {
116
- const normalizedKey = key.trim();
117
- if (normalizedKey.length === 0) {
118
- throw new PmCliError(`Template "${templateName}" contains an empty option key.`, EXIT_CODE.GENERIC_FAILURE);
119
- }
120
- if (typeof value === "string") {
121
- normalized[normalizedKey] = value;
122
- continue;
123
- }
124
- if (Array.isArray(value) && value.every((entry) => typeof entry === "string")) {
125
- normalized[normalizedKey] = [...value];
126
- continue;
127
- }
128
- throw new PmCliError(`Template "${templateName}" contains invalid value for option "${normalizedKey}".`, EXIT_CODE.GENERIC_FAILURE);
129
- }
130
- return sortTemplateOptions(normalized);
131
- }
132
-
133
- function parseStoredTemplateDocument(raw, normalizedName) {
134
- let parsed;
135
- try {
136
- parsed = JSON.parse(raw);
137
- } catch {
138
- throw new PmCliError(`Template "${normalizedName}" contains invalid JSON.`, EXIT_CODE.GENERIC_FAILURE);
139
- }
140
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
141
- throw new PmCliError(`Template "${normalizedName}" has invalid document shape.`, EXIT_CODE.GENERIC_FAILURE);
142
- }
143
- const options = parseStoredTemplateOptions(parsed.options, normalizedName);
144
- const now = nowIso();
145
- return {
146
- name: typeof parsed.name === "string" && parsed.name.trim().length > 0 ? parsed.name.trim() : normalizedName,
147
- created_at: typeof parsed.created_at === "string" ? parsed.created_at : now,
148
- updated_at: typeof parsed.updated_at === "string" ? parsed.updated_at : now,
149
- options,
150
- };
151
- }
152
-
153
- async function readStoredTemplateDocument(pmRoot, normalizedName) {
154
- const raw = await readFileIfExists(templatePath(pmRoot, normalizedName));
155
- if (raw === null) {
156
- throw new PmCliError(`Template "${normalizedName}" not found`, EXIT_CODE.NOT_FOUND);
157
- }
158
- return parseStoredTemplateDocument(raw, normalizedName);
24
+ export async function loadCreateTemplateOptions(pmRoot, rawTemplateName) {
25
+ return sdk.loadCreateTemplateOptions(pmRoot, rawTemplateName);
159
26
  }
160
-
161
27
  export async function runTemplatesSave(rawTemplateName, options, global) {
162
- const pmRoot = resolvePmRoot(process.cwd(), global.path);
163
- await ensureTrackerInitialized(pmRoot);
164
- const normalizedName = normalizeTemplateName(rawTemplateName);
165
- const nextOptions = extractTemplateOptions(options);
166
- if (Object.keys(nextOptions).length === 0) {
167
- throw new PmCliError("templates save requires at least one create option flag", EXIT_CODE.USAGE);
168
- }
169
-
170
- const now = nowIso();
171
- const storedPath = templatePath(pmRoot, normalizedName);
172
- let createdAt = now;
173
- if (await pathExists(storedPath)) {
174
- const existing = await readStoredTemplateDocument(pmRoot, normalizedName);
175
- createdAt = existing.created_at;
176
- }
177
-
178
- const document = {
179
- name: normalizedName,
180
- created_at: createdAt,
181
- updated_at: now,
182
- options: nextOptions,
183
- };
184
- await fs.mkdir(templatesDirectory(pmRoot), { recursive: true });
185
- await writeFileAtomic(storedPath, `${JSON.stringify(document, null, 2)}\n`);
186
- return {
187
- name: document.name,
188
- created_at: document.created_at,
189
- updated_at: document.updated_at,
190
- path: storedPath,
191
- options: document.options,
192
- };
28
+ return sdk.runTemplatesSave(rawTemplateName, options, global);
193
29
  }
194
-
195
30
  export async function runTemplatesList(global) {
196
- const pmRoot = resolvePmRoot(process.cwd(), global.path);
197
- await ensureTrackerInitialized(pmRoot);
198
- const dirPath = templatesDirectory(pmRoot);
199
- if (!(await pathExists(dirPath))) {
200
- return { templates: [], count: 0 };
201
- }
202
- const entries = await fs.readdir(dirPath);
203
- const templates = entries
204
- .filter((entry) => entry.toLowerCase().endsWith(TEMPLATE_FILE_EXTENSION))
205
- .map((entry) => entry.slice(0, -TEMPLATE_FILE_EXTENSION.length))
206
- .filter((entry) => TEMPLATE_NAME_PATTERN.test(entry))
207
- .sort((left, right) => left.localeCompare(right));
208
- return {
209
- templates,
210
- count: templates.length,
211
- };
31
+ return sdk.runTemplatesList(global);
212
32
  }
213
-
214
33
  export async function runTemplatesShow(rawTemplateName, global) {
215
- const pmRoot = resolvePmRoot(process.cwd(), global.path);
216
- await ensureTrackerInitialized(pmRoot);
217
- const normalizedName = normalizeTemplateName(rawTemplateName);
218
- const stored = await readStoredTemplateDocument(pmRoot, normalizedName);
219
- return {
220
- name: stored.name,
221
- created_at: stored.created_at,
222
- updated_at: stored.updated_at,
223
- path: templatePath(pmRoot, normalizedName),
224
- options: stored.options,
225
- };
34
+ return sdk.runTemplatesShow(rawTemplateName, global);
226
35
  }