@unbrained/pm-cli 2026.8.12 → 2026.8.13

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 (173) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +22 -0
  3. package/dist/cli/error-guidance.js +4 -8
  4. package/dist/cli/main.js +3 -2
  5. package/dist/cli/register-assurance.js +28 -17
  6. package/dist/cli-bundle/bundle-manifest.json +161 -161
  7. package/dist/cli-bundle/chunks/chunk-3ZMOWAFM.js +2 -0
  8. package/dist/cli-bundle/chunks/chunk-DEDU3DG7.js +196 -0
  9. package/dist/cli-bundle/chunks/chunk-DL5M5J3V.js +13 -0
  10. package/dist/cli-bundle/chunks/chunk-F7FJYGK3.js +8 -0
  11. package/dist/cli-bundle/chunks/{chunk-RBTK5EZV.js → chunk-HIUZVCMN.js} +2 -2
  12. package/dist/cli-bundle/chunks/chunk-IMGIN7R6.js +2 -0
  13. package/dist/cli-bundle/chunks/{chunk-WLAHPSOX.js → chunk-Q47C67TQ.js} +2 -2
  14. package/dist/cli-bundle/chunks/{chunk-BM5YJ2UW.js → chunk-QGTUPEU5.js} +52 -52
  15. package/dist/cli-bundle/chunks/chunk-TF3TPKPR.js +34 -0
  16. package/dist/cli-bundle/chunks/{chunk-KOQMGCTA.js → chunk-YLBAPY22.js} +50 -50
  17. package/dist/cli-bundle/chunks/{register-list-query-XPCJRUUD.js → register-list-query-4HIZ7EA3.js} +2 -2
  18. package/dist/cli-bundle/chunks/{register-mutation-4RJCBKRS.js → register-mutation-W64FZ5HN.js} +2 -2
  19. package/dist/cli-bundle/chunks/register-operations-C44ET7R5.js +2 -0
  20. package/dist/cli-bundle/chunks/{register-setup-LLHAKP2V.js → register-setup-634MFRXU.js} +2 -2
  21. package/dist/cli-bundle/focused-chunks/chunk-27N23W6M.js +31 -0
  22. package/dist/cli-bundle/focused-chunks/{chunk-YIAXMC3T.js → chunk-2JP7W7GO.js} +2 -2
  23. package/dist/cli-bundle/focused-chunks/chunk-2RI2FESN.js +4 -0
  24. package/dist/cli-bundle/focused-chunks/chunk-3BNVU6LC.js +8 -0
  25. package/dist/cli-bundle/focused-chunks/{chunk-KHM2CS2C.js → chunk-3DJSGWVB.js} +2 -2
  26. package/dist/cli-bundle/focused-chunks/{chunk-2DALMVF7.js → chunk-6MLIRBLV.js} +2 -2
  27. package/dist/cli-bundle/focused-chunks/chunk-6XYLENDV.js +155 -0
  28. package/dist/cli-bundle/focused-chunks/chunk-CP4K4WFS.js +2 -0
  29. package/dist/cli-bundle/focused-chunks/{chunk-RWPAWUOT.js → chunk-E3AVJ655.js} +2 -2
  30. package/dist/cli-bundle/focused-chunks/{chunk-5TAGTDRE.js → chunk-EBTNSFYE.js} +2 -2
  31. package/dist/cli-bundle/focused-chunks/{chunk-KPSXVBDV.js → chunk-HC2OL2H2.js} +2 -2
  32. package/dist/cli-bundle/focused-chunks/{chunk-GQW4BPUT.js → chunk-I75MANL7.js} +2 -2
  33. package/dist/cli-bundle/focused-chunks/{chunk-ZMGWAYH7.js → chunk-IIS2FRKL.js} +2 -2
  34. package/dist/cli-bundle/focused-chunks/chunk-NFHFZH2Z.js +2 -0
  35. package/dist/cli-bundle/focused-chunks/chunk-OGC4XSBC.js +17 -0
  36. package/dist/cli-bundle/focused-chunks/{chunk-JAFRIWVF.js → chunk-OOYYKQWX.js} +4 -4
  37. package/dist/cli-bundle/focused-chunks/{chunk-KTLOKKCQ.js → chunk-PKPOZXLL.js} +2 -2
  38. package/dist/cli-bundle/focused-chunks/chunk-QDZUABWL.js +2 -0
  39. package/dist/cli-bundle/focused-chunks/chunk-QQX5TDFT.js +16 -0
  40. package/dist/cli-bundle/focused-chunks/{chunk-NYLOUPOB.js → chunk-TEZIXMTH.js} +2 -2
  41. package/dist/cli-bundle/focused-chunks/chunk-WEH6NSL6.js +18 -0
  42. package/dist/cli-bundle/main.js +13 -13
  43. package/dist/cli-bundle/sdk-authoring.js +1 -1
  44. package/dist/cli-bundle/sdk-contracts.js +1 -1
  45. package/dist/cli-bundle/sdk-core.js +42 -41
  46. package/dist/cli-bundle/sdk-governance.js +1 -1
  47. package/dist/cli-bundle/sdk-graph.js +1 -1
  48. package/dist/cli-bundle/sdk-merge.js +1 -1
  49. package/dist/cli-bundle/sdk-query.js +1 -1
  50. package/dist/cli-bundle/sdk-runtime.js +1 -1
  51. package/dist/cli-bundle/sdk-testing.js +1 -1
  52. package/dist/cli-bundle/sdk.js +2 -2
  53. package/dist/core/checkpoint/checkpoint-gc.js +7 -12
  54. package/dist/core/extensions/activation-summary-markdown.js +5 -4
  55. package/dist/core/extensions/activation-summary.d.ts +2 -0
  56. package/dist/core/extensions/activation-summary.js +6 -2
  57. package/dist/core/extensions/capability-usage.d.ts +1 -1
  58. package/dist/core/extensions/capability-usage.js +4 -3
  59. package/dist/core/extensions/contribution-inventory.d.ts +1 -0
  60. package/dist/core/extensions/contribution-inventory.js +6 -2
  61. package/dist/core/extensions/extension-registries.js +3 -2
  62. package/dist/core/extensions/extension-types.d.ts +83 -1
  63. package/dist/core/extensions/extension-types.js +3 -2
  64. package/dist/core/extensions/loader.d.ts +2 -8
  65. package/dist/core/extensions/loader.js +53 -144
  66. package/dist/core/extensions/registration-values.d.ts +43 -0
  67. package/dist/core/extensions/registration-values.js +210 -0
  68. package/dist/core/extensions/runtime-registrations.d.ts +3 -1
  69. package/dist/core/extensions/runtime-registrations.js +12 -2
  70. package/dist/core/fs/fs-utils.d.ts +2 -0
  71. package/dist/core/fs/fs-utils.js +7 -3
  72. package/dist/core/history/drift-cache.js +4 -3
  73. package/dist/core/history/drift-scan.js +5 -11
  74. package/dist/core/lock/lock-gc.js +8 -13
  75. package/dist/core/lock/lock.js +5 -4
  76. package/dist/core/search/vector-stores.js +6 -11
  77. package/dist/core/store/item-metadata-cache.js +4 -4
  78. package/dist/core/telemetry/runtime.d.ts +6 -0
  79. package/dist/core/telemetry/runtime.js +101 -30
  80. package/dist/sdk/agent/command-recovery.d.ts +2 -0
  81. package/dist/sdk/agent/command-recovery.js +10 -2
  82. package/dist/sdk/annotations.js +4 -4
  83. package/dist/sdk/cli-contracts/completeness.js +9 -3
  84. package/dist/sdk/cli-contracts/enum-contracts.d.ts +1 -1
  85. package/dist/sdk/cli-contracts/flag-contracts.js +6 -3
  86. package/dist/sdk/cli-contracts/schemas/assurance-definition.d.ts +32 -0
  87. package/dist/sdk/cli-contracts/schemas/assurance-definition.js +25 -2
  88. package/dist/sdk/cli-contracts/tool-parameter-tables.js +35 -5
  89. package/dist/sdk/cli-contracts/tool-schema.js +17 -2
  90. package/dist/sdk/comments.js +4 -3
  91. package/dist/sdk/compile-cache.js +4 -3
  92. package/dist/sdk/compose.d.ts +3 -1
  93. package/dist/sdk/compose.js +16 -2
  94. package/dist/sdk/context-signal-store.js +4 -3
  95. package/dist/sdk/extension/install-runtime.js +4 -4
  96. package/dist/sdk/extension/managed-state.js +4 -3
  97. package/dist/sdk/extension-contracts.d.ts +1 -1
  98. package/dist/sdk/flag-invocation-contracts.js +5 -6
  99. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +14 -2
  100. package/dist/sdk/governance/assurance-action.d.ts +27 -3
  101. package/dist/sdk/governance/assurance-action.js +112 -28
  102. package/dist/sdk/governance/assurance-mutation-error.d.ts +7 -0
  103. package/dist/sdk/governance/assurance-mutation-error.js +25 -2
  104. package/dist/sdk/governance/assurance-presets.d.ts +54 -0
  105. package/dist/sdk/governance/assurance-presets.js +136 -0
  106. package/dist/sdk/governance/assurance-runtime.d.ts +4 -0
  107. package/dist/sdk/governance/assurance-runtime.js +109 -8
  108. package/dist/sdk/governance/assurance.d.ts +39 -0
  109. package/dist/sdk/governance/assurance.js +143 -4
  110. package/dist/sdk/governance/gc.js +5 -11
  111. package/dist/sdk/governance/health.js +5 -5
  112. package/dist/sdk/governance/validate.js +4 -4
  113. package/dist/sdk/graph/durable-cache.js +61 -3
  114. package/dist/sdk/graph/governance-contracts.d.ts +12 -0
  115. package/dist/sdk/graph/governance-contracts.js +27 -0
  116. package/dist/sdk/graph/governance.d.ts +30 -2
  117. package/dist/sdk/graph/governance.js +124 -5
  118. package/dist/sdk/guide.js +4 -4
  119. package/dist/sdk/index.d.ts +2 -1
  120. package/dist/sdk/index.js +4 -3
  121. package/dist/sdk/linked-artifacts.d.ts +2 -0
  122. package/dist/sdk/linked-artifacts.js +29 -4
  123. package/dist/sdk/merge/install.js +5 -4
  124. package/dist/sdk/query/activity.js +4 -3
  125. package/dist/sdk/relationship-history.js +5 -5
  126. package/dist/sdk/schema-migration.js +4 -4
  127. package/dist/sdk/test/execution.js +4 -4
  128. package/dist/sdk/workspace-memory.js +4 -4
  129. package/dist/sdk/workspace-snapshot.js +8 -14
  130. package/dist/sdk/workspace-transaction-gc.js +4 -9
  131. package/dist/sdk/workspace-transaction.js +4 -4
  132. package/dist/sdk/workspace.js +4 -3
  133. package/docs/ASSURANCE.md +154 -3
  134. package/docs/CONFIGURATION.md +2 -0
  135. package/docs/EXTENSIONS.md +11 -12
  136. package/docs/RELATIONSHIP_GRAPH.md +15 -0
  137. package/docs/SDK.md +17 -3
  138. package/docs/TESTING.md +24 -15
  139. package/marketplace.json +2 -2
  140. package/package.json +3 -3
  141. package/packages/pm-beads/package.json +1 -1
  142. package/packages/pm-calendar/package.json +1 -1
  143. package/packages/pm-command-kit/package.json +1 -1
  144. package/packages/pm-digital-twin/package.json +1 -1
  145. package/packages/pm-governance-audit/package.json +1 -1
  146. package/packages/pm-guide-shell/package.json +1 -1
  147. package/packages/pm-kanban/package.json +1 -1
  148. package/packages/pm-lifecycle-hooks/package.json +1 -1
  149. package/packages/pm-linked-test-adapters/package.json +1 -1
  150. package/packages/pm-search-advanced/package.json +1 -1
  151. package/packages/pm-templates/package.json +1 -1
  152. package/packages/pm-todos/package.json +1 -1
  153. package/packages/pm-vcs/package.json +1 -1
  154. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  155. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  156. package/sdk/public-surface.json +183 -33
  157. package/dist/cli-bundle/chunks/chunk-3PS7X6GS.js +0 -8
  158. package/dist/cli-bundle/chunks/chunk-7KL6KMWF.js +0 -13
  159. package/dist/cli-bundle/chunks/chunk-D55A5AEN.js +0 -33
  160. package/dist/cli-bundle/chunks/chunk-KIKDWECH.js +0 -196
  161. package/dist/cli-bundle/chunks/chunk-R76342NV.js +0 -2
  162. package/dist/cli-bundle/chunks/chunk-VLUQOIDT.js +0 -2
  163. package/dist/cli-bundle/chunks/register-operations-2OGISOVR.js +0 -2
  164. package/dist/cli-bundle/focused-chunks/chunk-5OQIMELN.js +0 -155
  165. package/dist/cli-bundle/focused-chunks/chunk-ECADZMVC.js +0 -18
  166. package/dist/cli-bundle/focused-chunks/chunk-EJGXRA6B.js +0 -2
  167. package/dist/cli-bundle/focused-chunks/chunk-FFGSZCPK.js +0 -16
  168. package/dist/cli-bundle/focused-chunks/chunk-ISKOBJCM.js +0 -2
  169. package/dist/cli-bundle/focused-chunks/chunk-LGYK3NUF.js +0 -8
  170. package/dist/cli-bundle/focused-chunks/chunk-NBLUKITQ.js +0 -4
  171. package/dist/cli-bundle/focused-chunks/chunk-Q4T463SD.js +0 -31
  172. package/dist/cli-bundle/focused-chunks/chunk-QVZVY53N.js +0 -2
  173. package/dist/cli-bundle/focused-chunks/chunk-UTEWXDEQ.js +0 -17
