@unbrained/pm-cli 2026.8.21 → 2026.8.23

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 (228) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +44 -0
  3. package/dist/cli/error-guidance.d.ts +22 -4
  4. package/dist/cli/error-guidance.js +73 -16
  5. package/dist/cli/main.d.ts +3 -0
  6. package/dist/cli/main.js +51 -9
  7. package/dist/cli/register-mutation.js +6 -6
  8. package/dist/cli/register-operations.d.ts +73 -0
  9. package/dist/cli/register-operations.js +39 -14
  10. package/dist/cli/register-setup.js +3 -3
  11. package/dist/cli/schema-registration-helpers.d.ts +8 -1
  12. package/dist/cli/schema-registration-helpers.js +14 -5
  13. package/dist/cli-bundle/bundle-manifest.json +149 -149
  14. package/dist/cli-bundle/chunks/chunk-3ENVHX6C.js +36 -0
  15. package/dist/cli-bundle/chunks/{chunk-LOVTQ52Z.js → chunk-DW2CGEMU.js} +2 -2
  16. package/dist/cli-bundle/chunks/chunk-EG6CLDZT.js +5 -0
  17. package/dist/cli-bundle/chunks/{chunk-LARJJ3RK.js → chunk-F3AI2JFL.js} +2 -2
  18. package/dist/cli-bundle/chunks/{chunk-N3DSV4CH.js → chunk-HWZ6CELB.js} +8 -8
  19. package/dist/cli-bundle/chunks/chunk-HZBMLSZI.js +201 -0
  20. package/dist/cli-bundle/chunks/chunk-JB4KZWBF.js +3 -0
  21. package/dist/cli-bundle/chunks/chunk-KPH73XXJ.js +2 -0
  22. package/dist/cli-bundle/chunks/{chunk-BKYB45NQ.js → chunk-KXPMB2YL.js} +50 -50
  23. package/dist/cli-bundle/chunks/{chunk-BUNIEJNE.js → chunk-QDVHNHAQ.js} +2 -2
  24. package/dist/cli-bundle/chunks/chunk-TFI5V5N2.js +13 -0
  25. package/dist/cli-bundle/chunks/{register-list-query-F57EWDEF.js → register-list-query-UJB5FMV2.js} +2 -2
  26. package/dist/cli-bundle/chunks/register-mutation-NX5XE4VX.js +20 -0
  27. package/dist/cli-bundle/chunks/register-operations-RXIJIYXC.js +2 -0
  28. package/dist/cli-bundle/chunks/{register-setup-HXU7IZZD.js → register-setup-GFUZEKRE.js} +2 -2
  29. package/dist/cli-bundle/focused-chunks/{chunk-F4YEW5I2.js → chunk-37Z4OEAP.js} +2 -2
  30. package/dist/cli-bundle/focused-chunks/chunk-3UPTYG44.js +8 -0
  31. package/dist/cli-bundle/focused-chunks/chunk-5S7E72FY.js +16 -0
  32. package/dist/cli-bundle/focused-chunks/{chunk-4ERLO7QD.js → chunk-AUFH5H35.js} +2 -2
  33. package/dist/cli-bundle/focused-chunks/chunk-E7X25GC3.js +2 -0
  34. package/dist/cli-bundle/focused-chunks/chunk-FQCSTBWE.js +4 -0
  35. package/dist/cli-bundle/focused-chunks/{chunk-FH6DYED3.js → chunk-FZS4H32O.js} +2 -2
  36. package/dist/cli-bundle/focused-chunks/chunk-IFLWKY2R.js +156 -0
  37. package/dist/cli-bundle/focused-chunks/{chunk-YKBKIEAJ.js → chunk-JOWDB2MH.js} +2 -2
  38. package/dist/cli-bundle/focused-chunks/chunk-LYVSW5VM.js +2 -0
  39. package/dist/cli-bundle/focused-chunks/chunk-MRCNF3U6.js +2 -0
  40. package/dist/cli-bundle/focused-chunks/{chunk-UZE7XUZK.js → chunk-OFVUGTLJ.js} +2 -2
  41. package/dist/cli-bundle/focused-chunks/{chunk-FJ22HNRP.js → chunk-OGLQBL46.js} +2 -2
  42. package/dist/cli-bundle/focused-chunks/chunk-OY7QAV4Y.js +51 -0
  43. package/dist/cli-bundle/focused-chunks/chunk-QGFNI65N.js +26 -0
  44. package/dist/cli-bundle/focused-chunks/{chunk-KDNG7TKQ.js → chunk-R27IDGHD.js} +2 -2
  45. package/dist/cli-bundle/focused-chunks/chunk-UYRFYCDQ.js +5 -0
  46. package/dist/cli-bundle/focused-chunks/{chunk-2NIY5NKG.js → chunk-ZHVA42R5.js} +9 -9
  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 -2
  50. package/dist/cli-bundle/sdk-core.js +40 -40
  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 +33 -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 -5
  58. package/dist/core/config/nested-settings.js +8 -2
  59. package/dist/core/config/positional-value.d.ts +1 -1
  60. package/dist/core/config/positional-value.js +5 -2
  61. package/dist/core/extensions/extension-hook-runtime.js +22 -20
  62. package/dist/core/extensions/extension-types.d.ts +8 -1
  63. package/dist/core/extensions/extension-types.js +2 -2
  64. package/dist/core/extensions/loader.js +7 -3
  65. package/dist/core/extensions/service-ownership.d.ts +8 -0
  66. package/dist/core/extensions/service-ownership.js +20 -0
  67. package/dist/core/history/history.js +3 -3
  68. package/dist/core/item/id.js +20 -5
  69. package/dist/core/item/item-format.js +81 -2
  70. package/dist/core/reproducibility/context.d.ts +4 -0
  71. package/dist/core/reproducibility/context.js +14 -8
  72. package/dist/core/shared/author.d.ts +55 -1
  73. package/dist/core/shared/author.js +333 -16
  74. package/dist/core/shared/constants.js +3 -2
  75. package/dist/core/shared/errors.d.ts +4 -0
  76. package/dist/core/shared/errors.js +2 -2
  77. package/dist/core/store/settings-validator.d.ts +1 -0
  78. package/dist/core/store/settings-validator.js +6 -3
  79. package/dist/core/store/settings.js +5 -2
  80. package/dist/mcp/server.d.ts +1 -1
  81. package/dist/mcp/server.js +30 -9
  82. package/dist/sdk/agent/identity-config.d.ts +63 -0
  83. package/dist/sdk/agent/identity-config.js +107 -0
  84. package/dist/sdk/agent/refusal-corpus-contracts.d.ts +76 -0
  85. package/dist/sdk/agent/refusal-corpus-contracts.js +194 -0
  86. package/dist/sdk/agent/refusal-reachability.d.ts +1 -1
  87. package/dist/sdk/authoring.d.ts +1 -1
  88. package/dist/sdk/authoring.js +2 -2
  89. package/dist/sdk/cli-contracts/agent-output-contracts.d.ts +77 -0
  90. package/dist/sdk/cli-contracts/agent-output-contracts.js +326 -2
  91. package/dist/sdk/cli-contracts/commander-mutation-options.js +3 -3
  92. package/dist/sdk/cli-contracts/enum-contracts.d.ts +4 -0
  93. package/dist/sdk/cli-contracts/enum-contracts.js +9 -2
  94. package/dist/sdk/cli-contracts/flag-contracts.js +9 -2
  95. package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +4 -4
  96. package/dist/sdk/cli-contracts/registration-helpers.js +5 -2
  97. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +3 -1
  98. package/dist/sdk/cli-contracts/runtime-contracts.js +4 -3
  99. package/dist/sdk/cli-contracts/tool-parameter-tables.js +22 -2
  100. package/dist/sdk/cli-contracts/tool-schema.d.ts +1 -1
  101. package/dist/sdk/cli-contracts/tool-schema.js +14 -3
  102. package/dist/sdk/cli-contracts.d.ts +4 -4
  103. package/dist/sdk/cli-contracts.js +5 -5
  104. package/dist/sdk/config.d.ts +6 -1
  105. package/dist/sdk/config.js +119 -14
  106. package/dist/sdk/context-intent-contracts.js +4 -2
  107. package/dist/sdk/core-governance.d.ts +1 -1
  108. package/dist/sdk/core-governance.js +3 -3
  109. package/dist/sdk/extension/install-sources.d.ts +1 -1
  110. package/dist/sdk/extension/install-sources.js +6 -3
  111. package/dist/sdk/extension/output-ownership.d.ts +1 -0
  112. package/dist/sdk/extension/output-ownership.js +3 -2
  113. package/dist/sdk/extension/scaffold.js +11 -5
  114. package/dist/sdk/flag-invocation-contracts.js +4 -2
  115. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +74 -2
  116. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +87 -26
  117. package/dist/sdk/governance/assurance-action.js +30 -10
  118. package/dist/sdk/governance/health.d.ts +3 -0
  119. package/dist/sdk/governance/health.js +39 -7
  120. package/dist/sdk/governance/hierarchy-validation.d.ts +29 -0
  121. package/dist/sdk/governance/hierarchy-validation.js +109 -0
  122. package/dist/sdk/governance/validate.d.ts +3 -9
  123. package/dist/sdk/governance/validate.js +84 -111
  124. package/dist/sdk/graph/assembly.d.ts +6 -1
  125. package/dist/sdk/graph/assembly.js +16 -22
  126. package/dist/sdk/graph/governance-contracts.d.ts +1 -1
  127. package/dist/sdk/graph/governance-contracts.js +8 -2
  128. package/dist/sdk/graph/governance.js +46 -2
  129. package/dist/sdk/graph/hierarchy-integrity.d.ts +94 -0
  130. package/dist/sdk/graph/hierarchy-integrity.js +311 -0
  131. package/dist/sdk/graph/index.d.ts +2 -1
  132. package/dist/sdk/graph/index.js +3 -2
  133. package/dist/sdk/graph/remediation.js +32 -2
  134. package/dist/sdk/graph/run.d.ts +31 -2
  135. package/dist/sdk/graph/run.js +80 -31
  136. package/dist/sdk/graph/workspace-relationship-kind-registry.d.ts +8 -0
  137. package/dist/sdk/graph/workspace-relationship-kind-registry.js +28 -0
  138. package/dist/sdk/index.d.ts +8 -3
  139. package/dist/sdk/index.js +9 -4
  140. package/dist/sdk/item-children.js +21 -8
  141. package/dist/sdk/lifecycle/create.js +129 -97
  142. package/dist/sdk/lifecycle/hierarchy-mutation-lock.d.ts +15 -0
  143. package/dist/sdk/lifecycle/hierarchy-mutation-lock.js +25 -0
  144. package/dist/sdk/lifecycle/update.d.ts +2 -0
  145. package/dist/sdk/lifecycle/update.js +174 -84
  146. package/dist/sdk/merge/three-way.js +105 -26
  147. package/dist/sdk/query/complete-list.d.ts +3 -3
  148. package/dist/sdk/query/complete-list.js +46 -3
  149. package/dist/sdk/query/list.d.ts +4 -3
  150. package/dist/sdk/query/list.js +89 -49
  151. package/dist/sdk/read-output-budget.d.ts +21 -0
  152. package/dist/sdk/read-output-budget.js +39 -2
  153. package/dist/sdk/read-output-contracts.d.ts +10 -4
  154. package/dist/sdk/read-output-contracts.js +105 -32
  155. package/dist/sdk/relationship-context.js +3 -4
  156. package/dist/sdk/relationships.js +17 -10
  157. package/dist/sdk/reproducibility/process.d.ts +19 -0
  158. package/dist/sdk/reproducibility/process.js +88 -0
  159. package/dist/sdk/runtime-primitives.d.ts +1 -1
  160. package/dist/sdk/runtime-primitives.js +3 -3
  161. package/dist/sdk/runtime.d.ts +3 -2
  162. package/dist/sdk/runtime.js +7 -5
  163. package/dist/sdk/test/batch.d.ts +6 -0
  164. package/dist/sdk/test/batch.js +26 -6
  165. package/dist/sdk/test/entry.d.ts +1 -1
  166. package/dist/sdk/test/entry.js +3 -2
  167. package/dist/sdk/test/execution.d.ts +28 -3
  168. package/dist/sdk/test/execution.js +201 -34
  169. package/dist/sdk/test/parsers.d.ts +6 -0
  170. package/dist/sdk/test/parsers.js +21 -2
  171. package/dist/sdk/test/trust.d.ts +33 -0
  172. package/dist/sdk/test/trust.js +207 -0
  173. package/dist/types.d.ts +34 -0
  174. package/dist/types.js +2 -2
  175. package/docs/AGENT_PROVENANCE_ADR.md +41 -5
  176. package/docs/AGENT_UX_CONTRACTS.md +20 -4
  177. package/docs/COMMANDS.md +29 -14
  178. package/docs/CONFIGURATION.md +4 -0
  179. package/docs/DEPENDENCY_KIND_CONTRACT.md +31 -3
  180. package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +115 -0
  181. package/docs/EXTENSIONS.md +2 -1
  182. package/docs/MERGE_SAFETY.md +15 -1
  183. package/docs/README.md +1 -0
  184. package/docs/READ_OUTPUT_CONTRACTS.md +19 -2
  185. package/docs/RELATIONSHIP_GRAPH.md +6 -3
  186. package/docs/REPRODUCIBLE_WORKSPACES.md +42 -8
  187. package/docs/SDK.md +9 -0
  188. package/docs/SDK_AGENT_SESSION_CONTEXT.md +6 -4
  189. package/docs/SDK_EVIDENCE_TRACEABILITY.md +1 -1
  190. package/docs/TESTING.md +83 -1
  191. package/docs/agent-task-token-baseline.json +2 -2
  192. package/docs/generated/FLAG_LEXICON_BUDGETS.md +2 -2
  193. package/marketplace.json +2 -2
  194. package/package.json +2 -2
  195. package/packages/pm-beads/package.json +1 -1
  196. package/packages/pm-calendar/package.json +1 -1
  197. package/packages/pm-command-kit/package.json +1 -1
  198. package/packages/pm-digital-twin/package.json +1 -1
  199. package/packages/pm-governance-audit/package.json +1 -1
  200. package/packages/pm-guide-shell/package.json +1 -1
  201. package/packages/pm-kanban/package.json +1 -1
  202. package/packages/pm-lifecycle-hooks/package.json +1 -1
  203. package/packages/pm-linked-test-adapters/package.json +1 -1
  204. package/packages/pm-search-advanced/package.json +1 -1
  205. package/packages/pm-templates/package.json +1 -1
  206. package/packages/pm-todos/package.json +1 -1
  207. package/packages/pm-vcs/package.json +1 -1
  208. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  209. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  210. package/sdk/public-surface.json +1021 -53
  211. package/dist/cli-bundle/chunks/chunk-2MA6ZQVZ.js +0 -197
  212. package/dist/cli-bundle/chunks/chunk-3AFAUHUE.js +0 -2
  213. package/dist/cli-bundle/chunks/chunk-7VHZS727.js +0 -5
  214. package/dist/cli-bundle/chunks/chunk-JSLOFXGA.js +0 -3
  215. package/dist/cli-bundle/chunks/chunk-OCLPLFAY.js +0 -35
  216. package/dist/cli-bundle/chunks/chunk-S4IRYKBU.js +0 -13
  217. package/dist/cli-bundle/chunks/register-mutation-7IY2D5KO.js +0 -20
  218. package/dist/cli-bundle/chunks/register-operations-FALL3YTU.js +0 -2
  219. package/dist/cli-bundle/focused-chunks/chunk-7WZRLCYF.js +0 -50
  220. package/dist/cli-bundle/focused-chunks/chunk-CKKQSJNN.js +0 -2
  221. package/dist/cli-bundle/focused-chunks/chunk-EEFKYMDR.js +0 -16
  222. package/dist/cli-bundle/focused-chunks/chunk-F2A56DHV.js +0 -8
  223. package/dist/cli-bundle/focused-chunks/chunk-FV5ACOK7.js +0 -2
  224. package/dist/cli-bundle/focused-chunks/chunk-JEAVFOWM.js +0 -2
  225. package/dist/cli-bundle/focused-chunks/chunk-NJ63LOP6.js +0 -155
  226. package/dist/cli-bundle/focused-chunks/chunk-NXRTQ7HI.js +0 -2
  227. package/dist/cli-bundle/focused-chunks/chunk-TJ7EMJ46.js +0 -4
  228. package/dist/cli-bundle/focused-chunks/chunk-ZOSEELYJ.js +0 -26
