@unbrained/pm-cli 2026.8.18 → 2026.8.20

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 (186) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +35 -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 +18 -13
  9. package/dist/cli/register-mutation.js +8 -8
  10. package/dist/cli/register-operations.js +6 -6
  11. package/dist/cli/register-structured-mutation.d.ts +2 -0
  12. package/dist/cli/register-structured-mutation.js +29 -6
  13. package/dist/cli-bundle/bundle-manifest.json +151 -143
  14. package/dist/cli-bundle/chunks/{chunk-UYCLQVL2.js → chunk-2RDVGYWE.js} +12 -12
  15. package/dist/cli-bundle/chunks/{chunk-BSK2IN3C.js → chunk-4GB2LTOQ.js} +2 -2
  16. package/dist/cli-bundle/chunks/{chunk-RZQTVMRQ.js → chunk-7BRF2BX2.js} +2 -2
  17. package/dist/cli-bundle/chunks/chunk-BLVQHFSY.js +35 -0
  18. package/dist/cli-bundle/chunks/chunk-CU25EQVV.js +5 -0
  19. package/dist/cli-bundle/chunks/chunk-K3EN3LK2.js +2 -0
  20. package/dist/cli-bundle/chunks/{chunk-YRGOLZA7.js → chunk-L4LGPBJU.js} +49 -49
  21. package/dist/cli-bundle/chunks/chunk-RS3IV2R6.js +197 -0
  22. package/dist/cli-bundle/chunks/chunk-TSMWLCHS.js +3 -0
  23. package/dist/cli-bundle/chunks/chunk-US2ZQW2M.js +77 -0
  24. package/dist/cli-bundle/chunks/{chunk-5UZZAJKR.js → chunk-XYDDWBZN.js} +2 -2
  25. package/dist/cli-bundle/chunks/register-list-query-JSAQCVOC.js +11 -0
  26. package/dist/cli-bundle/chunks/register-mutation-XJPAW63D.js +20 -0
  27. package/dist/cli-bundle/chunks/register-operations-DSOSB2XQ.js +2 -0
  28. package/dist/cli-bundle/chunks/{register-setup-PPPEF3SN.js → register-setup-QUR6QL2C.js} +2 -2
  29. package/dist/cli-bundle/focused-chunks/chunk-325UXIO7.js +2 -0
  30. package/dist/cli-bundle/focused-chunks/chunk-5L7M4AI7.js +2 -0
  31. package/dist/cli-bundle/focused-chunks/{chunk-ODOVCP45.js → chunk-6AHG2YW7.js} +44 -44
  32. package/dist/cli-bundle/focused-chunks/chunk-AZBACT5T.js +2 -0
  33. package/dist/cli-bundle/focused-chunks/{chunk-TN4AE665.js → chunk-BLJCGGID.js} +2 -2
  34. package/dist/cli-bundle/focused-chunks/chunk-FUREQLQN.js +18 -0
  35. package/dist/cli-bundle/focused-chunks/{chunk-M62NO7EI.js → chunk-G3C5ERXG.js} +2 -2
  36. package/dist/cli-bundle/focused-chunks/{chunk-K43KKAFS.js → chunk-GXWQBE3T.js} +2 -2
  37. package/dist/cli-bundle/focused-chunks/{chunk-UI6AJ5TD.js → chunk-JWKEDZJI.js} +3 -3
  38. package/dist/cli-bundle/focused-chunks/chunk-KYZ6JGPL.js +155 -0
  39. package/dist/cli-bundle/focused-chunks/{chunk-EX6MKP2X.js → chunk-M32HFIQB.js} +2 -2
  40. package/dist/cli-bundle/focused-chunks/{chunk-EUEGXZ2A.js → chunk-OM65KHGF.js} +2 -2
  41. package/dist/cli-bundle/focused-chunks/chunk-Q47EX4DI.js +2 -0
  42. package/dist/cli-bundle/focused-chunks/{chunk-V5XTGLK7.js → chunk-RIHDMCUM.js} +2 -2
  43. package/dist/cli-bundle/focused-chunks/chunk-T4ZFY7ZJ.js +16 -0
  44. package/dist/cli-bundle/focused-chunks/chunk-TDR5OGG3.js +2 -0
  45. package/dist/cli-bundle/focused-chunks/chunk-UGSS4F5X.js +2 -0
  46. package/dist/cli-bundle/focused-chunks/chunk-Z3PLWSGM.js +2 -0
  47. package/dist/cli-bundle/main.js +13 -13
  48. package/dist/cli-bundle/sdk-authoring.js +1 -1
  49. package/dist/cli-bundle/sdk-contracts.js +2 -1
  50. package/dist/cli-bundle/sdk-core.js +41 -41
  51. package/dist/cli-bundle/sdk-governance.js +1 -1
  52. package/dist/cli-bundle/sdk-graph.js +1 -1
  53. package/dist/cli-bundle/sdk-merge.js +32 -32
  54. package/dist/cli-bundle/sdk-query.js +1 -1
  55. package/dist/cli-bundle/sdk-runtime.js +1 -1
  56. package/dist/cli-bundle/sdk-testing.js +1 -1
  57. package/dist/cli-bundle/sdk.js +5 -4
  58. package/dist/core/output/mutation-projection.js +26 -2
  59. package/dist/core/shared/constants.d.ts +1 -5
  60. package/dist/core/shared/constants.js +3 -81
  61. package/dist/core/shared/errors.d.ts +2 -0
  62. package/dist/core/shared/errors.js +2 -2
  63. package/dist/core/shared/item-metadata-contract.d.ts +14 -0
  64. package/dist/core/shared/item-metadata-contract.js +90 -0
  65. package/dist/core/store/item-store.d.ts +60 -0
  66. package/dist/core/store/item-store.js +22 -5
  67. package/dist/sdk/agent/closed-domain-contracts.d.ts +25 -0
  68. package/dist/sdk/agent/closed-domain-contracts.js +140 -0
  69. package/dist/sdk/agent/refusal-closure.d.ts +53 -0
  70. package/dist/sdk/agent/refusal-closure.js +134 -0
  71. package/dist/sdk/agent/refusal-reachability.d.ts +27 -1
  72. package/dist/sdk/agent/refusal-reachability.js +26 -2
  73. package/dist/sdk/agent-capability-contracts.d.ts +13 -0
  74. package/dist/sdk/agent-capability-contracts.js +101 -9
  75. package/dist/sdk/cli-contracts/command-aliases.js +18 -2
  76. package/dist/sdk/cli-contracts/commander-mutation-options.js +30 -6
  77. package/dist/sdk/cli-contracts/commander-types.js +5 -4
  78. package/dist/sdk/cli-contracts/completeness.js +8 -2
  79. package/dist/sdk/cli-contracts/enum-contracts.d.ts +4 -2
  80. package/dist/sdk/cli-contracts/enum-contracts.js +16 -6
  81. package/dist/sdk/cli-contracts/flag-contracts.d.ts +7 -0
  82. package/dist/sdk/cli-contracts/flag-contracts.js +84 -8
  83. package/dist/sdk/cli-contracts/flag-lexicon-contracts.d.ts +72 -0
  84. package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +340 -0
  85. package/dist/sdk/cli-contracts/grammar-contracts.d.ts +83 -2
  86. package/dist/sdk/cli-contracts/grammar-contracts.js +618 -2
  87. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +15 -4
  88. package/dist/sdk/cli-contracts/runtime-contracts.js +47 -13
  89. package/dist/sdk/cli-contracts/tool-option-contracts.d.ts +28 -1
  90. package/dist/sdk/cli-contracts/tool-option-contracts.js +38 -3
  91. package/dist/sdk/cli-contracts/tool-schema.js +7 -2
  92. package/dist/sdk/cli-contracts.d.ts +4 -3
  93. package/dist/sdk/cli-contracts.js +6 -5
  94. package/dist/sdk/context-intent-contracts.d.ts +2 -2
  95. package/dist/sdk/context-intent-contracts.js +22 -7
  96. package/dist/sdk/contracts.d.ts +3 -0
  97. package/dist/sdk/contracts.js +5 -2
  98. package/dist/sdk/core.d.ts +1 -1
  99. package/dist/sdk/core.js +3 -3
  100. package/dist/sdk/flag-invocation-contracts.d.ts +37 -0
  101. package/dist/sdk/flag-invocation-contracts.js +218 -9
  102. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +206 -2
  103. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +244 -40
  104. package/dist/sdk/index.d.ts +11 -7
  105. package/dist/sdk/index.js +10 -6
  106. package/dist/sdk/init-agent-guidance.d.ts +5 -3
  107. package/dist/sdk/init-agent-guidance.js +69 -9
  108. package/dist/sdk/lifecycle/mcp-actions.d.ts +18 -0
  109. package/dist/sdk/lifecycle/mcp-actions.js +52 -0
  110. package/dist/sdk/lifecycle/reopen.d.ts +44 -0
  111. package/dist/sdk/lifecycle/reopen.js +69 -0
  112. package/dist/sdk/lifecycle/update.d.ts +31 -0
  113. package/dist/sdk/lifecycle/update.js +95 -13
  114. package/dist/sdk/output-projection.d.ts +2 -0
  115. package/dist/sdk/output-projection.js +11 -5
  116. package/dist/sdk/query/get.d.ts +1 -1
  117. package/dist/sdk/query/get.js +34 -49
  118. package/dist/sdk/query/list.d.ts +7 -21
  119. package/dist/sdk/query/list.js +44 -44
  120. package/dist/sdk/query/projection-contracts.d.ts +33 -0
  121. package/dist/sdk/query/projection-contracts.js +185 -0
  122. package/dist/sdk/query/search-contracts.d.ts +3 -2
  123. package/dist/sdk/query/search-contracts.js +30 -85
  124. package/dist/sdk/query/search.d.ts +15 -0
  125. package/dist/sdk/query/search.js +32 -6
  126. package/dist/sdk/read-output/continuation.d.ts +1 -1
  127. package/dist/sdk/read-output/continuation.js +7 -24
  128. package/dist/sdk/read-output-contracts.js +55 -6
  129. package/dist/sdk/read-output-rows.d.ts +4 -0
  130. package/dist/sdk/read-output-rows.js +47 -18
  131. package/dist/sdk/runtime-primitives.d.ts +1 -1
  132. package/dist/sdk/runtime-primitives.js +3 -3
  133. package/dist/sdk/runtime.d.ts +6 -0
  134. package/dist/sdk/runtime.js +25 -17
  135. package/dist/sdk/similarity.d.ts +13 -0
  136. package/dist/sdk/similarity.js +32 -6
  137. package/dist/sdk/workspace-snapshot.d.ts +2 -0
  138. package/dist/sdk/workspace-snapshot.js +10 -2
  139. package/docs/COMMANDS.md +29 -5
  140. package/docs/OUTPUT_PROJECTION_CONTRACTS.md +11 -2
  141. package/docs/README.md +1 -0
  142. package/docs/READ_OUTPUT_CONTRACTS.md +10 -6
  143. package/docs/RECURRENCE_RECOVERY_CONTRACTS.md +114 -0
  144. package/docs/SDK.md +16 -2
  145. package/docs/SDK_CONTEXT_INTEGRITY.md +45 -0
  146. package/docs/TESTING.md +14 -1
  147. package/docs/generated/AGENT_COMMAND_SURFACE.md +78 -78
  148. package/docs/generated/FLAG_LEXICON_BUDGETS.md +76 -0
  149. package/docs/performance/sdk-entrypoint-import-costs.md +14 -21
  150. package/marketplace.json +2 -2
  151. package/package.json +9 -7
  152. package/packages/pm-beads/package.json +1 -1
  153. package/packages/pm-calendar/package.json +1 -1
  154. package/packages/pm-command-kit/package.json +1 -1
  155. package/packages/pm-digital-twin/package.json +1 -1
  156. package/packages/pm-governance-audit/package.json +1 -1
  157. package/packages/pm-guide-shell/package.json +1 -1
  158. package/packages/pm-kanban/package.json +1 -1
  159. package/packages/pm-lifecycle-hooks/package.json +1 -1
  160. package/packages/pm-linked-test-adapters/package.json +1 -1
  161. package/packages/pm-search-advanced/package.json +1 -1
  162. package/packages/pm-templates/package.json +1 -1
  163. package/packages/pm-todos/package.json +1 -1
  164. package/packages/pm-vcs/package.json +1 -1
  165. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  166. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  167. package/scripts/generate-agent-capability-surfaces.mjs +20 -14
  168. package/sdk/public-surface.json +950 -24
  169. package/dist/cli-bundle/chunks/chunk-ALDJGKAK.js +0 -2
  170. package/dist/cli-bundle/chunks/chunk-DY4DMUMC.js +0 -197
  171. package/dist/cli-bundle/chunks/chunk-GNFAFIJI.js +0 -77
  172. package/dist/cli-bundle/chunks/chunk-L5Q2CLPE.js +0 -35
  173. package/dist/cli-bundle/chunks/chunk-PVRUN5ZS.js +0 -5
  174. package/dist/cli-bundle/chunks/chunk-SARFF5H5.js +0 -3
  175. package/dist/cli-bundle/chunks/register-list-query-I23LALEE.js +0 -11
  176. package/dist/cli-bundle/chunks/register-mutation-6YGU3GPH.js +0 -20
  177. package/dist/cli-bundle/chunks/register-operations-4HTFC6J7.js +0 -2
  178. package/dist/cli-bundle/focused-chunks/chunk-2PN4TJXH.js +0 -2
  179. package/dist/cli-bundle/focused-chunks/chunk-3TKWMNKF.js +0 -18
  180. package/dist/cli-bundle/focused-chunks/chunk-5AF3ZBNB.js +0 -155
  181. package/dist/cli-bundle/focused-chunks/chunk-C5IW2NDA.js +0 -2
  182. package/dist/cli-bundle/focused-chunks/chunk-RNDNMARJ.js +0 -16
  183. package/dist/cli-bundle/focused-chunks/chunk-TVV2DONO.js +0 -2
  184. package/dist/cli-bundle/focused-chunks/chunk-WGHQVU6P.js +0 -2
  185. package/dist/cli-bundle/focused-chunks/chunk-XYNBXTDQ.js +0 -2
  186. package/dist/cli-bundle/focused-chunks/chunk-Z56ECT7I.js +0 -2
