@unbrained/pm-cli 2026.8.21 → 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 (158) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/CHANGELOG.md +16 -0
  3. package/dist/cli/error-guidance.d.ts +9 -4
  4. package/dist/cli/error-guidance.js +16 -15
  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 +153 -153
  8. package/dist/cli-bundle/chunks/{chunk-BKYB45NQ.js → chunk-BWX4SK46.js} +48 -48
  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-LARJJ3RK.js → chunk-MYYI3ZOA.js} +2 -2
  12. package/dist/cli-bundle/chunks/{chunk-BUNIEJNE.js → chunk-MZTZQTMS.js} +2 -2
  13. package/dist/cli-bundle/chunks/{chunk-LOVTQ52Z.js → chunk-QI2CT3IX.js} +2 -2
  14. package/dist/cli-bundle/chunks/chunk-SMWXHMVB.js +35 -0
  15. package/dist/cli-bundle/chunks/{chunk-N3DSV4CH.js → chunk-U6GQ4VMV.js} +6 -6
  16. package/dist/cli-bundle/chunks/{chunk-3AFAUHUE.js → chunk-VMMIL3SI.js} +2 -2
  17. package/dist/cli-bundle/chunks/chunk-WG4STC36.js +5 -0
  18. package/dist/cli-bundle/chunks/{chunk-JSLOFXGA.js → chunk-YBPJAOQQ.js} +2 -2
  19. package/dist/cli-bundle/chunks/{register-list-query-F57EWDEF.js → register-list-query-HZKBQNWW.js} +2 -2
  20. package/dist/cli-bundle/chunks/{register-mutation-7IY2D5KO.js → register-mutation-HTKEEGRD.js} +2 -2
  21. package/dist/cli-bundle/chunks/{register-operations-FALL3YTU.js → register-operations-6EMRWJJY.js} +2 -2
  22. package/dist/cli-bundle/chunks/{register-setup-HXU7IZZD.js → register-setup-QK4OTOXN.js} +2 -2
  23. package/dist/cli-bundle/focused-chunks/{chunk-FJ22HNRP.js → chunk-2ARQGDDW.js} +2 -2
  24. package/dist/cli-bundle/focused-chunks/{chunk-CKKQSJNN.js → chunk-2AZT5WXZ.js} +2 -2
  25. package/dist/cli-bundle/focused-chunks/{chunk-F4YEW5I2.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-FH6DYED3.js → chunk-6S2MO3Q3.js} +2 -2
  29. package/dist/cli-bundle/focused-chunks/{chunk-UZE7XUZK.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-KDNG7TKQ.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-4ERLO7QD.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-ZOSEELYJ.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-2NIY5NKG.js → chunk-PH2OXXVZ.js} +2 -2
  38. package/dist/cli-bundle/focused-chunks/{chunk-YKBKIEAJ.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 +4 -0
  61. package/dist/core/shared/errors.js +2 -2
  62. package/dist/sdk/agent/refusal-reachability.d.ts +1 -1
  63. package/dist/sdk/authoring.d.ts +1 -1
  64. package/dist/sdk/authoring.js +2 -2
  65. package/dist/sdk/cli-contracts/agent-output-contracts.d.ts +77 -0
  66. package/dist/sdk/cli-contracts/agent-output-contracts.js +324 -2
  67. package/dist/sdk/cli-contracts/commander-mutation-options.js +3 -3
  68. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +3 -1
  69. package/dist/sdk/cli-contracts/runtime-contracts.js +4 -3
  70. package/dist/sdk/cli-contracts.d.ts +1 -1
  71. package/dist/sdk/cli-contracts.js +3 -3
  72. package/dist/sdk/extension/install-sources.d.ts +1 -1
  73. package/dist/sdk/extension/install-sources.js +6 -3
  74. package/dist/sdk/extension/output-ownership.d.ts +1 -0
  75. package/dist/sdk/extension/output-ownership.js +3 -2
  76. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +38 -14
  77. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +14 -2
  78. package/dist/sdk/governance/health.d.ts +3 -0
  79. package/dist/sdk/governance/health.js +39 -7
  80. package/dist/sdk/governance/hierarchy-validation.d.ts +29 -0
  81. package/dist/sdk/governance/hierarchy-validation.js +109 -0
  82. package/dist/sdk/governance/validate.d.ts +1 -7
  83. package/dist/sdk/governance/validate.js +47 -99
  84. package/dist/sdk/graph/assembly.d.ts +6 -1
  85. package/dist/sdk/graph/assembly.js +16 -22
  86. package/dist/sdk/graph/governance-contracts.d.ts +1 -1
  87. package/dist/sdk/graph/governance-contracts.js +8 -2
  88. package/dist/sdk/graph/governance.js +46 -2
  89. package/dist/sdk/graph/hierarchy-integrity.d.ts +94 -0
  90. package/dist/sdk/graph/hierarchy-integrity.js +311 -0
  91. package/dist/sdk/graph/index.d.ts +2 -1
  92. package/dist/sdk/graph/index.js +3 -2
  93. package/dist/sdk/graph/remediation.js +32 -2
  94. package/dist/sdk/graph/run.d.ts +31 -2
  95. package/dist/sdk/graph/run.js +80 -31
  96. package/dist/sdk/graph/workspace-relationship-kind-registry.d.ts +8 -0
  97. package/dist/sdk/graph/workspace-relationship-kind-registry.js +28 -0
  98. package/dist/sdk/index.d.ts +2 -2
  99. package/dist/sdk/index.js +3 -3
  100. package/dist/sdk/item-children.js +21 -8
  101. package/dist/sdk/lifecycle/create.js +125 -96
  102. package/dist/sdk/lifecycle/hierarchy-mutation-lock.d.ts +15 -0
  103. package/dist/sdk/lifecycle/hierarchy-mutation-lock.js +25 -0
  104. package/dist/sdk/lifecycle/update.d.ts +2 -0
  105. package/dist/sdk/lifecycle/update.js +171 -83
  106. package/dist/sdk/query/complete-list.d.ts +3 -3
  107. package/dist/sdk/query/complete-list.js +46 -3
  108. package/dist/sdk/query/list.d.ts +4 -3
  109. package/dist/sdk/query/list.js +89 -49
  110. package/dist/sdk/read-output-contracts.d.ts +5 -1
  111. package/dist/sdk/read-output-contracts.js +87 -22
  112. package/dist/sdk/relationship-context.js +3 -4
  113. package/dist/sdk/relationships.js +17 -10
  114. package/dist/sdk/runtime.d.ts +3 -2
  115. package/dist/sdk/runtime.js +3 -2
  116. package/dist/sdk/test/batch.js +13 -5
  117. package/dist/sdk/test/execution.js +10 -2
  118. package/dist/types.d.ts +11 -0
  119. package/dist/types.js +2 -2
  120. package/docs/AGENT_UX_CONTRACTS.md +20 -4
  121. package/docs/COMMANDS.md +29 -14
  122. package/docs/DEPENDENCY_KIND_CONTRACT.md +31 -3
  123. package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +98 -0
  124. package/docs/EXTENSIONS.md +2 -1
  125. package/docs/README.md +1 -0
  126. package/docs/READ_OUTPUT_CONTRACTS.md +9 -2
  127. package/docs/RELATIONSHIP_GRAPH.md +6 -3
  128. package/docs/TESTING.md +15 -0
  129. package/marketplace.json +2 -2
  130. package/package.json +1 -1
  131. package/packages/pm-beads/package.json +1 -1
  132. package/packages/pm-calendar/package.json +1 -1
  133. package/packages/pm-command-kit/package.json +1 -1
  134. package/packages/pm-digital-twin/package.json +1 -1
  135. package/packages/pm-governance-audit/package.json +1 -1
  136. package/packages/pm-guide-shell/package.json +1 -1
  137. package/packages/pm-kanban/package.json +1 -1
  138. package/packages/pm-lifecycle-hooks/package.json +1 -1
  139. package/packages/pm-linked-test-adapters/package.json +1 -1
  140. package/packages/pm-search-advanced/package.json +1 -1
  141. package/packages/pm-templates/package.json +1 -1
  142. package/packages/pm-todos/package.json +1 -1
  143. package/packages/pm-vcs/package.json +1 -1
  144. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  145. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  146. package/sdk/public-surface.json +593 -35
  147. package/dist/cli-bundle/chunks/chunk-2MA6ZQVZ.js +0 -197
  148. package/dist/cli-bundle/chunks/chunk-7VHZS727.js +0 -5
  149. package/dist/cli-bundle/chunks/chunk-OCLPLFAY.js +0 -35
  150. package/dist/cli-bundle/chunks/chunk-S4IRYKBU.js +0 -13
  151. package/dist/cli-bundle/focused-chunks/chunk-7WZRLCYF.js +0 -50
  152. package/dist/cli-bundle/focused-chunks/chunk-EEFKYMDR.js +0 -16
  153. package/dist/cli-bundle/focused-chunks/chunk-F2A56DHV.js +0 -8
  154. package/dist/cli-bundle/focused-chunks/chunk-FV5ACOK7.js +0 -2
  155. package/dist/cli-bundle/focused-chunks/chunk-JEAVFOWM.js +0 -2
  156. package/dist/cli-bundle/focused-chunks/chunk-NJ63LOP6.js +0 -155
  157. package/dist/cli-bundle/focused-chunks/chunk-NXRTQ7HI.js +0 -2
  158. package/dist/cli-bundle/focused-chunks/chunk-TJ7EMJ46.js +0 -4
@@ -4,13 +4,16 @@
4
4
  * Implements the pm create 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]="a10348fe-746d-5dc7-8cd4-30453c602a3f")}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]="4dff80ab-acfc-5f81-a546-3f19629d97be")}catch(e){}}();