@@ -5,6 +5,7 @@ import { type RuntimeStatusRegistry } from "../../core/schema/runtime-schema.js"
5
5
  import type { GlobalOptions } from "../../core/shared/command-types.js";
6
6
  import type { ItemMetadata, ItemStatus } from "../../types/index.js";
7
7
  import type { SharedItemFilterOptions } from "./item-filter-options.js";
8
+ import { type HierarchyRelationIndexes } from "../graph/hierarchy-integrity.js";
8
9
  import { type ListCommandName, type ListProjectionMode } from "./projection-contracts.js";
9
10
  export { BRIEF_LIST_FIELDS, DEFAULT_COMPACT_LIST_FIELDS, LIST_COMMAND_DEFAULT_PROJECTIONS, listListProjectionFields, type ListCommandName, type ListProjectionMode, } from "./projection-contracts.js";
10
11
  /** Documents the list options payload exchanged by command, SDK, and package integrations. */
@@ -236,10 +237,10 @@ declare function normalizeProjectionField(field: string): string;
236
237
  declare function parseSortField(raw: string | undefined): ListSortField | undefined;
237
238
  declare function parseSortOrder(raw: string | undefined): ListSortOrder | undefined;
238
239
  declare function parseAssigneeFilter(raw: string | undefined): "assigned" | "unassigned" | undefined;