@@ -4,7 +4,7 @@
4
4
  * Implements the pm init agent guidance 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]="b7c97e30-02c8-547c-b3db-c6c59e662b54")}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]="e404796d-439b-5f4c-9330-5b12ff41d7b2")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
10
  import readline from "node:readline/promises";
@@ -91,14 +91,14 @@ function findGuidanceBlockRange(content) {
91
91
  function hasGuidanceMarker(content) {
92
92
  return findGuidanceBlockRange(content) !== null;
93
93
  }
94
- function buildAgentGuidanceBlock(lineEnding) {
94
+ function buildAgentGuidanceBlock(lineEnding, projectTestCommand = "<your project test command>") {
95
95
  const lines = [
96
96
  AGENT_GUIDANCE_START_MARKER,
97
97
  "## pm Workflow (Agent Quickstart)",
98
98
  "",
99
99
  '- Orient before mutate: `pm context --limit 10`, `pm search "<keywords>" --limit 10`, `pm list --status open --limit 20`.',
100
100
  "- Claim and execute: `pm claim <id>` then `pm update <id> --status in_progress`.",
101
- '- Link evidence while coding: `pm files <id> --add ...`, `pm docs <id> --add ...`, `pm test <id> --add command="node scripts/run-tests.mjs test -- ..."`.',
101
+ `- Link evidence while coding: \`pm files <id> --add ...\`, \`pm docs <id> --add ...\`, \`pm test <id> --add command="${projectTestCommand}"\`.`,
102
102
  '- Verify and close: `pm test <id> --run --progress`, `pm close <id> "<evidence>" --validate-close warn`, `pm release <id>`.',
103
103
  "- Author identity is automatic for supported agent harnesses; use `--author` only for an explicit override.",
104
104
  "",
@@ -107,9 +107,9 @@ function buildAgentGuidanceBlock(lineEnding) {
107
107
  ];
108
108
  return lines.join(lineEnding);
109
109
  }
110
- function upsertAgentGuidanceBlock(existingContent) {
110
+ function upsertAgentGuidanceBlock(existingContent, projectTestCommand = "<your project test command>") {
111
111
  const lineEnding = detectLineEnding(existingContent);
112
- const nextBlock = buildAgentGuidanceBlock(lineEnding);
112
+ const nextBlock = buildAgentGuidanceBlock(lineEnding, projectTestCommand);
113
113
  const existingRange = findGuidanceBlockRange(existingContent);
114
114
  if (existingRange) {
115
115
  const trailingContent = existingContent.slice(existingRange.end_index);
@@ -135,6 +135,65 @@ function upsertAgentGuidanceBlock(existingContent) {
135
135
  changed: nextContent !== existingContent,
136
136
  };
137
137
  }
138
+ /** Resolve an executable linked-test command from a target repository's own files. */
139
+ export async function resolveProjectTestCommand(projectRoot) {
140
+ if (await pathExists(path.join(projectRoot, "scripts", "run-tests.mjs"))) {
141
+ return "node scripts/run-tests.mjs test";
142
+ }
143
+ let packageDocument;
144
+ try {
145
+ packageDocument = JSON.parse(await fs.readFile(path.join(projectRoot, "package.json"), "utf8"));
146
+ }
147
+ catch {
148
+ return "<your project test command>";
149
+ }
150
+ const manifest = normalizeProjectPackageManifest(packageDocument);
151
+ if (manifest === undefined) {
152
+ return "<your project test command>";
153
+ }
154
+ const packageManager = manifest.packageManager?.split("@")[0];
155
+ if (packageManager === "pnpm") {
156
+ return "pnpm test";
157
+ }
158
+ if (packageManager === "bun") {
159
+ return "bun run test";
160
+ }
161
+ if (packageManager === "yarn") {
162
+ return "yarn test";
163
+ }
164
+ if (packageManager === "npm")
165
+ return "npm test";
166
+ if (await pathExists(path.join(projectRoot, "pnpm-lock.yaml"))) {
167
+ return "pnpm test";
168
+ }
169
+ if ((await pathExists(path.join(projectRoot, "bun.lock"))) ||
170
+ (await pathExists(path.join(projectRoot, "bun.lockb")))) {
171
+ return "bun run test";
172
+ }
173
+ if (await pathExists(path.join(projectRoot, "yarn.lock")))
174
+ return "yarn test";
175
+ return "npm test";
176
+ }
177
+ /** Validate the minimal package manifest shape needed for executable test guidance. */
178
+ function normalizeProjectPackageManifest(value) {
179
+ if (typeof value !== "object" || value === null || !("scripts" in value)) {
180
+ return undefined;
181
+ }
182
+ const scripts = value.scripts;
183
+ if (typeof scripts !== "object" ||
184
+ scripts === null ||
185
+ !("test" in scripts) ||
186
+ typeof scripts.test !== "string" ||
187
+ scripts.test.trim().length === 0) {
188
+ return undefined;
189
+ }
190
+ return {
191
+ scripts: { test: scripts.test },
192
+ ...("packageManager" in value && typeof value.packageManager === "string"
193
+ ? { packageManager: value.packageManager }
194
+ : {}),
195
+ };
196
+ }
138
197
  function resolveProjectRoot(pmRoot, cwd) {
139
198
  const parent = path.dirname(pmRoot);
140
199
  if (path.basename(pmRoot) === "pm" && path.basename(parent) === ".agents") {
@@ -240,10 +299,10 @@ function applyAgentGuidanceState(settings, currentState) {
240
299
  }
241
300
  return { changed, state: currentState };
242
301
  }
243
- async function writeGuidanceFile(filePath) {
302
+ async function writeGuidanceFile(filePath, projectRoot = path.dirname(filePath)) {
244
303
  const exists = await pathExists(filePath);
245
304
  const currentContent = exists ? await fs.readFile(filePath, "utf8") : "";
246
- const nextContent = upsertAgentGuidanceBlock(currentContent);
305
+ const nextContent = upsertAgentGuidanceBlock(currentContent, await resolveProjectTestCommand(projectRoot));
247
306
  if (!nextContent.changed) {
248
307
  return { changed: false, warnings: [] };
249
308
  }
@@ -292,7 +351,7 @@ async function addAgentGuidanceBlockIfMissing(flow, context) {
292
351
  if (context.presentBefore) {
293
352
  return;
294
353
  }
295
- const writeResult = await writeGuidanceFile(context.targetPath);
354
+ const writeResult = await writeGuidanceFile(context.targetPath, context.projectRoot);
296
355
  flow.warnings.push(...writeResult.warnings);
297
356
  if (writeResult.changed) {
298
357
  flow.applied = true;
@@ -413,6 +472,7 @@ export async function runInitAgentGuidance(options) {
413
472
  targetRelativePath,
414
473
  checkedFiles,
415
474
  presentBefore,
475
+ projectRoot,
416
476
  });
417
477
  const stateUpdate = applyAgentGuidanceState(options.settings, flow.state);
418
478
  scans = await refreshGuidanceScansAfterApply(flow.applied, scans, projectRoot);
@@ -434,4 +494,4 @@ export async function runInitAgentGuidance(options) {
434
494
  };
435
495
  }
436
496
  //# sourceMappingURL=init-agent-guidance.js.map
437
- //# debugId=b7c97e30-02c8-547c-b3db-c6c59e662b54
497
+ //# debugId=e404796d-439b-5f4c-9330-5b12ff41d7b2
@@ -0,0 +1,18 @@
1
+ import type { GlobalOptions } from "../../core/shared/command-types.js";
2
+ /** Minimal generic dispatch context consumed by lifecycle mutation adapters. */
3
+ export interface LifecycleMutationActionContext {
4
+ /** Flat MCP/action arguments. */
5
+ args: Record<string, unknown>;
6
+ /** Normalized command option bag. */
7
+ options: Record<string, unknown>;
8
+ /** Item id resolved from flat arguments, when present. */
9
+ id: string | undefined;
10
+ /** Normalized transport-level force override. */
11
+ force?: boolean;
12
+ /** Presentation-neutral global command options. */
13
+ global: GlobalOptions;
14
+ }
15
+ /** Dispatch close through the shared MCP mutation compaction contract. */
16
+ export declare function runMcpCloseAction(context: LifecycleMutationActionContext): Promise<unknown>;
17
+ /** Dispatch recurrence through the shared MCP mutation compaction contract. */
18
+ export declare function runMcpReopenAction(context: LifecycleMutationActionContext): Promise<unknown>;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @module sdk/runtime-mutation-actions
3
+ *
4
+ * Keeps lifecycle-specific MCP mutation adapters outside the generic runtime
5
+ * dispatcher while preserving the shared token-efficient result projection.
6
+ */
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]="55869854-565d-52d2-8dca-b66aade074bb")}catch(e){}}();
9
+ import { projectMutationResult } from "../../core/output/mutation-projection.js";
10
+ import { PmCliError } from "../../core/shared/errors.js";
11
+ import { runClose } from "./close.js";
12
+ import { runReopen } from "./reopen.js";
13
+ import { readRuntimeString, withMutationCompaction } from "../runtime-input.js";
14
+ function requireLifecycleItemId(context, options) {
15
+ const id = context.id ?? readRuntimeString(options, "id");
16
+ if (!id) {
17
+ throw new PmCliError("Missing required argument: id", 64);
18
+ }
19
+ return id;
20
+ }
21
+ function readLifecycleReason(context, options) {
22
+ return (readRuntimeString(context.args, "reason") ??
23
+ readRuntimeString(context.args, "text") ??
24
+ readRuntimeString(options, "reason") ??
25
+ readRuntimeString(options, "text"));
26
+ }
27
+ /** Dispatch close through the shared MCP mutation compaction contract. */
28
+ export async function runMcpCloseAction(context) {
29
+ const { changedFields, idOnly, runnerOptions } = withMutationCompaction(context.args, context.options);
30
+ return projectMutationResult(await runClose(requireLifecycleItemId(context, runnerOptions), readLifecycleReason(context, runnerOptions), {
31
+ ...runnerOptions,
32
+ force: context.force === true || runnerOptions.force === true,
33
+ }, context.global), {
34
+ changedFields,
35
+ compactEnvelope: changedFields === "compact" && !idOnly,
36
+ idOnly,
37
+ });
38
+ }
39
+ /** Dispatch recurrence through the shared MCP mutation compaction contract. */
40
+ export async function runMcpReopenAction(context) {
41
+ const { changedFields, idOnly, runnerOptions } = withMutationCompaction(context.args, context.options);
42
+ return projectMutationResult(await runReopen(requireLifecycleItemId(context, runnerOptions), readLifecycleReason(context, runnerOptions) ?? "", {
43
+ ...runnerOptions,
44
+ force: context.force === true || runnerOptions.force === true,
45
+ }, context.global), {
46
+ changedFields,
47
+ compactEnvelope: changedFields === "compact" && !idOnly,
48
+ idOnly,
49
+ });
50
+ }
51
+ //# sourceMappingURL=mcp-actions.js.map
52
+ //# debugId=55869854-565d-52d2-8dca-b66aade074bb
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @module sdk/lifecycle/reopen
3
+ *
4
+ * Reopens terminal work as a recurrence while preserving immutable closure
5
+ * evidence and delegating every state change to the canonical update pipeline.
6
+ */
7
+ import type { GlobalOptions } from "../../core/shared/command-types.js";
8
+ import { type PreviousTerminalEvidence } from "./update.js";
9
+ export type { PreviousTerminalEvidence } from "./update.js";
10
+ /** Options accepted by the SDK and `pm item reopen` recurrence primitive. */
11
+ export interface ReopenCommandOptions {
12
+ /** Active target status; only the workspace open or in-progress status is allowed. */
13
+ status?: string;
14
+ /** Explicit mutation author override. */
15
+ author?: string;
16
+ /** Optional human-readable history message in addition to structured recurrence context. */
17
+ message?: string;
18
+ /** Override an ownership or stale-lock conflict. */
19
+ force?: boolean;
20
+ }
21
+ /** Structured recurrence receipt returned by every presentation surface. */
22
+ export interface RecurrenceReceipt {
23
+ /** Required reason that the terminal work became active again. */
24
+ reason: string;
25
+ /** Terminal status observed while holding the item lock. */
26
+ from_status: string;
27
+ /** Active status written through the update pipeline. */
28
+ to_status: string;
29
+ /** Prior terminal evidence retained in immutable history. */
30
+ previous_terminal: PreviousTerminalEvidence;
31
+ }
32
+ /** Result returned after a terminal item is reopened. */
33
+ export interface ReopenResult {
34
+ /** Reopened item metadata. */
35
+ item: Record<string, unknown>;
36
+ /** Fields changed by the canonical update pipeline. */
37
+ changed_fields: string[];
38
+ /** Non-fatal mutation and extension warnings. */
39
+ warnings: string[];
40
+ /** Immutable recurrence transition receipt. */
41
+ recurrence: RecurrenceReceipt;
42
+ }
43
+ /** Reopen terminal work through the canonical update mutation and history path. */
44
+ export declare function runReopen(id: string, reason: string, options: ReopenCommandOptions, global: GlobalOptions): Promise<ReopenResult>;
@@ -0,0 +1,69 @@
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]="08dcee99-5572-5133-b76a-6a50e4e292e7")}catch(e){}}();
3
+ import { EXIT_CODE } from "../../core/shared/constants.js";
4
+ import { PmCliError } from "../../core/shared/errors.js";
5
+ import { normalizeStatusInput } from "../../core/item/status.js";
6
+ import { resolveRuntimeStatusRegistry } from "../../core/schema/runtime-schema.js";
7
+ import { resolvePmRoot } from "../../core/store/paths.js";
8
+ import { readSettings } from "../../core/store/settings.js";
9
+ import { resolveStartTaskInProgressStatus } from "../start-task-status.js";
10
+ import { runReopenUpdate, } from "./update.js";
11
+ /** Reopen terminal work through the canonical update mutation and history path. */
12
+ export async function runReopen(id, reason, options, global) {
13
+ const normalizedReason = reason.trim();
14
+ if (normalizedReason.length === 0) {
15
+ throw new PmCliError("pm item reopen requires a non-empty recurrence reason.", EXIT_CODE.USAGE, {
16
+ code: "reopen_reason_required",
17
+ required: "Describe why the terminal work became active again.",
18
+ recovery: {
19
+ suggested_retry: `pm item reopen ${id} "<recurrence reason>"`,
20
+ suggested_retry_args: ["item", "reopen", id, "<recurrence reason>"],
21
+ },
22
+ });
23
+ }
24
+ const pmRoot = resolvePmRoot(process.cwd(), global.path);
25
+ const statusRegistry = resolveRuntimeStatusRegistry((await readSettings(pmRoot)).schema);
26
+ const openStatus = statusRegistry.open_status;
27
+ const inProgressStatus = resolveStartTaskInProgressStatus(statusRegistry);
28
+ const requestedStatus = options.status ?? openStatus;
29
+ const targetStatus = normalizeStatusInput(requestedStatus, statusRegistry) ?? requestedStatus;
30
+ if (targetStatus !== openStatus && targetStatus !== inProgressStatus) {
31
+ throw new PmCliError(`Reopen target status must be ${openStatus} or ${inProgressStatus}; received ${requestedStatus}.`, EXIT_CODE.USAGE, {
32
+ code: "reopen_target_status_invalid",
33
+ required: "Choose the workspace open or in-progress lifecycle status.",
34
+ recovery: {
35
+ allowed_values: [...new Set([openStatus, inProgressStatus])],
36
+ suggested_retry: `pm item reopen ${id} "${normalizedReason}" --status ${openStatus}`,
37
+ suggested_retry_args: [
38
+ "item",
39
+ "reopen",
40
+ id,
41
+ normalizedReason,
42
+ "--status",
43
+ openStatus,
44
+ ],
45
+ },
46
+ });
47
+ }
48
+ const update = await runReopenUpdate(id, {
49
+ status: targetStatus,
50
+ unset: [
51
+ "close-reason",
52
+ "resolution",
53
+ "expected-result",
54
+ "actual-result",
55
+ "fixed-version",
56
+ ],
57
+ author: options.author,
58
+ message: options.message,
59
+ force: options.force,
60
+ }, global, normalizedReason);
61
+ return {
62
+ item: update.item,
63
+ changed_fields: update.changed_fields,
64
+ warnings: update.warnings,
65
+ recurrence: update.lifecycle_transition,
66
+ };
67
+ }
68
+ //# sourceMappingURL=reopen.js.map
69
+ //# debugId=08dcee99-5572-5133-b76a-6a50e4e292e7
@@ -67,6 +67,35 @@ export interface UpdateResult {
67
67
  /** Value that configures or reports warnings for this contract. */
68
68
  warnings: string[];
69
69
  }