8
8
  import { assertInitializedTracker } from "../environment/tracker-preflight.js";
9
- import { removeFileIfExists, writeFileAtomic, appendHistoryEntry, createHistoryEntry, generateItemId, normalizeItemId, canonicalDocument, normalizeItemMetadata, serializeItemDocument, assertParentReferenceIsNotSelf, isPlaceholderReferenceToken, normalizeParentReferenceValue, validateMissingParentReference, validateSprintOrReleaseValue, assertNoUnknownCsvKeys, createStdinTokenResolver, looksLikeGenericKeyValueEntry, mergeAdditiveTags, parseCsvKv, parseOptionalNonNegativeInteger, parseOptionalNumber, parseTags, resolvePriority, getFocusedItem, normalizeStatusInput, canonicalizeCommandOptionKey, commandOptionFlagLabel, resolveItemTypeRegistry, resolveCommandOptionPolicyState, resolveTypeDefinition, resolveTypeName, validateTypeOptions, acquireLock, printError, buildInvalidTypeError, resolveTypeSynonym, collectRuntimeCreateFieldValues, resolveItemTypesFilePath, resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, EXIT_CODE, ITEM_METADATA_KEY_ORDER, PmCliError, nowIso, resolveIsoOrRelative, getActiveExtensionRegistrations, projectAfterCommandItemSnapshot, recordAfterCommandAffectedItem, runActiveCommandHandler, runActiveBeforeMutationHooks, runActiveOnWriteHooks, collectRegisteredItemFieldNames, applyRegisteredItemFieldDefaultsAndValidation, parseRegisteredItemFieldAssignments, listAllItemMetadataLight, locateItem, createMutationGuardSdk, getHistoryPath, getItemPath, resolvePmRoot, readSettings, resolveAuthor, } from "../runtime-primitives.js";
9
+ import { removeFileIfExists, writeFileAtomic, appendHistoryEntry, createHistoryEntry, generateItemId, normalizeItemId, canonicalDocument, normalizeItemMetadata, serializeItemDocument, assertParentReferenceIsNotSelf, isPlaceholderReferenceToken, normalizeParentReferenceValue, validateMissingParentReference, validateSprintOrReleaseValue, assertNoUnknownCsvKeys, createStdinTokenResolver, looksLikeGenericKeyValueEntry, mergeAdditiveTags, parseCsvKv, parseOptionalNonNegativeInteger, parseOptionalNumber, parseTags, resolvePriority, getFocusedItem, normalizeStatusInput, isTerminalStatus, canonicalizeCommandOptionKey, commandOptionFlagLabel, resolveItemTypeRegistry, resolveCommandOptionPolicyState, resolveTypeDefinition, resolveTypeName, validateTypeOptions, acquireLock, printError, buildInvalidTypeError, resolveTypeSynonym, collectRuntimeCreateFieldValues, resolveItemTypesFilePath, resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, EXIT_CODE, ITEM_METADATA_KEY_ORDER, PmCliError, nowIso, resolveIsoOrRelative, getActiveExtensionRegistrations, projectAfterCommandItemSnapshot, recordAfterCommandAffectedItem, runActiveCommandHandler, runActiveBeforeMutationHooks, runActiveOnWriteHooks, collectRegisteredItemFieldNames, applyRegisteredItemFieldDefaultsAndValidation, parseRegisteredItemFieldAssignments, listAllItemMetadataLight, locateItem, createMutationGuardSdk, getHistoryPath, getItemPath, resolvePmRoot, readSettings, resolveAuthor, } from "../runtime-primitives.js";
10
10
  import { requireTerminalReasonWithRecovery } from "../lifecycle-policy.js";
