@unbrained/pm-cli 2026.8.16 → 2026.8.18

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/.claude-plugin/marketplace.json +2 -2
  2. package/AGENTS.md +4 -3
  3. package/CHANGELOG.md +65 -6
  4. package/README.md +16 -16
  5. package/dist/cli/error-guidance.js +7 -4
  6. package/dist/cli/public.d.ts +2 -0
  7. package/dist/cli/public.js +21 -0
  8. package/dist/cli/register-list-query.js +132 -51
  9. package/dist/cli/register-mutation.js +4 -4
  10. package/dist/cli-bundle/bundle-manifest.json +148 -148
  11. package/dist/cli-bundle/chunks/chunk-5UZZAJKR.js +3 -0
  12. package/dist/cli-bundle/chunks/chunk-ALDJGKAK.js +2 -0
  13. package/dist/cli-bundle/chunks/chunk-BSK2IN3C.js +8 -0
  14. package/dist/cli-bundle/chunks/chunk-DY4DMUMC.js +197 -0
  15. package/dist/cli-bundle/chunks/{chunk-73UGEBRS.js → chunk-GNFAFIJI.js} +10 -10
  16. package/dist/cli-bundle/chunks/chunk-L5Q2CLPE.js +35 -0
  17. package/dist/cli-bundle/chunks/{chunk-RIS565OA.js → chunk-PVRUN5ZS.js} +5 -5
  18. package/dist/cli-bundle/chunks/chunk-RZQTVMRQ.js +2 -0
  19. package/dist/cli-bundle/chunks/chunk-SARFF5H5.js +3 -0
  20. package/dist/cli-bundle/chunks/chunk-UYCLQVL2.js +13 -0
  21. package/dist/cli-bundle/chunks/{chunk-URW4QRMI.js → chunk-YRGOLZA7.js} +59 -55
  22. package/dist/cli-bundle/chunks/register-list-query-I23LALEE.js +11 -0
  23. package/dist/cli-bundle/chunks/register-mutation-6YGU3GPH.js +20 -0
  24. package/dist/cli-bundle/chunks/{register-operations-KGDNRMCL.js → register-operations-4HTFC6J7.js} +2 -2
  25. package/dist/cli-bundle/chunks/{register-setup-NVXBOD5I.js → register-setup-PPPEF3SN.js} +2 -2
  26. package/dist/cli-bundle/focused-chunks/chunk-2PN4TJXH.js +2 -0
  27. package/dist/cli-bundle/focused-chunks/{chunk-C7JUBRFP.js → chunk-3TKWMNKF.js} +3 -3
  28. package/dist/cli-bundle/focused-chunks/chunk-5AF3ZBNB.js +155 -0
  29. package/dist/cli-bundle/focused-chunks/chunk-C5IW2NDA.js +2 -0
  30. package/dist/cli-bundle/focused-chunks/{chunk-CODV5LUT.js → chunk-EUEGXZ2A.js} +3 -3
  31. package/dist/cli-bundle/focused-chunks/{chunk-4JPEBFFC.js → chunk-EX6MKP2X.js} +2 -2
  32. package/dist/cli-bundle/focused-chunks/{chunk-SSNDYZTM.js → chunk-K43KKAFS.js} +2 -2
  33. package/dist/cli-bundle/focused-chunks/{chunk-6ROKKT4X.js → chunk-M62NO7EI.js} +2 -2
  34. package/dist/cli-bundle/focused-chunks/{chunk-T46KLOIB.js → chunk-ODOVCP45.js} +47 -47
  35. package/dist/cli-bundle/focused-chunks/chunk-RNDNMARJ.js +16 -0
  36. package/dist/cli-bundle/focused-chunks/chunk-TN4AE665.js +26 -0
  37. package/dist/cli-bundle/focused-chunks/chunk-TVV2DONO.js +2 -0
  38. package/dist/cli-bundle/focused-chunks/chunk-UI6AJ5TD.js +4 -0
  39. package/dist/cli-bundle/focused-chunks/chunk-V5XTGLK7.js +2 -0
  40. package/dist/cli-bundle/focused-chunks/chunk-WGHQVU6P.js +2 -0
  41. package/dist/cli-bundle/focused-chunks/chunk-XYNBXTDQ.js +2 -0
  42. package/dist/cli-bundle/focused-chunks/chunk-Z56ECT7I.js +2 -0
  43. package/dist/cli-bundle/main.js +7 -7
  44. package/dist/cli-bundle/sdk-authoring.js +1 -1
  45. package/dist/cli-bundle/sdk-contracts.js +1 -1
  46. package/dist/cli-bundle/sdk-core.js +31 -31
  47. package/dist/cli-bundle/sdk-governance.js +1 -1
  48. package/dist/cli-bundle/sdk-graph.js +1 -1
  49. package/dist/cli-bundle/sdk-merge.js +32 -32
  50. package/dist/cli-bundle/sdk-query.js +1 -1
  51. package/dist/cli-bundle/sdk-runtime.js +1 -1
  52. package/dist/cli-bundle/sdk-testing.js +1 -1
  53. package/dist/cli-bundle/sdk.js +4 -2
  54. package/dist/core/config/nested-settings.js +8 -2
  55. package/dist/core/extensions/exporter-output-contract.d.ts +12 -0
  56. package/dist/core/extensions/exporter-output-contract.js +67 -0
  57. package/dist/core/extensions/extension-types.d.ts +36 -1
  58. package/dist/core/extensions/extension-types.js +2 -2
  59. package/dist/core/extensions/loader.js +43 -48
  60. package/dist/core/extensions/manifest-schema.d.ts +20 -0
  61. package/dist/core/extensions/manifest-schema.js +52 -0
  62. package/dist/core/history/event-index.d.ts +5 -0
  63. package/dist/core/history/event-index.js +133 -27
  64. package/dist/core/history/replay.js +32 -14
  65. package/dist/core/schema/fields-file.d.ts +1 -1
  66. package/dist/core/schema/fields-file.js +2 -2
  67. package/dist/core/schema/runtime-field-values.js +115 -9
  68. package/dist/core/schema/runtime-schema.d.ts +3 -1
  69. package/dist/core/schema/runtime-schema.js +124 -3
  70. package/dist/core/sentry/helpers.js +3 -3
  71. package/dist/core/shared/constants.js +5 -2
  72. package/dist/core/shared/errors.d.ts +10 -0
  73. package/dist/core/shared/errors.js +2 -2
  74. package/dist/core/shared/time.d.ts +2 -0
  75. package/dist/core/shared/time.js +27 -2
  76. package/dist/core/store/settings-validator.d.ts +4 -0
  77. package/dist/core/store/settings-validator.js +3 -2
  78. package/dist/core/store/settings.js +8 -2
  79. package/dist/mcp/tool-definitions.js +12 -7
  80. package/dist/sdk/agent/refusal-reachability.d.ts +46 -6
  81. package/dist/sdk/agent/refusal-reachability.js +350 -8
  82. package/dist/sdk/authoring.d.ts +1 -1
  83. package/dist/sdk/authoring.js +2 -2
  84. package/dist/sdk/cli-bootstrap.d.ts +2 -2
  85. package/dist/sdk/cli-bootstrap.js +4 -4
  86. package/dist/sdk/cli-contracts/command-aliases.d.ts +34 -2
  87. package/dist/sdk/cli-contracts/command-aliases.js +64 -13
  88. package/dist/sdk/cli-contracts/enum-contracts.d.ts +4 -0
  89. package/dist/sdk/cli-contracts/enum-contracts.js +9 -2
  90. package/dist/sdk/cli-contracts/flag-contracts.js +11 -7
  91. package/dist/sdk/cli-contracts/grammar-contracts.d.ts +70 -0
  92. package/dist/sdk/cli-contracts/grammar-contracts.js +345 -0
  93. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +19 -2
  94. package/dist/sdk/cli-contracts/runtime-contracts.js +61 -14
  95. package/dist/sdk/cli-contracts/tool-parameter-tables.js +10 -4
  96. package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
  97. package/dist/sdk/cli-contracts/tool-schema.js +20 -11
  98. package/dist/sdk/cli-contracts.d.ts +2 -2
  99. package/dist/sdk/cli-contracts.js +4 -4
  100. package/dist/sdk/completion.js +13 -15
  101. package/dist/sdk/compose.d.ts +9 -5
  102. package/dist/sdk/compose.js +33 -3
  103. package/dist/sdk/context-intent-contracts.d.ts +8 -4
  104. package/dist/sdk/context-intent-contracts.js +76 -31
  105. package/dist/sdk/contracts.d.ts +1 -0
  106. package/dist/sdk/contracts.js +3 -2
  107. package/dist/sdk/core.d.ts +1 -1
  108. package/dist/sdk/core.js +3 -3
  109. package/dist/sdk/dependency-flag-validation.d.ts +9 -2
  110. package/dist/sdk/dependency-flag-validation.js +101 -35
  111. package/dist/sdk/environment/host-environment-errors.js +25 -7
  112. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +78 -14
  113. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +62 -14
  114. package/dist/sdk/governance/assurance-action.d.ts +3 -7
  115. package/dist/sdk/governance/assurance-action.js +97 -2
  116. package/dist/sdk/governance/boundary-fixtures.d.ts +86 -0
  117. package/dist/sdk/governance/boundary-fixtures.js +201 -0
  118. package/dist/sdk/governance/defect-recurrence-signals.d.ts +10 -0
  119. package/dist/sdk/governance/defect-recurrence-signals.js +25 -0
  120. package/dist/sdk/governance/defect-recurrence.d.ts +242 -0
  121. package/dist/sdk/governance/defect-recurrence.js +523 -0
  122. package/dist/sdk/governance.d.ts +2 -0
  123. package/dist/sdk/governance.js +4 -2
  124. package/dist/sdk/graph/governance.js +3 -2
  125. package/dist/sdk/guide-topics.js +193 -4
  126. package/dist/sdk/index.d.ts +7 -3
  127. package/dist/sdk/index.js +8 -5
  128. package/dist/sdk/init-agent-guidance.js +3 -3
  129. package/dist/sdk/lifecycle/create.js +4 -2
  130. package/dist/sdk/lifecycle/update-many.js +15 -2
  131. package/dist/sdk/lifecycle/update.js +5 -2
  132. package/dist/sdk/linked-artifacts.js +63 -14
  133. package/dist/sdk/mutation-events.d.ts +18 -2
  134. package/dist/sdk/mutation-events.js +59 -16
  135. package/dist/sdk/output.d.ts +44 -0
  136. package/dist/sdk/output.js +28 -2
  137. package/dist/sdk/query/complete-list.d.ts +94 -0
  138. package/dist/sdk/query/complete-list.js +173 -0
  139. package/dist/sdk/query/get.d.ts +2 -0
  140. package/dist/sdk/query/get.js +32 -7
  141. package/dist/sdk/query/list.js +5 -2
  142. package/dist/sdk/query.d.ts +1 -0
  143. package/dist/sdk/query.js +3 -2
  144. package/dist/sdk/read-output-contracts.d.ts +2 -2
  145. package/dist/sdk/read-output-contracts.js +36 -9
  146. package/dist/sdk/relationship-analytics.js +90 -14
  147. package/dist/sdk/relationship-kinds/contract.d.ts +4 -0
  148. package/dist/sdk/relationship-kinds/contract.js +3 -2
  149. package/dist/sdk/relationships.d.ts +1 -1
  150. package/dist/sdk/relationships.js +11 -2
  151. package/dist/sdk/runtime-extended-actions.js +10 -2
  152. package/dist/sdk/runtime.d.ts +8 -2
  153. package/dist/sdk/runtime.js +11 -8
  154. package/dist/sdk/schema.d.ts +1 -0
  155. package/dist/sdk/schema.js +2 -2
  156. package/dist/sdk/test/execution.d.ts +6 -2
  157. package/dist/sdk/test/execution.js +39 -13
  158. package/dist/types.d.ts +34 -2
  159. package/dist/types.js +4 -2
  160. package/docs/AGENT_GUIDE.md +25 -9
  161. package/docs/CLI_GRAMMAR.md +106 -0
  162. package/docs/COMMANDS.md +23 -23
  163. package/docs/CONFIGURATION.md +58 -1
  164. package/docs/CONTEXT_INTEGRITY_CONTRACTS.md +58 -0
  165. package/docs/DEFECT_RECURRENCE.md +134 -0
  166. package/docs/DEPENDENCY_KIND_CONTRACT.md +12 -2
  167. package/docs/ONBOARDING.md +4 -4
  168. package/docs/QUICKSTART.md +1 -1
  169. package/docs/README.md +4 -0
  170. package/docs/RELATIONSHIP_GRAPH.md +16 -2
  171. package/docs/RELEASING.md +30 -6
  172. package/docs/SDK.md +74 -7
  173. package/docs/SDK_ARTIFACT_OUTPUT.md +72 -0
  174. package/docs/SDK_CONTEXT_COORDINATION.md +46 -12
  175. package/docs/SDK_RUNTIME_BOUNDARIES.md +9 -1
  176. package/docs/TESTING.md +18 -1
  177. package/docs/TRUSTWORTHY_CONTEXT_EVIDENCE.md +1 -1
  178. package/docs/agent-task-token-baseline.json +5 -5
  179. package/marketplace.json +2 -2
  180. package/package.json +8 -5
  181. package/packages/pm-beads/package.json +1 -1
  182. package/packages/pm-calendar/package.json +1 -1
  183. package/packages/pm-command-kit/package.json +1 -1
  184. package/packages/pm-digital-twin/package.json +1 -1
  185. package/packages/pm-governance-audit/package.json +1 -1
  186. package/packages/pm-guide-shell/package.json +1 -1
  187. package/packages/pm-kanban/package.json +1 -1
  188. package/packages/pm-lifecycle-hooks/package.json +1 -1
  189. package/packages/pm-linked-test-adapters/package.json +1 -1
  190. package/packages/pm-search-advanced/package.json +1 -1
  191. package/packages/pm-templates/package.json +1 -1
  192. package/packages/pm-todos/package.json +1 -1
  193. package/packages/pm-vcs/package.json +1 -1
  194. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  195. package/plugins/pm-claude/skills/pm-audit/SKILL.md +26 -0
  196. package/plugins/pm-claude/skills/pm-developer/SKILL.md +26 -0
  197. package/plugins/pm-claude/skills/pm-planner/SKILL.md +26 -0
  198. package/plugins/pm-claude/skills/pm-release/SKILL.md +26 -0
  199. package/plugins/pm-claude/skills/pm-workflow/SKILL.md +26 -0
  200. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  201. package/plugins/pm-codex/skills/pm-auditor/SKILL.md +26 -0
  202. package/plugins/pm-codex/skills/pm-native/SKILL.md +26 -0
  203. package/plugins/pm-codex/skills/pm-release/SKILL.md +26 -0
  204. package/sdk/public-surface.json +1243 -54
  205. package/dist/cli-bundle/chunks/chunk-47OQEOQB.js +0 -2
  206. package/dist/cli-bundle/chunks/chunk-HCIYWD6M.js +0 -35
  207. package/dist/cli-bundle/chunks/chunk-I2LUWWR5.js +0 -3
  208. package/dist/cli-bundle/chunks/chunk-IC5W2T34.js +0 -2
  209. package/dist/cli-bundle/chunks/chunk-OAC5NIV4.js +0 -3
  210. package/dist/cli-bundle/chunks/chunk-PANOOBIS.js +0 -13
  211. package/dist/cli-bundle/chunks/chunk-TK6N7HGM.js +0 -8
  212. package/dist/cli-bundle/chunks/chunk-TOFG2URD.js +0 -197
  213. package/dist/cli-bundle/chunks/register-list-query-EYCXHZAG.js +0 -10
  214. package/dist/cli-bundle/chunks/register-mutation-7YVIG54J.js +0 -20
  215. package/dist/cli-bundle/focused-chunks/chunk-5NMFSX26.js +0 -155
  216. package/dist/cli-bundle/focused-chunks/chunk-725JSCMP.js +0 -2
  217. package/dist/cli-bundle/focused-chunks/chunk-DQ6SMTBF.js +0 -2
  218. package/dist/cli-bundle/focused-chunks/chunk-HAACPSUW.js +0 -2
  219. package/dist/cli-bundle/focused-chunks/chunk-J4UFYHOD.js +0 -2
  220. package/dist/cli-bundle/focused-chunks/chunk-JX5Z344Q.js +0 -2
  221. package/dist/cli-bundle/focused-chunks/chunk-L4RDYBIQ.js +0 -2
  222. package/dist/cli-bundle/focused-chunks/chunk-NJ5RLEFD.js +0 -26
  223. package/dist/cli-bundle/focused-chunks/chunk-QYZERYR5.js +0 -4
  224. package/dist/cli-bundle/focused-chunks/chunk-TZATVC4G.js +0 -16
  225. package/dist/cli-bundle/focused-chunks/chunk-WY3WRPVN.js +0 -2
