@unbrained/pm-cli 2026.8.20 → 2026.8.22

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 +38 -0
  3. package/dist/cli/error-guidance.d.ts +29 -4
  4. package/dist/cli/error-guidance.js +43 -43
  5. package/dist/cli/main.d.ts +3 -0
  6. package/dist/cli/main.js +40 -7
  7. package/dist/cli-bundle/bundle-manifest.json +150 -150
  8. package/dist/cli-bundle/chunks/{chunk-L4LGPBJU.js → chunk-BWX4SK46.js} +58 -58
  9. package/dist/cli-bundle/chunks/chunk-EMWDM5FI.js +13 -0
  10. package/dist/cli-bundle/chunks/chunk-HYG6LRL4.js +200 -0
  11. package/dist/cli-bundle/chunks/{chunk-TSMWLCHS.js → chunk-MYYI3ZOA.js} +2 -2
  12. package/dist/cli-bundle/chunks/{chunk-4GB2LTOQ.js → chunk-MZTZQTMS.js} +2 -2
  13. package/dist/cli-bundle/chunks/{chunk-7BRF2BX2.js → chunk-QI2CT3IX.js} +2 -2
  14. package/dist/cli-bundle/chunks/chunk-SMWXHMVB.js +35 -0
  15. package/dist/cli-bundle/chunks/{chunk-US2ZQW2M.js → chunk-U6GQ4VMV.js} +47 -47
  16. package/dist/cli-bundle/chunks/{chunk-K3EN3LK2.js → chunk-VMMIL3SI.js} +2 -2
  17. package/dist/cli-bundle/chunks/chunk-WG4STC36.js +5 -0
  18. package/dist/cli-bundle/chunks/{chunk-XYDDWBZN.js → chunk-YBPJAOQQ.js} +3 -3
  19. package/dist/cli-bundle/chunks/{register-list-query-JSAQCVOC.js → register-list-query-HZKBQNWW.js} +2 -2
  20. package/dist/cli-bundle/chunks/{register-mutation-XJPAW63D.js → register-mutation-HTKEEGRD.js} +2 -2
  21. package/dist/cli-bundle/chunks/{register-operations-DSOSB2XQ.js → register-operations-6EMRWJJY.js} +2 -2
  22. package/dist/cli-bundle/chunks/{register-setup-QUR6QL2C.js → register-setup-QK4OTOXN.js} +2 -2
  23. package/dist/cli-bundle/focused-chunks/{chunk-TDR5OGG3.js → chunk-2ARQGDDW.js} +2 -2
  24. package/dist/cli-bundle/focused-chunks/{chunk-AZBACT5T.js → chunk-2AZT5WXZ.js} +2 -2
  25. package/dist/cli-bundle/focused-chunks/{chunk-M32HFIQB.js → chunk-2POVTNLY.js} +2 -2
  26. package/dist/cli-bundle/focused-chunks/chunk-3LKU6PTJ.js +4 -0
  27. package/dist/cli-bundle/focused-chunks/chunk-5SHSBMX2.js +2 -0
  28. package/dist/cli-bundle/focused-chunks/{chunk-UGSS4F5X.js → chunk-6S2MO3Q3.js} +2 -2
  29. package/dist/cli-bundle/focused-chunks/{chunk-5L7M4AI7.js → chunk-A2BC5PQL.js} +2 -2
  30. package/dist/cli-bundle/focused-chunks/chunk-C4S4A4JJ.js +5 -0
  31. package/dist/cli-bundle/focused-chunks/{chunk-OM65KHGF.js → chunk-D6RBZEJJ.js} +2 -2
  32. package/dist/cli-bundle/focused-chunks/chunk-E2EWYPY6.js +16 -0
  33. package/dist/cli-bundle/focused-chunks/{chunk-G3C5ERXG.js → chunk-GMYPD4FX.js} +2 -2
  34. package/dist/cli-bundle/focused-chunks/chunk-L5LDSRO2.js +155 -0
  35. package/dist/cli-bundle/focused-chunks/{chunk-BLJCGGID.js → chunk-MB37AYN6.js} +2 -2
  36. package/dist/cli-bundle/focused-chunks/chunk-MCOR37QK.js +2 -0
  37. package/dist/cli-bundle/focused-chunks/{chunk-FUREQLQN.js → chunk-PH2OXXVZ.js} +2 -2
  38. package/dist/cli-bundle/focused-chunks/{chunk-325UXIO7.js → chunk-PMGJUFNQ.js} +2 -2
  39. package/dist/cli-bundle/focused-chunks/chunk-R6SR45XU.js +50 -0
  40. package/dist/cli-bundle/focused-chunks/chunk-WZE4LIPW.js +8 -0
  41. package/dist/cli-bundle/main.js +13 -13
  42. package/dist/cli-bundle/sdk-authoring.js +1 -1
  43. package/dist/cli-bundle/sdk-contracts.js +2 -2
  44. package/dist/cli-bundle/sdk-core.js +40 -40
  45. package/dist/cli-bundle/sdk-governance.js +1 -1
  46. package/dist/cli-bundle/sdk-graph.js +1 -1
  47. package/dist/cli-bundle/sdk-merge.js +32 -32
  48. package/dist/cli-bundle/sdk-query.js +1 -1
  49. package/dist/cli-bundle/sdk-runtime.js +1 -1
  50. package/dist/cli-bundle/sdk-testing.js +1 -1
  51. package/dist/cli-bundle/sdk.js +5 -5
  52. package/dist/core/extensions/extension-hook-runtime.js +22 -20
  53. package/dist/core/extensions/extension-types.d.ts +8 -1
  54. package/dist/core/extensions/extension-types.js +2 -2
  55. package/dist/core/extensions/loader.js +7 -3
  56. package/dist/core/extensions/service-ownership.d.ts +8 -0
  57. package/dist/core/extensions/service-ownership.js +20 -0
  58. package/dist/core/item/id.js +20 -5
  59. package/dist/core/item/item-format.js +27 -2
  60. package/dist/core/shared/errors.d.ts +20 -0
  61. package/dist/core/shared/errors.js +2 -2
  62. package/dist/core/store/item-store.js +6 -91
  63. package/dist/core/store/tracker-preflight.d.ts +7 -0
  64. package/dist/core/store/tracker-preflight.js +142 -0
  65. package/dist/sdk/agent/refusal-reachability.d.ts +1 -1
  66. package/dist/sdk/agent/tracker-preflight-contracts.d.ts +63 -0
  67. package/dist/sdk/agent/tracker-preflight-contracts.js +127 -0
  68. package/dist/sdk/annotations.js +6 -7
  69. package/dist/sdk/authoring.d.ts +1 -1
  70. package/dist/sdk/authoring.js +2 -2
  71. package/dist/sdk/cli-contracts/agent-output-contracts.d.ts +77 -0
  72. package/dist/sdk/cli-contracts/agent-output-contracts.js +324 -2
  73. package/dist/sdk/cli-contracts/commander-mutation-options.js +3 -3
  74. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +3 -1
  75. package/dist/sdk/cli-contracts/runtime-contracts.js +4 -3
  76. package/dist/sdk/cli-contracts.d.ts +1 -1
  77. package/dist/sdk/cli-contracts.js +3 -3
  78. package/dist/sdk/config.d.ts +5 -0
  79. package/dist/sdk/config.js +5 -5
  80. package/dist/sdk/context-intent-runtime.js +7 -4
  81. package/dist/sdk/contracts.d.ts +1 -0
  82. package/dist/sdk/contracts.js +3 -2
  83. package/dist/sdk/dependencies.js +5 -7
  84. package/dist/sdk/dependency-flag-validation.d.ts +1 -1
  85. package/dist/sdk/dependency-flag-validation.js +10 -4
  86. package/dist/sdk/environment/tracker-preflight.d.ts +6 -0
  87. package/dist/sdk/environment/tracker-preflight.js +10 -0
  88. package/dist/sdk/eval.js +5 -7
  89. package/dist/sdk/extension/install-sources.d.ts +1 -1
  90. package/dist/sdk/extension/install-sources.js +6 -3
  91. package/dist/sdk/extension/output-ownership.d.ts +1 -0
  92. package/dist/sdk/extension/output-ownership.js +3 -2
  93. package/dist/sdk/files.js +6 -10
  94. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +75 -15
  95. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +81 -8
  96. package/dist/sdk/governance/assurance.d.ts +36 -2
  97. package/dist/sdk/governance/assurance.js +184 -10
  98. package/dist/sdk/governance/gc.js +5 -6
  99. package/dist/sdk/governance/health.d.ts +3 -0
  100. package/dist/sdk/governance/health.js +42 -11
  101. package/dist/sdk/governance/hierarchy-validation.d.ts +29 -0
  102. package/dist/sdk/governance/hierarchy-validation.js +109 -0
  103. package/dist/sdk/governance/reindex.js +5 -6
  104. package/dist/sdk/governance/validate.d.ts +2 -9
  105. package/dist/sdk/governance/validate.js +51 -109
  106. package/dist/sdk/graph/assembly.d.ts +6 -1
  107. package/dist/sdk/graph/assembly.js +16 -22
  108. package/dist/sdk/graph/governance-contracts.d.ts +1 -1
  109. package/dist/sdk/graph/governance-contracts.js +8 -2
  110. package/dist/sdk/graph/governance.d.ts +7 -5
  111. package/dist/sdk/graph/governance.js +76 -16
  112. package/dist/sdk/graph/hierarchy-integrity.d.ts +94 -0
  113. package/dist/sdk/graph/hierarchy-integrity.js +311 -0
  114. package/dist/sdk/graph/index.d.ts +2 -1
  115. package/dist/sdk/graph/index.js +3 -2
  116. package/dist/sdk/graph/remediation.js +32 -2
  117. package/dist/sdk/graph/run.d.ts +31 -2
  118. package/dist/sdk/graph/run.js +83 -36
  119. package/dist/sdk/graph/traversal.js +14 -5
  120. package/dist/sdk/graph/workspace-relationship-kind-registry.d.ts +8 -0
  121. package/dist/sdk/graph/workspace-relationship-kind-registry.js +28 -0
  122. package/dist/sdk/history-compact.js +6 -9
  123. package/dist/sdk/history-read.js +5 -7
  124. package/dist/sdk/history-redact.js +5 -6
  125. package/dist/sdk/history-repair.js +6 -9
  126. package/dist/sdk/improvement-ledger.js +7 -10
  127. package/dist/sdk/index.d.ts +4 -2
  128. package/dist/sdk/index.js +5 -3
  129. package/dist/sdk/item-children.js +21 -8
  130. package/dist/sdk/lifecycle/append.d.ts +0 -5
  131. package/dist/sdk/lifecycle/append.js +5 -6
  132. package/dist/sdk/lifecycle/claim.d.ts +0 -5
  133. package/dist/sdk/lifecycle/claim.js +6 -9
  134. package/dist/sdk/lifecycle/close-many.d.ts +0 -5
  135. package/dist/sdk/lifecycle/close-many.js +5 -6
  136. package/dist/sdk/lifecycle/close.d.ts +0 -5
  137. package/dist/sdk/lifecycle/close.js +5 -6
  138. package/dist/sdk/lifecycle/copy.d.ts +0 -5
  139. package/dist/sdk/lifecycle/copy.js +5 -6
  140. package/dist/sdk/lifecycle/create.d.ts +0 -5
  141. package/dist/sdk/lifecycle/create.js +127 -102
  142. package/dist/sdk/lifecycle/delete.js +5 -6
  143. package/dist/sdk/lifecycle/focus.d.ts +0 -5
  144. package/dist/sdk/lifecycle/focus.js +5 -6
  145. package/dist/sdk/lifecycle/hierarchy-mutation-lock.d.ts +15 -0
  146. package/dist/sdk/lifecycle/hierarchy-mutation-lock.js +25 -0
  147. package/dist/sdk/lifecycle/plan.d.ts +0 -5
  148. package/dist/sdk/lifecycle/plan.js +5 -6
  149. package/dist/sdk/lifecycle/restore.js +5 -6
  150. package/dist/sdk/lifecycle/update-many.d.ts +0 -5
  151. package/dist/sdk/lifecycle/update-many.js +5 -6
  152. package/dist/sdk/lifecycle/update.d.ts +2 -5
  153. package/dist/sdk/lifecycle/update.js +211 -84
  154. package/dist/sdk/linked-artifacts.js +6 -7
  155. package/dist/sdk/merge/install.js +5 -6
  156. package/dist/sdk/mutation-events.js +5 -7
  157. package/dist/sdk/package-import-adapters.js +6 -8
  158. package/dist/sdk/profile.js +6 -7
  159. package/dist/sdk/query/activity.js +5 -6
  160. package/dist/sdk/query/calendar.js +5 -6
  161. package/dist/sdk/query/complete-list.d.ts +3 -3
  162. package/dist/sdk/query/complete-list.js +46 -3
  163. package/dist/sdk/query/get.d.ts +0 -5
  164. package/dist/sdk/query/get.js +5 -6
  165. package/dist/sdk/query/history.d.ts +0 -5
  166. package/dist/sdk/query/history.js +5 -6
  167. package/dist/sdk/query/list.d.ts +4 -3
  168. package/dist/sdk/query/list.js +92 -54
  169. package/dist/sdk/query/search.js +5 -7
  170. package/dist/sdk/read-output-contracts.d.ts +5 -1
  171. package/dist/sdk/read-output-contracts.js +87 -22
  172. package/dist/sdk/relationship-context.js +3 -4
  173. package/dist/sdk/relationship-kinds/contract.d.ts +8 -0
  174. package/dist/sdk/relationship-kinds/contract.js +13 -13
  175. package/dist/sdk/relationships.d.ts +1 -1
  176. package/dist/sdk/relationships.js +27 -2
  177. package/dist/sdk/runtime.d.ts +3 -2
  178. package/dist/sdk/runtime.js +3 -2
  179. package/dist/sdk/schema-migration.js +6 -7
  180. package/dist/sdk/schema.js +5 -6
  181. package/dist/sdk/stats.js +5 -8
  182. package/dist/sdk/templates.js +5 -6
  183. package/dist/sdk/test/batch.js +15 -9
  184. package/dist/sdk/test/execution.js +12 -5
  185. package/dist/sdk/test/runs.js +5 -7
  186. package/dist/types.d.ts +11 -0
  187. package/dist/types.js +2 -2
  188. package/docs/AGENT_UX_CONTRACTS.md +24 -1
  189. package/docs/COMMANDS.md +29 -14
  190. package/docs/DEPENDENCY_KIND_CONTRACT.md +40 -1
  191. package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +98 -0
  192. package/docs/EXTENSIONS.md +2 -1
  193. package/docs/README.md +1 -0
  194. package/docs/READ_OUTPUT_CONTRACTS.md +9 -2
  195. package/docs/RECURRENCE_RECOVERY_CONTRACTS.md +37 -0
  196. package/docs/RELATIONSHIP_GRAPH.md +97 -12
  197. package/docs/SDK_PRIMITIVE_INVENTORY.md +15 -1
  198. package/docs/TESTING.md +15 -0
  199. package/marketplace.json +2 -2
  200. package/package.json +1 -1
  201. package/packages/pm-beads/package.json +1 -1
  202. package/packages/pm-calendar/package.json +1 -1
  203. package/packages/pm-command-kit/package.json +1 -1
  204. package/packages/pm-digital-twin/package.json +1 -1
  205. package/packages/pm-governance-audit/package.json +1 -1
  206. package/packages/pm-guide-shell/package.json +1 -1
  207. package/packages/pm-kanban/package.json +1 -1
  208. package/packages/pm-lifecycle-hooks/package.json +1 -1
  209. package/packages/pm-linked-test-adapters/package.json +1 -1
  210. package/packages/pm-search-advanced/package.json +1 -1
  211. package/packages/pm-templates/package.json +1 -1
  212. package/packages/pm-todos/package.json +1 -1
  213. package/packages/pm-vcs/package.json +1 -1
  214. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  215. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  216. package/sdk/public-surface.json +848 -56
  217. package/dist/cli-bundle/chunks/chunk-2RDVGYWE.js +0 -13
  218. package/dist/cli-bundle/chunks/chunk-BLVQHFSY.js +0 -35
  219. package/dist/cli-bundle/chunks/chunk-CU25EQVV.js +0 -5
  220. package/dist/cli-bundle/chunks/chunk-RS3IV2R6.js +0 -197
  221. package/dist/cli-bundle/focused-chunks/chunk-6AHG2YW7.js +0 -50
  222. package/dist/cli-bundle/focused-chunks/chunk-GXWQBE3T.js +0 -8
  223. package/dist/cli-bundle/focused-chunks/chunk-JWKEDZJI.js +0 -4
  224. package/dist/cli-bundle/focused-chunks/chunk-KYZ6JGPL.js +0 -155
  225. package/dist/cli-bundle/focused-chunks/chunk-Q47EX4DI.js +0 -2
  226. package/dist/cli-bundle/focused-chunks/chunk-RIHDMCUM.js +0 -2
  227. package/dist/cli-bundle/focused-chunks/chunk-T4ZFY7ZJ.js +0 -16
  228. package/dist/cli-bundle/focused-chunks/chunk-Z3PLWSGM.js +0 -2
