@unbrained/pm-cli 2026.8.17 → 2026.8.19

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 (204) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/AGENTS.md +4 -3
  3. package/CHANGELOG.md +51 -5
  4. package/README.md +3 -3
  5. package/dist/cli/error-guidance.js +8 -4
  6. package/dist/cli/help-content.js +32 -13
  7. package/dist/cli/help-json-payload.d.ts +15 -0
  8. package/dist/cli/help-json-payload.js +101 -23
  9. package/dist/cli/main.js +6 -2
  10. package/dist/cli/register-list-query.js +138 -54
  11. package/dist/cli/register-mutation.js +8 -8
  12. package/dist/cli/register-operations.js +6 -6
  13. package/dist/cli-bundle/bundle-manifest.json +149 -149
  14. package/dist/cli-bundle/chunks/chunk-4NRRH7AM.js +2 -0
  15. package/dist/cli-bundle/chunks/chunk-4THEB6PD.js +13 -0
  16. package/dist/cli-bundle/chunks/{chunk-HBJAS566.js → chunk-BHYMXLAE.js} +2 -2
  17. package/dist/cli-bundle/chunks/chunk-GWMXAQOD.js +197 -0
  18. package/dist/cli-bundle/chunks/chunk-HVFQTLYM.js +35 -0
  19. package/dist/cli-bundle/chunks/chunk-OI4XI562.js +5 -0
  20. package/dist/cli-bundle/chunks/{chunk-3UEGXBMR.js → chunk-OIOKV6NO.js} +58 -54
  21. package/dist/cli-bundle/chunks/chunk-QXSH7BLM.js +3 -0
  22. package/dist/cli-bundle/chunks/chunk-SARFF5H5.js +3 -0
  23. package/dist/cli-bundle/chunks/{chunk-7IBRGCHX.js → chunk-TOXJM4WA.js} +2 -2
  24. package/dist/cli-bundle/chunks/{chunk-JOKATURE.js → chunk-YBMRWW4E.js} +44 -44
  25. package/dist/cli-bundle/chunks/register-list-query-Y56KINDU.js +11 -0
  26. package/dist/cli-bundle/chunks/register-mutation-AUWVCW4M.js +20 -0
  27. package/dist/cli-bundle/chunks/register-operations-PZQPHXW5.js +2 -0
  28. package/dist/cli-bundle/chunks/{register-setup-DOSFBGKE.js → register-setup-I4LUHGVW.js} +2 -2
  29. package/dist/cli-bundle/focused-chunks/chunk-34QBIYZI.js +155 -0
  30. package/dist/cli-bundle/focused-chunks/{chunk-MHPIL773.js → chunk-BJRYFVSH.js} +2 -2
  31. package/dist/cli-bundle/focused-chunks/chunk-DKPLYW3L.js +2 -0
  32. package/dist/cli-bundle/focused-chunks/{chunk-SALH6B6K.js → chunk-EF6ZS5GH.js} +44 -44
  33. package/dist/cli-bundle/focused-chunks/{chunk-XKAMP5OU.js → chunk-ESISGDAY.js} +2 -2
  34. package/dist/cli-bundle/focused-chunks/{chunk-SYZENPIT.js → chunk-EXBCLIBU.js} +2 -2
  35. package/dist/cli-bundle/focused-chunks/chunk-JDOMQ7VQ.js +4 -0
  36. package/dist/cli-bundle/focused-chunks/chunk-L623ZPNK.js +2 -0
  37. package/dist/cli-bundle/focused-chunks/chunk-MCZXYZAF.js +2 -0
  38. package/dist/cli-bundle/focused-chunks/chunk-ODHQEECS.js +2 -0
  39. package/dist/cli-bundle/focused-chunks/{chunk-ZQPGZZWQ.js → chunk-PRHY2IMX.js} +3 -3
  40. package/dist/cli-bundle/focused-chunks/chunk-RZU5U6Q7.js +2 -0
  41. package/dist/cli-bundle/focused-chunks/{chunk-ATEY76SX.js → chunk-US7VEYZG.js} +2 -2
  42. package/dist/cli-bundle/focused-chunks/chunk-VXDSU5MC.js +26 -0
  43. package/dist/cli-bundle/focused-chunks/chunk-YBMGXBFV.js +16 -0
  44. package/dist/cli-bundle/focused-chunks/chunk-YLVBJ6GF.js +2 -0
  45. package/dist/cli-bundle/focused-chunks/{chunk-CYFK5UPB.js → chunk-ZBIQQYMI.js} +2 -2
  46. package/dist/cli-bundle/main.js +13 -13
  47. package/dist/cli-bundle/sdk-authoring.js +1 -1
  48. package/dist/cli-bundle/sdk-contracts.js +2 -1
  49. package/dist/cli-bundle/sdk-core.js +28 -28
  50. package/dist/cli-bundle/sdk-governance.js +1 -1
  51. package/dist/cli-bundle/sdk-graph.js +1 -1
  52. package/dist/cli-bundle/sdk-merge.js +32 -32
  53. package/dist/cli-bundle/sdk-query.js +1 -1
  54. package/dist/cli-bundle/sdk-runtime.js +1 -1
  55. package/dist/cli-bundle/sdk-testing.js +1 -1
  56. package/dist/cli-bundle/sdk.js +5 -4
  57. package/dist/core/config/nested-settings.js +8 -2
  58. package/dist/core/extensions/exporter-output-contract.d.ts +12 -0
  59. package/dist/core/extensions/exporter-output-contract.js +67 -0
  60. package/dist/core/extensions/extension-types.d.ts +36 -1
  61. package/dist/core/extensions/extension-types.js +2 -2
  62. package/dist/core/extensions/loader.js +35 -44
  63. package/dist/core/history/event-index.d.ts +5 -0
  64. package/dist/core/history/event-index.js +133 -27
  65. package/dist/core/sentry/helpers.js +3 -3
  66. package/dist/core/shared/constants.js +5 -2
  67. package/dist/core/shared/errors.d.ts +2 -0
  68. package/dist/core/shared/errors.js +2 -2
  69. package/dist/core/store/settings-validator.d.ts +4 -0
  70. package/dist/core/store/settings-validator.js +3 -2
  71. package/dist/core/store/settings.js +8 -2
  72. package/dist/mcp/tool-definitions.js +12 -7
  73. package/dist/sdk/agent/refusal-closure.d.ts +41 -0
  74. package/dist/sdk/agent/refusal-closure.js +92 -0
  75. package/dist/sdk/agent/refusal-reachability.d.ts +1 -1
  76. package/dist/sdk/agent/refusal-reachability.js +4 -4
  77. package/dist/sdk/agent-capability-contracts.d.ts +13 -0
  78. package/dist/sdk/agent-capability-contracts.js +104 -7
  79. package/dist/sdk/authoring.d.ts +1 -1
  80. package/dist/sdk/authoring.js +2 -2
  81. package/dist/sdk/cli-bootstrap.d.ts +2 -2
  82. package/dist/sdk/cli-bootstrap.js +4 -4
  83. package/dist/sdk/cli-contracts/command-aliases.d.ts +34 -2
  84. package/dist/sdk/cli-contracts/command-aliases.js +80 -13
  85. package/dist/sdk/cli-contracts/commander-mutation-options.js +30 -6
  86. package/dist/sdk/cli-contracts/commander-types.js +5 -4
  87. package/dist/sdk/cli-contracts/enum-contracts.d.ts +4 -0
  88. package/dist/sdk/cli-contracts/enum-contracts.js +9 -2
  89. package/dist/sdk/cli-contracts/flag-contracts.d.ts +5 -0
  90. package/dist/sdk/cli-contracts/flag-contracts.js +84 -13
  91. package/dist/sdk/cli-contracts/flag-lexicon-contracts.d.ts +55 -0
  92. package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +240 -0
  93. package/dist/sdk/cli-contracts/grammar-contracts.d.ts +151 -0
  94. package/dist/sdk/cli-contracts/grammar-contracts.js +958 -0
  95. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +33 -5
  96. package/dist/sdk/cli-contracts/runtime-contracts.js +100 -23
  97. package/dist/sdk/cli-contracts/tool-option-contracts.d.ts +28 -1
  98. package/dist/sdk/cli-contracts/tool-option-contracts.js +38 -3
  99. package/dist/sdk/cli-contracts/tool-parameter-tables.js +7 -2
  100. package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
  101. package/dist/sdk/cli-contracts/tool-schema.js +20 -11
  102. package/dist/sdk/cli-contracts.d.ts +5 -4
  103. package/dist/sdk/cli-contracts.js +7 -6
  104. package/dist/sdk/completion.js +13 -15
  105. package/dist/sdk/compose.d.ts +3 -3
  106. package/dist/sdk/compose.js +2 -2
  107. package/dist/sdk/context-intent-contracts.d.ts +2 -2
  108. package/dist/sdk/context-intent-contracts.js +22 -7
  109. package/dist/sdk/contracts.d.ts +3 -0
  110. package/dist/sdk/contracts.js +5 -2
  111. package/dist/sdk/core.d.ts +1 -1
  112. package/dist/sdk/core.js +3 -3
  113. package/dist/sdk/environment/host-environment-errors.js +3 -3
  114. package/dist/sdk/flag-invocation-contracts.d.ts +37 -0
  115. package/dist/sdk/flag-invocation-contracts.js +218 -9
  116. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +186 -14
  117. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +194 -26
  118. package/dist/sdk/guide-topics.js +5 -5
  119. package/dist/sdk/index.d.ts +10 -7
  120. package/dist/sdk/index.js +10 -7
  121. package/dist/sdk/init-agent-guidance.js +3 -3
  122. package/dist/sdk/mutation-events.d.ts +18 -2
  123. package/dist/sdk/mutation-events.js +59 -16
  124. package/dist/sdk/output-projection.d.ts +2 -0
  125. package/dist/sdk/output-projection.js +11 -5
  126. package/dist/sdk/output.d.ts +44 -0
  127. package/dist/sdk/output.js +28 -2
  128. package/dist/sdk/query/complete-list.d.ts +94 -0
  129. package/dist/sdk/query/complete-list.js +173 -0
  130. package/dist/sdk/query/get.js +25 -6
  131. package/dist/sdk/query/list.js +19 -2
  132. package/dist/sdk/query/search-contracts.d.ts +1 -1
  133. package/dist/sdk/query/search-contracts.js +23 -9
  134. package/dist/sdk/query/search.js +3 -3
  135. package/dist/sdk/query.d.ts +1 -0
  136. package/dist/sdk/query.js +3 -2
  137. package/dist/sdk/read-output/continuation.d.ts +1 -1
  138. package/dist/sdk/read-output/continuation.js +7 -24
  139. package/dist/sdk/read-output-contracts.d.ts +2 -2
  140. package/dist/sdk/read-output-contracts.js +89 -13
  141. package/dist/sdk/read-output-rows.d.ts +4 -0
  142. package/dist/sdk/read-output-rows.js +47 -18
  143. package/dist/sdk/runtime-extended-actions.js +10 -2
  144. package/dist/sdk/runtime.d.ts +8 -2
  145. package/dist/sdk/runtime.js +18 -11
  146. package/dist/sdk/workspace-snapshot.d.ts +2 -0
  147. package/dist/sdk/workspace-snapshot.js +10 -2
  148. package/dist/types.d.ts +5 -0
  149. package/dist/types.js +2 -2
  150. package/docs/AGENT_GUIDE.md +25 -9
  151. package/docs/CLI_GRAMMAR.md +106 -0
  152. package/docs/COMMANDS.md +39 -27
  153. package/docs/ONBOARDING.md +4 -4
  154. package/docs/OUTPUT_PROJECTION_CONTRACTS.md +11 -2
  155. package/docs/QUICKSTART.md +1 -1
  156. package/docs/README.md +2 -0
  157. package/docs/READ_OUTPUT_CONTRACTS.md +10 -6
  158. package/docs/RELEASING.md +30 -6
  159. package/docs/SDK.md +42 -2
  160. package/docs/SDK_ARTIFACT_OUTPUT.md +72 -0
  161. package/docs/SDK_CONTEXT_COORDINATION.md +46 -12
  162. package/docs/TESTING.md +14 -1
  163. package/docs/agent-task-token-baseline.json +5 -5
  164. package/docs/generated/AGENT_COMMAND_SURFACE.md +78 -78
  165. package/docs/generated/FLAG_LEXICON_BUDGETS.md +76 -0
  166. package/marketplace.json +2 -2
  167. package/package.json +5 -2
  168. package/packages/pm-beads/package.json +1 -1
  169. package/packages/pm-calendar/package.json +1 -1
  170. package/packages/pm-command-kit/package.json +1 -1
  171. package/packages/pm-digital-twin/package.json +1 -1
  172. package/packages/pm-governance-audit/package.json +1 -1
  173. package/packages/pm-guide-shell/package.json +1 -1
  174. package/packages/pm-kanban/package.json +1 -1
  175. package/packages/pm-lifecycle-hooks/package.json +1 -1
  176. package/packages/pm-linked-test-adapters/package.json +1 -1
  177. package/packages/pm-search-advanced/package.json +1 -1
  178. package/packages/pm-templates/package.json +1 -1
  179. package/packages/pm-todos/package.json +1 -1
  180. package/packages/pm-vcs/package.json +1 -1
  181. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  182. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  183. package/scripts/generate-agent-capability-surfaces.mjs +20 -14
  184. package/sdk/public-surface.json +1245 -60
  185. package/dist/cli-bundle/chunks/chunk-2QLOXC3V.js +0 -3
  186. package/dist/cli-bundle/chunks/chunk-4JPYF536.js +0 -35
  187. package/dist/cli-bundle/chunks/chunk-6VDLG2FC.js +0 -13
  188. package/dist/cli-bundle/chunks/chunk-ION3E43Q.js +0 -197
  189. package/dist/cli-bundle/chunks/chunk-OAC5NIV4.js +0 -3
  190. package/dist/cli-bundle/chunks/chunk-TPXZIBIV.js +0 -5
  191. package/dist/cli-bundle/chunks/chunk-YM2YAMF7.js +0 -2
  192. package/dist/cli-bundle/chunks/register-list-query-Q7KII4G5.js +0 -10
  193. package/dist/cli-bundle/chunks/register-mutation-4WBRPXLV.js +0 -20
  194. package/dist/cli-bundle/chunks/register-operations-SSENDH5B.js +0 -2
  195. package/dist/cli-bundle/focused-chunks/chunk-267MUUS6.js +0 -16
  196. package/dist/cli-bundle/focused-chunks/chunk-2NNFLLNG.js +0 -2
  197. package/dist/cli-bundle/focused-chunks/chunk-2QSAKMIH.js +0 -2
  198. package/dist/cli-bundle/focused-chunks/chunk-BUCG4ZI2.js +0 -2
  199. package/dist/cli-bundle/focused-chunks/chunk-EHXIKD6K.js +0 -2
  200. package/dist/cli-bundle/focused-chunks/chunk-KGEXTMPG.js +0 -2
  201. package/dist/cli-bundle/focused-chunks/chunk-KP2VQQVQ.js +0 -2
  202. package/dist/cli-bundle/focused-chunks/chunk-POEEAD2V.js +0 -4
  203. package/dist/cli-bundle/focused-chunks/chunk-XPIC53VA.js +0 -26
  204. package/dist/cli-bundle/focused-chunks/chunk-ZT2DJS27.js +0 -155