239
- declare function applyFilters(items: ListedItem[], status: ItemStatus[] | undefined, options: ListOptions, typeRegistry: ItemTypeRegistry, statusRegistry: RuntimeStatusRegistry, runtimeFieldFilters: Record<string, unknown>): ListedItem[];
240
+ declare function applyFilters(items: ListedItem[], status: ItemStatus[] | undefined, options: ListOptions, typeRegistry: ItemTypeRegistry, statusRegistry: RuntimeStatusRegistry, runtimeFieldFilters: Record<string, unknown>, parentsByChild?: HierarchyRelationIndexes["parents_by_child"]): ListedItem[];
240
241
  declare function trimNonEmpty(value: string | undefined): string | undefined;
241
- declare function withTreeMetadata(item: ListedItem, depth: number, childCount: number): ListTreeItem;
242
- declare function orderItemsAsTree(sortedItems: ListedItem[], parentRoot: string | undefined, maxDepth: number | undefined): ListedItem[];
242
+ declare function withTreeMetadata(item: ListedItem, depth: number, childCount: number, parentId?: string): ListTreeItem;
243
+ declare function orderItemsAsTree(sortedItems: ListedItem[], parentRoot: string | undefined, maxDepth: number | undefined, hierarchyIndexes?: HierarchyRelationIndexes, completeItems?: readonly ListedItem[]): ListedItem[];
243
244
  declare function compareNullableString(left: string | null, right: string | null): number;