70
+ /** Terminal evidence captured atomically before a recurrence transition. */
71
+ export interface PreviousTerminalEvidence {
72
+ /** Prior close reason, when recorded. */
73
+ close_reason?: string;
74
+ /** Prior structured resolution, when recorded. */
75
+ resolution?: string;
76
+ /** Prior expected result, when recorded. */
77
+ expected_result?: string;
78
+ /** Prior actual result, when recorded. */
79
+ actual_result?: string;
80
+ /** Prior fixed version, when recorded. */
81
+ fixed_version?: string;
82
+ }
83
+ /** Internal update-path receipt consumed by the public recurrence primitive. */
84
+ export interface ReopenUpdateReceipt {
85
+ /** Recurrence reason stored in immutable history context. */
86
+ reason: string;
87
+ /** Terminal status observed while holding the item lock. */
88
+ from_status: string;
89
+ /** Active status written by the update path. */
90
+ to_status: string;
91
+ /** Terminal evidence removed from active metadata but retained in history. */
92
+ previous_terminal: PreviousTerminalEvidence;
93
+ }
94
+ /** Update result carrying the recurrence receipt produced by the locked transition. */
95
+ export interface ReopenUpdateResult extends UpdateResult {
96
+ /** Lifecycle-specific receipt populated by the recurrence primitive. */
97
+ lifecycle_transition: ReopenUpdateReceipt;
98
+ }
70
99
  declare function normalizeLegacyNoneUpdateOptions(options: UpdateCommandOptions): UpdateCommandOptions;
