@unbrained/pm-cli 2026.8.18 → 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 (139) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +16 -2
  3. package/dist/cli/error-guidance.js +3 -2
  4. package/dist/cli/help-content.js +32 -13
  5. package/dist/cli/help-json-payload.d.ts +15 -0
  6. package/dist/cli/help-json-payload.js +101 -23
  7. package/dist/cli/main.js +6 -2
  8. package/dist/cli/register-list-query.js +8 -5
  9. package/dist/cli/register-mutation.js +8 -8
  10. package/dist/cli/register-operations.js +6 -6
  11. package/dist/cli-bundle/bundle-manifest.json +139 -139
  12. package/dist/cli-bundle/chunks/chunk-4NRRH7AM.js +2 -0
  13. package/dist/cli-bundle/chunks/{chunk-UYCLQVL2.js → chunk-4THEB6PD.js} +2 -2
  14. package/dist/cli-bundle/chunks/{chunk-BSK2IN3C.js → chunk-BHYMXLAE.js} +2 -2
  15. package/dist/cli-bundle/chunks/chunk-GWMXAQOD.js +197 -0
  16. package/dist/cli-bundle/chunks/chunk-HVFQTLYM.js +35 -0
  17. package/dist/cli-bundle/chunks/chunk-OI4XI562.js +5 -0
  18. package/dist/cli-bundle/chunks/{chunk-YRGOLZA7.js → chunk-OIOKV6NO.js} +3 -3
  19. package/dist/cli-bundle/chunks/{chunk-5UZZAJKR.js → chunk-QXSH7BLM.js} +2 -2
  20. package/dist/cli-bundle/chunks/{chunk-RZQTVMRQ.js → chunk-TOXJM4WA.js} +2 -2
  21. package/dist/cli-bundle/chunks/{chunk-GNFAFIJI.js → chunk-YBMRWW4E.js} +44 -44
  22. package/dist/cli-bundle/chunks/{register-list-query-I23LALEE.js → register-list-query-Y56KINDU.js} +11 -11
  23. package/dist/cli-bundle/chunks/register-mutation-AUWVCW4M.js +20 -0
  24. package/dist/cli-bundle/chunks/register-operations-PZQPHXW5.js +2 -0
  25. package/dist/cli-bundle/chunks/{register-setup-PPPEF3SN.js → register-setup-I4LUHGVW.js} +2 -2
  26. package/dist/cli-bundle/focused-chunks/{chunk-5AF3ZBNB.js → chunk-34QBIYZI.js} +2 -2
  27. package/dist/cli-bundle/focused-chunks/{chunk-V5XTGLK7.js → chunk-BJRYFVSH.js} +2 -2
  28. package/dist/cli-bundle/focused-chunks/chunk-DKPLYW3L.js +2 -0
  29. package/dist/cli-bundle/focused-chunks/{chunk-ODOVCP45.js → chunk-EF6ZS5GH.js} +44 -44
  30. package/dist/cli-bundle/focused-chunks/{chunk-EX6MKP2X.js → chunk-ESISGDAY.js} +2 -2
  31. package/dist/cli-bundle/focused-chunks/{chunk-EUEGXZ2A.js → chunk-EXBCLIBU.js} +2 -2
  32. package/dist/cli-bundle/focused-chunks/{chunk-UI6AJ5TD.js → chunk-JDOMQ7VQ.js} +2 -2
  33. package/dist/cli-bundle/focused-chunks/chunk-L623ZPNK.js +2 -0
  34. package/dist/cli-bundle/focused-chunks/chunk-MCZXYZAF.js +2 -0
  35. package/dist/cli-bundle/focused-chunks/chunk-ODHQEECS.js +2 -0
  36. package/dist/cli-bundle/focused-chunks/{chunk-3TKWMNKF.js → chunk-PRHY2IMX.js} +2 -2
  37. package/dist/cli-bundle/focused-chunks/chunk-RZU5U6Q7.js +2 -0
  38. package/dist/cli-bundle/focused-chunks/{chunk-M62NO7EI.js → chunk-US7VEYZG.js} +2 -2
  39. package/dist/cli-bundle/focused-chunks/{chunk-TN4AE665.js → chunk-VXDSU5MC.js} +2 -2
  40. package/dist/cli-bundle/focused-chunks/chunk-YBMGXBFV.js +16 -0
  41. package/dist/cli-bundle/focused-chunks/chunk-YLVBJ6GF.js +2 -0
  42. package/dist/cli-bundle/focused-chunks/{chunk-K43KKAFS.js → chunk-ZBIQQYMI.js} +2 -2
  43. package/dist/cli-bundle/main.js +13 -13
  44. package/dist/cli-bundle/sdk-authoring.js +1 -1
  45. package/dist/cli-bundle/sdk-contracts.js +2 -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 +5 -4
  54. package/dist/core/shared/errors.d.ts +2 -0
  55. package/dist/core/shared/errors.js +2 -2
  56. package/dist/sdk/agent/refusal-closure.d.ts +41 -0
  57. package/dist/sdk/agent/refusal-closure.js +92 -0
  58. package/dist/sdk/agent/refusal-reachability.d.ts +1 -1
  59. package/dist/sdk/agent-capability-contracts.d.ts +13 -0
  60. package/dist/sdk/agent-capability-contracts.js +104 -7
  61. package/dist/sdk/cli-contracts/command-aliases.js +18 -2
  62. package/dist/sdk/cli-contracts/commander-mutation-options.js +30 -6
  63. package/dist/sdk/cli-contracts/commander-types.js +5 -4
  64. package/dist/sdk/cli-contracts/flag-contracts.d.ts +5 -0
  65. package/dist/sdk/cli-contracts/flag-contracts.js +75 -8
  66. package/dist/sdk/cli-contracts/flag-lexicon-contracts.d.ts +55 -0
  67. package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +240 -0
  68. package/dist/sdk/cli-contracts/grammar-contracts.d.ts +81 -0
  69. package/dist/sdk/cli-contracts/grammar-contracts.js +615 -2
  70. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +15 -4
  71. package/dist/sdk/cli-contracts/runtime-contracts.js +42 -12
  72. package/dist/sdk/cli-contracts/tool-option-contracts.d.ts +28 -1
  73. package/dist/sdk/cli-contracts/tool-option-contracts.js +38 -3
  74. package/dist/sdk/cli-contracts.d.ts +3 -2
  75. package/dist/sdk/cli-contracts.js +5 -4
  76. package/dist/sdk/context-intent-contracts.d.ts +2 -2
  77. package/dist/sdk/context-intent-contracts.js +22 -7
  78. package/dist/sdk/contracts.d.ts +2 -0
  79. package/dist/sdk/contracts.js +4 -2
  80. package/dist/sdk/flag-invocation-contracts.d.ts +37 -0
  81. package/dist/sdk/flag-invocation-contracts.js +218 -9
  82. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +134 -2
  83. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +154 -22
  84. package/dist/sdk/index.d.ts +7 -5
  85. package/dist/sdk/index.js +7 -5
  86. package/dist/sdk/output-projection.d.ts +2 -0
  87. package/dist/sdk/output-projection.js +11 -5
  88. package/dist/sdk/query/get.js +25 -6
  89. package/dist/sdk/query/list.js +16 -2
  90. package/dist/sdk/query/search-contracts.d.ts +1 -1
  91. package/dist/sdk/query/search-contracts.js +23 -9
  92. package/dist/sdk/query/search.js +3 -3
  93. package/dist/sdk/read-output/continuation.d.ts +1 -1
  94. package/dist/sdk/read-output/continuation.js +7 -24
  95. package/dist/sdk/read-output-contracts.js +55 -6
  96. package/dist/sdk/read-output-rows.d.ts +4 -0
  97. package/dist/sdk/read-output-rows.js +47 -18
  98. package/dist/sdk/runtime.js +9 -5
  99. package/dist/sdk/workspace-snapshot.d.ts +2 -0
  100. package/dist/sdk/workspace-snapshot.js +10 -2
  101. package/docs/COMMANDS.md +16 -4
  102. package/docs/OUTPUT_PROJECTION_CONTRACTS.md +11 -2
  103. package/docs/READ_OUTPUT_CONTRACTS.md +10 -6
  104. package/docs/SDK.md +6 -0
  105. package/docs/TESTING.md +14 -1
  106. package/docs/generated/AGENT_COMMAND_SURFACE.md +78 -78
  107. package/docs/generated/FLAG_LEXICON_BUDGETS.md +76 -0
  108. package/marketplace.json +2 -2
  109. package/package.json +5 -3
  110. package/packages/pm-beads/package.json +1 -1
  111. package/packages/pm-calendar/package.json +1 -1
  112. package/packages/pm-command-kit/package.json +1 -1
  113. package/packages/pm-digital-twin/package.json +1 -1
  114. package/packages/pm-governance-audit/package.json +1 -1
  115. package/packages/pm-guide-shell/package.json +1 -1
  116. package/packages/pm-kanban/package.json +1 -1
  117. package/packages/pm-lifecycle-hooks/package.json +1 -1
  118. package/packages/pm-linked-test-adapters/package.json +1 -1
  119. package/packages/pm-search-advanced/package.json +1 -1
  120. package/packages/pm-templates/package.json +1 -1
  121. package/packages/pm-todos/package.json +1 -1
  122. package/packages/pm-vcs/package.json +1 -1
  123. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  124. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  125. package/scripts/generate-agent-capability-surfaces.mjs +20 -14
  126. package/sdk/public-surface.json +576 -12
  127. package/dist/cli-bundle/chunks/chunk-ALDJGKAK.js +0 -2
  128. package/dist/cli-bundle/chunks/chunk-DY4DMUMC.js +0 -197
  129. package/dist/cli-bundle/chunks/chunk-L5Q2CLPE.js +0 -35
  130. package/dist/cli-bundle/chunks/chunk-PVRUN5ZS.js +0 -5
  131. package/dist/cli-bundle/chunks/register-mutation-6YGU3GPH.js +0 -20
  132. package/dist/cli-bundle/chunks/register-operations-4HTFC6J7.js +0 -2
  133. package/dist/cli-bundle/focused-chunks/chunk-2PN4TJXH.js +0 -2
  134. package/dist/cli-bundle/focused-chunks/chunk-C5IW2NDA.js +0 -2
  135. package/dist/cli-bundle/focused-chunks/chunk-RNDNMARJ.js +0 -16
  136. package/dist/cli-bundle/focused-chunks/chunk-TVV2DONO.js +0 -2
  137. package/dist/cli-bundle/focused-chunks/chunk-WGHQVU6P.js +0 -2
  138. package/dist/cli-bundle/focused-chunks/chunk-XYNBXTDQ.js +0 -2
  139. package/dist/cli-bundle/focused-chunks/chunk-Z56ECT7I.js +0 -2