@@ -4,8 +4,8 @@
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]="67c5ff91-1c04-5506-ae5b-32f6552f1d07")}catch(e){}}();
8
- import { pathExists } from "../../core/fs/fs-utils.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]="93e8c187-e198-50fc-bf2c-7dae2ea42219")}catch(e){}}();
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";
11
11
  import { isTerminalStatus } from "../../core/item/status.js";
@@ -24,9 +24,11 @@ import { compareTimestampStrings, matchesTimestampFilters, nowIso, resolveIsoOrR
24
24
  import { listAllItemMetadata, listAllItemMetadataLight, listAllItemMetadataWithBody, } from "../../core/store/item-store.js";
25
25
  import { HEAVY_METADATA_KEYS, readItemMetadataDerivedIndexState, } from "../../core/store/item-metadata-cache.js";
26
26
  import { queryItemMetadataIndex } from "../../core/store/item-metadata-query-index.js";
27
- import { getSettingsPath, resolvePmRoot } from "../../core/store/paths.js";
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
  }
@@ -891,9 +927,7 @@ function buildListPageExtras(limit, hasMore, nextCursor) {
891
927
  }
892
928
  async function resolveListRuntimeContext(options, global) {
893
929
  const pmRoot = resolvePmRoot(process.cwd(), global.path);
894
- if (!(await pathExists(getSettingsPath(pmRoot)))) {
895
- throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
896
- }
930
+ await assertInitializedTracker(pmRoot);
897
931
  const settings = await readSettings(pmRoot);
898
932
  const statusRegistry = resolveRuntimeStatusRegistry(settings.schema);
899
933
  const runtimeFieldRegistry = resolveRuntimeFieldRegistry(settings.schema);
@@ -1138,8 +1172,12 @@ export async function runList(status, options, global) {
1138
1172
  let page = indexedPage;
1139
1173
  if (!page) {
1140
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;
1141
1179
  appendUnknownTagWarning(items, options.tag, listWarnings);
1142
- 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);
1143
1181
  // Edge-aware blocked selection (GH-578): classify against the complete
1144
1182
  // loaded corpus so terminal blocker targets count as satisfied, then narrow
1145
1183
  // the already-filtered rows to the shared blocked set.
@@ -1151,7 +1189,7 @@ export async function runList(status, options, global) {
1151
1189
  : filtered;
1152
1190
  const sorted = sortItems(scoped, ordering.sortField, ordering.sortOrder, runtime.statusRegistry);
1153
1191
  const ordered = ordering.treeEnabled
1154
- ? orderItemsAsTree(sorted, ordering.parentRoot, ordering.treeDepth)
1192
+ ? orderItemsAsTree(sorted, ordering.parentRoot, ordering.treeDepth, hierarchyIndexes, items)
1155
1193
  : sorted;
1156
1194
  page = pageAndProjectListItems(ordered, options, runtime.projection, ordering.treeEnabled, buildListCursorFingerprint(statusSelection.filtersStatus, options, ordering));
1157
1195
  }
@@ -1243,4 +1281,4 @@ export const _testOnly = {
1243
1281
  withTreeMetadata,
1244
1282
  };
1245
1283
  //# sourceMappingURL=list.js.map
1246
- //# debugId=67c5ff91-1c04-5506-ae5b-32f6552f1d07
1284
+ //# debugId=93e8c187-e198-50fc-bf2c-7dae2ea42219
@@ -4,7 +4,8 @@
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]="c650f22f-5fcd-5489-aa9b-da11c2d1db63")}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]="a4117e19-af3e-50f5-b3cc-86c39aa4b439")}catch(e){}}();
8
+ import { assertInitializedTracker } from "../environment/tracker-preflight.js";
8
9
  import fs from "node:fs/promises";