71
100
  declare function parseUpdateUnsetTargets(raw: string[] | undefined, runtimeFieldRegistry?: RuntimeFieldRegistry, extensionFieldNames?: readonly string[]): {
72
101
  metadataKeys: Set<string>;
@@ -139,6 +168,8 @@ type UpdateStatusMutationContext = Pick<UpdateMutationContext, "options" | "stat
139
168
  declare function applyStatusAndCloseReasonMutations(document: ItemDocument, context: UpdateStatusMutationContext, previousStatusNormalized: string, changedFields: string[]): void;
140
169
  /** Implements run update for the public runtime surface of this module. */
141
170
  export declare function runUpdate(id: string, options: UpdateCommandOptions, global: GlobalOptions): Promise<UpdateResult>;
171
+ /** Execute a recurrence transition through the exact atomic update pipeline. */
172
+ export declare function runReopenUpdate(id: string, options: UpdateCommandOptions, global: GlobalOptions, recurrenceReason: string): Promise<ReopenUpdateResult>;
142
173
  /** Public contract for test only update command, shared by SDK and presentation-layer consumers. */
143
174
  export declare const _testOnlyUpdateCommand: {
144
175
  applyStatusAndCloseReasonMutations: typeof applyStatusAndCloseReasonMutations;
@@ -4,8 +4,9 @@
4
4
  * Implements the pm update 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]="a421c150-13a9-5334-85a4-5b3199a5d2c7")}catch(e){}}();