@@ -4,11 +4,12 @@
4
4
  * Owns search input parsing, output projection contracts, and tuning defaults.
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]="47576eb5-4ddf-5e04-9e1d-c961da39b754")}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]="e737cdf9-734c-5010-864f-60e8052dd9c1")}catch(e){}}();
8
8
  import { coerceNumberInRange } from "../../core/shared/primitives.js";
9
9
  import { EXIT_CODE } from "../../core/shared/constants.js";
10
10
  import { PmCliError } from "../../core/shared/errors.js";
11
11
  import { resolveIsoOrRelative } from "../../core/shared/time.js";
12
+ import { renderPmCommand } from "../command-line.js";
12
13
  const DEFAULT_COMPACT_SEARCH_FIELDS = [
13
14
  "id",
14
15
  "title",
@@ -174,23 +175,31 @@ export function parseSearchProjection(options) {
174
175
  return { mode: "full", fields: [] };
175
176
  }
176
177
  /** Validate explicit projection fields against core and runtime metadata. */
177
- export function validateSearchProjectionFields(projection, runtimeFieldRegistry) {
178
+ export function validateSearchProjectionFields(projection, runtimeFieldRegistry, query = "<query>") {
178
179
  if (projection.mode !== "fields")
179
180
  return;
180
181
  const runtimeKeys = new Set(runtimeFieldRegistry.definitions.flatMap((field) => [
181
182
  field.key,
182
183
  field.metadata_key,
183
184
  ]));
185
+ const allowedValues = new Set([
186
+ ...SEARCH_HIT_FIELD_KEYS,
187
+ ...SEARCH_ITEM_FIELD_KEYS,
188
+ ...[...SEARCH_ITEM_FIELD_KEYS].map((field) => `item.${field}`),
189
+ ...runtimeKeys,
190
+ ...[...runtimeKeys].map((field) => `item.${field}`),
191
+ ]);
184
192
  const unknown = projection.fields.filter((field) => {
185
193
  const normalized = field.trim();
186
- const itemKey = normalized.startsWith("item.")
187
- ? normalized.slice("item.".length)
188
- : normalized;
189
- return (!SEARCH_HIT_FIELD_KEYS.has(normalized) &&
190
- !SEARCH_ITEM_FIELD_KEYS.has(itemKey) &&
191
- !runtimeKeys.has(itemKey));
194
+ return !allowedValues.has(normalized);
192
195
  });
193
196
  if (unknown.length > 0) {
197
+ const suggestedRetryArguments = [
198
+ "search",
199
+ query,
200
+ "--fields",
201
+ "id,title,status,score",
202
+ ];
194
203
  throw new PmCliError(`Unknown search --fields value(s): ${unknown.join(", ")}`, EXIT_CODE.USAGE, {
195
204
  examples: [
196
205
  "pm search <query> --fields id,title,status,score",
@@ -199,6 +208,11 @@ export function validateSearchProjectionFields(projection, runtimeFieldRegistry)
199
208
  nextSteps: [
200
209
  "Use item.<field> for explicit item metadata fields, or run pm search --help for projection examples.",
201
210
  ],
211
+ recovery: {
212
+ allowed_values: [...allowedValues].sort(),
213
+ suggested_retry: renderPmCommand(suggestedRetryArguments),
214
+ suggested_retry_args: suggestedRetryArguments,
215
+ },
202
216
  });
203
217
  }
204
218
  }
@@ -283,4 +297,4 @@ export function resolveSearchTuning(settings) {
283
297
  };
284
298
  }
285
299
  //# sourceMappingURL=search-contracts.js.map
286
- //# debugId=47576eb5-4ddf-5e04-9e1d-c961da39b754
300
+ //# debugId=e737cdf9-734c-5010-864f-60e8052dd9c1
@@ -4,7 +4,7 @@
4
4
  * Implements the pm search 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]="1750b332-dd40-5497-b410-26c8c7436329")}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]="0582c462-43fc-563c-b209-d6e3c39948f4")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