9
10
  import path from "node:path";
10
11
  import { toNonEmptyStringOrUndefined } from "../../core/shared/primitives.js";
@@ -23,7 +24,6 @@ import { readVectorizationStatusLedger } from "../../core/search/cache.js";
23
24
  import { buildEventCorpus, buildPlanFlatCorpus, buildReminderCorpus, buildSearchCorpus, resolveSearchCorpusFields, } from "../../core/search/corpus.js";
24
25
  import { buildBm25Index, flattenSearchCorpusText, resolveBm25Params, scoreBm25Query, tokenizeBm25, } from "../../core/search/bm25.js";
25
26
  import { collectStaleVectorizationIds } from "../../core/search/staleness.js";
26
- import { pathExists } from "../../core/fs/fs-utils.js";
27
27
  import { parseItemDocument } from "../../core/item/item-format.js";
28
28
  import { toItemRecord } from "../../core/item/item-record.js";
29
29
  import { isTerminalStatus } from "../../core/item/status.js";
@@ -40,7 +40,7 @@ import { tokenizeAlphaNumeric } from "../../core/shared/text-normalization.js";
40
40
  import { compareTimestampStrings, matchesTimestampFilters, nowIso, } from "../../core/shared/time.js";
41
41
  import { listAllDocumentCandidatesCached } from "../../core/store/item-metadata-cache.js";