8
- import { pathExists, COMMON_MUTATION_COMMAND_OPTION_KEYS, canonicalizeCommandOptionKey, commandOptionFlagLabel, resolveItemTypeRegistry, resolveCommandOptionPolicyState, resolveTypeDefinition, resolveTypeName, validateTypeOptions, normalizeItemId, toItemRecord, buildInvalidTypeError, assertParentReferenceIsNotSelf, normalizeParentReferenceValue, validateMissingParentReference, validateSprintOrReleaseValue, applyAcceptanceCriteriaMutations, applyTagRemovals, assertNoUnknownCsvKeys, createStdinTokenResolver, looksLikeGenericKeyValueEntry, mergeAdditiveTags, parseCsvKv, parseOptionalNonNegativeInteger, parseOptionalNumber, parseTags, splitAcceptanceCriteria, resolvePriority, normalizeStatusInput, isTerminalStatus, collectRuntimeUpdateFieldValues, resolveItemTypesFilePath, resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, describeAllowedTransitions, evaluateTransition, resolveTypeWorkflows, EXIT_CODE, PmCliError, stableValueEquals, resolveIsoOrRelative, getActiveExtensionRegistrations, collectRegisteredItemFieldNames, applyRegisteredItemFieldDefaultsAndValidation, parseRegisteredItemFieldAssignments, buildItemNotFoundError, listAllItemMetadataLight, locateItem, mutateItem, readLocatedItem, getSettingsPath, resolvePmRoot, readSettings, resolveAuthor, } from "../runtime-primitives.js";
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]="3ab4f16d-ce37-546e-a2f6-0495fd1967c7")}catch(e){}}();
8
+ import { pathExists, COMMON_MUTATION_COMMAND_OPTION_KEYS, canonicalizeCommandOptionKey, commandOptionFlagLabel, resolveItemTypeRegistry, resolveCommandOptionPolicyState, resolveTypeDefinition, resolveTypeName, validateTypeOptions, normalizeItemId, toItemRecord, buildInvalidTypeError, assertParentReferenceIsNotSelf, normalizeParentReferenceValue, validateMissingParentReference, validateSprintOrReleaseValue, applyAcceptanceCriteriaMutations, applyTagRemovals, assertNoUnknownCsvKeys, createStdinTokenResolver, looksLikeGenericKeyValueEntry, mergeAdditiveTags, parseCsvKv, parseOptionalNonNegativeInteger, parseOptionalNumber, parseTags, splitAcceptanceCriteria, resolvePriority, normalizeStatusInput, isTerminalStatus, collectRuntimeUpdateFieldValues, resolveItemTypesFilePath, resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, describeAllowedTransitions, evaluateTransition, resolveTypeWorkflows, EXIT_CODE, PmCliError, stableValueEquals, resolveIsoOrRelative, getActiveExtensionRegistrations, collectRegisteredItemFieldNames, applyRegisteredItemFieldDefaultsAndValidation, parseRegisteredItemFieldAssignments, buildItemNotFoundError, listAllItemMetadataLight, locateItem, readLocatedItem, getSettingsPath, resolvePmRoot, readSettings, resolveAuthor, } from "../runtime-primitives.js";
9
+ import { mutateItemWithHistoryContextResolver } from "../../core/store/item-store.js";
9
10
  import { runClose } from "./close.js";