10
  import { toNonEmptyStringOrUndefined } from "../../core/shared/primitives.js";
@@ -1552,7 +1552,7 @@ async function resolveSearchRuntimeContext(prepared, global) {
1552
1552
  const settings = resolveSettingsWithSemanticRuntimeDefaults(storedSettings).settings;
1553
1553
  const statusRegistry = resolveRuntimeStatusRegistry(settings.schema);
1554
1554
  const runtimeFieldRegistry = resolveRuntimeFieldRegistry(settings.schema);
1555
- validateSearchProjectionFields(prepared.projection, runtimeFieldRegistry);
1555
+ validateSearchProjectionFields(prepared.projection, runtimeFieldRegistry, prepared.query);
1556
1556
  const runtimeFieldFilters = collectRuntimeFilterValues(prepared.options, runtimeFieldRegistry, "search");
1557
1557
  const typeRegistry = resolveItemTypeRegistry(settings, getActiveExtensionRegistrations());
1558
1558
  const providerResolution = resolveEmbeddingProviders(settings);
@@ -1961,4 +1961,4 @@ export async function runSearch(rawQuery, rawOptions, global) {
1961
1961
  return withSearchWorkspaceMemory(buildSearchResultForHits(response, projectedItems, total, page.limited.length, effectiveProjection, page.pageExtras), workspaceMemoryResult);
1962
1962
  }
1963
1963
  //# sourceMappingURL=search.js.map
1964
- //# debugId=1750b332-dd40-5497-b410-26c8c7436329
1964
+ //# debugId=0582c462-43fc-563c-b209-d6e3c39948f4
@@ -1,5 +1,5 @@
1
1
  import type { PmReadOutputCursorEnvelope, PmReadOutputSurface } from "../read-output-contracts.js";
2
- /** Fingerprint stable row identities without including volatile observation fields. */
2
+ /** Fingerprint the complete canonical row snapshot so changed evidence fails closed. */
3
3
  export declare function readOutputCollectionFingerprint(path: string, value: unknown[] | Record<string, unknown>): string;
4
4
  /** Encode one stable declared-row continuation for CLI, SDK, and MCP callers. */
5
5
  export declare function encodeReadOutputContinuationCursor(cursor: Omit<PmReadOutputCursorEnvelope, "version">): string;
@@ -6,38 +6,21 @@
6
6
  * resolution and budget policy.
7
7
  */
8
8
 
9
- !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]="8e523bbc-5745-514e-a1d8-a6ad6ece001a")}catch(e){}}();
9
+ !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]="1c73c31e-6246-5730-8c8a-d3ba7c9ec112")}catch(e){}}();
10
10
  import { createHash } from "node:crypto";