@@ -4,11 +4,11 @@
4
4
  * Implements the pm health 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]="af3d60bd-94d4-52e8-90e3-7929ce04428c")}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]="5cee1eaa-73f3-5709-867f-a8d73081da8b")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
10
  import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
11
- import { pathExists, readFileIfExists } from "../../core/fs/fs-utils.js";
11
+ import { isFileMissingError, pathExists, readFileIfExists } from "../../core/fs/fs-utils.js";
12
12
  import { activateExtensions, getActiveExtensionRegistrations, loadExtensions, runActiveOnReadHooks, } from "../../core/extensions/index.js";
13
13
  import { collectRegisteredItemFieldNames } from "../../core/extensions/item-fields.js";
14
14
  import { KNOWN_EXTENSION_CAPABILITIES, } from "../../core/extensions/loader.js";
@@ -207,7 +207,7 @@ async function listItemDocumentPaths(pmRoot, typeToFolder) {
207
207
  if (typeof error === "object" &&
208
208
  error !== null &&
209
209
  "code" in error &&
210
- error.code === "ENOENT") {
210
+ isFileMissingError(error)) {
211
211
  continue;
212
212
  }
213
213
  continue;
@@ -226,7 +226,7 @@ function shouldReportHistoryDirectoryUnreadable(error) {
226
226
  return !(typeof error === "object" &&
227
227
  error !== null &&
228
228
  "code" in error &&
229
- error.code === "ENOENT");
229
+ isFileMissingError(error));
230
230
  }