244
245
  declare function compareNullableTimestamp(left: string | null, right: string | null): number;
245
246
  declare function compareBySortField(left: ListedItem, right: ListedItem, field: ListSortField): number;
@@ -4,7 +4,7 @@
4
4
  * Implements the pm list 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]="361f891a-5f10-529c-8161-dc5193c7e12a")}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]="93e8c187-e198-50fc-bf2c-7dae2ea42219")}catch(e){}}();
8
8
  import { assertInitializedTracker } from "../environment/tracker-preflight.js";
9
9
  import { getActiveExtensionRegistrations, hasActiveOnReadHooks, } from "../../core/extensions/index.js";
10
10
  import { toItemRecord } from "../../core/item/item-record.js";
@@ -27,6 +27,8 @@ import { queryItemMetadataIndex } from "../../core/store/item-metadata-query-ind
27
27
  import { resolvePmRoot } from "../../core/store/paths.js";
28
28
  import { readSettings } from "../../core/store/settings.js";
29
29
  import { LIST_FILTER_FLAG_CONTRACTS } from "../cli-contracts/flag-contracts.js";
30
+ import { resolveWorkspaceRelationshipKindRegistry } from "../graph/assembly.js";
31
+ import { collectHierarchyRelations, indexHierarchyRelations, } from "../graph/hierarchy-integrity.js";
30
32
  import { createQueryFingerprint, encodeQueryCursor, resolveQueryCursorStart, selectCursorSemanticOptions, } from "../pagination.js";
31
33
  import { BRIEF_LIST_FIELDS, DEFAULT_COMPACT_LIST_FIELDS, listListProjectionFields, } from "./projection-contracts.js";
32
34
  export { BRIEF_LIST_FIELDS, DEFAULT_COMPACT_LIST_FIELDS, LIST_COMMAND_DEFAULT_PROJECTIONS, listListProjectionFields, } from "./projection-contracts.js";