11
11
  import { EXIT_CODE } from "../../core/shared/constants.js";
12
12
  import { PmCliError } from "../../core/shared/errors.js";
13
+ import { stableStringify } from "../../core/shared/serialization.js";
13
14
  import { resolveReadOutputSurface } from "../read-output-contracts.js";
14
- import { readOutputRowCollections, sliceReadOutputRowCollection, } from "../read-output-rows.js";
15
+ import { readOutputContinuationRowCollections, sliceReadOutputRowCollection, } from "../read-output-rows.js";
15
16
  const MAX_READ_OUTPUT_CURSOR_LENGTH = 4096;
16
17
  function isRecord(value) {
17
18
  return value !== null && typeof value === "object" && !Array.isArray(value);
18
19
  }
19
- /** Fingerprint stable row identities without including volatile observation fields. */
20
+ /** Fingerprint the complete canonical row snapshot so changed evidence fails closed. */
20
21
  export function readOutputCollectionFingerprint(path, value) {
21
- const identities = Array.isArray(value)
22
- ? value.map((row, index) => {
23
- if (!isRecord(row))
24
- return `index:${String(index)}`;
25
- for (const key of [
26
- "id",
27
- "assertion_id",
28
- "measurement_id",
29
- "event_id",
30
- ]) {
31
- const candidate = row[key];
32
- if (typeof candidate === "string" && candidate.length > 0) {
33
- return `${key}:${candidate}`;
34
- }
35
- }
36
- return `index:${String(index)}`;
37
- })
38
- : Object.keys(value);
39
22
  return createHash("sha256")
40
- .update(JSON.stringify({ path, identities }))
23
+ .update(stableStringify({ path, value }))
41
24
  .digest("base64url")
42
25
  .slice(0, 16);
43
26
  }
@@ -113,7 +96,7 @@ export function applyReadOutputContinuation(result, command, cursor) {
113
96
  if (cursor.command !== command) {
114
97
  throw new PmCliError(`The read-output cursor belongs to ${cursor.command}, not ${command}.`, EXIT_CODE.USAGE, { code: "read_output_cursor_command_mismatch" });
115
98
  }
116
- const collection = readOutputRowCollections(result).find((entry) => entry.path === cursor.path);
99
+ const collection = readOutputContinuationRowCollections(result).find((entry) => entry.path === cursor.path);
117
100
  const totalRows = collection
118
101
  ? Array.isArray(collection.value)
119
102
  ? collection.value.length
@@ -129,4 +112,4 @@ export function applyReadOutputContinuation(result, command, cursor) {
129
112
  return sliceReadOutputRowCollection(result, cursor.path, cursor.offset);
130
113
  }
131
114
  //# sourceMappingURL=continuation.js.map
132
- //# debugId=8e523bbc-5745-514e-a1d8-a6ad6ece001a
115
+ //# debugId=1c73c31e-6246-5730-8c8a-d3ba7c9ec112
@@ -5,12 +5,12 @@
5
5
  * surface without coupling package authors to command-specific option names.
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]="db1d54b0-ff27-51f5-a179-14556ced24eb")}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]="b3c001df-9891-5cf7-990b-8d9da7b51801")}catch(e){}}();
9
9
  import { EXIT_CODE } from "../core/shared/constants.js";
10
10
  import { PmCliError } from "../core/shared/errors.js";
11
11
  import { compactReadOutputToBudget, estimateReadOutputTokens, updateReadOutputReceiptEstimate, } from "./read-output-budget.js";
12
12
  import { resolvePmCommandOutputBudget } from "./cli-contracts/agent-output-contracts.js";
13
- import { boundReadOutputRows, countReadOutputRows, mapReadOutputRows, readOutputRowCollections, readOutputRowPaths, } from "./read-output-rows.js";
13
+ import { boundReadOutputRows, countReadOutputRows, mapReadOutputRows, readOutputBudgetCollections, readOutputContinuationRowCollections, readOutputRowPaths, } from "./read-output-rows.js";
14
14
  import { applyReadOutputContinuation, decodeReadOutputContinuationCursor, encodeReadOutputContinuationCursor, prioritizeAssuranceAssertions, readOutputCollectionFingerprint, } from "./read-output/continuation.js";
15
15
  export { decodeReadOutputContinuationCursor, encodeReadOutputContinuationCursor, } from "./read-output/continuation.js";
16
16
  import { applyReadOutputSessionReferences, attachReadOutputSessionReceipt, parseReadOutputSession, readOutputSessionRemainingTokens, } from "./read-output-session.js";
@@ -763,6 +763,54 @@ export function stabilizeReadOutputReceiptEstimates(result, options) {
763
763
  }
764
764
  return attachReadOutputSessionContracts(result, session, receipt);
765
765
  }