231
231
  async function scanItemIntegrity(pmRoot, typeToFolder, schema) {
232
232
  const paths = await listItemDocumentPaths(pmRoot, typeToFolder);
@@ -2007,4 +2007,4 @@ export const _testOnlyHealthCommand = {
2007
2007
  warningCode,
2008
2008
  };
2009
2009
  //# sourceMappingURL=health.js.map
2010
- //# debugId=af3d60bd-94d4-52e8-90e3-7929ce04428c
2010
+ //# debugId=5cee1eaa-73f3-5709-867f-a8d73081da8b
@@ -4,7 +4,7 @@
4
4
  * Implements the pm validate 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]="5affc1f1-2b4f-5f04-a6cb-c3e389bcb356")}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]="7dd04a2f-1798-5c16-8740-5b7094f81cc0")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import { realpathSync } from "node:fs";
10
10
  import { execFile } from "node:child_process";
@@ -13,7 +13,7 @@ import { promisify } from "node:util";
13
13
  import { buildRemediationCommands } from "../../core/diagnostics/remediation.js";
14
14
  import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
15
15
  import { collectRegisteredItemFieldNames } from "../../core/extensions/item-fields.js";
16
- import { pathExists } from "../../core/fs/fs-utils.js";
16
+ import { isFileMissingError, pathExists } from "../../core/fs/fs-utils.js";
17
17
  import { scanHistoryDrift } from "../../core/history/drift-scan.js";
18
18
  import { normalizeStatusInput } from "../../core/item/status.js";
19
19
  import { resolveItemTypeRegistry } from "../../core/item/type-registry.js";
@@ -475,7 +475,7 @@ async function listFilesRecursive(basePath, relativePath, output) {
475
475
  entries = await fs.readdir(targetDirectory, { withFileTypes: true });
476
476
  }
477
477
  catch (error) {
478
- if (hasFilesystemErrorCode(error, ["ENOENT"])) {
478
+ if (isFileMissingError(error)) {
479
479
  return;
480
480
  }
481
481
  throw error;
@@ -2356,4 +2356,4 @@ export async function runValidate(options, global, services = {}) {
2356
2356
  }
2357
2357
  /* c8 ignore stop */
2358
2358
  //# sourceMappingURL=validate.js.map
2359
- //# debugId=5affc1f1-2b4f-5f04-a6cb-c3e389bcb356
2359
+ //# debugId=7dd04a2f-1798-5c16-8740-5b7094f81cc0
@@ -15,11 +15,12 @@
15
15
  * threshold or after an explicit `pm graph index --rebuild` opt-in.
16
16
  */
17
17
 
18
- !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]="4cb399d6-7311-5e2d-a8d2-e0140530ec72")}catch(e){}}();
18
+ !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]="2f7f14e3-6d41-5f45-a560-ebfbb8aa5828")}catch(e){}}();
19
19
  import path from "node:path";
20
20
  import { readFileIfExists, removeFileIfExists, writeFileAtomic, } from "../../core/fs/fs-utils.js";
21
21
  import { acquireLock } from "../../core/lock/lock.js";
22
22
  import { isSemanticContextKind, } from "./governance.js";
23
+ import { RELATIONSHIP_AUDIT_FINDING_CODES } from "./governance-contracts.js";
23
24
  /** Envelope format version; any change invalidates persisted entries. */
24
25
  export const GRAPH_DURABLE_CACHE_VERSION = 1;
25
26
  /** Workspaces below this item count skip implicit persistence. */
@@ -173,6 +174,58 @@ function isNonnegativeCoverageByTypeRecord(value) {
173
174
  return Object.values(value).every((entry) => isRecord(entry) &&
174
175
  [entry.active, entry.isolated, entry.degree_leq_one].every(isNonnegativeInteger));
175
176
  }