@@ -4,7 +4,7 @@
4
4
  * Defines public SDK APIs and package-author helpers for Runtime.
5
5
  */
6
6
 
7
- !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]="bedbe090-60c3-5935-a656-da4997cd80f7")}catch(e){}}();
7
+ !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]="48d9b905-70a1-52c3-9b9c-33624661e6eb")}catch(e){}}();
8
8
  export { PM_GITIGNORE_END, PM_GITIGNORE_START, ensurePmGitignore, getPmGitignoreBlock, } from "./workspace.js";
9
9
  export { SEARCH_EXTENSION_FLAG_DEFINITIONS } from "./extension-contracts.js";
10
10
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -23,6 +23,8 @@ import { resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, } from "../c
23
23
  import { getSettingsPath, resolvePmRoot } from "../core/store/paths.js";
24
24
  import { readSettings } from "../core/store/settings.js";
25
25
  import { listClientItemMetadataLight } from "./query/light-metadata.js";
26
+ import { certifyCompleteListResult, createCompleteListOptions } from "./query/complete-list.js";
27
+ export { PmCompleteListValidationError, assertCompleteListResult, certifyCompleteListResult, createCompleteListOptions, inspectCompleteListResult } from "./query/complete-list.js";
26
28
  import { buildWorkspaceExtensionCommandContracts, buildWorkspaceFieldContracts, } from "./workspace-contracts.js";