766
+ /** Declare independently resumable validate diagnostic arrays on rich results. */
767
+ function attachValidateDiagnosticRowContract(command, result) {
768
+ if (command !== "validate")
769
+ return result;
770
+ const projection = isRecord(result.projection)
771
+ ? result.projection
772
+ : undefined;
773
+ const declaredFieldGroups = Array.isArray(projection?.declared_field_groups)
774
+ ? projection.declared_field_groups
775
+ : [];
776
+ if (!declaredFieldGroups.some((group) => isRecord(group) && group.name === "diagnostic_rows")) {
777
+ return result;
778
+ }
779
+ const diagnosticCollectionPaths = [
780
+ ...new Set(readOutputBudgetCollections(result)
781
+ .map(({ path }) => path)
782
+ .filter((path) => /^checks\.\d+\.details\./u.test(path))),
783
+ ];
784
+ const diagnosticRowKeys = diagnosticCollectionPaths.filter((path) => !diagnosticCollectionPaths.some((candidate) => candidate !== path && path.startsWith(`${candidate}.`)));
785
+ if (diagnosticRowKeys.length === 0)
786
+ return result;
787
+ const existingContract = isRecord(result.row_contract)
788
+ ? result.row_contract
789
+ : {};
790
+ const existingRowKeys = Array.isArray(existingContract.row_keys)
791
+ ? existingContract.row_keys.filter((entry) => typeof entry === "string")
792
+ : [];
793
+ const existingContinuationRowKeys = Array.isArray(existingContract.continuation_row_keys)
794
+ ? existingContract.continuation_row_keys.filter((entry) => typeof entry === "string")
795
+ : [];
796
+ const rowKeys = existingRowKeys.length > 0 ? existingRowKeys : diagnosticRowKeys;
797
+ const continuationRowKeys = [...new Set(diagnosticRowKeys)];
798
+ return JSON.stringify(rowKeys) === JSON.stringify(existingRowKeys) &&
799
+ JSON.stringify(continuationRowKeys) ===
800
+ JSON.stringify(existingContinuationRowKeys)
801
+ ? result
802
+ : {
803
+ ...result,
804
+ row_contract: {
805
+ ...existingContract,
806
+ row_keys: rowKeys,
807
+ continuation_row_keys: continuationRowKeys,
808
+ jq_selector: typeof existingContract.jq_selector === "string"
809
+ ? existingContract.jq_selector
810
+ : ".checks[].details",
811
+ },
812
+ };
813
+ }
766
814
  /** Apply field, amount, and repeat projections to every declared row path. */