177
+ /** Decode optional structural fields while normalizing pre-structure baselines. */
178
+ function decodeStructuralProfile(profile, affectedSubjectsByCode) {
179
+ const countFields = [
180
+ "articulation_points",
181
+ "bridge_edges",
182
+ "outcome_nodes",
183
+ "active_outcome_reachable_nodes",
184
+ "active_outcome_unreachable_nodes",
185
+ "terminal_nodes",
186
+ "terminal_outcome_reachable_nodes",
187
+ "terminal_outcome_unreachable_nodes",
188
+ "outcome_reachable_nodes",
189
+ "outcome_unreachable_nodes",
190
+ ];
191
+ const rateFields = [
192
+ "active_outcome_reachability_basis_points",
193
+ "terminal_outcome_reachability_basis_points",
194
+ "outcome_reachability_basis_points",
195
+ ];
196
+ const introducedStructuralFields = [
197
+ ...countFields,
198
+ ...rateFields,
199
+ "finding_subjects_by_code",
200
+ ];
201
+ const introducedStructuralFieldCount = introducedStructuralFields.filter((field) => profile[field] !== undefined).length;
202
+ if (introducedStructuralFieldCount !== 0 &&
203
+ introducedStructuralFieldCount !== introducedStructuralFields.length) {
204
+ return undefined;
205
+ }
206
+ const validCounts = countFields.every((field) => profile[field] === undefined || isNonnegativeInteger(profile[field]));
207
+ const validRates = rateFields.every((field) => profile[field] === undefined ||
208
+ (isNonnegativeInteger(profile[field]) && Number(profile[field]) <= 10_000));
209
+ if (!validCounts || !validRates)
210
+ return undefined;
211
+ if (profile.edge_basis !== undefined &&
212
+ profile.edge_basis !== "deduplicated_directed")
213
+ return undefined;
214
+ if (!isOptionalValid(profile.finding_subjects_by_code, isNonnegativeCountRecord))
215
+ return undefined;
216
+ const findingSubjects = isNonnegativeCountRecord(profile.finding_subjects_by_code)
217
+ ? profile.finding_subjects_by_code
218
+ : {};
219
+ return {
220
+ edge_basis: "deduplicated_directed",
221
+ ...Object.fromEntries(countFields.map((field) => [field, profile[field] ?? 0])),
222
+ ...Object.fromEntries(rateFields.map((field) => [field, profile[field] ?? 0])),
223
+ finding_subjects_by_code: Object.fromEntries(RELATIONSHIP_AUDIT_FINDING_CODES.map((code) => [
224
+ code,
225
+ findingSubjects[code] ?? affectedSubjectsByCode[code] ?? 0,
226
+ ])),
227
+ };
228
+ }
176
229
  /** Decode and cross-check optional graph-composition fields as one coherent unit. */
177
230
  function decodeGraphComposition(edges, edgesByKind, edgeShareByKind, semanticEdgesValue, semanticEdgeShareValue) {
178
231
  const values = [
@@ -225,7 +278,8 @@ function decodeBaseline(raw) {
225
278
  return undefined;
226
279
  if (typeof snapshot.fingerprint !== "string")
227
280
  return undefined;
228
- if (!isNonnegativeCountRecord(snapshot.affected_subjects_by_code)) {
281
+ const affectedSubjectsByCode = snapshot.affected_subjects_by_code;
282
+ if (!isNonnegativeCountRecord(affectedSubjectsByCode)) {
229
283
  return undefined;
230
284
  }
231
285
  if (!isRecord(profile))
@@ -248,12 +302,16 @@ function decodeBaseline(raw) {
248
302
  const composition = decodeGraphComposition(profile.edges, profile.edges_by_kind, profile.edge_share_by_kind, profile.semantic_edges, profile.semantic_edge_share);
249
303
  if (composition === undefined)
250
304
  return undefined;
305
+ const structural = decodeStructuralProfile(profile, affectedSubjectsByCode);
306
+ if (structural === undefined)
307
+ return undefined;
251
308
  const { coverage_by_type = {} } = profile;
252
309
  return {
253
310
  ...snapshot,
254
311
  profile: {
255
312
  ...profile,
256
313
  ...composition,
314
+ ...structural,
257
315
  coverage_by_type,
258
316
  },
259
317
  };
@@ -271,4 +329,4 @@ export async function saveGraphAuditBaseline(pmRoot, snapshot) {
271
329
  await writeFileAtomic(graphAuditBaselinePath(pmRoot), JSON.stringify(snapshot));
272
330
  }
273
331
  //# sourceMappingURL=durable-cache.js.map
274
- //# debugId=4cb399d6-7311-5e2d-a8d2-e0140530ec72
332
+ //# debugId=2f7f14e3-6d41-5f45-a560-ebfbb8aa5828
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @module sdk/graph/governance-contracts
3
+ *
4
+ * Shared, runtime-visible relationship-audit finding identifiers used by the
5
+ * live audit and backward-compatible durable baseline decoder. Keeping the
6
+ * tuple authoritative prevents the public type and persisted zero census from
7
+ * drifting when a finding family is added.
8
+ */
9
+ /** Stable machine-readable relationship audit finding families. */
10
+ export declare const RELATIONSHIP_AUDIT_FINDING_CODES: readonly ["missing_reference_active", "missing_reference_terminal", "legacy_no_blocker_sentinel", "ordering_cycle", "legacy_ordering_cycle", "duplicate_edge", "legacy_duplicate_edge", "duplicate_dependency_row", "legacy_duplicate_dependency_row", "stale_lifecycle_block", "isolated_active_node", "sparse_active_node"];
11
+ /** Machine-readable identifier for one relationship audit finding family. */
12
+ export type RelationshipAuditFindingCode = (typeof RELATIONSHIP_AUDIT_FINDING_CODES)[number];
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @module sdk/graph/governance-contracts
3
+ *
4
+ * Shared, runtime-visible relationship-audit finding identifiers used by the
5
+ * live audit and backward-compatible durable baseline decoder. Keeping the
6
+ * tuple authoritative prevents the public type and persisted zero census from
7
+ * drifting when a finding family is added.
8
+ */
9
+ /** Stable machine-readable relationship audit finding families. */
10
+
11
+ !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]="a2043b27-3dfe-5da8-a10f-d92ff33f3c28")}catch(e){}}();
12
+ export const RELATIONSHIP_AUDIT_FINDING_CODES = [
13
+ "missing_reference_active",
14
+ "missing_reference_terminal",
15
+ "legacy_no_blocker_sentinel",
16
+ "ordering_cycle",
17
+ "legacy_ordering_cycle",
18
+ "duplicate_edge",
19
+ "legacy_duplicate_edge",
20
+ "duplicate_dependency_row",
21
+ "legacy_duplicate_dependency_row",
22
+ "stale_lifecycle_block",
23
+ "isolated_active_node",
24
+ "sparse_active_node",
25
+ ];
26
+ //# sourceMappingURL=governance-contracts.js.map
27
+ //# debugId=a2043b27-3dfe-5da8-a10f-d92ff33f3c28
@@ -14,10 +14,10 @@
14
14
  */
15
15
  import type { RelationshipEdge } from "../relationships.js";
16
16
  import type { WorkspaceRelationshipAssembly } from "./assembly.js";
17
+ import { type RelationshipAuditFindingCode } from "./governance-contracts.js";
18
+ export type { RelationshipAuditFindingCode } from "./governance-contracts.js";
17
19
  /** Severity ladder shared by every relationship audit finding. */
18
20
  export type RelationshipAuditSeverity = "error" | "warning" | "info";
19
- /** Machine-readable identifier for one relationship audit finding family. */
20
- export type RelationshipAuditFindingCode = "missing_reference_active" | "missing_reference_terminal" | "legacy_no_blocker_sentinel" | "ordering_cycle" | "legacy_ordering_cycle" | "duplicate_edge" | "legacy_duplicate_edge" | "duplicate_dependency_row" | "legacy_duplicate_dependency_row" | "stale_lifecycle_block" | "isolated_active_node" | "sparse_active_node";
21
21
  /** One policy-aware relationship audit finding with bounded evidence. */
22
22
  export interface RelationshipAuditFinding {
23
23
  /** Machine-readable finding family identifier. */
@@ -72,6 +72,34 @@ export interface RelationshipCoverageProfile {
72
72
  degree_leq_one_active_nodes: number;
73
73
  /** Deterministic per-type connectivity coverage; untyped nodes bucket under `(untyped)`. */
74
74
  coverage_by_type: Record<string, RelationshipCoverageTypeProfile>;
75
+ /** Undirected cut vertices whose removal increases the component count. */
76
+ articulation_points: number;
77
+ /** Undirected cut edges whose removal disconnects their endpoints. */
78
+ bridge_edges: number;
79
+ /** Milestone nodes whose title explicitly declares an outcome. */
80
+ outcome_nodes: number;
81
+ /** Active non-outcome nodes with a typed hierarchy or implements path to an outcome. */
82
+ active_outcome_reachable_nodes: number;
83
+ /** Active non-outcome nodes without a typed hierarchy or implements path to an outcome. */
84
+ active_outcome_unreachable_nodes: number;
85
+ /** Active typed-outcome reachability expressed as integer basis points. */
86
+ active_outcome_reachability_basis_points: number;
87
+ /** Terminal non-placeholder, non-outcome nodes included in the all-status census. */
88
+ terminal_nodes: number;
89
+ /** Terminal non-outcome nodes with a typed hierarchy or implements path to an outcome. */
90
+ terminal_outcome_reachable_nodes: number;
91
+ /** Terminal non-outcome nodes without a typed hierarchy or implements path to an outcome. */
92
+ terminal_outcome_unreachable_nodes: number;
93
+ /** Terminal typed-outcome reachability expressed as integer basis points. */
94
+ terminal_outcome_reachability_basis_points: number;
95
+ /** All active and terminal non-outcome nodes with a typed path to an outcome. */
96
+ outcome_reachable_nodes: number;
97
+ /** All active and terminal non-outcome nodes without a typed path to an outcome. */
98
+ outcome_unreachable_nodes: number;
99
+ /** All-status typed-outcome reachability expressed as integer basis points. */
100
+ outcome_reachability_basis_points: number;
101
+ /** Affected-subject census containing every known finding code, including zero populations. */
102
+ finding_subjects_by_code: Record<RelationshipAuditFindingCode, number>;
75
103
  }
76
104
  /** Tuning and policy inputs accepted by the relationship audit. */
77
105
  export interface RelationshipAuditOptions {
@@ -1,8 +1,13 @@
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]="996cfe8f-1b9b-534e-9e22-ede6f76d7cac")}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]="ab8a4904-0302-5e36-9963-750b3ba79876")}catch(e){}}();
3
3
  import { isTransitiveKind, orientTransitiveEdge, transitiveFamilyKey, } from "./analytics.js";