11
11
  import { evaluateSimilarityGovernance, similarityAdvisoryWarnings, } from "../similarity.js";
12
12
  import { acquireItemMetadataDerivedIndexLock, refreshItemMetadataDerivedIndex, } from "../item-metadata-index.js";
13
13
  import { collectNewOrderingCycleWarnings } from "../graph/mutation-advisory.js";
14
+ import { assertHierarchyMutationAllowed } from "../graph/hierarchy-integrity.js";
15
+ import { resolveWorkspaceRelationshipKindRegistry } from "../graph/assembly.js";
16
+ import { acquireHierarchyMutationLock } from "./hierarchy-mutation-lock.js";
14
17
  import { normalizeRiskInput, normalizeSeverityInput, parseConfidenceInput, parseRegressionInput, } from "./metadata-normalizers.js";
15
18
  import { applyLegacyNoneCollectionNormalizers, createLegacyNoneCollectionNormalizers, assertNoLegacyNoneToken, assertNoLegacyNoneTokens, isLegacyNoneToken, } from "./legacy-none-tokens.js";
16
19
  import { suggestNextLifecycleTransition, } from "./lifecycle-transitions.js";
@@ -1440,114 +1443,140 @@ async function writeCreatedItem(params) {
1440
1443
  const { pmRoot, type, id, settings, typeRegistry, author, extensionFieldNames, afterDocument, beforeDocument, historyMessage, changedFields, nowValue, similarityCandidate, allowDuplicate, } = params;
1441
1444
  const itemPath = getItemPath(pmRoot, type, id, settings.item_format, typeRegistry.type_to_folder);
1442
1445
  const historyPath = getHistoryPath(pmRoot, id);
1443
- const lockRelease = await acquireLock(pmRoot, id, settings.locks.ttl_seconds, author, false, settings.governance.force_required_for_stale_lock, settings.locks.wait_ms);
1446
+ const relationshipRegistry = resolveWorkspaceRelationshipKindRegistry();
1447
+ const hierarchyMutationRequired = afterDocument.metadata.parent !== undefined ||
1448
+ (afterDocument.metadata.dependencies ?? []).some((dependency) => relationshipRegistry.resolve(dependency.kind)?.hierarchy);
1449
+ const hierarchyLockRelease = await acquireHierarchyMutationLock({
1450
+ pmRoot,
1451
+ author,
1452
+ ttlSeconds: settings.locks.ttl_seconds,
1453
+ waitMs: settings.locks.wait_ms,
1454
+ required: hierarchyMutationRequired,
1455
+ });
1456
+ let hierarchyLockHeld = hierarchyMutationRequired;
1444
1457
  let hookWarnings = [];
1445
1458
  try {
1446
- const graphBeforeCreate = afterDocument.metadata.dependencies &&
1447
- afterDocument.metadata.dependencies.length > 0
1448
- ? await listAllItemMetadataLight(pmRoot, settings.item_format, typeRegistry.type_to_folder, undefined, settings.schema)
1449
- : undefined;
1450
- const existing = await locateItem(pmRoot, id, settings.id_prefix, settings.item_format, typeRegistry.type_to_folder);
1451
- if (existing) {
1452
- throw new PmCliError(`Item "${id}" already exists`, EXIT_CODE.CONFLICT);
1453
- }
1454
- await runActiveBeforeMutationHooks({
1455
- pm_root: pmRoot,
1456
- operation: "create",
1457
- before: null,
1458
- after: afterDocument,
1459
- changed_fields: changedFields,
1460
- sdk: createMutationGuardSdk({
1461
- pmRoot,
1462
- settings,
1463
- typeToFolder: typeRegistry.type_to_folder,
1464
- }),
1465
- });
1466
- const releaseDerivedIndexLock = await acquireItemMetadataDerivedIndexLock(pmRoot, author, {
1467
- required: settings.governance.duplicate_detection_mode === "strict" &&
1468
- allowDuplicate !== true,
1469
- });
1470
- let derivedIndexWarnings = [];
1459
+ const lockRelease = await acquireLock(pmRoot, id, settings.locks.ttl_seconds, author, false, settings.governance.force_required_for_stale_lock, settings.locks.wait_ms);
1471
1460
  try {
1472
- if (settings.governance.duplicate_detection_mode === "strict" &&
1473
- allowDuplicate !== true) {
1474
- await evaluateSimilarityGovernance(similarityCandidate, {
1461
+ const graphBeforeCreate = afterDocument.metadata.parent !== undefined ||
1462
+ (afterDocument.metadata.dependencies !== undefined &&
1463
+ afterDocument.metadata.dependencies.length > 0)
1464
+ ? await listAllItemMetadataLight(pmRoot, settings.item_format, typeRegistry.type_to_folder, undefined, settings.schema)
1465
+ : undefined;
1466
+ const existing = await locateItem(pmRoot, id, settings.id_prefix, settings.item_format, typeRegistry.type_to_folder);
1467
+ if (existing) {
1468
+ throw new PmCliError(`Item "${id}" already exists`, EXIT_CODE.CONFLICT);
1469
+ }
1470
+ if (graphBeforeCreate) {
1471
+ const statusRegistry = resolveRuntimeStatusRegistry(settings.schema);
1472
+ assertHierarchyMutationAllowed(graphBeforeCreate, [...graphBeforeCreate, afterDocument.metadata], id, (status) => isTerminalStatus(status, statusRegistry), relationshipRegistry);
1473
+ }
1474
+ await runActiveBeforeMutationHooks({
1475
+ pm_root: pmRoot,
1476
+ operation: "create",
1477
+ before: null,
1478
+ after: afterDocument,
1479
+ changed_fields: changedFields,
1480
+ sdk: createMutationGuardSdk({
1475
1481
  pmRoot,
1476
- mode: "strict",
1477
- threshold: settings.governance.duplicate_detection_threshold,
1478
- limit: settings.governance.duplicate_detection_limit,
1479
- allowDuplicate: false,
1482
+ settings,
1483
+ typeToFolder: typeRegistry.type_to_folder,
1484
+ }),
1485
+ });
1486
+ const releaseDerivedIndexLock = await acquireItemMetadataDerivedIndexLock(pmRoot, author, {
1487
+ required: settings.governance.duplicate_detection_mode === "strict" &&
1488
+ allowDuplicate !== true,
1489
+ });
1490
+ let derivedIndexWarnings = [];
1491
+ try {
1492
+ if (settings.governance.duplicate_detection_mode === "strict" &&
1493
+ allowDuplicate !== true) {
1494
+ await evaluateSimilarityGovernance(similarityCandidate, {
1495
+ pmRoot,
1496
+ mode: "strict",
1497
+ threshold: settings.governance.duplicate_detection_threshold,
1498
+ limit: settings.governance.duplicate_detection_limit,
1499
+ allowDuplicate: false,
1500
+ });
1501
+ }
1502
+ await writeFileAtomic(itemPath, serializeItemDocument(afterDocument, {
1503
+ format: settings.item_format,
1504
+ schema: settings.schema,
1505
+ extensionFieldNames,
1506
+ }));
1507
+ try {
1508
+ const entry = createHistoryEntry({
1509
+ nowIso: nowValue,
1510
+ author,
1511
+ op: "create",
1512
+ before: beforeDocument,
1513
+ after: afterDocument,
1514
+ message: historyMessage,
1515
+ });
1516
+ await appendHistoryEntry(historyPath, entry);
1517
+ }
1518
+ catch (error) {
1519
+ await removeFileIfExists(itemPath);
1520
+ throw error;
1521
+ }
1522
+ if (hierarchyLockHeld) {
1523
+ await hierarchyLockRelease();
1524
+ hierarchyLockHeld = false;
1525
+ }
1526
+ derivedIndexWarnings = await refreshItemMetadataDerivedIndex({
1527
+ pmRoot,
1528
+ preferredFormat: settings.item_format,
1529
+ typeToFolder: typeRegistry.type_to_folder,
1530
+ schema: settings.schema,
1531
+ itemPath,
1532
+ document: afterDocument,
1480
1533
  });
1481
1534
  }
1482
- await writeFileAtomic(itemPath, serializeItemDocument(afterDocument, {
1483
- format: settings.item_format,
1484
- schema: settings.schema,
1485
- extensionFieldNames,
1486
- }));
1487
- try {
1488
- const entry = createHistoryEntry({
1489
- nowIso: nowValue,
1490
- author,
1535
+ finally {
1536
+ await releaseDerivedIndexLock();
1537
+ }
1538
+ hookWarnings = [
1539
+ ...(graphBeforeCreate
1540
+ ? collectNewOrderingCycleWarnings(graphBeforeCreate, [...graphBeforeCreate, afterDocument.metadata], id)
1541
+ : []),
1542
+ ...derivedIndexWarnings,
1543
+ ...(await runActiveOnWriteHooks({
1544
+ path: itemPath,
1545
+ scope: "project",
1491
1546
  op: "create",
1547
+ item_id: afterDocument.metadata.id,
1548
+ item_type: afterDocument.metadata.type,
1492
1549
  before: beforeDocument,
1493
1550
  after: afterDocument,
1494
- message: historyMessage,
1495
- });
1496
- await appendHistoryEntry(historyPath, entry);
1497
- }
1498
- catch (error) {
1499
- await removeFileIfExists(itemPath);
1500
- throw error;
1501
- }
1502
- derivedIndexWarnings = await refreshItemMetadataDerivedIndex({
1503
- pmRoot,
1504
- preferredFormat: settings.item_format,
1505
- typeToFolder: typeRegistry.type_to_folder,
1506
- schema: settings.schema,
1507
- itemPath,
1508
- document: afterDocument,
1551
+ changed_fields: changedFields,
1552
+ })),
1553
+ ...(await runActiveOnWriteHooks({
1554
+ path: historyPath,
1555
+ scope: "project",
1556
+ op: "create:history",
1557
+ item_id: afterDocument.metadata.id,
1558
+ item_type: afterDocument.metadata.type,
1559
+ before: beforeDocument,
1560
+ after: afterDocument,
1561
+ changed_fields: changedFields,
1562
+ })),
1563
+ ];
1564
+ recordAfterCommandAffectedItem({
1565
+ id: afterDocument.metadata.id,
1566
+ op: "create",
1567
+ item_type: afterDocument.metadata.type,
1568
+ status: afterDocument.metadata.status,
1569
+ current: projectAfterCommandItemSnapshot(afterDocument.metadata, changedFields),
1570
+ changed_fields: changedFields,
1509
1571
  });
1510
1572
  }
1511
1573
  finally {
1512
- await releaseDerivedIndexLock();
1574
+ await lockRelease();
1513
1575
  }
1514
- hookWarnings = [
1515
- ...(graphBeforeCreate
1516
- ? collectNewOrderingCycleWarnings(graphBeforeCreate, [...graphBeforeCreate, afterDocument.metadata], id)
1517
- : []),
1518
- ...derivedIndexWarnings,
1519
- ...(await runActiveOnWriteHooks({
1520
- path: itemPath,
1521
- scope: "project",
1522
- op: "create",
1523
- item_id: afterDocument.metadata.id,
1524
- item_type: afterDocument.metadata.type,
1525
- before: beforeDocument,
1526
- after: afterDocument,
1527
- changed_fields: changedFields,
1528
- })),
1529
- ...(await runActiveOnWriteHooks({
1530
- path: historyPath,
1531
- scope: "project",
1532
- op: "create:history",
1533
- item_id: afterDocument.metadata.id,
1534
- item_type: afterDocument.metadata.type,
1535
- before: beforeDocument,
1536
- after: afterDocument,
1537
- changed_fields: changedFields,
1538
- })),
1539
- ];
1540
- recordAfterCommandAffectedItem({
1541
- id: afterDocument.metadata.id,
1542
- op: "create",
1543
- item_type: afterDocument.metadata.type,
1544
- status: afterDocument.metadata.status,
1545
- current: projectAfterCommandItemSnapshot(afterDocument.metadata, changedFields),
1546
- changed_fields: changedFields,
1547
- });
1548
1576
  }
1549
1577
  finally {
1550
- await lockRelease();
1578
+ if (hierarchyLockHeld)
1579
+ await hierarchyLockRelease();
1551
1580
  }
1552
1581
  return hookWarnings;
1553
1582
  }
@@ -1886,4 +1915,4 @@ export const _testOnlyCreateCommand = {
1886
1915
  typeOptionExampleValue,
1887
1916
  };
1888
1917
  //# sourceMappingURL=create.js.map
1889
- //# debugId=a10348fe-746d-5dc7-8cd4-30453c602a3f
1918
+ //# debugId=4dff80ab-acfc-5f81-a546-3f19629d97be
@@ -0,0 +1,15 @@
1
+ /** Inputs for the internal workspace-wide hierarchy mutation lock. */
2
+ export interface HierarchyMutationLockOptions {
3
+ /** Tracker root whose hierarchy is being changed. */
4
+ pmRoot: string;
5
+ /** Principal recorded as the lock owner. */
6
+ author: string;
7
+ /** Tracker-configured stale-lock lifetime. */
8
+ ttlSeconds: number;
9
+ /** Tracker-configured bounded lock wait. */
10
+ waitMs: number;
11
+ /** Whether this mutation can add hierarchy evidence. */
12
+ required: boolean;
13
+ }
14
+ /** Acquire the shared hierarchy writer lock, or return a no-op release. */
15
+ export declare function acquireHierarchyMutationLock(options: HierarchyMutationLockOptions): Promise<() => Promise<void>>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @module sdk/lifecycle/hierarchy-mutation-lock
3
+ *
4
+ * Serializes hierarchy-affecting create and update transactions so each
5
+ * before/after integrity decision is made from a fresh workspace snapshot.
6
+ */
7
+
8
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="39a36d42-29b1-5f0f-a8b2-f3bfc0ef78c2")}catch(e){}}();
9
+ import { acquireLock } from "../../core/lock/lock.js";
10
+ const HIERARCHY_MUTATION_LOCK_ID = "hierarchy-integrity";
11
+ /** Acquire the shared hierarchy writer lock, or return a no-op release. */
12
+ export async function acquireHierarchyMutationLock(options) {
13
+ const release = options.required
14
+ ? await acquireLock(options.pmRoot, HIERARCHY_MUTATION_LOCK_ID, options.ttlSeconds, options.author, false, false, options.waitMs)
15
+ : async () => { };
16
+ let released = false;
17
+ return async () => {
18
+ if (released)
19
+ return;
20
+ released = true;
21
+ await release();
22
+ };
23
+ }
24
+ //# sourceMappingURL=hierarchy-mutation-lock.js.map
25
+ //# debugId=39a36d42-29b1-5f0f-a8b2-f3bfc0ef78c2
@@ -121,6 +121,8 @@ interface DependencyRemovalSelector {
121
121
  id: string;
122
122
  kind?: (typeof DEPENDENCY_KIND_VALUES)[number];
123
123
  source_kind?: string;
124
+ author?: string;
125
+ created_at?: string;
124
126
  }
125
127
  /** Parse dependency additions into their canonical storage representation. */
126
128
  export declare function parseDependencyAdditions(raw: string[] | undefined, prefix: string, nowIso: string, fallbackAuthor: string): ParsedDependencyUpdates;