767
815
  function projectReadOutputRows(result, resolved, session, cursor) {
768
816
  let projected = { ...result };
@@ -871,7 +919,7 @@ function attachReadOutputTruncationDisclosure(projected, resolved, receipt, bind
871
919
  if (!receipt.rows_compacted)
872
920
  return;
873
921
  const overridden = resolved.amount?.value === "unbounded" ? ["amount"] : [];
874
- const afterByPath = new Map(readOutputRowCollections(projected).map((collection) => [
922
+ const afterByPath = new Map(readOutputContinuationRowCollections(projected).map((collection) => [
875
923
  collection.path,
876
924
  Array.isArray(collection.value)
877
925
  ? collection.value.length
@@ -974,7 +1022,7 @@ function rebaseBudgetCompactedCursor(projected, originalItemCount, cursorSource,
974
1022
  return true;
975
1023
  }
976
1024
  function captureReadOutputContinuationState(projected, cursor, options) {
977
- const collectionsBeforeBudget = new Map(readOutputRowCollections(projected).map((collection) => {
1025
+ const collectionsBeforeBudget = new Map(readOutputContinuationRowCollections(projected).map((collection) => {
978
1026
  const rows = Array.isArray(collection.value)
979
1027
  ? collection.value.length
980
1028
  : Object.keys(collection.value).length;
@@ -1032,8 +1080,9 @@ export function applyReadOutputDimensions(command, options, result) {
1032
1080
  canReturnReadOutputUnchanged(resolved, requested, session, result)) {
1033
1081
  return result;
1034
1082
  }
1083
+ const continuationReadyResult = attachValidateDiagnosticRowContract(resolved.command, result);
1035
1084
  const bindingBudget = resolveBindingReadOutputBudget(resolved, session);
1036
- let projected = projectReadOutputRows(result, resolved, session, cursor);
1085
+ let projected = projectReadOutputRows(continuationReadyResult, resolved, session, cursor);
1037
1086
  const continuationState = captureReadOutputContinuationState(projected, cursor, options);
1038
1087
  const receipt = {
1039
1088
  contract_version: 1,
@@ -1085,4 +1134,4 @@ export function resolveReadOutputEncoding(command, options) {
1085
1134
  : undefined;
1086
1135
  }
1087
1136
  //# sourceMappingURL=read-output-contracts.js.map
1088
- //# debugId=db1d54b0-ff27-51f5-a179-14556ced24eb
1137
+ //# debugId=b3c001df-9891-5cf7-990b-8d9da7b51801
@@ -15,8 +15,12 @@ export interface PmReadOutputRowCollection {
15
15
  export declare function sliceReadOutputRowCollection(result: Record<string, unknown>, rowPath: string, offset: number): Record<string, unknown>;
16
16
  /** Resolve declared row paths, falling back to top-level array properties. */
17
17
  export declare function readOutputRowPaths(result: Record<string, unknown>): string[];
18
+ /** Resolve collections that may be resumed independently from primary result rows. */
19
+ export declare function readOutputContinuationRowPaths(result: Record<string, unknown>): string[];
18
20
  /** Resolve every declared row path that currently contains iterable rows. */
19
21
  export declare function readOutputRowCollections(result: Record<string, unknown>): PmReadOutputRowCollection[];
22
+ /** Resolve every declared continuation path that currently contains iterable rows. */
23
+ export declare function readOutputContinuationRowCollections(result: Record<string, unknown>): PmReadOutputRowCollection[];
20
24
  /**
21
25
  * Discover every collection the token-budget degradation ladder may reduce.
22
26
  *
@@ -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
@@ -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]="48d9b905-70a1-52c3-9b9c-33624661e6eb")}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";
@@ -1349,13 +1349,14 @@ async function runMcpListAction(ctx) {
1349
1349
  return withQuerySummary((await runList(readString(ctx.args, "status") ?? readString(listOptions, "status"), listOptions, ctx.global)), listOptions);
1350
1350
  }
1351
1351
  async function runMcpSearchAction(ctx) {
1352
- const searchOptions = applyContextIntentProjection("search", ctx.options);
1352
+ const query = readRequiredString(ctx.args, "query");
1353
+ const searchOptions = applyContextIntentProjection("search", ctx.options, [query]);
1353
1354
  if (searchOptions.compact === undefined &&
1354
1355
  searchOptions.full === undefined &&
1355
1356
  searchOptions.fields === undefined) {
1356
1357
  searchOptions.compact = true;
1357
1358
  }
1358
- return withQuerySummary((await runSearch(readRequiredString(ctx.args, "query"), searchOptions, ctx.global)), searchOptions);
1359
+ return withQuerySummary((await runSearch(query, searchOptions, ctx.global)), searchOptions);
1359
1360
  }
1360
1361
  async function runMcpCreateAction(ctx) {
1361
1362
  const { changedFields, idOnly, runnerOptions } = withMutationCompaction(ctx.args, ctx.options);
@@ -1783,7 +1784,10 @@ const SDK_ACTION_HANDLERS = {
1783
1784
  event: runRuntimeSchedulingAction,
1784
1785
  remind: runRuntimeSchedulingAction,
1785
1786
  list: runMcpListAction,
1786
- 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
+ },
1787
1791
  search: runMcpSearchAction,
1788
1792
  duplicates: (ctx) => {
1789
1793
  const status = typeof ctx.options.status === "string"
@@ -1936,4 +1940,4 @@ async function loadWorkspaceExtensionRegistrations(pmRoot, settings, cwd) {
1936
1940
  }
1937
1941
  }
1938
1942
  //# sourceMappingURL=runtime.js.map
1939
- //# debugId=48d9b905-70a1-52c3-9b9c-33624661e6eb
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/docs/COMMANDS.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  This is a task-oriented command guide. For exact flags, use runtime help because extensions and settings can change the active surface:
4
4
 
5
- Tracked implementation updates: [pm-52eh](../.agents/pm/features/pm-52eh.toon), [pm-mcxr](../.agents/pm/issues/pm-mcxr.toon), [pm-qd3woa](../.agents/pm/issues/pm-qd3woa.toon), [pm-ypuc39](../.agents/pm/issues/pm-ypuc39.toon), [pm-tz2ikr](../.agents/pm/issues/pm-tz2ikr.toon), the schema-migration recovery contract [pm-s79kel](../.agents/pm/issues/pm-s79kel.toon), the lossless mutation contracts [pm-x3dq0l](../.agents/pm/issues/pm-x3dq0l.toon), [pm-lppm6y](../.agents/pm/issues/pm-lppm6y.toon), and [pm-embm6t](../.agents/pm/issues/pm-embm6t.toon), and the SDK-first agent grammar tranche [pm-p316vn](../.agents/pm/issues/pm-p316vn.toon), [pm-st7wgu](../.agents/pm/issues/pm-st7wgu.toon), [pm-mkinft](../.agents/pm/issues/pm-mkinft.toon), [pm-ulqu](../.agents/pm/issues/pm-ulqu.toon), [pm-qmjx](../.agents/pm/issues/pm-qmjx.toon), [pm-4bzq](../.agents/pm/features/pm-4bzq.toon), [pm-x2vx](../.agents/pm/issues/pm-x2vx.toon), and [pm-g543](../.agents/pm/issues/pm-g543.toon).
5
+ Tracked implementation updates: [pm-52eh](../.agents/pm/features/pm-52eh.toon), [pm-mcxr](../.agents/pm/issues/pm-mcxr.toon), [pm-qd3woa](../.agents/pm/issues/pm-qd3woa.toon), [pm-ypuc39](../.agents/pm/issues/pm-ypuc39.toon), [pm-tz2ikr](../.agents/pm/issues/pm-tz2ikr.toon), the schema-migration recovery contract [pm-s79kel](../.agents/pm/issues/pm-s79kel.toon), the lossless mutation contracts [pm-x3dq0l](../.agents/pm/issues/pm-x3dq0l.toon), [pm-lppm6y](../.agents/pm/issues/pm-lppm6y.toon), and [pm-embm6t](../.agents/pm/issues/pm-embm6t.toon), positional action discovery [pm-2tan](../.agents/pm/issues/pm-2tan.toon), and the SDK-first agent grammar tranche [pm-p316vn](../.agents/pm/issues/pm-p316vn.toon), [pm-st7wgu](../.agents/pm/issues/pm-st7wgu.toon), [pm-mkinft](../.agents/pm/issues/pm-mkinft.toon), [pm-ulqu](../.agents/pm/issues/pm-ulqu.toon), [pm-qmjx](../.agents/pm/issues/pm-qmjx.toon), [pm-4bzq](../.agents/pm/features/pm-4bzq.toon), [pm-x2vx](../.agents/pm/issues/pm-x2vx.toon), and [pm-g543](../.agents/pm/issues/pm-g543.toon).
6
6
 
7
7
  Workspace-integrity contracts are tracked by [pm-22rzjp](../.agents/pm/issues/pm-22rzjp.toon), [pm-76fkpp](../.agents/pm/issues/pm-76fkpp.toon), [pm-igdvfq](../.agents/pm/issues/pm-igdvfq.toon), [pm-643e0k](../.agents/pm/issues/pm-643e0k.toon), and [pm-larv4r](../.agents/pm/issues/pm-larv4r.toon).
8
8
 
@@ -1120,6 +1120,13 @@ Profiles are extensible: a package can ship its own archetype with `api.register
1120
1120
 
1121
1121
  Plan creation shares the normal create contract. Governance fields such as `--status`, `--deadline`, `--estimate`, `--acceptance-criteria`, `--assignee`, review/risk fields, comments, notes, learnings, reminders, events, and linked resources are accepted directly and pass through the same strict/progressive schema validation as `pm create`.
1122
1122
 
1123
+ Every positional plan action is also a discoverable virtual command path. Use
1124
+ `pm plan create --help --json` or `pm help plan create --json` for its exact
1125
+ arguments and effective flags, and use `pm contracts --command "plan create"
1126
+ --flags-only --json` for the matching machine contract. Root `pm plan --help
1127
+ --json` publishes the same action inventory under `subcommands`; omitting the
1128
+ required action fails as `missing_required_argument` before mutation dispatch.
1129
+
1123
1130
  ```bash
1124
1131
  pm plan create --title "Refactor lock retry" --scope "Improve retry semantics" --harness claude-code --parent pm-epic1 --related pm-rel1,pm-rel2 --claim
1125
1132
  pm plan create --title "Fix flaky retry test" --step "Read lock.ts" --step "Write the fix" --step "Run the tests"
@@ -1190,9 +1197,14 @@ Project-governance setters use the separate `governance_contracts` value
1190
1197
  domains; in particular, workflow enforcement is `off|warn|strict`, not the
1191
1198
  extension policy token `enforce`.
1192
1199
  Use `pm contracts --summary --json` first when bootstrapping in a tight context
1193
- window. `command_summaries` contains exactly one row per advertised command
1194
- path—including aliases and namespace childrenwith a meaningful intent plus
1195
- `default_max_estimated_tokens` and the format-specific TOON/JSON ceilings.
1200
+ window. `command_summaries` contains one row per registered command path,
1201
+ including aliases and namespace children, with a meaningful intent plus
1202
+ `default_max_estimated_tokens`. The low-token summary intentionally does not
1203
+ repeat the 32 virtual positional Plan, Assurance, and workspace-snapshot action rows;
1204
+ `grammar_contracts.positional_action_count` and `positional_action_parents`
1205
+ retain their complete discoverability and route callers to root help. A
1206
+ command-scoped contract for an exact action restores its typed positional
1207
+ signature, exact flags, provenance, and format-specific TOON/JSON ceilings.
1196
1208
  Package commands contribute their intent through command registration (falling
1197
1209
  back to the registered description), so agents never need a generic
1198
1210
  `Inspect flags.` placeholder. Request heavier command-specific flags or schemas
@@ -15,7 +15,8 @@ selectors are tracked by
15
15
  [pm-x710qm](../.agents/pm/issues/pm-x710qm.toon). Default contract suppression
16
16
  and canonical TOON tables are tracked by
17
17
  [pm-gjjurs](../.agents/pm/issues/pm-gjjurs.toon) and
18
- [pm-5y05kq](../.agents/pm/issues/pm-5y05kq.toon).
18
+ [pm-5y05kq](../.agents/pm/issues/pm-5y05kq.toon). Nested evidence continuation
19
+ is tracked by [pm-8nev0o](../.agents/pm/issues/pm-8nev0o.toon).
19
20
 
20
21
  ## Agent Quick Context
21
22
 
@@ -73,6 +74,7 @@ or not the current page has rows:
73
74
  "command": "list",
74
75
  "row_kind": "collection",
75
76
  "row_keys": ["items"],
77
+ "continuation_row_keys": ["items"],
76
78
  "fields": "supported",
77
79
  "jq_selector": ".row_contract.row_keys[] as $key | getpath($key | split(\".\")) | if type == \"array\" then .[] else if type == \"object\" then to_entries[] else empty end end",
78
80
  "toon_encoding": "tabular_when_uniform"
@@ -89,6 +91,12 @@ nested dependency graph and relationship-context rows addressable as
89
91
  `graph.nodes`, `graph.edges`, `context.nodes`, and `context.edges` without
90
92
  duplicating them at the envelope root. Array collections produce their
91
93
  elements; object maps produce jq `to_entries` rows.
94
+ `continuation_row_keys` is optional and defaults to `row_keys`. A command uses
95
+ it only when independently resumable nested evidence differs from its primary
96
+ amount-bounded rows. Validate, for example, keeps `checks` and `warnings` as
97
+ primary rows while a rich result can name
98
+ `checks.0.details.missing_resolution_rows` as a continuation row. This prevents
99
+ an inner diagnostic array from disabling `--output-limit` on the outer checks.
92
100
  `toon_encoding: "tabular_when_uniform"` declares that an array of flat objects
93
101
  with one shared key set renders as a length-marked TOON table; mixed, nested,
94
102
  or heterogeneous arrays retain the expanded representation. Quoted,
@@ -107,7 +115,8 @@ publish a row contract.
107
115
  SDK and package authors can import `PM_READ_ROW_CONTRACTS`,
108
116
  `PM_READ_ROW_JQ_SELECTOR`, and `resolveReadRowContract` from
109
117
  `@unbrained/pm-cli/sdk`. Existing package declarations are preserved only
110
- when `command`, `row_kind`, `row_keys`, `fields`, the conditional
118
+ when `command`, `row_kind`, `row_keys`, optional unique non-empty
119
+ `continuation_row_keys`, `fields`, the conditional
111
120
  `jq_selector`, and any supplied `toon_encoding` form a structurally valid row contract; malformed declarations
112
121
  are replaced by the canonical built-in contract when one applies.
113
122
 
@@ -15,10 +15,13 @@ Every built-in read surface uses four output dimensions: what to include, how mu
15
15
 
16
16
  The contract covers `list`, `context`, `search`, `get`, `next`, `health`, `deps`, `graph`, `history`, `activity`, `validate`, `events`, `contracts`, `comments`, `notes`, `files`, `docs`, `stats`, and `aggregate`, including list aliases and `ctx`.
17
17
 
18
- Row shaping follows each envelope's `row_contract.row_keys`, including
19
- dot-delimited nested arrays and object maps such as `graph.nodes`. Include,
20
- amount, repeat suppression, and cost compaction therefore operate on the same
21
- machine-declared rows; they do not rely on command-specific top-level keys.
18
+ Primary row shaping follows each envelope's `row_contract.row_keys`, including
19
+ dot-delimited arrays and object maps such as `graph.nodes`. Include, amount, and
20
+ repeat suppression therefore remain bound to the rows the command says it
21
+ returns. A result may additionally declare `continuation_row_keys` when a
22
+ nested evidence collection must resume independently without redefining the
23
+ primary rows that `--output-limit` bounds. Cost compaction may inspect both
24
+ primary and nested collections; it does not rely on command-specific keys.
22
25
  The runtime uses that declaration internally on every read but omits the
23
26
  repeated metadata from results by default. Request
24
27
  `--output-row-contract` / `outputRowContract: true` when a consumer needs the
@@ -153,8 +156,9 @@ producer cursor, a universal output cursor, and a terminal page;
153
156
  `next_cursor` mirrors the first universal entry for ordinary one-path
154
157
  consumers. Replay the same query and budget
155
158
  with `--output-cursor <cursor>` / `outputCursor`. The cursor validates the
156
- command, declared row path, total, and stable row identities before slicing, so
157
- a mismatched or stale replay fails closed instead of skipping evidence. A
159
+ command, declared continuation path, total, and canonical content fingerprint
160
+ before slicing, so same-cardinality content changes and other stale replays
161
+ fail closed instead of skipping evidence. A
158
162
  bounded recovery therefore does not require replacing a 600-token request with
159
163
  an unbounded multi-megabyte response;
160
164
  `recovery_budget_multiplier: 1` declares that each next page retains the same
package/docs/SDK.md CHANGED
@@ -50,6 +50,10 @@ first-class recurrence relationships are tracked by
50
50
  Fail-closed whole-corpus reads and package-catalog output controls are tracked by
51
51
  [pm-y4aaol](../.agents/pm/issues/pm-y4aaol.toon) and
52
52
  [pm-2firut](../.agents/pm/issues/pm-2firut.toon).
53
+ Positional command signatures, action-scoped discovery, and MCP/CLI option
54
+ parity are tracked by [pm-ya7x55](../.agents/pm/tasks/pm-ya7x55.toon),
55
+ [pm-2tan](../.agents/pm/issues/pm-2tan.toon), and
56
+ [pm-y0htkd](../.agents/pm/issues/pm-y0htkd.toon).
53
57
 
54
58
  Use it for extension authoring, package authoring, command/action contract discovery, and deterministic app or CI automation. Do not import private `src/core/...` modules from external integrations or packages.
55
59
 
@@ -340,6 +344,8 @@ Command/action contract exports:
340
344
  - Execution and diagnostics contracts: `TestCommandOptions` / `TestResult` / `TestRunResult`, `TestAllCommandOptions` / `TestAllResult`, `StartBackgroundRunCommandOptions` / `StartBackgroundRunResult`, `TestRuns*CommandOptions`, `EvalOptions` / `EvalResult`, `TelemetryCommandOptions` / `TelemetrySubcommand`, and `StatsCommandOptions` / `StatsResult`.
341
345
  - Linked-test authoring primitives: `parseLinkedTestJsonEntries`, the `parseLinkedTest*` field parsers, `LINKED_TEST_PM_CONTEXT_MODE_VALUES`, `LINKED_TEST_PROTECTED_ENV_KEYS`, `classifyLinkedTestFailure`, `countFailureCategories`, and `summarizeContextPreflight` let custom hosts validate, execute, classify, and report linked tests without duplicating CLI policy.
342
346
  - Agent command primitives: `normalizeItemAddressInvocation` and `supportsItemIdAlias` project one item-id grammar across CLI adapters; `renderMissingOptionRetry`, `resolveMissingOptionPlaceholder`, and `resolveRecoveryCommandName` preserve attempted argv, derive enum/boolean/scalar recovery arity from flag contracts, and identify the actual command without mistaking a global option value for one; `createUnknownSubcommandError` provides one typed positional refusal with complete allowed values and deterministic nearest retry; `rankCommandPaths` and `scoreCommandPathMatch` provide deterministic synonym/edit-distance/substring ranking; `resolveCreateExplicitEmptyFlag` and `supportsCreateExplicitEmpty` model a considered-but-empty strict repeatable input without inventing metadata or graph edges.
347
+ - Positional grammar primitives: `PM_COMMAND_POSITIONAL_CONTRACTS` declares every core and known-package command signature as ordered, typed slots; `PM_POSITIONAL_ACTION_CONTRACTS` promotes positional plan and assurance actions into discoverable virtual command paths with action-scoped flags, examples, and intent. `resolvePmCommandPositionalContract`, `resolvePmPositionalActionContract`, and `verifyPmCommandPositionalContracts` let custom hosts resolve or fail-closed compare the same signatures emitted by runtime contracts. The grammar receipt ratchets distinct semantic shapes through `positional_shape_budget` so a new arity cannot silently expand agent context.
348
+ - MCP/CLI option parity primitive: `verifyToolOptionCliParity` compares one `ToolOptionFlagContract` table with its executable `CliFlagContract` table. It fails when the transport-selected canonical flag is absent or when a parameter such as `linkedFile` cannot be invoked using its kebab-case CLI spelling (`--linked-file`) canonically or through a registered alias. Core create/update parity is part of the required command-grammar gate.
343
349
  - Refusal reachability primitives: generated `PmErrorCodeContract.owned_states` declarations bind stable codes to concrete states, probe ids, entrypoints, and exit classes; `verifyPmRefusalReachability` compares those declarations with real CLI, SDK, MCP, or package observations and fails closed for missing, duplicate, wrong-entrypoint, mismatched, or undeclared probes.
344
350
  - Typed plan workflow primitives on `PmClient`: `plan`, `planCreate`, `planShow`, `planAddStep`, `planUpdateStep`, `planCompleteStep`, `planBlockStep`, `planReorderStep`, `planRemoveStep`, `planLink`, `planUnlink`, `planDecision`, `planDiscovery`, `planValidation`, `planResume`, `planApprove`, and `planMaterialize`
345
351
  - Plan contracts: `PlanSubcommand`, `PlanCommandOptions`, `PlanCommandResult`, `PlanResultPlan`, `PlanStepSummary`, `PlanShowDepth`, and `PlanTemplateName`