4
+ import { findRelationshipCutStructure } from "./centrality.js";
5
+ import { RELATIONSHIP_AUDIT_FINDING_CODES, } from "./governance-contracts.js";
4
6
  /** Default bounded sample size applied to every finding family. */
5
7
  const DEFAULT_MAX_SAMPLE_SIZE = 25;
8
+ /** Canonical item type and title marker that identify explicit outcomes. */
9
+ const OUTCOME_MILESTONE_TYPE = "milestone";
10
+ const OUTCOME_MILESTONE_TITLE_PREFIX = "outcome milestone:";
6
11
  /** Relationship kinds that preserve why work exists or how evidence supports it. */
7
12
  const SEMANTIC_CONTEXT_KINDS = new Set([
8
13
  "discovered_from",
@@ -290,6 +295,104 @@ function collectDuplicateRowFindings(assembly, maxSampleSize) {
290
295
  appendFinding(findings, legacy, maxSampleSize, "legacy_duplicate_dependency_row", "info", "Identical repeated dependency rows on terminal holders are historical storage noise with no scheduling effect.", (count) => `${count} exactly duplicated stored dependency row(s) on terminal holder(s)`, "Leave as history debt or clean up in a dedicated changelog-safe closed-item batch.");
291
296
  return findings;
292
297
  }
298
+ /** Build the reverse typed paths that can carry context toward an outcome. */
299
+ function buildOutcomeReverseIndex(assembly, signal) {
300
+ const reverse = new Map();
301
+ for (const edge of assembly.graph.edges()) {
302
+ signal?.throwIfAborted();
303
+ const definition = assembly.graph.registry().require(edge.kind);
304
+ let oriented;
305
+ if (definition.hierarchy) {
306
+ oriented = orientTransitiveEdge(edge, definition);
307
+ }
308
+ else if (definition.kind === "implements") {
309
+ oriented = { from: edge.source, to: edge.target };
310
+ }
311
+ if (oriented === undefined)
312
+ continue;
313
+ const sources = reverse.get(oriented.to) ?? new Set();
314
+ sources.add(oriented.from);
315
+ reverse.set(oriented.to, sources);
316
+ }
317
+ return reverse;
318
+ }
319
+ /** Expand outcome nodes through every deterministic reverse typed path. */
320
+ function expandOutcomeReachability(outcomes, reverse, signal) {
321
+ const reachable = new Set(outcomes);
322
+ const queue = [...outcomes].sort();
323
+ for (let index = 0; index < queue.length; index += 1) {
324
+ signal?.throwIfAborted();
325
+ for (const source of [...(reverse.get(queue[index]) ?? [])].sort()) {
326
+ if (reachable.has(source))
327
+ continue;
328
+ reachable.add(source);
329
+ queue.push(source);
330
+ }
331
+ }
332
+ return reachable;
333
+ }
334
+ /** Count active and terminal nodes against the resolved outcome-reachable set. */
335
+ function tallyOutcomeReachability(nodeStates, outcomes, reachable, signal) {
336
+ let activeReachable = 0;
337
+ let activeUnreachable = 0;
338
+ let terminal = 0;
339
+ let terminalReachable = 0;
340
+ for (const state of nodeStates.values()) {
341
+ signal?.throwIfAborted();
342
+ if (outcomes.has(state.id))
343
+ continue;
344
+ if (state.missing || state.status === "external")
345
+ continue;
346
+ if (state.terminal) {
347
+ terminal += 1;
348
+ if (reachable.has(state.id))
349
+ terminalReachable += 1;
350
+ continue;
351
+ }
352
+ if (reachable.has(state.id))
353
+ activeReachable += 1;
354
+ else
355
+ activeUnreachable += 1;
356
+ }
357
+ const active = activeReachable + activeUnreachable;
358
+ const terminalUnreachable = terminal - terminalReachable;
359
+ const outcomeReachable = activeReachable + terminalReachable;
360
+ const outcomeUnreachable = activeUnreachable + terminalUnreachable;
361
+ const outcomePopulation = outcomeReachable + outcomeUnreachable;
362
+ return {
363
+ active_outcome_reachable_nodes: activeReachable,
364
+ active_outcome_unreachable_nodes: activeUnreachable,
365
+ active_outcome_reachability_basis_points: active === 0 ? 0 : Math.floor((activeReachable * 10_000) / active),
366
+ terminal_nodes: terminal,
367
+ terminal_outcome_reachable_nodes: terminalReachable,
368
+ terminal_outcome_unreachable_nodes: terminalUnreachable,
369
+ terminal_outcome_reachability_basis_points: terminal === 0 ? 0 : Math.floor((terminalReachable * 10_000) / terminal),
370
+ outcome_reachable_nodes: outcomeReachable,
371
+ outcome_unreachable_nodes: outcomeUnreachable,
372
+ outcome_reachability_basis_points: outcomePopulation === 0
373
+ ? 0
374
+ : Math.floor((outcomeReachable * 10_000) / outcomePopulation),
375
+ };
376
+ }
377
+ /**
378
+ * Count nodes with an explicit typed path to an outcome milestone. Hierarchy
379
+ * edges flow child to parent and `implements` flows implementation to outcome;
380
+ * unrelated association edges deliberately contribute no reachability.
381
+ */
382
+ function profileOutcomeReachability(assembly, nodeStates, signal) {
383
+ const outcomes = new Set(assembly.details
384
+ .filter((detail) => detail.type?.toLowerCase() === OUTCOME_MILESTONE_TYPE &&
385
+ detail.title
386
+ .trim()
387
+ .toLowerCase()
388
+ .startsWith(OUTCOME_MILESTONE_TITLE_PREFIX))
389
+ .map((detail) => detail.id));
390
+ const reachable = expandOutcomeReachability(outcomes, buildOutcomeReverseIndex(assembly, signal), signal);
391
+ return {
392
+ outcome_nodes: outcomes.size,
393
+ ...tallyOutcomeReachability(nodeStates, outcomes, reachable, signal),
394
+ };
395
+ }
293
396
  /** Fold one active node's degree into the aggregate and per-type coverage tallies. */
294
397
  function tallyActiveCoverageNode(tallies, state, degree, exemptIsolates, isolateExemptTypes) {
295
398
  tallies.active += 1;
@@ -316,7 +419,7 @@ function tallyActiveCoverageNode(tallies, state, degree, exemptIsolates, isolate
316
419
  else
317
420
  tallies.sparse.push(state.id);
318
421
  }
319
- function collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExemptTypes, maxSampleSize, edgesByKind) {
422
+ function collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExemptTypes, maxSampleSize, edgesByKind, signal) {
320
423
  const tallies = {
321
424
  active: 0,
322
425
  missing: 0,
@@ -327,6 +430,7 @@ function collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExem
327
430
  byType: new Map(),
328
431
  };
329
432
  for (const id of assembly.graph.nodes()) {
433
+ signal?.throwIfAborted();
330
434
  const state = nodeStates.get(id);
331
435
  /* c8 ignore next -- every graph node originates from assembly details by construction */
332
436
  if (!state)
@@ -346,6 +450,10 @@ function collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExem
346
450
  const edgeCount = assembly.graph.edges().length;
347
451
  const sortedEdgesByKind = Object.fromEntries(Object.entries(edgesByKind).sort(([left], [right]) => left.localeCompare(right)));
348
452
  const semanticEdges = Object.entries(sortedEdgesByKind).reduce((count, [kind, value]) => count + (isSemanticContextKind(kind) ? value : 0), 0);
453
+ const cutStructure = findRelationshipCutStructure(assembly.graph, {
454
+ signal,
455
+ }).value;
456
+ const outcomeReachability = profileOutcomeReachability(assembly, nodeStates, signal);
349
457
  return {
350
458
  findings,
351
459
  profile: {
@@ -364,6 +472,10 @@ function collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExem
364
472
  isolated_active_nodes: tallies.isolated,
365
473
  degree_leq_one_active_nodes: tallies.degreeLeqOne,
366
474
  coverage_by_type: Object.fromEntries([...tallies.byType.entries()].sort(([left], [right]) => left < right ? -1 : 1)),
475
+ articulation_points: cutStructure.articulationPoints.length,
476
+ bridge_edges: cutStructure.bridges.length,
477
+ ...outcomeReachability,
478
+ finding_subjects_by_code: Object.fromEntries(RELATIONSHIP_AUDIT_FINDING_CODES.map((code) => [code, 0])),
367
479
  },
368
480
  };
369
481
  }
@@ -410,14 +522,21 @@ export function auditWorkspaceRelationshipGraph(assembly, options = {}) {
410
522
  options.signal?.throwIfAborted();
411
523
  findings.push(...collectDuplicateEdgeFindings(assembly, nodeStates, maxSampleSize), ...collectDuplicateRowFindings(assembly, maxSampleSize));
412
524
  options.signal?.throwIfAborted();
413
- const coverage = collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExemptTypes, maxSampleSize, edgesByKind);
525
+ const coverage = collectCoverageReport(assembly, nodeStates, exemptIsolates, isolateExemptTypes, maxSampleSize, edgesByKind, options.signal);
414
526
  findings.push(...coverage.findings);
415
527
  findings.sort((left, right) => SEVERITY_RANK[left.severity] - SEVERITY_RANK[right.severity] ||
416
528
  left.code.localeCompare(right.code) ||
417
529
  left.sample[0].localeCompare(right.sample[0]));
530
+ const findingSubjectsByCode = coverage.profile.finding_subjects_by_code;
531
+ for (const finding of findings) {
532
+ findingSubjectsByCode[finding.code] += finding.count;
533
+ }
418
534
  return {
419
535
  findings,
420
- profile: coverage.profile,
536
+ profile: {
537
+ ...coverage.profile,
538
+ finding_subjects_by_code: findingSubjectsByCode,
539
+ },
421
540
  };
422
541
  }
423
542
  /** Subtract two count records, keeping only non-zero signed deltas in sorted key order. */
@@ -491,4 +610,4 @@ export function diffRelationshipAuditSnapshots(baseline, current) {
491
610
  };
492
611
  }
493
612
  //# sourceMappingURL=governance.js.map
494
- //# debugId=996cfe8f-1b9b-534e-9e22-ede6f76d7cac
613
+ //# debugId=ab8a4904-0302-5e36-9963-750b3ba79876
package/dist/sdk/guide.js CHANGED
@@ -4,7 +4,8 @@
4
4
  * Implements the pm guide 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]="9376fbdf-c942-5fa6-9252-92125ae44e73")}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]="27be0fa5-1c6a-53de-a0e8-179aab7c795a")}catch(e){}}();