@@ -640,7 +642,9 @@ function resolveListFilterSet(status, options, typeRegistry, statusRegistry) {
640
642
  parentFilter: options.parent?.trim(),
641
643
  treeEnabled: options.tree === true,
642
644
  sprintFilter: parseStringFilterSet(options.sprint, { label: "--sprint" }),
643
- releaseFilter: parseStringFilterSet(options.release, { label: "--release" }),
645
+ releaseFilter: parseStringFilterSet(options.release, {
646
+ label: "--release",
647
+ }),
644
648
  missingMetadataFilters,
645
649
  missingMetadataActive: hasMissingMetadataFilter(missingMetadataFilters),
646
650
  lifecycleClassifier: lifecycleClassifierFromStatusRegistry(statusRegistry),
@@ -648,12 +652,6 @@ function resolveListFilterSet(status, options, typeRegistry, statusRegistry) {
648
652
  contentFiltersActive: hasContentFieldFilter(contentFieldFilters),
649
653
  };
650
654
  }
651
- function matchesListScalarFilters(item, filters, statusRegistry) {
652
- return (matchesListIdentityFilters(item, filters, statusRegistry) &&
653
- matchesListDateFilters(item, filters) &&
654
- matchesListAssigneeFilterSet(item, filters) &&
655
- matchesListScopeFilters(item, filters));
656
- }
657
655
  function matchesListIdentityFilters(item, filters, statusRegistry) {
658
656
  if (filters.idsFilter && !filters.idsFilter.has(item.id))
659
657
  return false;
@@ -681,10 +679,17 @@ function matchesListAssigneeFilterSet(item, filters) {
681
679
  return (filters.assigneeFilter === undefined ||
682
680
  (item.assignee !== undefined && filters.assigneeFilter.has(item.assignee)));
683
681
  }
684
- function matchesListScopeFilters(item, filters) {
682
+ function matchesListScopeFilters(item, filters, parentsByChild) {
683
+ const scalarParent = item.parent?.trim().toLowerCase();
684
+ const logicalParentIds = [
685
+ ...new Set([
686
+ ...(parentsByChild?.get(item.id.trim().toLowerCase()) ?? []),
687
+ ...(scalarParent ? [scalarParent] : []),
688
+ ]),
689
+ ];
685
690
  if (filters.parentFilter !== undefined &&
686
691
  !filters.treeEnabled &&
687
- item.parent !== filters.parentFilter)
692
+ !logicalParentIds.includes(filters.parentFilter.trim().toLowerCase()))
688
693
  return false;
689
694
  if (filters.sprintFilter !== undefined &&
690
695
  (item.sprint === undefined || !filters.sprintFilter.has(item.sprint)))
@@ -692,8 +697,11 @@ function matchesListScopeFilters(item, filters) {
692
697
  return (filters.releaseFilter === undefined ||
693
698
  (item.release !== undefined && filters.releaseFilter.has(item.release)));
694
699
  }
695
- function matchesListFilterSet(item, filters, statusRegistry, runtimeFieldFilters) {
696
- if (!matchesListScalarFilters(item, filters, statusRegistry)) {
700
+ function matchesListFilterSet(item, filters, statusRegistry, runtimeFieldFilters, parentsByChild) {
701
+ if (!matchesListIdentityFilters(item, filters, statusRegistry) ||
702
+ !matchesListDateFilters(item, filters) ||
703
+ !matchesListAssigneeFilterSet(item, filters) ||
704
+ !matchesListScopeFilters(item, filters, parentsByChild)) {
697
705
  return false;
698
706
  }
699
707
  if (filters.missingMetadataActive &&
@@ -709,9 +717,9 @@ function matchesListFilterSet(item, filters, statusRegistry, runtimeFieldFilters
709
717
  }
710
718
  return true;
711
719
  }
712
- function applyFilters(items, status, options, typeRegistry, statusRegistry, runtimeFieldFilters) {
720
+ function applyFilters(items, status, options, typeRegistry, statusRegistry, runtimeFieldFilters, parentsByChild) {
713
721
  const filters = resolveListFilterSet(status, options, typeRegistry, statusRegistry);
714
- return items.filter((item) => matchesListFilterSet(item, filters, statusRegistry, runtimeFieldFilters));
722
+ return items.filter((item) => matchesListFilterSet(item, filters, statusRegistry, runtimeFieldFilters, parentsByChild));
715
723
  }
716
724
  function trimNonEmpty(value) {
717
725
  if (typeof value !== "string") {
@@ -720,10 +728,12 @@ function trimNonEmpty(value) {
720
728
  const trimmed = value.trim();
721
729
  return trimmed.length > 0 ? trimmed : undefined;
722
730
  }
723
- function withTreeMetadata(item, depth, childCount) {
731
+ function withTreeMetadata(item, depth, childCount, parentId) {
724
732
  const itemRecord = toItemRecord(item);
725
733
  const title = typeof itemRecord.title === "string" ? itemRecord.title : "";
726
- const parent = trimNonEmpty(typeof itemRecord.parent === "string" ? itemRecord.parent : undefined) ?? null;
734
+ const parent = parentId ??
735
+ trimNonEmpty(typeof itemRecord.parent === "string" ? itemRecord.parent : undefined) ??
736
+ null;
727
737
  return {
728
738
  ...item,
729
739
  tree_depth: depth,
@@ -732,47 +742,73 @@ function withTreeMetadata(item, depth, childCount) {
732
742
  tree_title: `${" ".repeat(depth)}${title}`,
733
743
  };
734
744
  }
735
- function orderItemsAsTree(sortedItems, parentRoot, maxDepth) {
745
+ function buildListTreeIndexes(sortedItems, hierarchyIndexes) {
736
746
  const byId = new Map();
737
747
  const childrenByParent = new Map();
738
748
  for (const item of sortedItems) {
739
- byId.set(item.id, item);
740
- const parentId = trimNonEmpty(item.parent);
741
- if (!parentId) {
742
- continue;
743
- }
744
- const bucket = childrenByParent.get(parentId);
745
- if (bucket) {
746
- bucket.push(item);
747
- }
748
- else {
749
- childrenByParent.set(parentId, [item]);
749
+ const itemId = item.id.trim().toLowerCase();
750
+ byId.set(itemId, item);
751
+ const parentIds = hierarchyIndexes
752
+ ? (hierarchyIndexes.parents_by_child.get(itemId) ?? [])
753
+ : [trimNonEmpty(item.parent)?.toLowerCase()].filter((value) => value !== undefined);
754
+ for (const parentId of parentIds) {
755
+ const children = childrenByParent.get(parentId) ?? [];
756
+ children.push(item);
757
+ childrenByParent.set(parentId, children);
750
758
  }
751
759
  }
752
- const roots = parentRoot
753
- ? [...(childrenByParent.get(parentRoot) ?? [])]
760
+ return { byId, childrenByParent };
761
+ }
762
+ function resolveListTreeRoots(sortedItems, parentRoot, byId, childrenByParent, hierarchyIndexes) {
763
+ return parentRoot
764
+ ? [...(childrenByParent.get(parentRoot.toLowerCase()) ?? [])]
754
765
  : sortedItems.filter((item) => {
755
- const parentId = trimNonEmpty(item.parent);
756
- return !parentId || !byId.has(parentId);
766
+ const parentIds = hierarchyIndexes
767
+ ? (hierarchyIndexes.parents_by_child.get(item.id.trim().toLowerCase()) ?? [])
768
+ : [trimNonEmpty(item.parent)?.toLowerCase()].filter((value) => value !== undefined);
769
+ return parentIds.every((parentId) => !byId.has(parentId));
757
770
  });
771
+ }
772
+ function orderItemsAsTree(sortedItems, parentRoot, maxDepth, hierarchyIndexes, completeItems = sortedItems) {
773
+ const { byId, childrenByParent } = buildListTreeIndexes(sortedItems, hierarchyIndexes);
774
+ const roots = resolveListTreeRoots(sortedItems, parentRoot, byId, childrenByParent, hierarchyIndexes);
758
775
  const ordered = [];
759
776
  const visited = new Set();
760
- const pushNode = (node, depth) => {
761
- if (visited.has(node.id)) {
762
- return;
763
- }
764
- visited.add(node.id);
765
- const children = childrenByParent.get(node.id) ?? [];
766
- ordered.push(withTreeMetadata(node, depth, children.length));
767
- if (maxDepth !== undefined && depth >= maxDepth) {
768
- return;
777
+ const canonicalIdByLowercase = new Map(completeItems.map((item) => [item.id.trim().toLowerCase(), item.id.trim()]));
778
+ const pending = [...roots].reverse().map((node) => ({
779
+ node,
780
+ depth: 0,
781
+ parentId: parentRoot === undefined
782
+ ? undefined
783
+ : (canonicalIdByLowercase.get(parentRoot.trim().toLowerCase()) ??
784
+ parentRoot.trim()),
785
+ }));
786
+ while (pending.length > 0) {
787
+ const { node, depth, parentId } = pending.pop();
788
+ const nodeId = node.id.trim().toLowerCase();
789
+ if (visited.has(nodeId))
790
+ continue;
791
+ visited.add(nodeId);
792
+ const children = childrenByParent.get(nodeId) ?? [];
793
+ ordered.push(withTreeMetadata(node, depth, children.length, parentId));
794
+ if (maxDepth !== undefined && depth >= maxDepth)
795
+ continue;
796
+ for (const child of [...children].reverse()) {
797
+ pending.push({
798
+ node: child,
799
+ depth: depth + 1,
800
+ parentId: canonicalIdByLowercase.get(nodeId),
801
+ });
769
802
  }
770
- for (const child of children) {
771
- pushNode(child, depth + 1);
803
+ }
804
+ if (parentRoot === undefined && maxDepth === undefined) {
805
+ for (const item of sortedItems) {
806
+ const itemId = item.id.trim().toLowerCase();
807
+ if (visited.has(itemId))
808
+ continue;
809
+ visited.add(itemId);
810
+ ordered.push(withTreeMetadata(item, 0, childrenByParent.get(itemId)?.length ?? 0));
772
811
  }
773
- };
774
- for (const root of roots) {
775
- pushNode(root, 0);
776
812
  }
777
813
  return ordered;
778
814
  }
@@ -1136,8 +1172,12 @@ export async function runList(status, options, global) {
1136
1172
  let page = indexedPage;
1137
1173
  if (!page) {
1138
1174
  const items = await loadListItems(options, runtime, listWarnings);
1175
+ const needsHierarchyIndexes = ordering.treeEnabled || trimNonEmpty(options.parent) !== undefined;
1176
+ const hierarchyIndexes = needsHierarchyIndexes
1177
+ ? indexHierarchyRelations(collectHierarchyRelations(items, resolveWorkspaceRelationshipKindRegistry()))
1178
+ : undefined;
1139
1179
  appendUnknownTagWarning(items, options.tag, listWarnings);
1140
- const filtered = applyFilters(items, statusSelection.resolvedStatus, statusSelection.effectiveOptions, runtime.typeRegistry, runtime.statusRegistry, runtime.runtimeFieldFilters);
1180
+ const filtered = applyFilters(items, statusSelection.resolvedStatus, statusSelection.effectiveOptions, runtime.typeRegistry, runtime.statusRegistry, runtime.runtimeFieldFilters, hierarchyIndexes?.parents_by_child);
1141
1181
  // Edge-aware blocked selection (GH-578): classify against the complete
1142
1182
  // loaded corpus so terminal blocker targets count as satisfied, then narrow
1143
1183
  // the already-filtered rows to the shared blocked set.
@@ -1149,7 +1189,7 @@ export async function runList(status, options, global) {
1149
1189
  : filtered;
1150
1190
  const sorted = sortItems(scoped, ordering.sortField, ordering.sortOrder, runtime.statusRegistry);
1151
1191
  const ordered = ordering.treeEnabled
1152
- ? orderItemsAsTree(sorted, ordering.parentRoot, ordering.treeDepth)
1192
+ ? orderItemsAsTree(sorted, ordering.parentRoot, ordering.treeDepth, hierarchyIndexes, items)
1153
1193
  : sorted;
1154
1194
  page = pageAndProjectListItems(ordered, options, runtime.projection, ordering.treeEnabled, buildListCursorFingerprint(statusSelection.filtersStatus, options, ordering));
1155
1195
  }
@@ -1241,4 +1281,4 @@ export const _testOnly = {
1241
1281
  withTreeMetadata,
1242
1282
  };
1243
1283
  //# sourceMappingURL=list.js.map
1244
- //# debugId=361f891a-5f10-529c-8161-dc5193c7e12a
1284
+ //# debugId=93e8c187-e198-50fc-bf2c-7dae2ea42219
@@ -5,6 +5,27 @@
5
5
  * read-output contract without expanding its public declaration module.
6
6
  */
7
7
  import type { PmReadOutputReceipt } from "./read-output-contracts.js";
8
+ /** Input to the deterministic finite-retry recommendation contract. */
9
+ export interface PmReadOutputRecoveryBudgetInput {
10
+ /** Ceiling that already bound and truncated the response. */
11
+ effective_budget_tokens: number;
12
+ /** Measured cost of the useful result before row compaction. */
13
+ measured_result_tokens: number;
14
+ }
15
+ /** Executable next-budget recommendation shared by CLI, SDK, and MCP. */
16
+ export interface PmReadOutputRecoveryBudget {
17
+ /** Rounded finite retry ceiling, or the only truthful safe fallback. */
18
+ output_budget: number | "unbounded";
19
+ /** Ratio to the binding request, absent when finite arithmetic is unsafe. */
20
+ recovery_budget_multiplier: number | null;
21
+ /** Stable algorithm revision for consumers and fixtures. */
22
+ rule_version: "v1";
23
+ }
24
+ /**
25
+ * Recommend a retry that is strictly larger than both the binding request and
26
+ * the pre-compaction result, with a 25% envelope margin rounded to 100 tokens.
27
+ */
28
+ export declare function resolveReadOutputRecoveryBudget(input: PmReadOutputRecoveryBudgetInput): PmReadOutputRecoveryBudget;
8
29
  /** Estimate the conservative token cost of a JSON-shaped result. */
9
30
  export declare function estimateReadOutputTokens(result: unknown): number;
10
31
  /** Update a receipt to the fixed-point estimate of the result containing it. */
@@ -1,8 +1,45 @@
1
1
 
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="737ac274-c165-5d1a-8b8e-cb5d57a81c46")}catch(e){}}();
2
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="02a0bd0c-6ab0-5193-807b-00394a4712b7")}catch(e){}}();
3
3
  import { countReadOutputRows, readOutputBudgetCollections, } from "./read-output-rows.js";
4
4
  const MAX_ESTIMATE_ITERATIONS = 8;
5
5
  const MAX_COMPACTION_ITERATIONS = 64;
6
+ const RECOVERY_MARGIN_NUMERATOR = 5;
7
+ const RECOVERY_MARGIN_DENOMINATOR = 4;
8
+ const RECOVERY_ROUNDING_TOKENS = 100;
9
+ /**
10
+ * Recommend a retry that is strictly larger than both the binding request and
11
+ * the pre-compaction result, with a 25% envelope margin rounded to 100 tokens.
12
+ */
13
+ export function resolveReadOutputRecoveryBudget(input) {
14
+ const binding = Math.trunc(input.effective_budget_tokens);
15
+ const measured = Math.trunc(input.measured_result_tokens);
16
+ if (!Number.isSafeInteger(binding) ||
17
+ binding <= 0 ||
18
+ !Number.isSafeInteger(measured) ||
19
+ measured <= 0) {
20
+ return {
21
+ output_budget: "unbounded",
22
+ recovery_budget_multiplier: null,
23
+ rule_version: "v1",
24
+ };
25
+ }
26
+ const baseline = Math.max(binding + 1, measured);
27
+ const withMargin = Math.ceil((baseline * RECOVERY_MARGIN_NUMERATOR) / RECOVERY_MARGIN_DENOMINATOR);
28
+ const rounded = Math.ceil(withMargin / RECOVERY_ROUNDING_TOKENS) *
29
+ RECOVERY_ROUNDING_TOKENS;
30
+ if (!Number.isSafeInteger(rounded)) {
31
+ return {
32
+ output_budget: "unbounded",
33
+ recovery_budget_multiplier: null,
34
+ rule_version: "v1",
35
+ };
36
+ }
37
+ return {
38
+ output_budget: rounded,
39
+ recovery_budget_multiplier: rounded / binding,
40
+ rule_version: "v1",
41
+ };
42
+ }
6
43
  /** Estimate the conservative token cost of a JSON-shaped result. */
7
44
  export function estimateReadOutputTokens(result) {
8
45
  return Math.ceil(Buffer.byteLength(JSON.stringify(result), "utf8") / 4);
@@ -96,4 +133,4 @@ export function compactReadOutputToBudget(result, receipt, budget, minimumRowsBy
96
133
  return compacted;
97
134
  }
98
135
  //# sourceMappingURL=read-output-budget.js.map
99
- //# debugId=737ac274-c165-5d1a-8b8e-cb5d57a81c46
136
+ //# debugId=02a0bd0c-6ab0-5193-807b-00394a4712b7
@@ -1,3 +1,5 @@
1
+ export { resolveReadOutputRecoveryBudget } from "./read-output-budget.js";
2
+ export type { PmReadOutputRecoveryBudget, PmReadOutputRecoveryBudgetInput, } from "./read-output-budget.js";
1
3
  export { decodeReadOutputContinuationCursor, encodeReadOutputContinuationCursor, } from "./read-output/continuation.js";
2
4
  import { type PmReadOutputSessionReceipt, type PmReadOutputSessionState } from "./read-output-session.js";
3
5
  /** Stable output dimensions shared by every read surface. */
@@ -5,7 +7,7 @@ export declare const PM_READ_OUTPUT_DIMENSIONS: readonly ["include", "amount", "
5
7
  /** One member of the universal read-output dimension set. */
6
8
  export type PmReadOutputDimension = (typeof PM_READ_OUTPUT_DIMENSIONS)[number];
7
9
  /** Built-in command roots whose primary operation is a read. */
8
- export declare const PM_READ_OUTPUT_SURFACES: readonly ["list", "context", "search", "get", "next", "health", "deps", "graph", "history", "activity", "validate", "events", "contracts", "comments", "notes", "files", "docs", "stats", "aggregate", "package-catalog", "package-manage", "comments-audit", "assurance"];
10
+ export declare const PM_READ_OUTPUT_SURFACES: readonly ["list", "context", "search", "get", "next", "health", "deps", "graph", "history", "activity", "validate", "events", "contracts", "comments", "notes", "files", "docs", "stats", "aggregate", "duplicates", "package-catalog", "package-manage", "comments-audit", "assurance"];
9
11
  /** Built-in read command supported by the universal output contract. */
10
12
  export type PmReadOutputSurface = (typeof PM_READ_OUTPUT_SURFACES)[number];
11
13
  /** Canonical output controls accepted by every built-in read action. */
@@ -81,6 +83,8 @@ export interface PmResolvedReadOutputDimensions {
81
83
  cost?: PmResolvedReadOutputDimension<number | "unbounded">;
82
84
  /** Requested static encoding or a retained legacy streaming behavior. */
83
85
  encoding?: PmResolvedReadOutputDimension<"json" | "toon" | "stream">;
86
+ /** Canonical CLI options observed on the invocation. */
87
+ canonical_options_used?: string[];
84
88
  /** Compatibility flags observed on the invocation. */
85
89
  legacy_aliases_used: string[];
86
90
  /** One-line migration instructions for observed compatibility flags. */
@@ -102,6 +106,8 @@ export interface PmReadOutputReceipt {
102
106
  budget_tokens?: number;
103
107
  /** Deterministic precedence used during resolution. */
104
108
  precedence: readonly ["canonical", "legacy", "intent", "default"];
109
+ /** Canonical CLI options observed on the invocation. */
110
+ canonical_options_used?: string[];
105
111
  /** Compatibility options observed on the invocation. */
106
112
  legacy_aliases_used: string[];
107
113
  /** One-line migration instructions for compatibility options. */
@@ -138,7 +144,7 @@ export interface PmReadOutputTruncationDisclosure {
138
144
  /** Whether at least one declared row collection can be resumed within the budget. */
139
145
  continuation_available: boolean;
140
146
  /** Maximum next-page useful-result budget relative to the current budget. */
141
- recovery_budget_multiplier: 1;
147
+ recovery_budget_multiplier: number | null;
142
148
  /** Bounded continuation instructions for every compacted declared row path. */
143
149
  continuations: PmReadOutputContinuation[];
144
150
  /** Executable recovery instruction for retrieving the complete result. */
@@ -156,10 +162,10 @@ export interface PmReadOutputTruncationDisclosure {
156
162
  } | {
157
163
  cli: string;
158
164
  sdk: {
159
- outputBudget: number;
165
+ outputBudget: number | "unbounded";
160
166
  };
161
167
  mcp: {
162
- outputBudget: number;
168
+ outputBudget: number | "unbounded";
163
169
  };
164
170
  };
165
171
  }