10
11
  import { normalizeRiskInput, normalizeSeverityInput, parseConfidenceInput, parseRegressionInput, } from "./metadata-normalizers.js";
11
12
  import { applyLegacyNoneCollectionNormalizers, createLegacyNoneCollectionNormalizers, assertNoLegacyNoneToken, assertNoLegacyNoneTokens, isLegacyNoneToken, } from "./legacy-none-tokens.js";
@@ -1214,8 +1215,8 @@ function applyStatusMutation(document, context, statusInput, previousStatusNorma
1214
1215
  changedFields.push("closed_at", "completed_at");
1215
1216
  return;
1216
1217
  }
1217
- if (status !== context.statusRegistry.close_status &&
1218
- previousStatusNormalized === context.statusRegistry.close_status &&
1218
+ if (!isTerminalStatus(status, context.statusRegistry) &&
1219
+ isTerminalStatus(previousStatusNormalized, context.statusRegistry) &&
1219
1220
  document.metadata.closed_at !== undefined) {
1220
1221
  delete document.metadata.closed_at;
1221
1222
  changedFields.push("closed_at");
@@ -1254,8 +1255,8 @@ function applyCloseReasonMutations(document, context, previousStatusNormalized,
1254
1255
  return;
1255
1256
  }
1256
1257
  if (context.options.status !== undefined &&
1257
- previousStatusNormalized === context.statusRegistry.close_status &&
1258
- document.metadata.status !== context.statusRegistry.canceled_status &&
1258
+ isTerminalStatus(previousStatusNormalized, context.statusRegistry) &&
1259
+ !isTerminalStatus(document.metadata.status, context.statusRegistry) &&
1259
1260
  document.metadata.close_reason !== undefined) {
1260
1261
  delete document.metadata.close_reason;
1261
1262
  changedFields.push("close_reason");
@@ -1700,7 +1701,7 @@ function mutateUpdateDocument(document, context) {
1700
1701
  return { changedFields: actualChangedFields, warnings };
1701
1702
  }
1702
1703
  /** Implements run update for the public runtime surface of this module. */
1703
- export async function runUpdate(id, options, global) {
1704
+ async function runUpdateWithContext(id, options, global, execution = {}) {
1704
1705
  options = await resolveStdinUpdateOptions(options);
1705
1706
  const pmRoot = resolvePmRoot(process.cwd(), global.path);
1706
1707
  await assertUpdateTrackerInitialized(pmRoot);
@@ -1820,23 +1821,32 @@ export async function runUpdate(id, options, global) {
1820
1821
  let graphBeforeUpdate = fieldFlags.dep || fieldFlags.depRemove || fieldFlags.blockedBy
1821
1822
  ? await listAllItemMetadataLight(pmRoot, settings.item_format, typeRegistry.type_to_folder, undefined, settings.schema)
1822
1823
  : undefined;
1823
- const result = await mutateItem({
1824
+ let lifecycleTransition;
1825
+ let recurrenceHistoryContext;
1826
+ const result = await mutateItemWithHistoryContextResolver({
1824
1827
  pmRoot,
1825
1828
  settings,
1826
1829
  typeToFolder: typeRegistry.type_to_folder,
1827
1830
  id,
1828
- op: options.ownershipMetadataBypass === true ||
1829
- options.ownershipDependencyBypass === true
1830
- ? "update_ownership_bypass"
1831
- : "update",
1831
+ op: resolveUpdateHistoryOperation(options, execution),
1832
1832
  author,
1833
1833
  message: options.message,
1834
+ resolveHistoryContext: () => recurrenceHistoryContext,
1834
1835
  force: options.force,
1835
1836
  bypassAssigneeConflict: options.ownershipMetadataBypass === true ||
1836
1837
  options.ownershipDependencyBypass === true,
1837
1838
  extensionFieldNames,
1838
1839
  skipNoop: true,
1839
1840
  mutate(document) {
1841
+ lifecycleTransition = prepareRecurrenceTransition({
1842
+ document,
1843
+ recurrenceReason: execution.recurrenceReason,
1844
+ requestedStatus: options.status,
1845
+ statusRegistry,
1846
+ });
1847
+ recurrenceHistoryContext = lifecycleTransition
1848
+ ? { recurrence: lifecycleTransition }
1849
+ : undefined;
1840
1850
  graphBeforeUpdate = graphBeforeUpdate?.map((item) => item.id === document.metadata.id
1841
1851
  ? structuredClone(document.metadata)
1842
1852
  : item);
@@ -1880,8 +1890,80 @@ export async function runUpdate(id, options, global) {
1880
1890
  ...orderingCycleWarnings,
1881
1891
  ...result.warnings,
1882
1892
  ],
1893
+ ...(lifecycleTransition === undefined
1894
+ ? {}
1895
+ : { lifecycle_transition: lifecycleTransition }),
1883
1896
  };
1884
1897
  }
1898
+ /** Resolve the immutable operation name for ordinary, bypass, and recurrence updates. */
1899
+ function resolveUpdateHistoryOperation(options, execution) {
1900
+ if (options.ownershipMetadataBypass === true ||
1901
+ options.ownershipDependencyBypass === true) {
1902
+ return "update_ownership_bypass";
1903
+ }
1904
+ return execution.recurrenceReason === undefined ? "update" : "reopen";
1905
+ }
1906
+ /** Validate and capture a terminal-to-active recurrence while the item lock is held. */
1907
+ function prepareRecurrenceTransition(params) {
1908
+ if (params.recurrenceReason === undefined) {
1909
+ return undefined;
1910
+ }
1911
+ const fromStatus = normalizeStatusInput(params.document.metadata.status, params.statusRegistry) ?? params.document.metadata.status;
1912
+ if (!isTerminalStatus(fromStatus, params.statusRegistry)) {
1913
+ throw new PmCliError(`Item ${params.document.metadata.id} is already active with status ${fromStatus}; recurrence transitions require a terminal item.`, EXIT_CODE.CONFLICT, {
1914
+ code: "item_already_active",
1915
+ reason: "recurrence_requires_terminal_item",
1916
+ required: "Use item reopen only for a terminal item whose work has recurred.",
1917
+ why: "Appending a recurrence event to active work would corrupt lifecycle history.",
1918
+ recovery: {
1919
+ suggested_retry: `pm get ${params.document.metadata.id} --full`,
1920
+ suggested_retry_args: ["get", params.document.metadata.id, "--full"],
1921
+ },
1922
+ nextSteps: [
1923
+ `Inspect the active item with: pm get ${params.document.metadata.id} --full`,
1924
+ `Continue the existing work with: pm update ${params.document.metadata.id} ...`,
1925
+ ],
1926
+ });
1927
+ }
1928
+ const requestedStatus = params.requestedStatus ?? params.statusRegistry.open_status;
1929
+ const toStatus = normalizeStatusInput(requestedStatus, params.statusRegistry) ??
1930
+ requestedStatus;
1931
+ const metadata = toItemRecord(params.document.metadata);
1932
+ const previousTerminal = Object.fromEntries([
1933
+ "close_reason",
1934
+ "resolution",
1935
+ "expected_result",
1936
+ "actual_result",
1937
+ "fixed_version",
1938
+ ].flatMap((key) => {
1939
+ const value = metadata[key];
1940
+ return typeof value === "string" ? [[key, value]] : [];
1941
+ }));
1942
+ return {
1943
+ reason: params.recurrenceReason,
1944
+ from_status: fromStatus,
1945
+ to_status: toStatus,
1946
+ previous_terminal: previousTerminal,
1947
+ };
1948
+ }
1949
+ /** Implements run update for the public runtime surface of this module. */
1950
+ export async function runUpdate(id, options, global) {
1951
+ return runUpdateWithContext(id, options, global);
1952
+ }
1953
+ /** Execute a recurrence transition through the exact atomic update pipeline. */
1954
+ export async function runReopenUpdate(id, options, global, recurrenceReason) {
1955
+ const result = await runUpdateWithContext(id, options, global, {
1956
+ recurrenceReason,
1957
+ });
1958
+ if (result.lifecycle_transition === undefined) {
1959
+ throw new PmCliError(`Item ${id} did not produce the required recurrence receipt.`, EXIT_CODE.GENERIC_FAILURE, {
1960
+ code: "reopen_receipt_missing",
1961
+ reason: "recurrence_transition_not_recorded",
1962
+ required: "A successful reopen must return the terminal-to-active lifecycle transition recorded in immutable history.",
1963
+ });
1964
+ }
1965
+ return { ...result, lifecycle_transition: result.lifecycle_transition };
1966
+ }
1885
1967
  /* c8 ignore stop */
1886
1968
  /** Public contract for test only update command, shared by SDK and presentation-layer consumers. */
1887
1969
  export const _testOnlyUpdateCommand = {
@@ -1900,4 +1982,4 @@ export const _testOnlyUpdateCommand = {
1900
1982
  resolveRuntimeUnsetDefinition: (token, registry) => resolveRuntimeUnsetFieldDefinition(token, "update", registry),
1901
1983
  };
1902
1984
  //# sourceMappingURL=update.js.map
1903
- //# debugId=a421c150-13a9-5334-85a4-5b3199a5d2c7
1985
+ //# debugId=3ab4f16d-ce37-546e-a2f6-0495fd1967c7
@@ -33,6 +33,8 @@ export interface ReadRowContract {
33
33
  row_kind: "collection" | "none";
34
34
  /** Dot-delimited paths to array or object-map collections containing iterable result rows. */
35
35
  row_keys: string[];
36
+ /** Optional nested collections that are independently resumable without redefining primary result rows. */
37
+ continuation_row_keys?: string[];
36
38
  /** Whether the command accepts an explicit row-field projection. */
37
39
  fields: "supported" | "unsupported";
38
40
  /** Universal jq expression that iterates every declared collection path. */
@@ -4,7 +4,7 @@
4
4
  * Declares machine-readable field-group omissions for bounded command results.
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]="d059aa19-3822-5ff4-b4be-e2be8f537d1e")}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]="8ffd2cd5-8b7e-5ae1-a0c6-aab488edb73c")}catch(e){}}();
8
8
  import { EXIT_CODE } from "../core/shared/constants.js";
9
9
  import { PmCliError } from "../core/shared/errors.js";
10
10
  const MATERIAL_FIELD_GROUPS_BY_RESULT = new WeakMap();
@@ -161,15 +161,21 @@ const READ_ROW_TOON_ENCODINGS = new Set([
161
161
  ]);
162
162
  const READ_ROW_KINDS = new Set(["collection", "none"]);
163
163
  const READ_ROW_FIELD_MODES = new Set(["supported", "unsupported"]);
164
+ function isUniqueNonEmptyStringArray(value, allowEmpty) {
165
+ return (Array.isArray(value) &&
166
+ (allowEmpty || value.length > 0) &&
167
+ value.every((entry) => typeof entry === "string" && entry.length > 0) &&
168
+ new Set(value).size === value.length);
169
+ }
164
170
  /** Return whether an unknown value is a structurally valid row declaration. */
165
171
  export function isReadRowContract(value) {
166
172
  return (isRecord(value) &&
167
173
  typeof value.command === "string" &&
168
174
  value.command.trim().length > 0 &&
169
175
  READ_ROW_KINDS.has(value.row_kind) &&
170
- Array.isArray(value.row_keys) &&
171
- value.row_keys.every((key) => typeof key === "string" && key.length > 0) &&
172
- new Set(value.row_keys).size === value.row_keys.length &&
176
+ isUniqueNonEmptyStringArray(value.row_keys, true) &&
177
+ (value.continuation_row_keys === undefined ||
178
+ isUniqueNonEmptyStringArray(value.continuation_row_keys, false)) &&
173
179
  READ_ROW_FIELD_MODES.has(value.fields) &&
174
180
  READ_ROW_TOON_ENCODINGS.has(value.toon_encoding) &&
175
181
  (value.row_kind === "collection"
@@ -414,4 +420,4 @@ export function attachOutputOmissionReceipt(command, result) {
414
420
  : { ...disclosedResult, omission_receipt: receipt };
415
421
  }
416
422
  //# sourceMappingURL=output-projection.js.map
417
- //# debugId=d059aa19-3822-5ff4-b4be-e2be8f537d1e
423
+ //# debugId=8ffd2cd5-8b7e-5ae1-a0c6-aab488edb73c
@@ -7,6 +7,7 @@ import { type GlobalOptions } from "../runtime-primitives.js";
7
7
  import { type ChildRollupContext } from "../item-children.js";
8
8
  import { type ItemScheduleContext } from "../item-schedule.js";
9
9
  import type { ItemMetadata, LinkedDoc, LinkedFile, LinkedTest } from "../../types/index.js";
10
+ export { GET_DEPTH_VALUES, listGetProjectionFields, } from "./projection-contracts.js";
10
11
  interface ClaimHistoryContext {
11
12
  ts: string;
12
13
  author: string;
@@ -92,4 +93,3 @@ export declare function runGet(id: string, global: GlobalOptions, options?: GetO
92
93
  export declare const _testOnlyGetCommand: {
93
94
  shouldAutoIncludeGetChildren: typeof shouldAutoIncludeGetChildren;
94
95
  };
95
- export {};