8
+ import { isFileAbsentError } from "../core/fs/fs-utils.js";
8
9
  import { readFile } from "node:fs/promises";
9
10
  import path from "node:path";
10
11
  import { resolveConfiguredPmPackageRoot, EXIT_CODE, PmCliError, } from "./runtime-primitives.js";
@@ -119,8 +120,7 @@ async function renderGuideDocs(topic, depth, packageRoot) {
119
120
  }
120
121
  }
121
122
  catch (error) {
122
- const code = error?.code;
123
- const missing = code === "ENOENT";
123
+ const missing = isFileAbsentError(error);
124
124
  docs.push({
125
125
  path: doc.path,
126
126
  purpose: doc.purpose,
@@ -277,4 +277,4 @@ export function renderGuideMarkdown(result) {
277
277
  return lines.join("\n");
278
278
  }
279
279
  //# sourceMappingURL=guide.js.map
280
- //# debugId=9376fbdf-c942-5fa6-9252-92125ae44e73
280
+ //# debugId=27be0fa5-1c6a-53de-a0e8-179aab7c795a
@@ -58,6 +58,7 @@ export * from "./compose.js";
58
58
  export * from "./governance/assurance.js";
59
59
  export * from "./governance/assurance-action.js";
60
60
  export * from "./governance/assurance-runtime.js";
61
+ export * from "./governance/assurance-presets.js";
61
62
  export * from "./compile-cache.js";
62
63
  export * from "./environment/project-runtime-compatibility.js";
63
64
  export * from "./environment/source-context.js";
@@ -94,7 +95,7 @@ export { runDeps, type DepsCollapseMode, type DepsFormat, type DepsGraphEdge, ty
94
95
  export * from "./graph/index.js";
95
96
  export { runDocs } from "./docs.js";
96
97
  export { runFiles, runFilesDiscover, runFilesLookup, type FilesDiscoveryCandidate, type FilesLookupItem, type FilesLookupMatch, } from "./files.js";
97
- export { applyPathMigrations, applyStandaloneNote, artifactKey, dedupeLinkedArtifacts, ensureScope, expandAddGlobEntries, normalizeLinkedPath, parseAddEntries, parseAddGlobEntries, parseMigrateEntries, parseRemoveEntries, renameArtifactsResultKey, runLinkedArtifacts, sortLinkedArtifacts, validateLinkedPaths, type AddGlobEntry, type LinkedArtifact, type LinkedArtifactCommandOptions, type LinkedArtifactKindConfig, type LinkedArtifactResult, type LinkedPathValidation, type PathMigration, } from "./linked-artifacts.js";
98
+ export { applyPathMigrations, applyStandaloneNote, artifactKey, assertLinkedArtifactMutationIsUnambiguous, dedupeLinkedArtifacts, ensureScope, expandAddGlobEntries, normalizeLinkedPath, parseAddEntries, parseAddGlobEntries, parseMigrateEntries, parseRemoveEntries, renameArtifactsResultKey, runLinkedArtifacts, sortLinkedArtifacts, validateLinkedPaths, type AddGlobEntry, type LinkedArtifact, type LinkedArtifactCommandOptions, type LinkedArtifactKindConfig, type LinkedArtifactResult, type LinkedPathValidation, type PathMigration, } from "./linked-artifacts.js";
98
99
  export * from "./pagination.js";
99
100
  export * from "./query/item-filter-options.js";
100
101
  export * from "./query/parsers.js";
package/dist/sdk/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * Defines public SDK APIs and package-author helpers for Index.
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]="14672b89-6a87-59a0-8164-6b01a9c91ee1")}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]="8664ab01-dc47-5344-b2d7-9ac315e8a74b")}catch(e){}}();
8
8
  export { PM_COMMAND_VISIBILITY_CONTRACTS, PM_MCP_PROMPT_CONTRACTS, PM_MCP_RESOURCE_CONTRACTS, PM_MCP_TOOL_COMMAND_CONTRACTS, listPmCommandsForTier, listPmMcpToolsForProfile, renderPmCommandVisibilityMarkdown, resolvePmCommandVisibilityTier, } from "./agent-capability-contracts.js";