27
29
  import { PM_TOOL_ACTIONS } from "./cli-contracts/enum-contracts.js";
28
30
  import { clearWorkspaceContractsCache, memoizeWorkspaceExtensionRegistrations, } from "./workspace-contracts-cache.js";
@@ -181,6 +183,8 @@ export class PmClient {
181
183
  list(options = {}) {
182
184
  return this.runTyped("list", { options });
183
185
  }
186
+ /** Return every status and full item row only after fail-closed corpus certification. */
187
+ async listAllComplete(options = {}) { return certifyCompleteListResult(await this.list(createCompleteListOptions(options))); }
184
188
  /** Search items with the MCP/agent compact defaults. */
185
189
  search(query, options = {}) {
186
190
  return this.runTyped("search", { query, options });
@@ -673,9 +677,7 @@ export class PmClient {
673
677
  return this.runTyped("package-reload", { options });
674
678
  }
675
679
  /** Read bundled package catalog metadata using the same action as `pm package catalog`. */
676
- packageCatalog(options = {}) {
677
- return this.runTyped("package-catalog", { options });
678
- }
680
+ packageCatalog(options = {}) { return this.runTyped("package-catalog", { options }); }
679
681
  /** Enable an installed package using the same action as `pm package activate`. */
680
682
  packageActivate(target, options = {}) {
681
683
  return this.runTyped("package-activate", { target, options });
@@ -704,6 +706,8 @@ export function context(options = {}, clientOptions = {}) {
704
706
  export function list(options = {}, clientOptions = {}) {
705
707
  return new PmClient(clientOptions).list(options);
706
708
  }
709
+ /** Return every status and full item row with fail-closed corpus proof. */
710
+ export function listAllComplete(options = {}, clientOptions = {}) { return new PmClient(clientOptions).listAllComplete(options); }
707
711
  /** Search items with the MCP/agent compact defaults without constructing a reusable client. */
708
712
  export function search(query, options = {}, clientOptions = {}) {
709
713
  return new PmClient(clientOptions).search(query, options);
@@ -997,9 +1001,7 @@ export function packageReload(options = {}, clientOptions = {}) {
997
1001
  return new PmClient(clientOptions).packageReload(options);
998
1002
  }
999
1003
  /** Read bundled package catalog metadata without constructing a reusable client. */
1000
- export function packageCatalog(options = {}, clientOptions = {}) {
1001
- return new PmClient(clientOptions).packageCatalog(options);
1002
- }
1004
+ export function packageCatalog(options = {}, clientOptions = {}) { return new PmClient(clientOptions).packageCatalog(options); }
1003
1005
  /** Enable a package without constructing a reusable client. */
1004
1006
  export function packageActivate(target, options = {}, clientOptions = {}) {
1005
1007
  return new PmClient(clientOptions).packageActivate(target, options);
@@ -1338,6 +1340,7 @@ async function runMcpListAction(ctx) {
1338
1340
  const listOptions = applyContextIntentProjection("list", ctx.options);
1339
1341
  if (listOptions.compact === undefined &&
1340
1342
  listOptions.brief === undefined &&
1343
+ listOptions.full === undefined &&
1341
1344
  listOptions.fields === undefined &&
1342
1345
  listOptions.includeBody === undefined) {
1343
1346
  listOptions.compact = true;
@@ -1933,4 +1936,4 @@ async function loadWorkspaceExtensionRegistrations(pmRoot, settings, cwd) {
1933
1936
  }
1934
1937
  }
1935
1938
  //# sourceMappingURL=runtime.js.map
1936
- //# debugId=bedbe090-60c3-5935-a656-da4997cd80f7
1939
+ //# debugId=48d9b905-70a1-52c3-9b9c-33624661e6eb
@@ -500,6 +500,7 @@ export declare function formatSchemaApplyPresetHuman(result: SchemaApplyPresetRe
500
500
  export declare function formatSchemaInferTypesHuman(result: SchemaAddTypeInferResult): string;
501
501
  /** Re-export so register-mutation can surface the hint in usage examples without importing the core module directly. */
502
502
  export { buildInvalidTypeHint };
503
+ export type { RuntimeFieldDefinition, RuntimeFieldValueSchema, } from "../core/schema/fields-file.js";
503
504
  /** Public contract for test only schema command, shared by SDK and presentation-layer consumers. */
504
505
  export declare const _testOnlySchemaCommand: {
505
506
  workflowSlotsReferencing: typeof workflowSlotsReferencing;
@@ -4,7 +4,7 @@
4
4
  * Owns typed schema customization primitives shared by SDK, CLI, and MCP consumers.
5
5
  */
6
6
 
7
- !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]="1a035e10-b8fe-52cd-a9c7-0762dd0ab160")}catch(e){}}();
7
+ !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]="2ab8a5a9-dbea-526f-a541-b7ca2b106ac5")}catch(e){}}();
8
8
  import path from "node:path";
9
9
  import { mkdir } from "node:fs/promises";
10
10
  import { resolveAuthor } from "../core/shared/author.js";
@@ -1365,4 +1365,4 @@ export const _testOnlySchemaCommand = {
1365
1365
  workflowSlotsReferencing,
1366
1366
  };
1367
1367
  //# sourceMappingURL=schema.js.map
1368
- //# debugId=1a035e10-b8fe-52cd-a9c7-0762dd0ab160
1368
+ //# debugId=2ab8a5a9-dbea-526f-a541-b7ca2b106ac5
@@ -201,7 +201,9 @@ declare function formatLinkedTestExecutionError(result: LinkedTestExecutionResul
201
201
  export declare function classifyLinkedTestFailure(result: Pick<LinkedTestExecutionResult, "stdout" | "stderr" | "spawnError" | "signal" | "timedOut" | "maxBufferExceeded">): LinkedTestFailureCategory;
202
202
  /** Implements count failure categories for the public runtime surface of this module. */
203
203
  export declare function countFailureCategories(runResults: TestRunResult[]): Record<LinkedTestFailureCategory, number>;
204
- declare function copyIntoSandboxIfPresent(sourcePath: string, targetPath: string, recursive?: boolean): Promise<void>;
204
+ declare function copyIntoSandboxIfPresent(sourcePath: string, targetPath: string, recursive?: boolean, makeDirectory?: (targetPath: string, options: {
205
+ recursive: true;
206
+ }) => Promise<unknown>): Promise<void>;
205
207
  declare function seedLinkedTestSandbox(sandboxPmPath: string, sandboxGlobalPath: string, sourceRoots: LinkedTestSandboxSourceRoots): Promise<void>;
206
208
  declare function seedLinkedTestTrackerData(sourceRoot: string, sandboxRoot: string): Promise<void>;
207
209
  declare function countLinkedTestItemFiles(pmRoot: string): Promise<number>;
@@ -242,7 +244,8 @@ interface LinkedTestSandboxCounts {
242
244
  trackerProjectItemCount: number;
243
245
  trackerGlobalItemCount: number;
244
246
  }
245
- declare function initializeLinkedTestSandboxes(layout: LinkedTestSandboxLayout, initialize?: (...args: Parameters<typeof runInit>) => Promise<unknown>): Promise<void>;
247
+ declare function initializeLinkedTestSandboxes(layout: LinkedTestSandboxLayout, initialize?: (...args: Parameters<typeof runInit>) => Promise<unknown>, includeTrackerData?: boolean): Promise<void>;
248
+ declare function linkedTestsRequireTrackerData(tests: LinkedTest[], runLevelPmContextMode: LinkedTestPmContextMode, options: RunLinkedTestsOptions | undefined): boolean;
246
249
  declare function buildLinkedTestExecutionContext(params: {
247
250
  layout: LinkedTestSandboxLayout;
248
251
  counts: LinkedTestSandboxCounts;
@@ -280,6 +283,7 @@ export declare const _testOnlyTestCommand: {
280
283
  formatLinkedTestExecutionError: typeof formatLinkedTestExecutionError;
281
284
  hasLinkedTestAssertions: typeof hasLinkedTestAssertions;
282
285
  initializeLinkedTestSandboxes: typeof initializeLinkedTestSandboxes;
286
+ linkedTestsRequireTrackerData: typeof linkedTestsRequireTrackerData;
283
287
  parseAddJsonEntries: typeof parseAddJsonEntries;
284
288
  parseLinkedTestTimeoutSeconds: typeof parseLinkedTestTimeoutSeconds;
285
289
  parsePmContextMode: typeof parsePmContextMode;
@@ -4,7 +4,7 @@
4
4
  * Implements the pm test command surface and its agent-facing runtime behavior.
5
5
  */
6
6
 
7
- !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]="76053150-cc55-57e0-80d6-369196284cd0")}catch(e){}}();
7
+ !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]="4322c352-6b95-5796-94eb-5a68745d53bc")}catch(e){}}();
8
8
  import { spawn } from "node:child_process";