42
42
  import { listAllItemMetadata } from "../../core/store/item-store.js";
43
- import { getItemPath, getSettingsPath, resolveGlobalPmRoot, resolvePmRoot, } from "../../core/store/paths.js";
43
+ import { getItemPath, resolveGlobalPmRoot, resolvePmRoot, } from "../../core/store/paths.js";
44
44
  import { readSettings } from "../../core/store/settings.js";
45
45
  import { resolveSearchPage } from "./search-pagination.js";
46
46
  import { normalizeSearchPhrase, parseMinScoreOverride, parseSearchBoolean, parseSearchDeadline, parseSearchMatchMode, parseSearchMode, parseSearchProjection, parseSearchTokens, parseSemanticWeightOverride, parseTimestampWindow, resolveHybridSemanticWeight, resolveSearchMaxResults, resolveSearchScoreThreshold, resolveSearchTuning, validateSearchProjectionFields, } from "./search-contracts.js";
@@ -1571,9 +1571,7 @@ function prepareSearchInput(rawQuery, rawOptions) {
1571
1571
  }
1572
1572
  async function resolveSearchRuntimeContext(prepared, global) {
1573
1573
  const pmRoot = resolvePmRoot(process.cwd(), global.path);
1574
- if (!(await pathExists(getSettingsPath(pmRoot)))) {
1575
- throw new PmCliError(`Tracker is not initialized at ${pmRoot}. Run pm init first.`, EXIT_CODE.NOT_FOUND);
1576
- }
1574
+ await assertInitializedTracker(pmRoot);
1577
1575
  const storedSettings = await readSettings(pmRoot);
1578
1576
  const settings = resolveSettingsWithSemanticRuntimeDefaults(storedSettings).settings;
1579
1577
  const statusRegistry = resolveRuntimeStatusRegistry(settings.schema);
@@ -1987,4 +1985,4 @@ export async function runSearch(rawQuery, rawOptions, global) {
1987
1985
  return withSearchWorkspaceMemory(buildSearchResultForHits(response, projectedItems, total, page.limited.length, effectiveProjection, page.pageExtras), workspaceMemoryResult);
1988
1986
  }
1989
1987
  //# sourceMappingURL=search.js.map
1990
- //# debugId=c650f22f-5fcd-5489-aa9b-da11c2d1db63
1988
+ //# debugId=a4117e19-af3e-50f5-b3cc-86c39aa4b439
@@ -5,7 +5,7 @@ export declare const PM_READ_OUTPUT_DIMENSIONS: readonly ["include", "amount", "
5
5
  /** One member of the universal read-output dimension set. */
6
6
  export type PmReadOutputDimension = (typeof PM_READ_OUTPUT_DIMENSIONS)[number];
7
7
  /** 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"];
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", "duplicates", "package-catalog", "package-manage", "comments-audit", "assurance"];
9
9
  /** Built-in read command supported by the universal output contract. */
10
10
  export type PmReadOutputSurface = (typeof PM_READ_OUTPUT_SURFACES)[number];
11
11
  /** Canonical output controls accepted by every built-in read action. */
@@ -81,6 +81,8 @@ export interface PmResolvedReadOutputDimensions {
81
81
  cost?: PmResolvedReadOutputDimension<number | "unbounded">;
82
82
  /** Requested static encoding or a retained legacy streaming behavior. */
83
83
  encoding?: PmResolvedReadOutputDimension<"json" | "toon" | "stream">;
84
+ /** Canonical CLI options observed on the invocation. */
85
+ canonical_options_used?: string[];
84
86
  /** Compatibility flags observed on the invocation. */
85
87
  legacy_aliases_used: string[];
86
88
  /** One-line migration instructions for observed compatibility flags. */
@@ -102,6 +104,8 @@ export interface PmReadOutputReceipt {
102
104
  budget_tokens?: number;
103
105
  /** Deterministic precedence used during resolution. */
104
106
  precedence: readonly ["canonical", "legacy", "intent", "default"];
107
+ /** Canonical CLI options observed on the invocation. */
108
+ canonical_options_used?: string[];
105
109
  /** Compatibility options observed on the invocation. */
106
110
  legacy_aliases_used: string[];
107
111
  /** One-line migration instructions for compatibility options. */
@@ -5,7 +5,7 @@
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]="b3c001df-9891-5cf7-990b-8d9da7b51801")}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]="a1272c1f-c03e-580c-8c44-6b3ddeedd240")}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";
@@ -43,6 +43,7 @@ export const PM_READ_OUTPUT_SURFACES = [
43
43
  "docs",
44
44
  "stats",
45
45
  "aggregate",
46
+ "duplicates",
46
47
  "package-catalog",
47
48
  "package-manage",
48
49
  "comments-audit",
@@ -60,6 +61,7 @@ const CANONICAL_OPTIONS = {
60
61
  cost: "--output-budget",
61
62
  encoding: "--output-format",
62
63
  };
64
+ const READ_OUTPUT_INVOCATION_PROVENANCE = Symbol.for("pm.readOutputInvocationProvenance");
63
65
  /** Canonical CLI flags that opt a read invocation into universal output shaping. */
64
66
  export const PM_READ_OUTPUT_OPTION_FLAGS = Object.freeze(PM_READ_OUTPUT_DIMENSIONS.map((dimension) => CANONICAL_OPTIONS[dimension]));
65
67
  /** Canonical control that composes the four per-call dimensions across reads. */
@@ -136,6 +138,7 @@ const LEGACY_FLAGS_BY_COMMAND = {
136
138
  docs: {},
137
139
  stats: {},
138
140
  aggregate: {},
141
+ duplicates: { amount: ["--limit"] },
139
142
  "package-catalog": {},
140
143
  "package-manage": {},
141
144
  "comments-audit": {},
@@ -363,14 +366,32 @@ export function applyReadOutputIncludeModes(command, includeValue, commandOption
363
366
  const modeOptions = readOutputIncludeModeOptions(command);
364
367
  const selectors = [];
365
368
  const modes = [];
369
+ const optionsWithProvenance = commandOptions;
370
+ const existingProvenance = optionsWithProvenance[READ_OUTPUT_INVOCATION_PROVENANCE];
371
+ const canonicalModes = new Set(existingProvenance?.canonical_include_modes ?? []);
372
+ const explicitLegacyAliases = new Set(existingProvenance?.explicit_legacy_aliases ?? []);
366
373
  for (const token of requested) {
367
374
  const option = modeOptions.get(token);
368
375
  if (option === undefined) {
369
376
  selectors.push(token);
370
377
  continue;
371
378
  }
379
+ const legacyFlag = `--${token.replaceAll("_", "-")}`;
380
+ if (isRequestedOption(readOption(commandOptions, legacyFlag))) {
381
+ explicitLegacyAliases.add(legacyFlag);
382
+ }
372
383
  commandOptions[option] = true;
373
384
  modes.push(token);
385
+ canonicalModes.add(token);
386
+ }
387
+ if (modes.length > 0) {
388
+ optionsWithProvenance[READ_OUTPUT_INVOCATION_PROVENANCE] = {
389
+ canonical_include_modes: [...canonicalModes],
390
+ explicit_legacy_aliases: [...explicitLegacyAliases],
391
+ ...(existingProvenance?.cli_invocation_observed === true
392
+ ? { cli_invocation_observed: true }
393
+ : {}),
394
+ };
374
395
  }
375
396
  return { selectors, modes };
376
397
  }
@@ -430,8 +451,10 @@ function positiveInteger(value) {
430
451
  : Number.NaN;
431
452
  return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : undefined;
432
453
  }
433
- function resolveLegacyDimension(contract, options, usable) {
454
+ function resolveLegacyDimension(contract, options, usable, ignore) {
434
455
  for (const alias of contract.legacy_aliases) {
456
+ if (ignore(alias.flag))
457
+ continue;
435
458
  const value = readOption(options, alias.flag);
436
459
  const candidate = { value, flag: alias.flag };
437
460
  if (isRequestedOption(value) && usable(candidate))
@@ -496,12 +519,43 @@ function resolveEncodingValue(canonical, legacy) {
496
519
  ? { source: "legacy", value: legacy.value }
497
520
  : undefined;
498
521
  }
522
+ function shouldIgnoreReadOutputLegacyAlias(provenance, dimension, flag) {
523
+ if (!provenance)
524
+ return false;
525
+ const explicitLegacyAliases = new Set(provenance.explicit_legacy_aliases);
526
+ if (provenance.cli_invocation_observed === true) {
527
+ return !explicitLegacyAliases.has(flag);
528
+ }
529
+ const forwardedIncludeAliases = new Set(provenance.canonical_include_modes.map((mode) => `--${mode.replaceAll("_", "-")}`));
530
+ return (dimension === "include" &&
531
+ forwardedIncludeAliases.has(flag) &&
532
+ !explicitLegacyAliases.has(flag));
533
+ }
534
+ function hasCompleteReadOutputIntent(command, legacyByDimension, provenance) {
535
+ const root = command
536
+ .trim()
537
+ .toLowerCase()
538
+ .replaceAll(/\s+/gu, " ")
539
+ .split(" ")[0];
540
+ return (root === "list-all" ||
541
+ legacyByDimension.amount?.flag === "--no-truncate" ||
542
+ legacyByDimension.include?.flag === "--full" ||
543
+ provenance?.canonical_include_modes.includes("full") === true);
544
+ }
545
+ function canonicalReadOutputOptionsUsed(resolvedByDimension, provenance) {
546
+ return PM_READ_OUTPUT_DIMENSIONS.flatMap((dimension) => resolvedByDimension[dimension]?.source === "canonical" ||
547
+ (dimension === "include" &&
548
+ (provenance?.canonical_include_modes.length ?? 0) > 0)
549
+ ? [CANONICAL_OPTIONS[dimension]]
550
+ : []);
551
+ }
499
552
  /** Resolve canonical and compatibility controls into the universal dimension set. */
500
553
  export function resolveReadOutputDimensions(command, options) {
501
554
  const normalizedCommand = resolveReadOutputSurface(command, options);
502
555
  if (!normalizedCommand)
503
556
  return undefined;
504
557
  const contract = SURFACE_CONTRACT_BY_COMMAND.get(normalizedCommand);
558
+ const invocationProvenance = options[READ_OUTPUT_INVOCATION_PROVENANCE];
505
559
  const legacyResolvers = {
506
560
  include: (candidate) => resolveIncludeValue(undefined, candidate),
507
561
  amount: (candidate) => resolveAmountValue(undefined, candidate),
@@ -510,7 +564,7 @@ export function resolveReadOutputDimensions(command, options) {
510
564
  };
511
565
  const legacyByDimension = Object.fromEntries(PM_READ_OUTPUT_DIMENSIONS.map((dimension) => [
512
566
  dimension,
513
- resolveLegacyDimension(contract.dimensions[dimension], options, (candidate) => legacyResolvers[dimension](candidate) !== undefined),
567
+ resolveLegacyDimension(contract.dimensions[dimension], options, (candidate) => legacyResolvers[dimension](candidate) !== undefined, (flag) => shouldIgnoreReadOutputLegacyAlias(invocationProvenance, dimension, flag)),
514
568
  ]));
515
569
  const legacyAliasesUsed = PM_READ_OUTPUT_DIMENSIONS.flatMap((dimension) => {
516
570
  const resolved = legacyByDimension[dimension];
@@ -524,29 +578,31 @@ export function resolveReadOutputDimensions(command, options) {
524
578
  return [alias.migration_hint];
525
579
  });
526
580
  const encoding = resolveEncodingValue(options.outputFormat ?? options.output_format, legacyByDimension.encoding);
581
+ const include = resolveIncludeValue(options.outputInclude ?? options.output_include, legacyByDimension.include);
582
+ const amount = resolveAmountValue(options.outputLimit ?? options.output_limit, legacyByDimension.amount);
527
583
  const explicitCost = resolveCostValue(options.outputBudget ?? options.output_budget, legacyByDimension.cost);
528
- const completeResultIntent = command.trim().toLowerCase().replaceAll(/\s+/gu, " ").split(" ")[0] ===
529
- "list-all" ||
530
- legacyByDimension.amount?.flag === "--no-truncate" ||
531
- legacyByDimension.include?.flag === "--full";
584
+ const completeResultIntent = hasCompleteReadOutputIntent(command, legacyByDimension, invocationProvenance);
532
585
  const budget = resolvePmCommandOutputBudget(command, {
533
586
  generateFallback: true,
534
587
  });
535
588
  const resolvedOutputFormat = encoding?.value === "json" || options.resolvedOutputFormat === "json"
536
589
  ? "json"
537
590
  : "toon";
591
+ const cost = explicitCost ??
592
+ (completeResultIntent
593
+ ? { source: "intent", value: "unbounded" }
594
+ : {
595
+ source: "default",
596
+ value: budget.default_max_estimated_tokens_by_format[resolvedOutputFormat],
597
+ });
598
+ const resolvedByDimension = { include, amount, cost, encoding };
538
599
  return {
539
600
  command: normalizedCommand,
540
- include: resolveIncludeValue(options.outputInclude ?? options.output_include, legacyByDimension.include),
541
- amount: resolveAmountValue(options.outputLimit ?? options.output_limit, legacyByDimension.amount),
542
- cost: explicitCost ??
543
- (completeResultIntent
544
- ? { source: "intent", value: "unbounded" }
545
- : {
546
- source: "default",
547
- value: budget.default_max_estimated_tokens_by_format[resolvedOutputFormat],
548
- }),
601
+ include,
602
+ amount,
603
+ cost,
549
604
  encoding,
605
+ canonical_options_used: canonicalReadOutputOptionsUsed(resolvedByDimension, invocationProvenance),
550
606
  legacy_aliases_used: legacyAliasesUsed,
551
607
  migration_hints: migrationHints,
552
608
  precedence: READ_OUTPUT_PRECEDENCE,
@@ -732,8 +788,9 @@ function applyAmountBound(result, amount) {
732
788
  return bounded;
733
789
  }
734
790
  function requestedDimensions(resolved) {
735
- return PM_READ_OUTPUT_DIMENSIONS.filter((dimension) => resolved[dimension] !== undefined &&
736
- resolved[dimension]?.source !== "default");
791
+ return PM_READ_OUTPUT_DIMENSIONS.filter((dimension) => (resolved[dimension] !== undefined &&
792
+ resolved[dimension]?.source !== "default") ||
793
+ resolved.canonical_options_used.includes(CANONICAL_OPTIONS[dimension]));
737
794
  }
738
795
  /** Stabilize the per-call and cross-call receipts in one complete envelope. */
739
796
  function attachReadOutputSessionContracts(result, state, receipt) {
@@ -847,6 +904,12 @@ function resolveBindingReadOutputBudget(resolved, session) {
847
904
  ];
848
905
  return budgets.sort((left, right) => left.tokens - right.tokens)[0];
849
906
  }
907
+ function canonicalReadOutputReceiptFields(resolved) {
908
+ const canonicalOptions = resolved.canonical_options_used;
909
+ return canonicalOptions && canonicalOptions.length > 0
910
+ ? { canonical_options_used: canonicalOptions }
911
+ : {};
912
+ }
850
913
  /** Build the smallest truthful omission envelope or reject an exhausted session. */
851
914
  function omitReadOutputForBudget(resolved, requested, session, bindingBudget, omittedResultEstimatedTokens) {
852
915
  const minimalReceipt = {
@@ -860,6 +923,7 @@ function omitReadOutputForBudget(resolved, requested, session, bindingBudget, om
860
923
  }
861
924
  : {}),
862
925
  precedence: resolved.precedence,
926
+ ...canonicalReadOutputReceiptFields(resolved),
863
927
  legacy_aliases_used: [],
864
928
  migration_hints: [],
865
929
  estimated_tokens: 0,
@@ -893,10 +957,10 @@ function omitReadOutputForBudget(resolved, requested, session, bindingBudget, om
893
957
  return boundedOmission;
894
958
  }
895
959
  /** Decide whether shaping would add no value to an already-bounded result. */
896
- function canReturnReadOutputUnchanged(resolved, requested, session, result) {
960
+ function canReturnReadOutputUnchanged(resolved, session, result) {
897
961
  if (session !== undefined)
898
962
  return false;
899
- const canonicalRequestedCount = requested.filter((dimension) => resolved[dimension]?.source === "canonical").length;
963
+ const canonicalRequestedCount = resolved.canonical_options_used.length;
900
964
  if (resolved.cost?.value === "unbounded") {
901
965
  return (canonicalRequestedCount === (resolved.cost.source === "canonical" ? 1 : 0));
902
966
  }
@@ -1077,7 +1141,7 @@ export function applyReadOutputDimensions(command, options, result) {
1077
1141
  : undefined;
1078
1142
  const requested = requestedDimensions(resolved);
1079
1143
  if (cursor === undefined &&
1080
- canReturnReadOutputUnchanged(resolved, requested, session, result)) {
1144
+ canReturnReadOutputUnchanged(resolved, session, result)) {
1081
1145
  return result;
1082
1146
  }
1083
1147
  const continuationReadyResult = attachValidateDiagnosticRowContract(resolved.command, result);
@@ -1095,6 +1159,7 @@ export function applyReadOutputDimensions(command, options, result) {
1095
1159
  }
1096
1160
  : {}),
1097
1161
  precedence: resolved.precedence,
1162
+ ...canonicalReadOutputReceiptFields(resolved),
1098
1163
  legacy_aliases_used: resolved.legacy_aliases_used,
1099
1164
  migration_hints: resolved.migration_hints,
1100
1165
  estimated_tokens: 0,
@@ -1134,4 +1199,4 @@ export function resolveReadOutputEncoding(command, options) {
1134
1199
  : undefined;
1135
1200
  }
1136
1201
  //# sourceMappingURL=read-output-contracts.js.map
1137
- //# debugId=b3c001df-9891-5cf7-990b-8d9da7b51801
1202
+ //# debugId=a1272c1f-c03e-580c-8c44-6b3ddeedd240
@@ -5,7 +5,7 @@
5
5
  * packet for agents, custom tools, and presentation-layer adapters.
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]="31a800f7-1374-5e7c-ad23-ae3d8ebcebe0")}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]="afdba960-ae43-52be-b21d-282dac1f22ff")}catch(e){}}();
9
9
  import { createQueryFingerprint, encodeQueryCursor, resolveQueryCursorStart, } from "./pagination.js";
10
10
  import { createRelationshipKindRegistry, } from "./relationships.js";
11
11
  /** Deterministic priority used when one node matches several semantic families. */
@@ -37,8 +37,7 @@ function explainDirectEdge(edge, node, registry) {
37
37
  return node === before ? "prerequisite" : "dependent";
38
38
  }
39
39
  if (definition?.hierarchy) {
40
- // Legacy and JSON-parsed definitions may predate explicit hierarchy direction.
41
- const sourceIsParent = (definition.hierarchyDirection ?? "source_parent") === "source_parent";
40
+ const sourceIsParent = definition.hierarchyDirection === "source_parent";
42
41
  const parent = sourceIsParent ? edge.source : edge.target;
43
42
  return node === parent ? "ancestor" : "descendant";
44
43
  }
@@ -283,4 +282,4 @@ export function buildRelationshipContext(graph, rootId, details, options = {}) {
283
282
  };
284
283
  }
285
284
  //# sourceMappingURL=relationship-context.js.map
286
- //# debugId=31a800f7-1374-5e7c-ad23-ae3d8ebcebe0
285
+ //# debugId=afdba960-ae43-52be-b21d-282dac1f22ff
@@ -15,12 +15,20 @@ export type RelationshipTemporalOrder = "source_after_target";
15
15
  export type RelationshipPrecedence = "source_before_target" | "target_before_source";
16
16
  /** Endpoint that represents the structural parent for hierarchy kinds. */
17
17
  export type RelationshipHierarchyDirection = "source_parent" | "target_parent";
18
+ /** Closure family that gives a relationship its default traversal vocabulary. */
19
+ export type RelationshipTraversalFamily = "hierarchy" | "ordering" | "semantic" | "association";
20
+ /** Direction in which an edge can carry a node toward a declared outcome. */
21
+ export type RelationshipOutcomeTraversal = "source_to_target" | "target_to_source" | "both";
18
22
  /** Versioned semantic definition for a built-in or application-defined edge kind. */
19
23
  export interface RelationshipKindDefinition {
20
24
  /** Canonical, case-insensitive kind identifier. */
21
25
  kind: string;
22
26
  /** Whether traversing source to target has distinct meaning from the reverse. */
23
27
  direction: RelationshipDirection;
28
+ /** Default closure vocabulary; omitted custom definitions infer it from legacy flags. */
29
+ traversal?: RelationshipTraversalFamily;
30
+ /** Direction this kind contributes to typed outcome reachability, when any. */
31
+ outcomeTraversal?: RelationshipOutcomeTraversal;
24
32
  /** Optional canonical kind used when traversing a directed edge in reverse. */
25
33
  inverse?: string;
26
34
  /** Whether the kind participates in execution-order cycle checks. */