9
9
  export * from "./agent-session-context.js";
10
10
  export { isErrnoError, limitAnnotationEntries, parseAnnotationTextInput, readAnnotationEntries, normalizeAnnotationTransportOptions, resolveAnnotationInput, resolveAnnotationIndex, runAnnotationCommand, wrapOwnershipConflict, } from "./annotations.js";
@@ -56,6 +56,7 @@ export * from "./compose.js";
56
56
  export * from "./governance/assurance.js";
57
57
  export * from "./governance/assurance-action.js";
58
58
  export * from "./governance/assurance-runtime.js";
59
+ export * from "./governance/assurance-presets.js";
59
60
  export * from "./compile-cache.js";
60
61
  export * from "./environment/project-runtime-compatibility.js";
61
62
  export * from "./environment/source-context.js";
@@ -92,7 +93,7 @@ export { runDeps, } from "./dependencies.js";
92
93
  export * from "./graph/index.js";
93
94
  export { runDocs } from "./docs.js";
94
95
  export { runFiles, runFilesDiscover, runFilesLookup, } from "./files.js";
95
- export { applyPathMigrations, applyStandaloneNote, artifactKey, dedupeLinkedArtifacts, ensureScope, expandAddGlobEntries, normalizeLinkedPath, parseAddEntries, parseAddGlobEntries, parseMigrateEntries, parseRemoveEntries, renameArtifactsResultKey, runLinkedArtifacts, sortLinkedArtifacts, validateLinkedPaths, } from "./linked-artifacts.js";
96
+ export { applyPathMigrations, applyStandaloneNote, artifactKey, assertLinkedArtifactMutationIsUnambiguous, dedupeLinkedArtifacts, ensureScope, expandAddGlobEntries, normalizeLinkedPath, parseAddEntries, parseAddGlobEntries, parseMigrateEntries, parseRemoveEntries, renameArtifactsResultKey, runLinkedArtifacts, sortLinkedArtifacts, validateLinkedPaths, } from "./linked-artifacts.js";
96
97
  export * from "./pagination.js";