9
9
  import { cp, mkdir, mkdtemp, open, readdir, rm } from "node:fs/promises";
10
10
  import { tmpdir } from "node:os";
@@ -28,6 +28,7 @@ import { LINKED_TEST_PM_CONTEXT_MODE_VALUES as PM_CONTEXT_MODE_VALUES, LINKED_TE
28
28
  import { parseOnlyIndexValue, resolveLinkedTestRunSelection, } from "../../core/test/run-selectors.js";
29
29
  import { SCOPE_VALUES } from "../../types/index.js";
30
30
  import { diffTestRunMeasurements, parseTestRunMeasurements, queryTestRunMeasurementsBelow, } from "./measurements.js";
31
+ import { withHostEnvironmentBoundary } from "../environment/host-environment-errors.js";
31
32
  import { SOURCE_CONTEXT_ACCESS_ENV } from "../environment/source-context.js";
32
33
  const TEST_OUTPUT_MAX_BUFFER_BYTES = 20 * 1024 * 1024;
33
34
  const DEFAULT_LINKED_TEST_TIMEOUT_FORCE_KILL_DELAY_MS = 3000;
@@ -973,17 +974,24 @@ function resolveRuntimeDirectives(envSetEntries, envClearEntries, sharedHostSafe
973
974
  };
974
975
  }
975
976
  /* c8 ignore start -- sandbox copy race/path permutations are covered by filesystem integration suites */