@@ -5,7 +5,7 @@
5
5
  * envelopes, including dot-delimited nested paths used by graph projections.
6
6
  */
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]="0c69ff43-7bbc-5128-9533-bbf15365126b")}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]="810d42b5-98f4-57a7-bdd9-2dfa1b2b1c03")}catch(e){}}();
9
9
  const BUDGET_METADATA_ROOT_KEYS = new Set([
10
10
  "applied_bound",
11
11
  "completeness",
@@ -29,31 +29,43 @@ function isRecord(value) {
29
29
  function valueAtPath(result, rowPath) {
30
30
  let value = result;
31
31
  for (const segment of rowPath.split(".")) {
32
- if (!isRecord(value))
33
- return undefined;
34
- value = value[segment];
32
+ if (Array.isArray(value)) {
33
+ if (!/^\d+$/u.test(segment))
34
+ return undefined;
35
+ value = value[Number(segment)];
36
+ }
37
+ else {
38
+ if (!isRecord(value))
39
+ return undefined;
40
+ value = value[segment];
41
+ }
35
42
  }
36
43
  return value;
37
44
  }
38
45
  /** Clone the owners along one row path and replace only its terminal value. */
39
46
  function replaceValueAtPath(result, rowPath, replacement) {
40
47
  const segments = rowPath.split(".");
41
- const root = { ...result };
42
- let source = result;
43
- let target = root;
44
- for (const segment of segments.slice(0, -1)) {
45
- const sourceChild = source[segment];
46
- const targetChild = { ...sourceChild };
47
- target[segment] = targetChild;
48
- source = sourceChild;
49
- target = targetChild;
50
- }
51
- target[segments.at(-1)] = replacement;
52
- return root;
48
+ const replace = (value, offset) => {
49
+ if (offset === segments.length)
50
+ return replacement;
51
+ const segment = segments[offset];
52
+ if (Array.isArray(value)) {
53
+ const index = Number(segment);
54
+ const cloned = [...value];
55
+ cloned[index] = replace(value[index], offset + 1);
56
+ return cloned;
57
+ }
58
+ const record = value;
59
+ return {
60
+ ...record,
61
+ [segment]: replace(record[segment], offset + 1),
62
+ };
63
+ };
64
+ return replace(result, 0);
53
65
  }
54
66
  /** Replace one declared row collection with a suffix beginning at an offset. */
55
67
  export function sliceReadOutputRowCollection(result, rowPath, offset) {
56
- const collection = readOutputRowCollections(result).find((entry) => entry.path === rowPath);
68
+ const collection = readOutputContinuationRowCollections(result).find((entry) => entry.path === rowPath);
57
69
  if (!collection)
58
70
  return result;
59
71
  const replacement = Array.isArray(collection.value)
@@ -71,6 +83,14 @@ export function readOutputRowPaths(result) {
71
83
  .filter(([, value]) => Array.isArray(value))
72
84
  .map(([key]) => key);
73
85
  }
86
+ /** Resolve collections that may be resumed independently from primary result rows. */
87
+ export function readOutputContinuationRowPaths(result) {
88
+ const contract = result.row_contract;
89
+ if (isRecord(contract) && Array.isArray(contract.continuation_row_keys)) {
90
+ return contract.continuation_row_keys.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
91
+ }
92
+ return readOutputRowPaths(result);
93
+ }
74
94
  /** Resolve every declared row path that currently contains iterable rows. */
75
95
  export function readOutputRowCollections(result) {
76
96
  return readOutputRowPaths(result).flatMap((rowPath) => {
@@ -80,6 +100,15 @@ export function readOutputRowCollections(result) {
80
100
  : [];
81
101
  });
82
102
  }
103
+ /** Resolve every declared continuation path that currently contains iterable rows. */
104
+ export function readOutputContinuationRowCollections(result) {
105
+ return readOutputContinuationRowPaths(result).flatMap((rowPath) => {
106
+ const value = valueAtPath(result, rowPath);
107
+ return Array.isArray(value) || isRecord(value)
108
+ ? [{ path: rowPath, value }]
109
+ : [];
110
+ });
111
+ }
83
112
  /**
84
113
  * Discover every collection the token-budget degradation ladder may reduce.
85
114
  *
@@ -155,4 +184,4 @@ export function boundReadOutputRows(result, amount) {
155
184
  return { result: projected, truncated };
156
185
  }
157
186
  //# sourceMappingURL=read-output-rows.js.map
158
- //# debugId=0c69ff43-7bbc-5128-9533-bbf15365126b
187
+ //# debugId=810d42b5-98f4-57a7-bdd9-2dfa1b2b1c03
@@ -1,5 +1,5 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="37ac2a74-f150-5b9d-96d6-d9cc441215be")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="0492d773-2af2-5072-8164-9f8aab536191")}catch(e){}}();
3
3
  import { EXIT_CODE } from "../core/shared/constants.js";
4
4
  import { PmCliError } from "../core/shared/errors.js";
5
5
  import { createUnknownSubcommandError } from "./agent/subcommand-recovery.js";
@@ -32,6 +32,13 @@ export function runRuntimeEvalAction(context) {
32
32
  /** Dispatch one bounded mutation-event page through the public SDK runner. */
33
33
  export function runRuntimeEventsAction(context) {
34
34
  const input = mergedInput(context);
35
+ const rawCursorMode = input.cursorMode;
36
+ if (rawCursorMode !== undefined &&
37
+ rawCursorMode !== "batch" &&
38
+ rawCursorMode !== "row") {
39
+ throw new PmCliError("Mutation event cursor mode must be batch or row.", EXIT_CODE.USAGE, { code: "invalid_event_cursor_mode" });
40
+ }
41
+ const cursorMode = rawCursorMode;
35
42
  return listMutationEvents({
36
43
  cwd: readRuntimeString(input, "cwd"),
37
44
  pmRoot: readRuntimeString(input, "path"),
@@ -43,6 +50,7 @@ export function runRuntimeEventsAction(context) {
43
50
  ? undefined
44
51
  : parseRuntimeInteger(input.limit, "limit"),
45
52
  full: input.full === true,
53
+ cursorMode,
46
54
  ...(input.provenance === undefined
47
55
  ? {}
48
56
  : { provenance: input.provenance === true }),
@@ -161,4 +169,4 @@ export function runRuntimeSchedulingAction(context) {
161
169
  return runRemind(title, input, context.global);
162
170
  }
163
171
  //# sourceMappingURL=runtime-extended-actions.js.map
164
- //# debugId=37ac2a74-f150-5b9d-96d6-d9cc441215be
172
+ //# debugId=0492d773-2af2-5072-8164-9f8aab536191
@@ -8,6 +8,8 @@ export { SEARCH_EXTENSION_FLAG_DEFINITIONS } from "./extension-contracts.js";
8
8
  export type { FlagDefinition } from "../core/extensions/loader.js";
9
9
  import { EXIT_CODE } from "../core/shared/constants.js";
10
10
  import type { ItemMetadata } from "../types/index.js";
11
+ import { type PmCompleteListOptions, type PmCompleteListResult } from "./query/complete-list.js";
12
+ export { PmCompleteListValidationError, assertCompleteListResult, certifyCompleteListResult, createCompleteListOptions, inspectCompleteListResult, type PmCompleteListCertificate, type PmCompleteListFailureReceipt, type PmCompleteListFinding, type PmCompleteListFindingCode, type PmCompleteListInspection, type PmCompleteListOptions, type PmCompleteListResult } from "./query/complete-list.js";
11
13
  export type { WorkspaceExtensionCommandContract, WorkspaceFieldContract, } from "./workspace-contracts.js";
12
14
  import { type PmReadOutputOptions, type PmReadOutputResultFor } from "./read-output-contracts.js";
13
15
  export type { PmReadOutputBudgetExceeded, PmReadOutputOptions, PmReadOutputResult, PmReadOutputResultFor, PmReadOutputSurfaceContract, } from "./read-output-contracts.js";
@@ -138,6 +140,8 @@ export declare class PmClient {
138
140
  listAllItemMetadataLight(): Promise<ItemMetadata[]>;
139
141
  /** List items with the MCP/agent compact defaults. */
140
142
  list<Options extends ReadOptions<ListOptions> = ListOptions>(options?: Options): ReadPromise<ListResult, Options>;
143
+ /** Return every status and full item row only after fail-closed corpus certification. */
144
+ listAllComplete(options?: PmCompleteListOptions): Promise<PmCompleteListResult>;
141
145
  /** Search items with the MCP/agent compact defaults. */
142
146
  search<Options extends ReadOptions<SearchOptions> = SearchOptions>(query: string, options?: Options): ReadPromise<SearchResult, Options>;
143
147
  /** Read one item by id. */
@@ -336,7 +340,7 @@ export declare class PmClient {
336
340
  /** Reload installed package extensions using the same action as `pm package reload`. */
337
341
  packageReload(options?: PackageCommandOptions): Promise<PackageCommandResult>;
338
342
  /** Read bundled package catalog metadata using the same action as `pm package catalog`. */
339
- packageCatalog(options?: PackageCommandOptions): Promise<PackageCommandResult>;
343
+ packageCatalog<Options extends ReadOptions<PackageCommandOptions> = PackageCommandOptions>(options?: Options): ReadPromise<PackageCommandResult, Options>;
340
344
  /** Enable an installed package using the same action as `pm package activate`. */
341
345
  packageActivate(target: string, options?: PackageCommandOptions): Promise<PackageCommandResult>;
342
346
  /** Disable an installed package using the same action as `pm package deactivate`. */
@@ -350,6 +354,8 @@ export declare class PmClient {
350
354
  export declare function context<Options extends ReadOptions<ContextOptions> = ContextOptions>(options?: Options, clientOptions?: PmClientOptions): ReadPromise<ContextResult, Options>;
351
355
  /** List items with the MCP/agent compact defaults without constructing a reusable client. */
352
356
  export declare function list<Options extends ReadOptions<ListOptions> = ListOptions>(options?: Options, clientOptions?: PmClientOptions): ReadPromise<ListResult, Options>;
357
+ /** Return every status and full item row with fail-closed corpus proof. */
358
+ export declare function listAllComplete(options?: PmCompleteListOptions, clientOptions?: PmClientOptions): Promise<PmCompleteListResult>;
353
359
  /** Search items with the MCP/agent compact defaults without constructing a reusable client. */
354
360
  export declare function search<Options extends ReadOptions<SearchOptions> = SearchOptions>(query: string, options?: Options, clientOptions?: PmClientOptions): ReadPromise<SearchResult, Options>;
355
361
  /** Read one item by id without constructing a reusable client. */
@@ -510,7 +516,7 @@ export declare function packageDescribe(target?: string, options?: PackageComman
510
516
  /** Reload package extensions without constructing a reusable client. */
511
517
  export declare function packageReload(options?: PackageCommandOptions, clientOptions?: PmClientOptions): Promise<PackageCommandResult>;
512
518
  /** Read bundled package catalog metadata without constructing a reusable client. */
513
- export declare function packageCatalog(options?: PackageCommandOptions, clientOptions?: PmClientOptions): Promise<PackageCommandResult>;
519
+ export declare function packageCatalog<Options extends ReadOptions<PackageCommandOptions> = PackageCommandOptions>(options?: Options, clientOptions?: PmClientOptions): ReadPromise<PackageCommandResult, Options>;
514
520
  /** Enable a package without constructing a reusable client. */
515
521
  export declare function packageActivate(target: string, options?: PackageCommandOptions, clientOptions?: PmClientOptions): Promise<PackageCommandResult>;
516
522
  /** Disable a package without constructing a reusable client. */
@@ -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]="95764dd9-1b0d-5732-9f10-b13b334ce27d")}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;
@@ -1346,13 +1349,14 @@ async function runMcpListAction(ctx) {
1346
1349
  return withQuerySummary((await runList(readString(ctx.args, "status") ?? readString(listOptions, "status"), listOptions, ctx.global)), listOptions);
1347
1350
  }
1348
1351
  async function runMcpSearchAction(ctx) {
1349
- const searchOptions = applyContextIntentProjection("search", ctx.options);
1352
+ const query = readRequiredString(ctx.args, "query");
1353
+ const searchOptions = applyContextIntentProjection("search", ctx.options, [query]);
1350
1354
  if (searchOptions.compact === undefined &&
1351
1355
  searchOptions.full === undefined &&
1352
1356
  searchOptions.fields === undefined) {
1353
1357
  searchOptions.compact = true;
1354
1358
  }
1355
- return withQuerySummary((await runSearch(readRequiredString(ctx.args, "query"), searchOptions, ctx.global)), searchOptions);
1359
+ return withQuerySummary((await runSearch(query, searchOptions, ctx.global)), searchOptions);
1356
1360
  }
1357
1361
  async function runMcpCreateAction(ctx) {
1358
1362
  const { changedFields, idOnly, runnerOptions } = withMutationCompaction(ctx.args, ctx.options);
@@ -1780,7 +1784,10 @@ const SDK_ACTION_HANDLERS = {
1780
1784
  event: runRuntimeSchedulingAction,
1781
1785
  remind: runRuntimeSchedulingAction,
1782
1786
  list: runMcpListAction,
1783
- get: (ctx) => runGet(requireMcpItemId(ctx), ctx.global, applyContextIntentProjection("get", ctx.options)),
1787
+ get: (ctx) => {
1788
+ const id = requireMcpItemId(ctx);
1789
+ return runGet(id, ctx.global, applyContextIntentProjection("get", ctx.options, [id]));
1790
+ },
1784
1791
  search: runMcpSearchAction,
1785
1792
  duplicates: (ctx) => {
1786
1793
  const status = typeof ctx.options.status === "string"
@@ -1933,4 +1940,4 @@ async function loadWorkspaceExtensionRegistrations(pmRoot, settings, cwd) {
1933
1940
  }
1934
1941
  }
1935
1942
  //# sourceMappingURL=runtime.js.map
1936
- //# debugId=bedbe090-60c3-5935-a656-da4997cd80f7
1943
+ //# debugId=95764dd9-1b0d-5732-9f10-b13b334ce27d
@@ -1,5 +1,7 @@
1
1
  /** Current content-addressed workspace snapshot manifest schema identifier. */
2
2
  export declare const SNAPSHOT_SCHEMA = "https://schema.unbrained.dev/pm/workspace-snapshot/v1";
3
+ /** Workspace snapshot action tokens accepted by the SDK and CLI dispatcher. */
4
+ export declare const WORKSPACE_SNAPSHOT_ACTIONS: readonly ["create", "list", "inspect", "restore", "delete"];
3
5
  /** Filesystem operations required by atomic snapshot publish and restore swaps. */
4
6
  export interface WorkspaceSnapshotAtomicOperations {
5
7
  /** Rename one filesystem entry atomically. */
@@ -5,7 +5,7 @@
5
5
  * state while excluding clone-local caches, locks, and recovery journals.
6
6
  */
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]="36aacc71-c5f5-56f1-85f4-28b2be5b02e2")}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]="2580e043-8675-5070-b57e-30cae333228c")}catch(e){}}();
9
9
  import crypto from "node:crypto";
10
10
  import { cp, lstat, mkdir, readFile, readdir, rename, rm, writeFile, } from "node:fs/promises";
11
11
  import path from "node:path";
@@ -18,6 +18,14 @@ import { PmCliError } from "../core/shared/errors.js";
18
18
  import { withHostEnvironmentBoundary } from "./environment/host-environment-errors.js";
19
19
  /** Current content-addressed workspace snapshot manifest schema identifier. */
20
20
  export const SNAPSHOT_SCHEMA = "https://schema.unbrained.dev/pm/workspace-snapshot/v1";
21
+ /** Workspace snapshot action tokens accepted by the SDK and CLI dispatcher. */
22
+ export const WORKSPACE_SNAPSHOT_ACTIONS = [
23
+ "create",
24
+ "list",
25
+ "inspect",
26
+ "restore",
27
+ "delete",
28
+ ];
21
29
  const SNAPSHOT_RUNTIME_PATH = path.join("runtime", "workspace-snapshots");
22
30
  const EXCLUDED_ROOT_NAMES = new Set([
23
31
  "checkpoints",
@@ -603,4 +611,4 @@ export async function deleteWorkspaceSnapshot(pmRoot, target) {
603
611
  return { deleted: "object", target };
604
612
  }
605
613
  //# sourceMappingURL=workspace-snapshot.js.map
606
- //# debugId=36aacc71-c5f5-56f1-85f4-28b2be5b02e2
614
+ //# debugId=2580e043-8675-5070-b57e-30cae333228c
package/dist/types.d.ts CHANGED
@@ -1078,6 +1078,11 @@ export interface PmSettings {
1078
1078
  output: {
1079
1079
  default_format: "toon" | "json";
1080
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
+ };
1081
1086
  /** Value that configures or reports history for this contract. */
1082
1087
  history: {
1083
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]="4e2028b3-6718-509a-b687-d1df58962387")}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",
@@ -243,4 +243,4 @@ export const CONTEXT_SECTION_VALUES = [
243
243
  "tests",
244
244
  ];
245
245
  //# sourceMappingURL=types.js.map
246
- //# debugId=4e2028b3-6718-509a-b687-d1df58962387
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.