97
98
  export * from "./query/item-filter-options.js";
98
99
  export * from "./query/parsers.js";
@@ -150,4 +151,4 @@ export * from "./governance.js";
150
151
  export * from "./query.js";
151
152
  export * from "./testing.js";
152
153
  //# sourceMappingURL=index.js.map
153
- //# debugId=14672b89-6a87-59a0-8164-6b01a9c91ee1
154
+ //# debugId=8664ab01-dc47-5344-b2d7-9ac315e8a74b
@@ -115,6 +115,8 @@ export declare function parseRemoveEntries(raw: string[] | undefined): string[];
115
115
  export declare function parseMigrateEntries(raw: string[] | undefined): PathMigration[];
116
116
  /** Implements apply path migrations for the public runtime surface of this module. */
117
117
  export declare function applyPathMigrations(artifactPath: string, migrations: PathMigration[]): string;
118
+ /** Reject a transaction that resolves the same linked path into both add and remove sets. */
119
+ export declare function assertLinkedArtifactMutationIsUnambiguous(adds: LinkedArtifact[], removes: string[], migrations?: PathMigration[]): void;
118
120
  /** Implements normalize linked path for the public runtime surface of this module. */
119
121
  export declare function normalizeLinkedPath(value: string): string;
120
122
  /** Anchor a local linked path to the project workspace while preserving remote references and absolute paths. */
@@ -4,11 +4,11 @@
4
4
  * Implements the pm linked artifacts 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]="3fe80124-596b-591c-9f0d-fbbc129c6bb4")}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]="585364aa-e5ff-56b6-8276-8f741fbd6be4")}catch(e){}}();
8
8
  import fs from "node:fs/promises";
9
9
  import path from "node:path";
10
10
  import fg from "fast-glob";
11
- import { pathExists } from "../core/fs/fs-utils.js";
11
+ import { isFileAbsentError, pathExists } from "../core/fs/fs-utils.js";
12
12
  import { getActiveExtensionRegistrations } from "../core/extensions/index.js";
13
13
  import { assertNoUnknownCsvKeys, createStdinTokenResolver, looksLikeGenericKeyValueEntry, parseCsvKv, } from "../core/item/parse.js";
14
14
  import { resolveItemTypeRegistry } from "../core/item/type-registry.js";
@@ -179,6 +179,30 @@ export function applyPathMigrations(artifactPath, migrations) {
179
179
  }
180
180
  return next;
181
181
  }
182
+ /** Reject a transaction that resolves the same linked path into both add and remove sets. */
183
+ export function assertLinkedArtifactMutationIsUnambiguous(adds, removes, migrations = []) {
184
+ if (adds.length === 0 || removes.length === 0) {
185
+ return;
186
+ }
187
+ const addedPaths = new Set(adds.map((entry) => applyPathMigrations(entry.path, migrations)));
188
+ const conflicts = [
189
+ ...new Set(removes
190
+ .map((entry) => applyPathMigrations(entry, migrations))
191
+ .filter((entry) => addedPaths.has(entry))),
192
+ ].sort((left, right) => left.localeCompare(right));
193
+ if (conflicts.length === 0) {
194
+ return;
195
+ }
196
+ throw new PmCliError(`Linked artifact mutation cannot add and remove the same normalized path in one transaction: ${conflicts.join(", ")}. Split the replacement into separate commands so each history event has one unambiguous intent.`, EXIT_CODE.USAGE, {
197
+ code: "linked_artifact_mutation_conflict",
198
+ reason: "same_path_added_and_removed",
199
+ required: "Use distinct normalized paths for --add and --remove in one invocation.",
200
+ why: "Conflicting batch intent cannot be applied deterministically without silently discarding metadata or a removal.",
201
+ nextSteps: [
202
+ "Run the removal and addition as separate commands with a --message describing each intent.",
203
+ ],
204
+ });
205
+ }
182
206
  /** Implements normalize linked path for the public runtime surface of this module. */
183
207
  export function normalizeLinkedPath(value) {
184
208
  return value.split(path.sep).join("/");
@@ -293,7 +317,7 @@ export async function validateLinkedPaths(paths, workspaceRoot = process.cwd())
293
317
  if (typeof error === "object" &&
294
318
  error !== null &&
295
319
  "code" in error &&
296
- error.code === "ENOENT") {
320
+ isFileAbsentError(error)) {
297
321
  missingPaths.push(relativePath);
298
322
  continue;
299
323
  }
@@ -384,6 +408,7 @@ export async function runLinkedArtifacts(id, options, global, config) {
384
408
  const adds = applyStandaloneNote([...parsedAdds, ...expandedGlobAdds], options.note, parsedAdds.length > 0 || addGlobs.length > 0);
385
409
  const removes = parseRemoveEntries(resolvedRemoves).map((entry) => anchorLinkedPath(entry, workspaceRoot, invocationRoot));
386
410
  const migrations = parseMigrateEntries(resolvedMigrations);
411
+ assertLinkedArtifactMutationIsUnambiguous(adds, removes, migrations);
387
412
  const shouldMutate = adds.length > 0 || removes.length > 0 || migrations.length > 0;
388
413
  if (!shouldMutate) {
389
414
  const located = await locateItem(pmRoot, id, settings.id_prefix, settings.item_format, typeRegistry.type_to_folder);
@@ -454,4 +479,4 @@ export function renameArtifactsResultKey(result, key) {
454
479
  return out;
455
480
  }
456
481
  //# sourceMappingURL=linked-artifacts.js.map
457
- //# debugId=3fe80124-596b-591c-9f0d-fbbc129c6bb4
482
+ //# debugId=585364aa-e5ff-56b6-8276-8f741fbd6be4