976
- async function copyIntoSandboxIfPresent(sourcePath, targetPath, recursive = false) {
977
+ async function copyIntoSandboxIfPresent(sourcePath, targetPath, recursive = false, makeDirectory = mkdir) {
977
978
  if (!(await pathExists(sourcePath))) {
978
979
  return;
979
980
  }
980
- await mkdir(path.dirname(targetPath), { recursive: true });
981
981
  try {
982
- if (recursive) {
983
- await cp(sourcePath, targetPath, { recursive: true, force: true });
984
- return;
985
- }
986
- await cp(sourcePath, targetPath, { force: true });
982
+ await withHostEnvironmentBoundary("seed_linked_test", async () => {
983
+ await makeDirectory(path.dirname(targetPath), { recursive: true });
984
+ if (recursive) {
985
+ await cp(sourcePath, targetPath, { recursive: true, force: true });
986
+ return;
987
+ }
988
+ await cp(sourcePath, targetPath, { force: true });
989
+ }, {
990
+ why: "Linked tests need an isolated PM context without mutating the source tracker.",
991
+ nextSteps: [
992
+ "Reclaim capacity on the filesystem that hosts the linked-test temporary directory.",
993
+ ],
994
+ });
987
995
  }
988
996
  catch (error) {
989
997
  if (typeof error === "object" &&
@@ -1257,22 +1265,38 @@ function createLinkedTestSandboxLayout(sandboxRoot) {
1257
1265
  trackerGlobalPmPath: path.join(sandboxRoot, "tracker", "global"),
1258
1266
  };
1259
1267
  }
1260
- async function initializeLinkedTestSandboxes(layout, initialize = runInit) {
1268
+ async function initializeLinkedTestSandboxes(layout, initialize = runInit, includeTrackerData = true) {
1261
1269
  const initOptions = { defaults: true, agentGuidance: "skip" };
1262
1270
  await initialize(undefined, { path: layout.schemaProjectPmPath }, initOptions);
1263
1271
  await initialize(undefined, { path: layout.schemaGlobalPmPath }, initOptions);
1272
+ if (!includeTrackerData) {
1273
+ return;
1274
+ }
1264
1275
  await initialize(undefined, { path: layout.trackerProjectPmPath }, initOptions);
1265
1276
  await initialize(undefined, { path: layout.trackerGlobalPmPath }, initOptions);
1266
1277
  }
1267
- async function seedLinkedTestSandboxesFromSource(layout, sourceRoots) {
1278
+ async function seedLinkedTestSandboxesFromSource(layout, sourceRoots, includeTrackerData) {
1268
1279
  if (!sourceRoots) {
1269
1280
  return;
1270
1281
  }
1271
1282
  await seedLinkedTestSandbox(layout.schemaProjectPmPath, layout.schemaGlobalPmPath, sourceRoots);
1283
+ if (!includeTrackerData) {
1284
+ return;
1285
+ }
1272
1286
  await seedLinkedTestSandbox(layout.trackerProjectPmPath, layout.trackerGlobalPmPath, sourceRoots);
1273
1287
  await seedLinkedTestTrackerData(sourceRoots.projectPmRoot, layout.trackerProjectPmPath);
1274
1288
  await seedLinkedTestTrackerData(sourceRoots.globalPmRoot, layout.trackerGlobalPmPath);
1275
1289
  }
1290
+ function linkedTestsRequireTrackerData(tests, runLevelPmContextMode, options) {
1291
+ return tests.some((linkedTest) => {
1292
+ const command = linkedTest.command ?? "";
1293
+ const isPmTrackerReadCommand = command.length > 0 && commandInvokesPmTrackerReadCommand(command);
1294
+ const requestedPmContextMode = options?.autoPmContext === true && isPmTrackerReadCommand
1295
+ ? "auto"
1296
+ : resolveLinkedTestRequestedContextMode(linkedTest, runLevelPmContextMode, options?.overrideLinkedPmContext === true);
1297
+ return (resolveLinkedTestEffectiveContextMode(requestedPmContextMode, isPmTrackerReadCommand) === "tracker");
1298
+ });
1299
+ }
1276
1300
  async function countLinkedTestSandboxItems(layout, sourceRoots) {
1277
1301
  return {
1278
1302
  sourceProjectItemCount: sourceRoots
@@ -1510,9 +1534,10 @@ export async function runLinkedTests(tests, defaultTimeoutSeconds, options) {
1510
1534
  const progressMode = options?.progress === true ? "always" : "auto";
1511
1535
  const runtimeDirectives = resolveRuntimeDirectives(options?.envSet, options?.envClear, options?.sharedHostSafe);
1512
1536
  const sourceRoots = options?.sourceRoots;
1537
+ const includeTrackerData = linkedTestsRequireTrackerData(tests, runLevelPmContextMode, options);
1513
1538
  try {
1514
- await initializeLinkedTestSandboxes(layout);
1515
- await seedLinkedTestSandboxesFromSource(layout, sourceRoots);
1539
+ await initializeLinkedTestSandboxes(layout, runInit, includeTrackerData);
1540
+ await seedLinkedTestSandboxesFromSource(layout, sourceRoots, includeTrackerData);
1516
1541
  const counts = await countLinkedTestSandboxItems(layout, sourceRoots);
1517
1542
  for (let index = 0; index < tests.length; index += 1) {
1518
1543
  const linkedTest = tests[index];
@@ -1920,6 +1945,7 @@ export const _testOnlyTestCommand = {
1920
1945
  formatLinkedTestExecutionError,
1921
1946
  hasLinkedTestAssertions,
1922
1947
  initializeLinkedTestSandboxes,
1948
+ linkedTestsRequireTrackerData,
1923
1949
  parseAddJsonEntries,
1924
1950
  parseLinkedTestTimeoutSeconds,
1925
1951
  parsePmContextMode,
@@ -1939,4 +1965,4 @@ export const _testOnlyTestCommand = {
1939
1965
  summarizeRunResultStatuses,
1940
1966
  };
1941
1967
  //# sourceMappingURL=execution.js.map
1942
- //# debugId=76053150-cc55-57e0-80d6-369196284cd0
1968
+ //# debugId=4322c352-6b95-5796-94eb-5a68745d53bc
package/dist/types.d.ts CHANGED
@@ -32,7 +32,7 @@ export declare const RUNTIME_UNKNOWN_FIELD_POLICY_VALUES: readonly ["allow", "wa
32
32
  /** Restricts runtime unknown field policy values accepted by command, SDK, and storage contracts. */
33
33
  export type RuntimeUnknownFieldPolicy = (typeof RUNTIME_UNKNOWN_FIELD_POLICY_VALUES)[number];
34
34
  /** Supported values accepted by the dependency kind contract. */
35
- export declare const DEPENDENCY_KIND_VALUES: readonly ["blocks", "parent", "child", "parent_child", "child_of", "related", "related_to", "discovered_from", "blocked_by", "incident_from", "epic", "implements", "supersedes", "task", "verifies"];
35
+ export declare const DEPENDENCY_KIND_VALUES: readonly ["blocks", "parent", "child", "parent_child", "child_of", "related", "related_to", "discovered_from", "blocked_by", "incident_from", "epic", "implements", "recurs_from", "supersedes", "task", "verifies"];
36
36
  /** Restricts dependency kind values accepted by command, SDK, and storage contracts. */
37
37
  export type DependencyKind = (typeof DEPENDENCY_KIND_VALUES)[number];
38
38
  /** Supported values accepted by the scope contract. */
@@ -266,7 +266,7 @@ export declare const PLAN_HARNESS_VALUES: readonly ["codex", "claude-code", "cur
266
266
  /** Restricts plan harness values accepted by command, SDK, and storage contracts. */
267
267
  export type PlanHarness = (typeof PLAN_HARNESS_VALUES)[number];
268
268
  /** Supported values accepted by the plan step link kind contract. */
269
- export declare const PLAN_STEP_LINK_KIND_VALUES: readonly ["related", "blocks", "blocked_by", "depends_on", "discovered_from", "implements", "verifies", "supersedes"];
269
+ export declare const PLAN_STEP_LINK_KIND_VALUES: readonly ["related", "blocks", "blocked_by", "depends_on", "discovered_from", "implements", "recurs_from", "verifies", "supersedes"];
270
270
  /** Restricts plan step link kind values accepted by command, SDK, and storage contracts. */
271
271
  export type PlanStepLinkKind = (typeof PLAN_STEP_LINK_KIND_VALUES)[number];
272
272
  /** Documents the plan step link payload exchanged by command, SDK, and package integrations. */
@@ -437,6 +437,31 @@ export interface RuntimeStatusDefinition {
437
437
  /** Value that configures or reports order for this contract. */
438
438
  order?: number;
439
439
  }
440
+ /** Declarative JSON-value constraints enforced before custom-field persistence. */
441
+ export interface RuntimeFieldValueSchema {
442
+ /** Optional JSON value type constraint. */
443
+ type?: "string" | "number" | "boolean" | "array" | "object";
444
+ /** Exact JSON value required by this schema branch. */
445
+ const?: StructuredJsonValue;
446
+ /** Complete allowed JSON value set. */
447
+ enum?: StructuredJsonValue[];
448
+ /** Minimum accepted string length. */
449
+ min_length?: number;
450
+ /** Minimum accepted array length. */
451
+ min_items?: number;
452
+ /** Optional semantic string format. */
453
+ format?: "date-time";
454
+ /** Object-property schemas keyed by the persisted property name. */
455
+ properties?: Record<string, RuntimeFieldValueSchema>;
456
+ /** Object properties that must be present. */
457
+ required?: string[];
458
+ /** Whether properties absent from `properties` are accepted. */
459
+ additional_properties?: boolean;
460
+ /** Schema applied to every array element. */
461
+ items?: RuntimeFieldValueSchema;
462
+ /** Alternative schemas of which exactly one must match. */
463
+ one_of?: RuntimeFieldValueSchema[];
464
+ }
440
465
  /** Documents the runtime field definition payload exchanged by command, SDK, and package integrations. */
441
466
  export interface RuntimeFieldDefinition {
442
467
  /** Value that configures or reports key for this contract. */
@@ -467,6 +492,8 @@ export interface RuntimeFieldDefinition {
467
492
  required_types?: string[];
468
493
  /** Value that configures or reports allow unset for this contract. */
469
494
  allow_unset?: boolean;
495
+ /** Optional semantic JSON-value constraints enforced on create and update. */
496
+ value_schema?: RuntimeFieldValueSchema;
470
497
  }
471
498
  /** Documents the runtime workflow definition payload exchanged by command, SDK, and package integrations. */
472
499
  export interface RuntimeWorkflowDefinition {
@@ -1051,6 +1078,11 @@ export interface PmSettings {
1051
1078
  output: {
1052
1079
  default_format: "toon" | "json";
1053
1080
  };
1081
+ /** Agent and human interaction preferences that do not change command semantics. */
1082
+ ux?: {
1083
+ /** Emit one stderr migration hint when a deprecated command alias is invoked. */
1084
+ deprecation_hints?: boolean;
1085
+ };
1054
1086
  /** Value that configures or reports history for this contract. */
1055
1087
  history: {
1056
1088
  missing_stream: "auto_create" | "strict_error";
package/dist/types.js CHANGED
@@ -5,7 +5,7 @@
5
5
  */
6
6
  /** Supported values accepted by the builtin item type contract. */
7
7
 
8
- !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]="8b39bc01-0325-5dc6-8492-585c98608076")}catch(e){}}();
8
+ !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]="f6ab5bae-53b3-5feb-b89f-46e64afe7058")}catch(e){}}();
9
9
  export const BUILTIN_ITEM_TYPE_VALUES = [
10
10
  "Epic",
11
11
  "Feature",
@@ -81,6 +81,7 @@ export const DEPENDENCY_KIND_VALUES = [
81
81
  "incident_from",
82
82
  "epic",
83
83
  "implements",
84
+ "recurs_from",
84
85
  "supersedes",
85
86
  "task",
86
87
  "verifies",
@@ -217,6 +218,7 @@ export const PLAN_STEP_LINK_KIND_VALUES = [
217
218
  "depends_on",
218
219
  "discovered_from",
219
220
  "implements",
221
+ "recurs_from",
220
222
  "verifies",
221
223
  "supersedes",
222
224
  ];
@@ -241,4 +243,4 @@ export const CONTEXT_SECTION_VALUES = [
241
243
  "tests",
242
244
  ];
243
245
  //# sourceMappingURL=types.js.map
244
- //# debugId=8b39bc01-0325-5dc6-8492-585c98608076
246
+ //# debugId=f6ab5bae-53b3-5feb-b89f-46e64afe7058
@@ -9,8 +9,8 @@ Run this before heavy work:
9
9
  ```bash
10
10
  pm context --limit 10
11
11
  pm search "<request keywords>" --limit 10
12
- pm list-open --limit 20
13
- pm list-in-progress --limit 20
12
+ pm list --status open --limit 20
13
+ pm list --status in_progress --limit 20
14
14
  pm init --agent-guidance status
15
15
  pm install guide-shell --project
16
16
  pm guide workflows
@@ -28,8 +28,8 @@ Tracked documentation work: [pm-u9d0](../.agents/pm/epics/pm-u9d0.toon).
28
28
  ```bash
29
29
  pm context --limit 10
30
30
  pm search "<keywords>" --limit 10
31
- pm list-open --limit 20
32
- pm list-in-progress --limit 20
31
+ pm list --status open --limit 20
32
+ pm list --status in_progress --limit 20
33
33
  ```
34
34
 
35
35
  2. **Create only when necessary**
@@ -115,13 +115,13 @@ pm release <item-id>
115
115
  | Require every query token | `pm search "<keywords>" --match-mode and` (hard-filter; `exact` = contiguous phrase; default `or` adds an all-terms ranking bonus) |
116
116
  | Just the match count | `pm search "<keywords>" --count` (no hit rows; `count`/`total` carry the matched total) |
117
117
  | Per-query score threshold | `pm search "<keywords>" --min-score 5` (overrides settings `search.score_threshold` for this query) |
118
- | Every matched row (no cap) | `pm list-all --no-truncate --brief` (alias `--all`; `result.total` reports the full count when a `--limit`/`--offset` truncates) |
119
- | Item bodies in bulk (one call) | `pm list-open --json --include-body` (avoids one `pm get` per item) |
118
+ | Every matched row (no cap) | `pm list --all --no-truncate --brief` (`result.total` reports the full count when a `--limit`/`--offset` truncates) |
119
+ | Item bodies in bulk (one call) | `pm list --status open --json --include-body` (avoids one `pm get` per item) |
120
120
  | Open work only | `pm search "<keywords>" --status open` (drops closed-history noise; did-you-mean on typos) |
121
121
  | Scope search like list | `pm search "<keywords>" --type Task --assignee <name> --parent <id>` (full `pm list` filter parity) |
122
- | Items changed since last window | `pm list-all --updated-after <prev-run-ISO> --brief` (relative `-2h`/`-7d` also work) |
123
- | Open items changed today | `pm list-open --today --brief` (local-midnight shorthand; mutually exclusive with `--updated-after`) |
124
- | Items changed recently | `pm list-all --recent --brief` (last seven days; mutually exclusive with `--updated-after`) |
122
+ | Items changed since last window | `pm list --all --updated-after <prev-run-ISO> --brief` (relative `-2h`/`-7d` also work) |
123
+ | Open items changed today | `pm list --status open --today --brief` (local-midnight shorthand; mutually exclusive with `--updated-after`) |
124
+ | Items changed recently | `pm list --all --recent --brief` (last seven days; mutually exclusive with `--updated-after`) |
125
125
  | Single item | `pm get <id>` |
126
126
  | Full machine payload | `pm get <id> --full --json` |
127
127
  | Command flags | `pm <command> --help --json` |
@@ -171,6 +171,22 @@ Use the canonical [guide topic map](README.md#guide-topic-map) when local in-CLI
171
171
  - Use `--force` only for explicit override paths.
172
172
  - Release when pausing, handing off, or after close.
173
173
 
174
+ ## Reviewed Delivery Closeout
175
+
176
+ Treat PM evidence, item closure, and the generated changelog as part of the
177
+ reviewed change. Add all evidence known before merge to the active branch,
178
+ close and release the item there, regenerate `CHANGELOG.md`, and include those
179
+ artifacts in the same pull request.
180
+
181
+ If evidence depends on the merge commit SHA or a post-merge hosted result, use
182
+ a normal `main`-based follow-up pull request for the repository mutation. Never
183
+ push tracker-only or changelog-only closeout directly to `main`: that direct
184
+ commit becomes the release candidate but has no reviewed analyzer provenance,
185
+ so `Release analyzer readiness (main)` must refuse it. Record external
186
+ post-merge observations on GitHub without changing repository state when no
187
+ tracked closeout update is required. See [Releasing](RELEASING.md#reviewed-delivery-closeout)
188
+ for the release contract.
189
+
174
190
  ## Documentation Rules for Agents
175
191
 
176
192
  - Keep [README](../README.md) short.
@@ -0,0 +1,106 @@
1
+ # Noun–Verb CLI Grammar and Compatibility Policy
2
+
3
+ Tracked by [pm-pbyu](../.agents/pm/decisions/pm-pbyu.toon), implemented through [pm-0z7n](../.agents/pm/features/pm-0z7n.toon), [pm-pfqi](../.agents/pm/tasks/pm-pfqi.toon), [pm-yy8rmx](../.agents/pm/tasks/pm-yy8rmx.toon), and [pm-wt43zj](../.agents/pm/tasks/pm-wt43zj.toon).
4
+
5
+ ## Agent Quick Context
6
+
7
+ Use the canonical noun-first form when generating commands. Existing spellings remain executable, but deprecated compatibility aliases are absent from default help and completion discovery and emit one migration hint on stderr. Machine clients can read alias lifecycle and replacement tokens from `pm contracts --full --json`.
8
+
9
+ The first completed consolidation is the list family:
10
+
11
+ ```bash
12
+ pm list # active lifecycle rows
13
+ pm list --status open # one lifecycle class
14
+ pm list --status open,blocked # several classes
15
+ pm list --status blocked # status- or dependency-blocked semantics
16
+ pm list --all # every lifecycle status
17
+ ```
18
+
19
+ `list-all`, `list-draft`, `list-open`, `list-in-progress`, `list-blocked`, `list-closed`, and `list-canceled` preserve command results and stdout behavior. Their documented migration hint may add one stderr line.
20
+
21
+ ## Status
22
+
23
+ Accepted. The grammar contract, destination census, and compatibility policy are executable SDK data and mandatory static gates.
24
+
25
+ ## Context
26
+
27
+ pm grew by adding one top-level spelling per feature. That made help, completions, contracts, documentation, and agent routing grow linearly even when several commands represented the same concept. The list family alone repeated almost the same help surface eight times. A universal project-management tool needs extensible behavior without requiring every agent to memorize an ever-growing flat vocabulary.
28
+
29
+ The governing product principle is `project management = context management`: command discovery must route an agent to the smallest authoritative context, while compatibility must preserve scripts and historical instructions.
30
+
31
+ ## Decision Drivers
32
+
33
+ - Preserve every published invocation and its stdout behavior.
34
+ - Keep frequent operations concise without making aliases the discovery model.
35
+ - Make domain ownership explicit enough to generate routing, help, completions, SDK contracts, MCP projections, and documentation.
36
+ - Prevent surface regrowth with a fail-closed, bidirectional contract gate.
37
+ - Let packages add domain behavior without consuming the core noun budget.
38
+ - Make migration guidance suppressible for automation while keeping canonical replacements machine-readable.
39
+
40
+ ## Alternatives Considered
41
+
42
+ ### Flat surface status quo
43
+
44
+ Rejected. Each feature adds another root spelling and duplicates contract/help context. A byte-count snapshot records growth but does not decide whether the new command belongs in the architecture.
45
+
46
+ ### Pure git-style subcommands
47
+
48
+ Rejected as an exclusive rule. Noun-first paths are canonical, but forcing high-frequency operations such as `create`, `get`, `update`, `claim`, and `close` to pay an extra token on every invocation would regress the agent hot path. Named permanent aliases may remain visible and are distinguished from deprecated compatibility shims in contract data.
49
+
50
+ ### BusyBox-style multi-binary surface
51
+
52
+ Rejected. Separate binaries multiply distribution, signing, package resolution, documentation, and shell-discovery surfaces without improving domain routing.
53
+
54
+ ## Decision
55
+
56
+ 1. The core routing vocabulary has twelve nouns: `item`, `list`, `context`, `search`, `graph`, `history`, `workspace`, `package`, `ops`, `plan`, `contracts`, and `help`.
57
+ 2. Canonical forms are noun-first. Verbs and facets are subcommands; projections and predicates are flags.
58
+ 3. Shared semantics use a shared verb vocabulary. Noun-specific verbs require an explicit checked-in disposition.
59
+ 4. Scope precedes its operation: for example, `workspace snapshot create`, not `workspace create snapshot`.
60
+ 5. Package-owned commands are declared as such and do not silently expand the core noun set.
61
+ 6. Published spellings are not removed. Deprecated spellings are hidden aliases with a canonical token sequence, PM owner, lifecycle, and one stderr migration hint.
62
+ 7. Permanent hot-path aliases and deprecated aliases are different contract states. Permanent aliases are ergonomic API; deprecated aliases are compatibility state.
63
+ 8. Every live command has exactly one destination row. A row may name its target noun, a tracked consolidation owner, a package owner, or a reasoned keep-as-is exception.
64
+ 9. The census is bidirectional: missing live rows and stale checked-in rows both fail CI.
65
+ 10. Default-visible top-level growth is ceilinged. Lowering the ceiling is always valid; raising it requires a tracked noun-placement decision rather than regenerating a baseline.
66
+
67
+ ## SDK Contract
68
+
69
+ Package authors and embedded clients use the public exports:
70
+
71
+ ```ts
72
+ import {
73
+ PM_CLI_GRAMMAR_CONTRACT,
74
+ PM_COMMAND_ALIAS_CONTRACTS,
75
+ PM_COMMAND_DESTINATION_CONTRACTS,
76
+ resolvePmCommandAlias,
77
+ verifyPmCliGrammar,
78
+ } from "@unbrained/pm-cli/sdk";
79
+ ```
80
+
81
+ `PM_COMMAND_ALIAS_CONTRACTS` carries `alias`, `canonical`, `canonical_argv`, `lifecycle`, `hidden`, `registration`, and `owner`. `verifyPmCliGrammar` returns deterministic findings with an offending spelling and nearest conforming target.
82
+
83
+ Runtime contracts expose the compact noun/verb policy in summary output and include the exhaustive destination census in full output. Deprecated aliases remain queryable but are excluded from the default command-summary denominator.
84
+
85
+ ## Compatibility and Migration Hints
86
+
87
+ Hints go to stderr exactly once per deprecated-alias invocation and never alter stdout. Disable them for a project when an automation intentionally retains old spellings:
88
+
89
+ ```bash
90
+ pm config project set ux_deprecation_hints false
91
+ ```
92
+
93
+ This setting changes presentation only. It does not disable aliases or change command results. The uniform machine result-envelope receipt is intentionally deferred to its separately tracked cross-command contract so this implementation does not create a list-only shape.
94
+
95
+ ## Enforcement
96
+
97
+ `pnpm quality:command-grammar` builds the SDK, reads the live runtime command contracts, and compares them with the checked-in destination and alias tables. Package-owned destination rows are conditional because installed packages vary by workspace; every activated package command still requires a declared row, while an inactive package does not make its row stale. The gate also proves parity between discoverable SDK actions, the MCP `pm_run` action enum, and narrow MCP tools. The same gate runs inside `quality:static`, alongside contract drift checks. Its negative controls prove that unknown commands, stale core rows, broken alias targets, MCP drift, and surface-ceiling growth fail upward.
98
+
99
+ ## Consequences
100
+
101
+ - Agents discover one list command instead of eight repeated help pages.
102
+ - Existing scripts keep working and receive an actionable replacement.
103
+ - CLI, SDK, completion, and contract consumers share one alias table.
104
+ - New commands require an explicit architectural home and PM owner.
105
+ - The compatibility table is long-lived public API and must be reviewed like any other SDK contract.
106
+ - Consolidation proceeds incrementally: current legacy commands may remain only with a named disposition until their owning PM item lands.
package/docs/COMMANDS.md CHANGED
@@ -141,8 +141,8 @@ pm search "calendar reminder validation" --limit 10
141
141
  pm get pm-a1b2 # read one item; add --fields/--depth for lower-token projections
142
142
  pm get pm-a1b2 --tree --tree-depth 2 # item plus its descendant subtree
143
143
  pm get pm-a1b2 --at 7 # verified, mutation-free historical version
144
- pm list-open --type Task --priority 1 --limit 20
145
- pm list-in-progress --limit 20
144
+ pm list --status open --type Task --priority 1 --limit 20
145
+ pm list --status in_progress --limit 20
146
146
  pm aggregate --group-by parent,type --status open
147
147
  pm aggregate --group-by parent,type --completion --include-unparented
148
148
  pm duplicates --status all --threshold 0.8
@@ -173,7 +173,7 @@ Each aggregate row carries an explicit `group_label`: a blank/null group value (
173
173
  `--sort` accepts `priority|deadline|updated_at|created_at|title|parent`, plus the convenience aliases `updated` (→ `updated_at`) and `created` (→ `created_at`):
174
174
 
175
175
  ```bash
176
- pm list-all --sort updated --order desc
176
+ pm list --all --sort updated --order desc
177
177
  ```
178
178
 
179
179
  ### Incremental "what changed since" filters
@@ -182,16 +182,16 @@ Every `list*` command accepts `--updated-after`/`--updated-before`/`--created-af
182
182
 
183
183
  ```bash
184
184
  # Items touched since my last context window (feed back the previous run's `now`)
185
- pm list-all --updated-after 2026-06-04T15:18:32Z --brief
185
+ pm list --all --updated-after 2026-06-04T15:18:32Z --brief
186
186
 
187
187
  # Relative offsets are SIGNED: -2h/-7d reach into the past, +1d into the future.
188
188
  # Units are h/d/w/m (m = months — there is no minutes unit).
189
- pm list-open --updated-after=-2h --brief
190
- pm list-all --created-after=-7d --status open
189
+ pm list --status open --updated-after=-2h --brief
190
+ pm list --status open --created-after=-7d
191
191
 
192
- # Common list windows avoid date math (`list-open` keeps the view open-only).
193
- pm list-open --today --brief
194
- pm list-all --recent --brief
192
+ # Common list windows avoid date math (`pm list --status open` keeps the view open-only).
193
+ pm list --status open --today --brief
194
+ pm list --all --recent --brief
195
195
 
196
196
  # Search scoped to open work only (drops closed-history noise); statuses accept
197
197
  # all (no lifecycle restriction), open/closed/canceled aliases, or configured
@@ -293,12 +293,12 @@ pm eval --fail-under 0.6 --json # CI gate: exit non-zero when aggregate nDC
293
293
 
294
294
  ### Full results, totals, and bodies
295
295
 
296
- `pm list*` returns every matched row when neither `--limit` nor `--offset` is set. Every JSON/TOON result has the same pagination envelope: `total` is the pre-pagination match count, `has_more` and `truncated` are booleans, and `next_cursor` is either the continuation token or `null`. `completeness` reports whether the corpus was `complete`, `partial`, or `unchecked` (derived-index page), with unreadable item/directory counts. Use `--strict-read` when omissions must fail the command. The `filters` object omits unset values instead of emitting null placeholders, keeping long-running agent context stable and lean. Pass `--no-truncate` (alias `--all`) to force the entire matched set and override any `--limit` in one call the canonical "give me everything" flag for large-corpus audits:
296
+ `pm list` returns every matched row when neither `--limit` nor `--offset` is set. Every JSON/TOON result has the same pagination envelope: `total` is the pre-pagination match count, `has_more` and `truncated` are booleans, and `next_cursor` is either the continuation token or `null`. `completeness` reports whether the corpus was `complete`, `partial`, or `unchecked` (derived-index page), with unreadable item/directory counts. Use `--strict-read` when omissions must fail the command. The `filters` object omits unset values instead of emitting null placeholders, keeping long-running agent context stable and lean. Pass `--no-truncate` to force the entire matched set and override any `--limit` in one call. `--all` selects every lifecycle status; combine the flags for an unbounded all-status audit:
297
297
 
298
298
  ```bash
299
- pm list-all --no-truncate --brief # every matched row, ignoring any --limit
300
- pm list-open --limit 20 --json # stable total/has_more/truncated/next_cursor envelope
301
- pm list-all --strict-read --json # fail if any source item cannot be read
299
+ pm list --all --no-truncate --brief # every matched row, ignoring any --limit
300
+ pm list --status open --limit 20 --json # stable total/has_more/truncated/next_cursor envelope
301
+ pm list --all --strict-read --json # fail if any source item cannot be read
302
302
  ```
303
303
 
304
304
  Compatibility note: older responses emitted `total` only when pagination
@@ -312,7 +312,7 @@ unconditional pre-pagination match count, branch on `has_more` or
312
312
  JSON output is compact by default (id/status/type/title) for token efficiency. To pull item bodies in bulk in a single call — instead of one `pm get` per item — add `--include-body`, which expands each row to the full field set plus `body`:
313
313
 
314
314
  ```bash
315
- pm list-open --json --include-body # full fields + body for every returned row
315
+ pm list --status open --json --include-body # full fields + body for every returned row
316
316
  ```
317
317
 
318
318
  `pm get <id> --json` returns the item's `body` **inside** the `item` object (i.e. `.item.body`), matching where `list --include-body` places it and the long-form `description`/`acceptance_criteria` fields — so a single read exposes every field at a consistent path. Body is included at the default `standard` depth and above; `--depth brief` omits it.
@@ -322,10 +322,10 @@ pm list-open --json --include-body # full fields + body for every return
322
322
  `pm list*` accepts `--format <csv|table|json|ndjson|toon>` to choose how rows render. `csv` and `table` are **human export** modes — pipe them into a spreadsheet or read them directly in a terminal — while `json`/`toon` override the machine output format the same way the global `--json` flag does. `ndjson` writes each projected item as one self-contained JSON object per line, with no wrapper or trailing summary. The rendered fields follow the active projection, so combine `--format` with `--fields`/`--brief`/`--compact` to control exactly what appears:
323
323
 
324
324
  ```bash
325
- pm list-open --format table # aligned, monospace-friendly columns
326
- pm list-all --fields id,title,priority --format csv # spreadsheet export with chosen columns
327
- pm list-open --format csv > backlog.csv # capture for reporting
328
- pm list-all --brief --format ndjson | jq -c 'select(.status == "open")'
325
+ pm list --status open --format table # aligned, monospace-friendly columns
326
+ pm list --all --fields id,title,priority --format csv # spreadsheet export with chosen columns
327
+ pm list --status open --format csv > backlog.csv # capture for reporting
328
+ pm list --all --brief --format ndjson | jq -c 'select(.status == "open")'
329
329
  ```
330
330
 
331
331
  CSV output is RFC 4180 compliant (values with commas, quotes, or newlines are quoted; array fields such as `tags` join with `;`). `--format csv|table|ndjson` cannot be combined with the legacy envelope-oriented `--stream` mode.
@@ -338,13 +338,13 @@ The same `list*` commands and `pm search` extend this with governance-field pres
338
338
 
339
339
  ```bash
340
340
  # Find open Tasks that still need acceptance criteria
341
- pm list-open --type Task --filter-ac-missing --brief
341
+ pm list --status open --type Task --filter-ac-missing --brief
342
342
 
343
343
  # Closed items that were never given a resolution
344
- pm list-closed --filter-resolution-missing --json
344
+ pm list --status closed --filter-resolution-missing --json
345
345
 
346
346
  # Open items that still need a reviewer assigned
347
- pm list-open --filter-reviewer-missing --brief
347
+ pm list --status open --filter-reviewer-missing --brief
348
348
  ```
349
349
 
350
350
  ### Content-field presence filters
@@ -353,10 +353,10 @@ pm list-open --filter-reviewer-missing --brief
353
353
 
354
354
  ```bash
355
355
  # Closed items that shipped no documented learnings
356
- pm list-closed --no-learnings --brief
356
+ pm list --status closed --no-learnings --brief
357
357
 
358
358
  # Open work that has linked tests but no linked files yet
359
- pm list-open --has-tests --no-files --json
359
+ pm list --status open --has-tests --no-files --json
360
360
  ```
361
361
 
362
362
  ## Bulk Operations