@unbrained/pm-cli 2026.11.2 → 2026.11.4

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 (242) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +24 -0
  3. package/dist/cli/error-guidance.d.ts +23 -35
  4. package/dist/cli/error-guidance.js +4 -3
  5. package/dist/cli/expected-revisions.d.ts +55 -0
  6. package/dist/cli/expected-revisions.js +2 -0
  7. package/dist/cli/main.js +2 -2
  8. package/dist/cli/runtime/field-route-retry.d.ts +15 -0
  9. package/dist/cli/runtime/field-route-retry.js +2 -0
  10. package/dist/cli/runtime/invocation-options.js +1 -1
  11. package/dist/cli-bundle/bundle-manifest.json +1 -1
  12. package/dist/cli-bundle/chunks/{chunk-3A4NVHYS.js → chunk-2GW662DP.js} +2 -2
  13. package/dist/cli-bundle/chunks/chunk-3OXQGGRD.js +115 -0
  14. package/dist/cli-bundle/chunks/chunk-5BVZ32G7.js +2 -0
  15. package/dist/cli-bundle/chunks/chunk-5S6RT5LX.js +9 -0
  16. package/dist/cli-bundle/chunks/chunk-5Z6LWFDL.js +31 -0
  17. package/dist/cli-bundle/chunks/{chunk-RGHLQGEX.js → chunk-6T2V3UIK.js} +2 -2
  18. package/dist/cli-bundle/chunks/{chunk-JRXD7SIL.js → chunk-7PGNAHNW.js} +2 -2
  19. package/dist/cli-bundle/chunks/chunk-7RCI7AAA.js +20 -0
  20. package/dist/cli-bundle/chunks/chunk-AQ5UHHQS.js +2 -0
  21. package/dist/cli-bundle/chunks/chunk-BK2XAQVC.js +2 -0
  22. package/dist/cli-bundle/chunks/{chunk-ABFFRQRO.js → chunk-BRIPGUAO.js} +2 -2
  23. package/dist/cli-bundle/chunks/chunk-BWAXA6S4.js +6 -0
  24. package/dist/cli-bundle/chunks/{chunk-HOGKWJU5.js → chunk-CERNIZLB.js} +66 -66
  25. package/dist/cli-bundle/chunks/chunk-DSCFJTHB.js +122 -0
  26. package/dist/cli-bundle/chunks/{chunk-VEOFWE32.js → chunk-L4BKTPJ6.js} +2 -2
  27. package/dist/cli-bundle/chunks/{chunk-NGRPD3ZO.js → chunk-NPEDFOVQ.js} +2 -2
  28. package/dist/cli-bundle/chunks/{chunk-J3JM36EH.js → chunk-O4ZLEN4T.js} +2 -2
  29. package/dist/cli-bundle/chunks/{chunk-533L6D2N.js → chunk-ODMJ3HIB.js} +3 -3
  30. package/dist/cli-bundle/chunks/{chunk-KJLGBLR3.js → chunk-QN7VCOUU.js} +2 -2
  31. package/dist/cli-bundle/chunks/chunk-QQHMNUZT.js +2 -0
  32. package/dist/cli-bundle/chunks/{chunk-D52QQ7LP.js → chunk-RSAN2YUU.js} +2 -2
  33. package/dist/cli-bundle/chunks/chunk-SRDO2NJU.js +2 -0
  34. package/dist/cli-bundle/chunks/chunk-T56MB6SF.js +2 -0
  35. package/dist/cli-bundle/chunks/chunk-TX2W6G37.js +3 -0
  36. package/dist/cli-bundle/chunks/{chunk-GK2CHAT3.js → chunk-UJMQP2HP.js} +2 -2
  37. package/dist/cli-bundle/chunks/{indexed-receipt-blobs-IEJ2QOW3.js → indexed-receipt-blobs-I6RQGD6Y.js} +2 -2
  38. package/dist/cli-bundle/chunks/item-revision-UAZOBP2Q.js +2 -0
  39. package/dist/cli-bundle/chunks/item-transaction-N5F4LXYV.js +2 -0
  40. package/dist/cli-bundle/chunks/mutation-admission-QZQI2NN5.js +2 -0
  41. package/dist/cli-bundle/chunks/{register-list-query-NZTK3AXA.js → register-list-query-P3NOKQUA.js} +2 -2
  42. package/dist/cli-bundle/chunks/{register-mutation-2OFAMOVH.js → register-mutation-A6I5K5N6.js} +2 -2
  43. package/dist/cli-bundle/chunks/register-operations-SPKB3TNM.js +2 -0
  44. package/dist/cli-bundle/chunks/register-setup-ZZRHJ4IS.js +2 -0
  45. package/dist/cli-bundle/chunks/{settlement-hook-UTCEZBFT.js → settlement-hook-JHXLUBEN.js} +2 -2
  46. package/dist/cli-bundle/chunks/{stage-VLI4OBVX.js → stage-L3T725DS.js} +2 -2
  47. package/dist/cli-bundle/focused-chunks/chunk-5NGNO54M.js +44 -0
  48. package/dist/cli-bundle/focused-chunks/{chunk-PCCZ72C3.js → chunk-A2246ZM7.js} +54 -54
  49. package/dist/cli-bundle/focused-chunks/chunk-B6U44WPW.js +2 -0
  50. package/dist/cli-bundle/focused-chunks/chunk-BAW3DGQO.js +91 -0
  51. package/dist/cli-bundle/focused-chunks/chunk-BHNY3KPJ.js +2 -0
  52. package/dist/cli-bundle/focused-chunks/chunk-C3O6JJPO.js +2 -0
  53. package/dist/cli-bundle/focused-chunks/{chunk-745IDMTD.js → chunk-C7UX2ZI3.js} +2 -2
  54. package/dist/cli-bundle/focused-chunks/chunk-CBG67HUP.js +23 -0
  55. package/dist/cli-bundle/focused-chunks/{chunk-NJFMG3IK.js → chunk-CO2DNPH7.js} +2 -2
  56. package/dist/cli-bundle/focused-chunks/chunk-CXTDEQ3N.js +8 -0
  57. package/dist/cli-bundle/focused-chunks/chunk-FEPE2CE4.js +2 -0
  58. package/dist/cli-bundle/focused-chunks/chunk-FFO7RBLN.js +2 -0
  59. package/dist/cli-bundle/focused-chunks/{chunk-QNXXOFLQ.js → chunk-FXFDVM5O.js} +2 -2
  60. package/dist/cli-bundle/focused-chunks/{chunk-QVFE5LIX.js → chunk-G6ERMFJ5.js} +2 -2
  61. package/dist/cli-bundle/focused-chunks/chunk-I5LGPUWH.js +2 -0
  62. package/dist/cli-bundle/focused-chunks/{chunk-MQVBWFJF.js → chunk-IDAYTYNN.js} +2 -2
  63. package/dist/cli-bundle/focused-chunks/chunk-J3YOATXR.js +80 -0
  64. package/dist/cli-bundle/focused-chunks/{chunk-3UD6F2KQ.js → chunk-J6FDCAMH.js} +2 -2
  65. package/dist/cli-bundle/focused-chunks/chunk-J7M52SCZ.js +2 -0
  66. package/dist/cli-bundle/focused-chunks/chunk-JQS7TYQ6.js +12 -0
  67. package/dist/cli-bundle/focused-chunks/chunk-MEJKELWC.js +26 -0
  68. package/dist/cli-bundle/focused-chunks/chunk-PMKR4MJI.js +2 -0
  69. package/dist/cli-bundle/focused-chunks/chunk-PNPYQDHU.js +2 -0
  70. package/dist/cli-bundle/focused-chunks/chunk-Q4OIRSKL.js +2 -0
  71. package/dist/cli-bundle/focused-chunks/{chunk-I4Z2SCV5.js → chunk-QEVJ3Y67.js} +2 -2
  72. package/dist/cli-bundle/focused-chunks/{chunk-Q23K6WLV.js → chunk-SDLIUZEL.js} +2 -2
  73. package/dist/cli-bundle/focused-chunks/chunk-TFYTTDAK.js +2 -0
  74. package/dist/cli-bundle/focused-chunks/chunk-W3CSX6GI.js +3 -0
  75. package/dist/cli-bundle/focused-chunks/{chunk-B6OOKKOX.js → chunk-Y5GOUUYJ.js} +3 -3
  76. package/dist/cli-bundle/focused-chunks/{indexed-receipt-blobs-FT3KF6VJ.js → indexed-receipt-blobs-7XGVHYAO.js} +2 -2
  77. package/dist/cli-bundle/focused-chunks/item-revision-L6GVT42D.js +2 -0
  78. package/dist/cli-bundle/focused-chunks/item-transaction-GYGP264N.js +2 -0
  79. package/dist/cli-bundle/focused-chunks/mutation-admission-UWTH56OD.js +2 -0
  80. package/dist/cli-bundle/focused-chunks/{settlement-hook-KMIBD4F2.js → settlement-hook-H56537UV.js} +2 -2
  81. package/dist/cli-bundle/focused-chunks/{stage-6B3O2GZ6.js → stage-WRSNJ7VI.js} +2 -2
  82. package/dist/cli-bundle/main.js +30 -29
  83. package/dist/cli-bundle/sdk-authoring.js +1 -1
  84. package/dist/cli-bundle/sdk-contracts.js +5 -5
  85. package/dist/cli-bundle/sdk-core.js +1 -1
  86. package/dist/cli-bundle/sdk-governance.js +1 -1
  87. package/dist/cli-bundle/sdk-graph.js +1 -1
  88. package/dist/cli-bundle/sdk-merge.js +57 -57
  89. package/dist/cli-bundle/sdk-query.js +1 -1
  90. package/dist/cli-bundle/sdk-runtime.js +1 -1
  91. package/dist/cli-bundle/sdk-testing.js +1 -1
  92. package/dist/cli-bundle/sdk.js +11 -11
  93. package/dist/core/config/positional-value.d.ts +1 -1
  94. package/dist/core/config/positional-value.js +1 -1
  95. package/dist/core/extensions/extension-hook-runtime.js +1 -1
  96. package/dist/core/extensions/item-fields.d.ts +1 -1
  97. package/dist/core/extensions/item-fields.js +1 -1
  98. package/dist/core/extensions/reserved-host-flags.js +1 -1
  99. package/dist/core/history/history-rewrite.js +1 -1
  100. package/dist/core/schema/runtime-field-values.d.ts +30 -0
  101. package/dist/core/schema/runtime-field-values.js +1 -1
  102. package/dist/core/sentry/helpers.js +1 -1
  103. package/dist/core/sentry/instrument.js +1 -1
  104. package/dist/core/shared/command-types.d.ts +7 -0
  105. package/dist/core/shared/error-details.d.ts +98 -0
  106. package/dist/core/shared/error-details.js +2 -0
  107. package/dist/core/shared/errors.d.ts +37 -0
  108. package/dist/core/shared/errors.js +1 -1
  109. package/dist/core/store/item-mutation-precondition.d.ts +70 -6
  110. package/dist/core/store/item-mutation-precondition.js +1 -1
  111. package/dist/core/store/item-store.js +1 -1
  112. package/dist/core/store/settings-validator.js +1 -1
  113. package/dist/core/store/settings.js +1 -1
  114. package/dist/mcp/server.js +2 -2
  115. package/dist/sdk/cli-contracts/bootstrap-command-scanner.js +1 -1
  116. package/dist/sdk/cli-contracts/completeness.js +1 -1
  117. package/dist/sdk/cli-contracts/enum-contracts.d.ts +11 -0
  118. package/dist/sdk/cli-contracts/enum-contracts.js +1 -1
  119. package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +1 -1
  120. package/dist/sdk/cli-contracts/registration-helpers.js +1 -1
  121. package/dist/sdk/cli-contracts/tool-parameter-tables.js +1 -1
  122. package/dist/sdk/cli-contracts/tool-schema.js +1 -1
  123. package/dist/sdk/cli-program.js +1 -1
  124. package/dist/sdk/config.d.ts +1 -1
  125. package/dist/sdk/config.js +1 -1
  126. package/dist/sdk/environment/project-runtime-compatibility.js +1 -1
  127. package/dist/sdk/errors.d.ts +6 -2
  128. package/dist/sdk/errors.js +1 -1
  129. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1 -1
  130. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -1
  131. package/dist/sdk/governance/validate.js +1 -1
  132. package/dist/sdk/history/salvage.js +3 -3
  133. package/dist/sdk/history-compact.d.ts +7 -1
  134. package/dist/sdk/history-compact.js +1 -1
  135. package/dist/sdk/history-repair.d.ts +2 -1
  136. package/dist/sdk/history-repair.js +1 -1
  137. package/dist/sdk/index.d.ts +4 -1
  138. package/dist/sdk/index.js +1 -1
  139. package/dist/sdk/lifecycle/checkpoint-rollback.d.ts +10 -2
  140. package/dist/sdk/lifecycle/checkpoint-rollback.js +1 -1
  141. package/dist/sdk/lifecycle/claim.js +1 -1
  142. package/dist/sdk/lifecycle/close-many.d.ts +11 -2
  143. package/dist/sdk/lifecycle/close-many.js +1 -1
  144. package/dist/sdk/lifecycle/close.d.ts +15 -0
  145. package/dist/sdk/lifecycle/close.js +1 -1
  146. package/dist/sdk/lifecycle/core-field-recovery.d.ts +26 -0
  147. package/dist/sdk/lifecycle/core-field-recovery.js +1 -1
  148. package/dist/sdk/lifecycle/create.js +1 -1
  149. package/dist/sdk/lifecycle/item-revision.d.ts +162 -0
  150. package/dist/sdk/lifecycle/item-revision.js +2 -0
  151. package/dist/sdk/lifecycle/restore.js +1 -1
  152. package/dist/sdk/lifecycle/start-blockers.d.ts +52 -0
  153. package/dist/sdk/lifecycle/start-blockers.js +2 -0
  154. package/dist/sdk/lifecycle/task-composition.d.ts +11 -0
  155. package/dist/sdk/lifecycle/task-composition.js +1 -1
  156. package/dist/sdk/lifecycle/update-many.d.ts +11 -2
  157. package/dist/sdk/lifecycle/update-many.js +1 -1
  158. package/dist/sdk/lifecycle/update.js +2 -2
  159. package/dist/sdk/public-surface.json +1 -1
  160. package/dist/sdk/query/declared-blockers.d.ts +16 -0
  161. package/dist/sdk/query/declared-blockers.js +2 -0
  162. package/dist/sdk/query/get.d.ts +7 -0
  163. package/dist/sdk/query/get.js +1 -1
  164. package/dist/sdk/query/projection-contracts.js +1 -1
  165. package/dist/sdk/runtime-input.d.ts +12 -0
  166. package/dist/sdk/runtime-input.js +1 -1
  167. package/dist/sdk/runtime.d.ts +11 -1
  168. package/dist/sdk/runtime.js +1 -1
  169. package/dist/sdk/structured-mutations.js +1 -1
  170. package/dist/sdk/test/batch.js +2 -2
  171. package/dist/sdk/test/entry.d.ts +5 -0
  172. package/dist/sdk/test/entry.js +2 -2
  173. package/dist/sdk/test/execution.d.ts +1 -2
  174. package/dist/sdk/test/execution.js +2 -2
  175. package/dist/sdk/test/linked-command-detection.d.ts +10 -0
  176. package/dist/sdk/test/linked-command-detection.js +1 -1
  177. package/dist/sdk/test/update.d.ts +2 -0
  178. package/dist/sdk/test/update.js +1 -1
  179. package/dist/sdk/workspace-transaction.d.ts +17 -6
  180. package/dist/sdk/workspace-transaction.js +1 -1
  181. package/dist/types.d.ts +6 -0
  182. package/dist/types.js +1 -1
  183. package/docs/COMMANDS.md +91 -0
  184. package/docs/CONFIGURATION.md +1 -0
  185. package/docs/EXTENSIONS.md +2 -2
  186. package/docs/LINKED_TEST_EDITS.md +38 -5
  187. package/docs/SDK.md +185 -1
  188. package/docs/agent-task-token-baseline.json +1 -1
  189. package/docs/generated/FLAG_LEXICON_BUDGETS.md +111 -111
  190. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +15 -3
  191. package/marketplace.json +1 -1
  192. package/package.json +1 -1
  193. package/packages/pm-beads/package.json +1 -1
  194. package/packages/pm-calendar/package.json +1 -1
  195. package/packages/pm-command-kit/package.json +1 -1
  196. package/packages/pm-digital-twin/package.json +1 -1
  197. package/packages/pm-governance-audit/package.json +1 -1
  198. package/packages/pm-guide-shell/package.json +1 -1
  199. package/packages/pm-kanban/package.json +1 -1
  200. package/packages/pm-lifecycle-hooks/package.json +1 -1
  201. package/packages/pm-linked-test-adapters/package.json +1 -1
  202. package/packages/pm-search-advanced/package.json +1 -1
  203. package/packages/pm-templates/package.json +1 -1
  204. package/packages/pm-todos/package.json +1 -1
  205. package/packages/pm-vcs/package.json +1 -1
  206. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  207. package/plugins/pm-claude/package.json +1 -1
  208. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  209. package/plugins/pm-codex/package.json +1 -1
  210. package/plugins/pm-codex/plugin.json +1 -1
  211. package/runtime-dependencies.json +1 -1
  212. package/dist/cli-bundle/chunks/chunk-3ZQQVJT2.js +0 -20
  213. package/dist/cli-bundle/chunks/chunk-4HW253W2.js +0 -2
  214. package/dist/cli-bundle/chunks/chunk-4OELCF3O.js +0 -2
  215. package/dist/cli-bundle/chunks/chunk-BFZUJ5QP.js +0 -115
  216. package/dist/cli-bundle/chunks/chunk-DAZFCSDV.js +0 -2
  217. package/dist/cli-bundle/chunks/chunk-EN27ZQSV.js +0 -2
  218. package/dist/cli-bundle/chunks/chunk-K46GDAKX.js +0 -6
  219. package/dist/cli-bundle/chunks/chunk-OJR2YGXF.js +0 -31
  220. package/dist/cli-bundle/chunks/chunk-QHHFXNSQ.js +0 -3
  221. package/dist/cli-bundle/chunks/chunk-ZNWDYDFF.js +0 -129
  222. package/dist/cli-bundle/chunks/item-transaction-JHPBH6N7.js +0 -2
  223. package/dist/cli-bundle/chunks/mutation-admission-QUNQZCZ5.js +0 -2
  224. package/dist/cli-bundle/chunks/register-operations-RFMM5KZ6.js +0 -2
  225. package/dist/cli-bundle/chunks/register-setup-6B6Q7M5L.js +0 -2
  226. package/dist/cli-bundle/focused-chunks/chunk-4NVPDZLX.js +0 -12
  227. package/dist/cli-bundle/focused-chunks/chunk-4UUE3YXZ.js +0 -2
  228. package/dist/cli-bundle/focused-chunks/chunk-5UDDRPYR.js +0 -8
  229. package/dist/cli-bundle/focused-chunks/chunk-AK2CI2GI.js +0 -2
  230. package/dist/cli-bundle/focused-chunks/chunk-EJJWOFP5.js +0 -91
  231. package/dist/cli-bundle/focused-chunks/chunk-FUGYXUUL.js +0 -80
  232. package/dist/cli-bundle/focused-chunks/chunk-HMXVTWIV.js +0 -3
  233. package/dist/cli-bundle/focused-chunks/chunk-JLN5CFYM.js +0 -2
  234. package/dist/cli-bundle/focused-chunks/chunk-K4FMZB4Y.js +0 -23
  235. package/dist/cli-bundle/focused-chunks/chunk-PF553UVP.js +0 -44
  236. package/dist/cli-bundle/focused-chunks/chunk-RUCG6UWN.js +0 -2
  237. package/dist/cli-bundle/focused-chunks/chunk-SGWYNU7T.js +0 -2
  238. package/dist/cli-bundle/focused-chunks/chunk-TGS5RXBY.js +0 -26
  239. package/dist/cli-bundle/focused-chunks/chunk-WD43E7RU.js +0 -2
  240. package/dist/cli-bundle/focused-chunks/chunk-YM4AMP7H.js +0 -2
  241. package/dist/cli-bundle/focused-chunks/item-transaction-F4SN7TXJ.js +0 -2
  242. package/dist/cli-bundle/focused-chunks/mutation-admission-7R2FXJ5O.js +0 -2
@@ -1,2 +1,2 @@
1
- (function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="9261d364-cb6c-5442-9ad0-41d0aefa8184")}catch{}})();import crypto from"node:crypto";import{ITEM_MUTATION_FACET_OPTION_MAPPINGS}from"./lifecycle/mutation-facet-contracts.js";import{normalizeItemId,normalizePrefix}from"../core/item/id.js";import{preserveMutationStdinTokenFields,preserveMutationStdinTokenLiterals}from"../core/item/parse.js";import{preserveLiteralMutationInputFields}from"../core/item/literal-mutation-input.js";import{EXIT_CODE}from"../core/shared/constants.js";import{PmCliError}from"../core/shared/errors.js";import{levenshteinDistanceWithinLimit}from"../core/shared/levenshtein.js";import{describeUnknownError}from"./error-runtime.js";import{CLOSE_FLAG_CONTRACTS,RELEASE_FLAG_CONTRACTS}from"./cli-contracts/flag-contracts.js";import{CREATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS,UPDATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS}from"./cli-contracts/commander-mutation-options.js";import{runtimeFieldOptionTarget}from"../core/schema/runtime-schema.js";import{CORE_ITEM_FIELD_KEYS as ITEM_FIELD_KEYS,resolveCoreUpsertMetadataKey}from"./lifecycle/core-item-fields.js";import{readRuntimeFieldOptionValue}from"../core/schema/runtime-field-values.js";import{assertMutationOptionValueTypes}from"./lifecycle/mutation-option-validation.js";const MUTATION_ROW_KEYS=["op","id","reason","options","unique","match"],REFERENCED_MUTATION_ROW_KEYS=[...MUTATION_ROW_KEYS,"ref"],DOCUMENT_MUTATION_ROW_KEYS=[...REFERENCED_MUTATION_ROW_KEYS,"item"],DERIVED_TRANSACTION_ID_PREFIX="mutate-",SYNTHESIZED_REFERENCE_PREFIX="row-",MUTATION_DOCUMENT_KEYS=["schema_version","mutations"],MUTATION_REFERENCE_SOURCE="[a-z][a-z0-9._-]{0,63}",MUTATION_REFERENCE_PATTERN=new RegExp(`^${MUTATION_REFERENCE_SOURCE}$`,"u"),MUTATION_DEPENDENCY_REFERENCE_PATTERN=new RegExp(`(^|,)id=@(${MUTATION_REFERENCE_SOURCE})(?=,|$)`,"gu"),flagToOptionKey=flag=>flag.slice(2).replaceAll(/-([a-z])/gu,(_match,letter)=>letter.toUpperCase()),ITEM_ENVELOPE_KEYS=["item","linked","schedule","claim_state","children","omission_receipt","row_contract","context_intent"],READ_ONLY_ITEM_KEYS=new Set(["created_at","updated_at","closed_at","version","format_version","path","author","collection_counts","notes_count","tests_count"]),UPDATE_READ_ONLY_ITEM_KEYS=new Set([...READ_ONLY_ITEM_KEYS,"completed_at","id"]),MUTATION_OPTION_KEYS={create:CREATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS.map(contract=>contract.target),update:UPDATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS.map(contract=>contract.target),close:CLOSE_FLAG_CONTRACTS.map(contract=>flagToOptionKey(contract.flag)).filter(key=>key!=="reason"),release:RELEASE_FLAG_CONTRACTS.map(contract=>flagToOptionKey(contract.flag))};function deriveMutationTransactionId(input){const digest=crypto.createHash("sha256").update(input).digest("hex");return`${DERIVED_TRANSACTION_ID_PREFIX}${digest.slice(0,24)}`}function parseAtomicMutationControls(value){const controls={},compensation=value.createCompensation;if(compensation!==void 0){if(compensation!=="close"&&compensation!=="delete")throw new PmCliError("createCompensation must be close or delete.",EXIT_CODE.USAGE);controls.createCompensation=compensation}for(const key of["lockTtlSeconds","lockWaitMs"]){const raw=value[key];if(raw===void 0)continue;const parsed=typeof raw=="number"||typeof raw=="string"&&raw.trim().length>0?Number(raw):Number.NaN;if(!Number.isSafeInteger(parsed)||parsed<=0)throw new PmCliError(`${key} must be a positive safe integer.`,EXIT_CODE.USAGE);controls[key]=parsed}return controls}function isPlainObject(value){if(typeof value!="object"||value===null||Array.isArray(value))return!1;const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}function nearestKey(key,candidates){const limit=Math.max(1,Math.min(3,Math.floor(key.length/4)+1));let best;for(const candidate of candidates){const distance=levenshteinDistanceWithinLimit(key,candidate,limit);distance!==null&&(best===void 0||distance<best.distance)&&(best={key:candidate,distance})}return best?.key}function unknownKeyError(scope,key,candidates){const suggestion=nearestKey(key,candidates);return new PmCliError(suggestion===void 0?`${scope} does not recognize key "${key}". Allowed keys: ${candidates.join(", ")}.`:`${scope} does not recognize key "${key}". Did you mean "${suggestion}"?`,EXIT_CODE.USAGE,{code:"stdin_json_unknown_key",required:`Use documented ${scope} keys only.`,why:"Strict structured input prevents silent typos from creating incomplete or unintended mutations.",nextSteps:[suggestion===void 0?`Remove or correct "${key}".`:`Replace "${key}" with "${suggestion}".`]})}function parseJsonValue(input,label){try{return JSON.parse(input)}catch(error){const detail=error instanceof Error?error.message:String(error);throw new PmCliError(`${label} must be valid JSON: ${detail}`,EXIT_CODE.USAGE,{code:"stdin_json_invalid",required:`Pipe one valid JSON ${label.toLowerCase()} into stdin.`,why:"Structured mutation input must parse deterministically before any tracker write begins."})}}function validateMutationObject(value,index){if(!isPlainObject(value))throw new PmCliError(`Mutation ${index+1} must be an object.`,EXIT_CODE.USAGE);for(const key of Object.keys(value))if(!MUTATION_ROW_KEYS.includes(key))throw unknownKeyError(`mutation ${index+1}`,key,MUTATION_ROW_KEYS);return value}function validateMutationOptions(options,op,index,runtimeFields){if(options===void 0)return;if(!isPlainObject(options))throw new PmCliError(`Mutation ${index+1} options must be an object.`,EXIT_CODE.USAGE);const allowed=[...MUTATION_OPTION_KEYS[op],...runtimeFieldOptionKeys(op,runtimeFields)];for(const key of Object.keys(options))if(!allowed.includes(key))throw unknownKeyError(`mutation ${index+1} ${op} options`,key,allowed);return assertMutationOptionValueTypes(options,op,index),options}function validateMutationKeyGuard(value,op,index,field){if(value===void 0)return;const allowedOp=field==="unique"?"create":"update";if(op!==allowedOp)throw new PmCliError(`Mutation ${index+1} ${field} is only valid for ${allowedOp} operations.`,EXIT_CODE.USAGE);const key=isPlainObject(value)&&typeof value.key=="string"?value.key.trim():"";if(!isPlainObject(value)||key.length===0||value.value===void 0||value.value===null)throw new PmCliError(`Mutation ${index+1} ${field} must be an object with a non-empty key and a value.`,EXIT_CODE.USAGE);return{key,value:value.value}}function validateMutationRow(value,index,runtimeFields){const mutation=validateMutationObject(value,index),{op,id,reason}=mutation;if(op!=="create"&&op!=="update"&&op!=="close"&&op!=="release")throw new PmCliError(`Mutation ${index+1} op must be create, update, close, or release.`,EXIT_CODE.USAGE);const options=validateMutationOptions(mutation.options,op,index,runtimeFields),unique=validateMutationKeyGuard(mutation.unique,op,index,"unique"),match=validateMutationKeyGuard(mutation.match,op,index,"match");if(typeof id!="string"||id.trim().length===0)throw new PmCliError(`Mutation ${index+1} requires a non-empty id.`,EXIT_CODE.USAGE);const normalizedId=id.trim();if(op==="close"){if(typeof reason!="string"||reason.trim().length===0)throw new PmCliError(`Mutation ${index+1} close requires a non-empty reason.`,EXIT_CODE.USAGE);return{op,id:normalizedId,reason:reason.trim(),...options===void 0?{}:{options}}}if(op==="release")return{op,id:normalizedId,...options===void 0?{}:{options}};if(!isPlainObject(options))throw new PmCliError(`Mutation ${index+1} ${op} requires an options object.`,EXIT_CODE.USAGE);return{op,id:normalizedId,options,...unique===void 0?{}:{unique},...match===void 0?{}:{match}}}function parseItemMutationBatch(input,parseOptions={}){const parsed=parseJsonValue(input,"Mutation batch"),rows=Array.isArray(parsed)?parsed:isPlainObject(parsed)&&Array.isArray(parsed.mutations)?parsed.mutations:void 0;if(rows===void 0||rows.length===0)throw new PmCliError("Mutation batch must be a non-empty JSON array or an object with a non-empty mutations array.",EXIT_CODE.USAGE);const runtimeFields=parseOptions.runtimeFields??[];return rows.map((row,index)=>{const mutation=validateMutationRow(row,index,runtimeFields);return mutation.options!==void 0&&preserveMutationStdinTokenLiterals(mutation.options),mutation})}function deriveReferencedItemId(transactionId,reference,idPrefix){const digest=crypto.createHash("sha256").update(transactionId).update("\0").update(reference).digest("hex"),token=BigInt(`0x${digest.slice(0,16)}`).toString(36).padStart(13,"0").slice(-12);return`${normalizePrefix(idPrefix)}${token}`}function replaceExactMutationReference(value,references){if(typeof value!="string"||!value.startsWith("@"))return value;const reference=value.slice(1),resolved=references[reference];if(resolved===void 0)throw new PmCliError(`Unknown mutation reference "${value}".`,EXIT_CODE.USAGE);return resolved}function replaceDependencyReference(value,references){if(typeof value!="string")return value;const resolvedValue=value.replace(MUTATION_DEPENDENCY_REFERENCE_PATTERN,(_match,prefix,reference)=>{const resolved=references[reference];if(resolved===void 0)throw new PmCliError(`Unknown mutation reference "@${reference}".`,EXIT_CODE.USAGE);return`${prefix}id=${resolved}`});if(/(^|,)id=@/u.test(resolvedValue))throw new PmCliError(`Malformed mutation reference in dependency "${value}".`,EXIT_CODE.USAGE);return resolvedValue}function referencedAliases(value){return typeof value!="string"?[]:value.startsWith("@")?[value.slice(1)]:[...value.matchAll(MUTATION_DEPENDENCY_REFERENCE_PATTERN)].map(match=>match[1]).filter(reference=>reference!==void 0)}function assertAcyclicCreateReferences(rows,inputReferences){const graph=new Map;for(const[index,row]of rows.entries()){const reference=inputReferences[index];if(reference===void 0)continue;const mutationOptions=isPlainObject(row.options)?row.options:{},dependencies=Array.isArray(mutationOptions.dep)?mutationOptions.dep:mutationOptions.dep===void 0?[]:[mutationOptions.dep];graph.set(reference,[mutationOptions.parent,mutationOptions.blockedBy,...dependencies].flatMap(referencedAliases))}const visiting=new Set,visited=new Set,visit=reference=>{if(visiting.has(reference))throw new PmCliError(`Mutation reference cycle includes "@${reference}".`,EXIT_CODE.USAGE);if(!visited.has(reference)){visiting.add(reference);for(const dependency of graph.get(reference))graph.has(dependency)&&visit(dependency);visiting.delete(reference),visited.add(reference)}};for(const reference of graph.keys())visit(reference)}function parseJsonLinesRows(input){const candidates=input.split(/\r?\n/u).map((line,index)=>({line:line.trim(),number:index+1})).filter(entry=>entry.line.length>0);if(candidates.length<2)return null;const parsed=candidates.map(entry=>{try{return{...entry,ok:!0,value:JSON.parse(entry.line)}}catch(error){return{...entry,ok:!1,error}}}),first=parsed[0];if(!first.ok&&(first.line.startsWith("[")||first.line==="{"||parsed.at(-1).line==="}")||!parsed.some(entry=>entry.ok&&isPlainObject(entry.value)))return null;const rows=[];for(const entry of parsed){if(!entry.ok)throw new PmCliError(`Mutation document line ${entry.number} must be one valid JSON object: ${describeUnknownError(entry.error)}`,EXIT_CODE.USAGE,{code:"stdin_json_invalid",required:"Provide one JSON object per line (JSON Lines), a JSON array, or a {schema_version, mutations} document.",why:"Structured mutation input must parse deterministically before any tracker write begins."});if(!isPlainObject(entry.value))throw new PmCliError(`Mutation document line ${entry.number} must be a JSON object.`,EXIT_CODE.USAGE);rows.push(entry.value)}return rows}function isMutationEnvelope(value){return Object.hasOwn(value,"mutations")||Object.hasOwn(value,"schema_version")}function parseMutationDocumentEnvelope(input){let parsed;try{parsed=parseJsonValue(input,"Mutation document")}catch(error){const rows=parseJsonLinesRows(input);if(rows===null)throw error;return{schema_version:1,mutations:rows}}return Array.isArray(parsed)?{schema_version:1,mutations:parsed}:isPlainObject(parsed)&&!isMutationEnvelope(parsed)?{schema_version:1,mutations:[parsed]}:parsed}function normalizeDocumentRow(row,index){const normalized=Object.hasOwn(row,"op")?validateOperationRow(row,index):normalizeCreateDocumentRow(row,index);if(normalized.op==="create"&&normalized.id===void 0&&isPlainObject(normalized.item)&&normalized.item.id!==void 0){if(typeof normalized.item.id!="string")throw new PmCliError(`Mutation ${index+1} item id must be a string.`,EXIT_CODE.USAGE);normalized.id=normalized.item.id}return normalized}function validateOperationRow(row,index){for(const key of Object.keys(row))if(!DOCUMENT_MUTATION_ROW_KEYS.includes(key))throw unknownKeyError(`mutation ${index+1}`,key,DOCUMENT_MUTATION_ROW_KEYS);if(row.item!==void 0&&row.op!=="create")throw new PmCliError(`Mutation ${index+1} item documents are only valid for create operations.`,EXIT_CODE.USAGE);if(row.item!==void 0&&row.options!==void 0)throw new PmCliError(`Mutation ${index+1} must declare either item or options, not both.`,EXIT_CODE.USAGE);return{...row}}function normalizeCreateDocumentRow(row,index){const{ref,id,item,...fields}=row,document=item!==void 0?item:fields;if(item!==void 0&&Object.keys(fields).length>0)throw new PmCliError(`Mutation ${index+1} must not mix item document keys with top-level fields.`,EXIT_CODE.USAGE);if(!isPlainObject(document))throw new PmCliError(`Mutation ${index+1} item document must be an object.`,EXIT_CODE.USAGE);return{op:"create",...ref===void 0?{}:{ref},...id===void 0?{}:{id},item:document}}function parseMutationDocumentRows(input){const envelope=parseMutationDocumentEnvelope(input);if(!isPlainObject(envelope))throw new PmCliError("Mutation document must be a JSON array or object.",EXIT_CODE.USAGE);for(const key of Object.keys(envelope))if(!MUTATION_DOCUMENT_KEYS.includes(key))throw unknownKeyError("mutation document",key,MUTATION_DOCUMENT_KEYS);if(envelope.schema_version!==void 0&&envelope.schema_version!==1)throw new PmCliError("Mutation document schema_version must be 1.",EXIT_CODE.USAGE);if(!Array.isArray(envelope.mutations)||envelope.mutations.length===0)throw new PmCliError("Mutation document requires a non-empty mutations array.",EXIT_CODE.USAGE);return envelope.mutations.map((row,index)=>{if(!isPlainObject(row))throw new PmCliError(`Mutation ${index+1} must be an object.`,EXIT_CODE.USAGE);return normalizeDocumentRow(row,index)})}function excludeOwnCreateIds(upsert,rows,options){const ownIds=new Set(Object.values(collectMutationReferences(rows,options,Object.create(null))));for(const row of rows)row.op==="create"&&typeof row.id=="string"&&row.id.trim().length>0&&ownIds.add(normalizeItemId(row.id,options.idPrefix));return{...upsert,existing:upsert.existing.filter(candidate=>!ownIds.has(candidate.id))}}function synthesizeMissingReferences(rows){const declared=new Set(rows.map(row=>row.ref).filter(ref=>typeof ref=="string"));for(const[index,row]of rows.entries()){if(row.op!=="create"||row.ref!==void 0||typeof row.id=="string"&&row.id.trim().length>0)continue;const synthesized=`${SYNTHESIZED_REFERENCE_PREFIX}${index+1}`;if(declared.has(synthesized))throw new PmCliError(`Mutation ${index+1} receives the synthesized ref "${synthesized}", but another row declares that ref. Rename it or give mutation ${index+1} its own ref; ${SYNTHESIZED_REFERENCE_PREFIX}<n> aliases are reserved for rows without one.`,EXIT_CODE.USAGE);row.ref=synthesized}}function itemDocumentToBatchOptions(item,mode,runtimeFields){const converted=itemDocumentToMutationOptions(JSON.stringify(item),mode,{},runtimeFields);return delete converted.stdinJson,delete converted.documentAnnotationSnapshot,converted}function runtimeFieldOptionKeys(op,runtimeFields){return op!=="create"&&op!=="update"?[]:runtimeFields.filter(definition=>definition.commands.includes(op)).map(definition=>runtimeFieldOptionTarget(definition))}function convertItemDocumentRows(rows,runtimeFields){for(const row of rows)isPlainObject(row.item)&&(row.options=itemDocumentToBatchOptions(row.item,"create",runtimeFields),delete row.item)}function itemDocumentMetadataKey(key,runtimeFields){return runtimeFields.some(field=>field.metadata_key===key)?key:resolveCoreUpsertMetadataKey(key)}function readUpsertKeyValue(row,key,runtimeFields){const camel=key.replaceAll(/_([a-z])/gu,(_match,letter)=>letter.toUpperCase());if(isPlainObject(row.item)){if(row.item[key]!==void 0)return row.item[key];if(itemDocumentMetadataKey(camel,runtimeFields)===key&&row.item[camel]!==void 0)return row.item[camel]}const options=isPlainObject(row.options)?row.options:{},declared=runtimeFields.find(field=>field.metadata_key===key);return declared!==void 0&&options[runtimeFieldOptionTarget(declared)]!==void 0?options[runtimeFieldOptionTarget(declared)]:options[key]!==void 0?options[key]:options[camel]!==void 0?options[camel]:(Array.isArray(options.field)?options.field:[]).map(String).find(entry=>entry.startsWith(`${key}=`))?.slice(key.length+1)}function compareCodeUnits(left,right){return left<right?-1:+(left!==right)}function canonicalizeUpsertValue(value){return Array.isArray(value)?value.map(canonicalizeUpsertValue):isPlainObject(value)?Object.fromEntries(Object.entries(value).sort(([left],[right])=>compareCodeUnits(left,right)).map(([key,nested])=>[key,canonicalizeUpsertValue(nested)])):value}function stableUpsertValue(value){return typeof value=="string"?value.trim():JSON.stringify(canonicalizeUpsertValue(value))}function applyKeyedUpsert(rows,upsert,idPrefix,runtimeFields,references){const key=upsert.key.trim();if(key.length===0)throw new PmCliError("Upsert key must be a non-empty field name.",EXIT_CODE.USAGE);const existingByValue=indexUpsertCandidates(upsert.existing),seen=new Map,upserted=new Set;for(const[index,row]of rows.entries()){if(row.op!=="create")continue;const stable=readStableUpsertKey(row,key,index,seen,runtimeFields),match=resolveUpsertMatch(existingByValue.get(stable)??[],key,stable);if(match===void 0){row.unique={key,value:readUpsertKeyValue(row,key,runtimeFields)};continue}const id=normalizeItemId(match,idPrefix);typeof row.ref=="string"&&(references[row.ref]=id),convertRowToUpsertUpdate(row,id,runtimeFields,{key,value:readUpsertKeyValue(row,key,runtimeFields)}),upserted.add(index)}return upserted}function indexUpsertCandidates(existing){const existingByValue=new Map;for(const candidate of existing){if(candidate.value===void 0||candidate.value===null)continue;const stable=stableUpsertValue(candidate.value);existingByValue.set(stable,[...existingByValue.get(stable)??[],candidate.id])}return existingByValue}function readStableUpsertKey(row,key,index,seen,runtimeFields){const value=readUpsertKeyValue(row,key,runtimeFields);if(value==null||value==="")throw new PmCliError(`Mutation ${index+1} is missing the upsert key "${key}".`,EXIT_CODE.USAGE,{code:"upsert_key_missing",required:`Every create record must carry a non-empty "${key}" value when --upsert-key ${key} is set.`,why:"Keyed upsert identifies existing items by that field; a record without it cannot be matched or safely created."});const stable=stableUpsertValue(value),previous=seen.get(stable);if(previous!==void 0)throw new PmCliError(`Mutations ${previous+1} and ${index+1} share the upsert key value ${JSON.stringify(stable)} for "${key}".`,EXIT_CODE.USAGE,{code:"upsert_key_duplicate",required:"Each record must carry a distinct upsert key value within one batch.",why:"Two records with the same key would race for the same existing item."});return seen.set(stable,index),stable}function resolveUpsertMatch(matches,key,stable){if(matches.length>1)throw new PmCliError(`Upsert key "${key}" value ${JSON.stringify(stable)} matches ${matches.length} existing items: ${matches.join(", ")}.`,EXIT_CODE.CONFLICT,{code:"upsert_key_ambiguous",required:"Resolve the duplicate existing items or choose a key that is unique per item.",why:"An ambiguous key cannot select one item to update without guessing."});return matches[0]}function convertRowToUpsertUpdate(row,id,runtimeFields,match){const updateKeys=new Set([...MUTATION_OPTION_KEYS.update,...runtimeFieldOptionKeys("update",runtimeFields)]),options=isPlainObject(row.item)?itemDocumentToBatchOptions(row.item,"update",runtimeFields):Object.fromEntries(Object.entries(row.options).filter(([optionKey])=>updateKeys.has(optionKey)));delete row.item,delete row.ref,row.op="update",row.id=id,row.options=options,row.match=match}function collectMutationReferences(rows,options,references){for(const[index,row]of rows.entries())if(row.ref!==void 0){if(row.op!=="create")throw new PmCliError(`Mutation ${index+1} ref is only valid for create operations.`,EXIT_CODE.USAGE);if(typeof row.ref!="string"||!MUTATION_REFERENCE_PATTERN.test(row.ref))throw new PmCliError(`Mutation ${index+1} ref must match ${MUTATION_REFERENCE_PATTERN.source}.`,EXIT_CODE.USAGE);if(references[row.ref]!==void 0)throw new PmCliError(`Duplicate mutation ref "${row.ref}".`,EXIT_CODE.USAGE);references[row.ref]=typeof row.id=="string"&&row.id.trim().length>0?normalizeItemId(row.id,options.idPrefix):deriveReferencedItemId(options.transactionId,row.ref,options.idPrefix)}return references}function resolveItemMutationDocument(input,options){const rows=parseMutationDocumentRows(input);synthesizeMissingReferences(rows);const inputReferences=rows.map(row=>typeof row.ref=="string"?row.ref:void 0),references=Object.create(null),upserted=options.upsert===void 0?new Set:applyKeyedUpsert(rows,excludeOwnCreateIds(options.upsert,rows,options),options.idPrefix,options.runtimeFields??[],references);convertItemDocumentRows(rows,options.runtimeFields??[]),collectMutationReferences(rows,options,references),assertAcyclicCreateReferences(rows,inputReferences);const resolvedRows=rows.map(row=>{const resolved={...row},reference=typeof resolved.ref=="string"?resolved.ref:void 0;if(delete resolved.ref,reference!==void 0?resolved.id=references[reference]:resolved.id=replaceExactMutationReference(resolved.id,references),isPlainObject(resolved.options)){const mutationOptions={...resolved.options};for(const key of["parent","blockedBy"])mutationOptions[key]!==void 0&&(mutationOptions[key]=replaceExactMutationReference(mutationOptions[key],references));Array.isArray(mutationOptions.dep)?mutationOptions.dep=mutationOptions.dep.map(entry=>replaceDependencyReference(entry,references)):mutationOptions.dep!==void 0&&(mutationOptions.dep=replaceDependencyReference(mutationOptions.dep,references)),resolved.options=mutationOptions}return resolved}),mutations=parseItemMutationBatch(JSON.stringify(resolvedRows),{runtimeFields:options.runtimeFields??[]}),createIds=mutations.filter(mutation=>mutation.op==="create").map(mutation=>mutation.id);if(new Set(createIds).size!==createIds.length)throw new PmCliError("Duplicate resolved create id in mutation document.",EXIT_CODE.USAGE);const receiptRows=mutations.map((mutation,index)=>{const reference=inputReferences[index];return{index,...typeof reference=="string"?{ref:reference}:{},id:mutation.id,op:mutation.op,...upserted.has(index)?{upserted:!0}:{}}});return{schema_version:1,mutations,references,rows:receiptRows}}function serializePairs(value,keys){return keys.filter(key=>value[key]!==void 0&&value[key]!==null).map(key=>{const rendered=String(value[key]);return`${key}=${/[",\n\r\\]/u.test(rendered)?JSON.stringify(rendered):rendered}`}).join(",")}function serializeObjectArray(value,keys,label){if(value!==void 0){if(!Array.isArray(value)||!value.every(isPlainObject))throw new PmCliError(`${label} must be an array of objects.`,EXIT_CODE.USAGE);return value.map(entry=>serializePairs(entry,keys))}}function scalarItemOption(key,value){return key==="tags"&&Array.isArray(value)&&value.every(entry=>typeof entry=="string")?JSON.stringify(value):typeof value=="number"||typeof value=="boolean"?String(value):value}function appendFacetOptions(target,source,skipPersistedAnnotations=!1){for(const[sourceKey,targetKey,keys]of ITEM_MUTATION_FACET_OPTION_MAPPINGS){const sourceValue=source[sourceKey],serialized=serializeObjectArray(skipPersistedAnnotations&&["comments","notes","learnings"].includes(sourceKey)&&Array.isArray(sourceValue)?sourceValue.filter(entry=>!isPlainObject(entry)||entry.created_at===void 0):sourceValue,keys,sourceKey);serialized!==void 0&&serialized.length>0&&(target[targetKey]=serialized)}}function validateItemDocumentKeys(parsed,envelope){for(const key of Object.keys(parsed)){if(envelope){if(!ITEM_ENVELOPE_KEYS.includes(key))throw unknownKeyError("item envelope",key,ITEM_ENVELOPE_KEYS);continue}if(!ITEM_FIELD_KEYS.has(key)&&nearestKey(key,[...ITEM_FIELD_KEYS])===void 0&&nearestKey(key,ITEM_ENVELOPE_KEYS)==="item")throw unknownKeyError("item envelope",key,ITEM_ENVELOPE_KEYS)}}function resolveItemDocument(parsed){const envelope=Object.hasOwn(parsed,"item");validateItemDocumentKeys(parsed,envelope);const item=envelope?parsed.item:parsed;if(!isPlainObject(item))throw new PmCliError("Item document item must be an object.",EXIT_CODE.USAGE);return{item,...envelope&&isPlainObject(parsed.linked)?{linked:parsed.linked}:{}}}function appendItemDocumentEntry(documentOptions,key,value,mode,runtimeFields,explicitOptions){if((mode==="update"?UPDATE_READ_ONLY_ITEM_KEYS:READ_ONLY_ITEM_KEYS).has(key))return;const definition=runtimeFields.find(field=>field.metadata_key===key&&field.commands.includes(mode));if(definition!==void 0){const explicitValue=readRuntimeFieldOptionValue(explicitOptions,definition);documentOptions[runtimeFieldOptionTarget(definition)]=explicitValue!==void 0?explicitValue:definition.type==="array"||definition.type==="object"?JSON.stringify(value):value;return}if(!ITEM_FIELD_KEYS.has(key)){if(nearestKey(key,[...ITEM_FIELD_KEYS])!==void 0)throw unknownKeyError("item document",key,[...ITEM_FIELD_KEYS]);const fields=Array.isArray(documentOptions.field)?documentOptions.field:[];fields.push(`${key}=${typeof value=="string"?value:JSON.stringify(value)}`),documentOptions.field=fields;return}["dependencies","comments","notes","learnings","files","tests","docs","reminders","events","type_options"].includes(key)||(documentOptions[key.replaceAll(/_([a-z])/gu,(_match,letter)=>letter.toUpperCase())]=scalarItemOption(key,value))}function explicitDocumentOptionKeys(explicitOptions,mode,runtimeFields){const explicitKeys=new Set(Object.entries(explicitOptions).filter(([,value])=>value!==void 0).map(([key])=>key)),contracts=mode==="create"?CREATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS:UPDATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS;for(const{target,keys}of contracts)keys.some(key=>explicitKeys.has(key))&&explicitKeys.add(target);for(const definition of runtimeFields)readRuntimeFieldOptionValue(explicitOptions,definition)!==void 0&&explicitKeys.add(runtimeFieldOptionTarget(definition));return explicitKeys}function removeOverriddenDocumentOptions(documentOptions,mode,explicitKeys){const contracts=mode==="create"?CREATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS:UPDATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS;for(const{target}of contracts)target!=="field"&&explicitKeys.has(target)&&delete documentOptions[target]}function itemDocumentToMutationOptions(input,mode,explicitOptions={},runtimeFields=[]){const parsed=parseJsonValue(input,"Item document");if(!isPlainObject(parsed))throw new PmCliError("Item document must be a JSON object.",EXIT_CODE.USAGE);const{item,linked}=resolveItemDocument(parsed),documentOptions={};for(const[key,value]of Object.entries(item)){const metadataKey=itemDocumentMetadataKey(key,runtimeFields);metadataKey!==key&&Object.hasOwn(item,metadataKey)||appendItemDocumentEntry(documentOptions,metadataKey,value,mode,runtimeFields,explicitOptions)}appendFacetOptions(documentOptions,item,mode==="update"),linked!==void 0&&appendFacetOptions(documentOptions,linked);const explicitKeys=explicitDocumentOptionKeys(explicitOptions,mode,runtimeFields);if(removeOverriddenDocumentOptions(documentOptions,mode,explicitKeys),mode==="update"){const annotations=Object.fromEntries(["comments","notes","learnings"].filter(key=>Object.hasOwn(item,key)&&!explicitKeys.has(key.slice(0,-1))).map(key=>[key,item[key].filter(entry=>isPlainObject(entry)&&entry.created_at!==void 0)]));Object.keys(annotations).length>0&&(documentOptions.documentAnnotationSnapshot=annotations)}const merged={...documentOptions,...Object.fromEntries(Object.entries(explicitOptions).filter(([,value])=>value!==void 0)),...Array.isArray(documentOptions.field)&&Array.isArray(explicitOptions.field)?{field:[...documentOptions.field,...explicitOptions.field]}:{},stdinJson:void 0},literalKeys=Object.keys(documentOptions).filter(key=>!explicitKeys.has(key));return preserveMutationStdinTokenFields(preserveLiteralMutationInputFields(merged,literalKeys),literalKeys)}function validateItemMutationRows(value){return parseItemMutationBatch(JSON.stringify(value))}export{deriveMutationTransactionId,itemDocumentToMutationOptions,parseAtomicMutationControls,parseItemMutationBatch,resolveItemMutationDocument,stableUpsertValue,validateItemMutationRows};
1
+ (function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a17df3f5-aee8-5734-b1ce-b643482be3a7")}catch{}})();import crypto from"node:crypto";import{ITEM_MUTATION_FACET_OPTION_MAPPINGS}from"./lifecycle/mutation-facet-contracts.js";import{normalizeItemId,normalizePrefix}from"../core/item/id.js";import{preserveMutationStdinTokenFields,preserveMutationStdinTokenLiterals}from"../core/item/parse.js";import{preserveLiteralMutationInputFields}from"../core/item/literal-mutation-input.js";import{EXIT_CODE}from"../core/shared/constants.js";import{PmCliError}from"../core/shared/errors.js";import{levenshteinDistanceWithinLimit}from"../core/shared/levenshtein.js";import{describeUnknownError}from"./error-runtime.js";import{CLOSE_FLAG_CONTRACTS,RELEASE_FLAG_CONTRACTS}from"./cli-contracts/flag-contracts.js";import{CREATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS,UPDATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS}from"./cli-contracts/commander-mutation-options.js";import{runtimeFieldOptionTarget}from"../core/schema/runtime-schema.js";import{CORE_ITEM_FIELD_KEYS as ITEM_FIELD_KEYS,resolveCoreUpsertMetadataKey}from"./lifecycle/core-item-fields.js";import{readRuntimeFieldOptionValue}from"../core/schema/runtime-field-values.js";import{assertMutationOptionValueTypes}from"./lifecycle/mutation-option-validation.js";const MUTATION_ROW_KEYS=["op","id","reason","options","unique","match"],REFERENCED_MUTATION_ROW_KEYS=[...MUTATION_ROW_KEYS,"ref"],DOCUMENT_MUTATION_ROW_KEYS=[...REFERENCED_MUTATION_ROW_KEYS,"item"],DERIVED_TRANSACTION_ID_PREFIX="mutate-",SYNTHESIZED_REFERENCE_PREFIX="row-",MUTATION_DOCUMENT_KEYS=["schema_version","mutations"],MUTATION_REFERENCE_SOURCE="[a-z][a-z0-9._-]{0,63}",MUTATION_REFERENCE_PATTERN=new RegExp(`^${MUTATION_REFERENCE_SOURCE}$`,"u"),MUTATION_DEPENDENCY_REFERENCE_PATTERN=new RegExp(`(^|,)id=@(${MUTATION_REFERENCE_SOURCE})(?=,|$)`,"gu"),flagToOptionKey=flag=>flag.slice(2).replaceAll(/-([a-z])/gu,(_match,letter)=>letter.toUpperCase()),ITEM_ENVELOPE_KEYS=["item","item_hash","linked","schedule","claim_state","children","omission_receipt","row_contract","context_intent"],READ_ONLY_ITEM_KEYS=new Set(["created_at","updated_at","closed_at","version","format_version","path","author","collection_counts","notes_count","tests_count"]),UPDATE_READ_ONLY_ITEM_KEYS=new Set([...READ_ONLY_ITEM_KEYS,"completed_at","id"]),MUTATION_OPTION_KEYS={create:CREATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS.map(contract=>contract.target),update:UPDATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS.map(contract=>contract.target),close:CLOSE_FLAG_CONTRACTS.map(contract=>flagToOptionKey(contract.flag)).filter(key=>key!=="reason"),release:RELEASE_FLAG_CONTRACTS.map(contract=>flagToOptionKey(contract.flag))};function deriveMutationTransactionId(input){const digest=crypto.createHash("sha256").update(input).digest("hex");return`${DERIVED_TRANSACTION_ID_PREFIX}${digest.slice(0,24)}`}function parseAtomicMutationControls(value){const controls={},compensation=value.createCompensation;if(compensation!==void 0){if(compensation!=="close"&&compensation!=="delete")throw new PmCliError("createCompensation must be close or delete.",EXIT_CODE.USAGE);controls.createCompensation=compensation}for(const key of["lockTtlSeconds","lockWaitMs"]){const raw=value[key];if(raw===void 0)continue;const parsed=typeof raw=="number"||typeof raw=="string"&&raw.trim().length>0?Number(raw):Number.NaN;if(!Number.isSafeInteger(parsed)||parsed<=0)throw new PmCliError(`${key} must be a positive safe integer.`,EXIT_CODE.USAGE);controls[key]=parsed}return controls}function isPlainObject(value){if(typeof value!="object"||value===null||Array.isArray(value))return!1;const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}function nearestKey(key,candidates){const limit=Math.max(1,Math.min(3,Math.floor(key.length/4)+1));let best;for(const candidate of candidates){const distance=levenshteinDistanceWithinLimit(key,candidate,limit);distance!==null&&(best===void 0||distance<best.distance)&&(best={key:candidate,distance})}return best?.key}function unknownKeyError(scope,key,candidates){const suggestion=nearestKey(key,candidates);return new PmCliError(suggestion===void 0?`${scope} does not recognize key "${key}". Allowed keys: ${candidates.join(", ")}.`:`${scope} does not recognize key "${key}". Did you mean "${suggestion}"?`,EXIT_CODE.USAGE,{code:"stdin_json_unknown_key",required:`Use documented ${scope} keys only.`,why:"Strict structured input prevents silent typos from creating incomplete or unintended mutations.",nextSteps:[suggestion===void 0?`Remove or correct "${key}".`:`Replace "${key}" with "${suggestion}".`]})}function parseJsonValue(input,label){try{return JSON.parse(input)}catch(error){const detail=error instanceof Error?error.message:String(error);throw new PmCliError(`${label} must be valid JSON: ${detail}`,EXIT_CODE.USAGE,{code:"stdin_json_invalid",required:`Pipe one valid JSON ${label.toLowerCase()} into stdin.`,why:"Structured mutation input must parse deterministically before any tracker write begins."})}}function validateMutationObject(value,index){if(!isPlainObject(value))throw new PmCliError(`Mutation ${index+1} must be an object.`,EXIT_CODE.USAGE);for(const key of Object.keys(value))if(!MUTATION_ROW_KEYS.includes(key))throw unknownKeyError(`mutation ${index+1}`,key,MUTATION_ROW_KEYS);return value}function validateMutationOptions(options,op,index,runtimeFields){if(options===void 0)return;if(!isPlainObject(options))throw new PmCliError(`Mutation ${index+1} options must be an object.`,EXIT_CODE.USAGE);const allowed=[...MUTATION_OPTION_KEYS[op],...runtimeFieldOptionKeys(op,runtimeFields)];for(const key of Object.keys(options))if(!allowed.includes(key))throw unknownKeyError(`mutation ${index+1} ${op} options`,key,allowed);return assertMutationOptionValueTypes(options,op,index),options}function validateMutationKeyGuard(value,op,index,field){if(value===void 0)return;const allowedOp=field==="unique"?"create":"update";if(op!==allowedOp)throw new PmCliError(`Mutation ${index+1} ${field} is only valid for ${allowedOp} operations.`,EXIT_CODE.USAGE);const key=isPlainObject(value)&&typeof value.key=="string"?value.key.trim():"";if(!isPlainObject(value)||key.length===0||value.value===void 0||value.value===null)throw new PmCliError(`Mutation ${index+1} ${field} must be an object with a non-empty key and a value.`,EXIT_CODE.USAGE);return{key,value:value.value}}function validateMutationRow(value,index,runtimeFields){const mutation=validateMutationObject(value,index),{op,id,reason}=mutation;if(op!=="create"&&op!=="update"&&op!=="close"&&op!=="release")throw new PmCliError(`Mutation ${index+1} op must be create, update, close, or release.`,EXIT_CODE.USAGE);const options=validateMutationOptions(mutation.options,op,index,runtimeFields),unique=validateMutationKeyGuard(mutation.unique,op,index,"unique"),match=validateMutationKeyGuard(mutation.match,op,index,"match");if(typeof id!="string"||id.trim().length===0)throw new PmCliError(`Mutation ${index+1} requires a non-empty id.`,EXIT_CODE.USAGE);const normalizedId=id.trim();if(op==="close"){if(typeof reason!="string"||reason.trim().length===0)throw new PmCliError(`Mutation ${index+1} close requires a non-empty reason.`,EXIT_CODE.USAGE);return{op,id:normalizedId,reason:reason.trim(),...options===void 0?{}:{options}}}if(op==="release")return{op,id:normalizedId,...options===void 0?{}:{options}};if(!isPlainObject(options))throw new PmCliError(`Mutation ${index+1} ${op} requires an options object.`,EXIT_CODE.USAGE);return{op,id:normalizedId,options,...unique===void 0?{}:{unique},...match===void 0?{}:{match}}}function parseItemMutationBatch(input,parseOptions={}){const parsed=parseJsonValue(input,"Mutation batch"),rows=Array.isArray(parsed)?parsed:isPlainObject(parsed)&&Array.isArray(parsed.mutations)?parsed.mutations:void 0;if(rows===void 0||rows.length===0)throw new PmCliError("Mutation batch must be a non-empty JSON array or an object with a non-empty mutations array.",EXIT_CODE.USAGE);const runtimeFields=parseOptions.runtimeFields??[];return rows.map((row,index)=>{const mutation=validateMutationRow(row,index,runtimeFields);return mutation.options!==void 0&&preserveMutationStdinTokenLiterals(mutation.options),mutation})}function deriveReferencedItemId(transactionId,reference,idPrefix){const digest=crypto.createHash("sha256").update(transactionId).update("\0").update(reference).digest("hex"),token=BigInt(`0x${digest.slice(0,16)}`).toString(36).padStart(13,"0").slice(-12);return`${normalizePrefix(idPrefix)}${token}`}function replaceExactMutationReference(value,references){if(typeof value!="string"||!value.startsWith("@"))return value;const reference=value.slice(1),resolved=references[reference];if(resolved===void 0)throw new PmCliError(`Unknown mutation reference "${value}".`,EXIT_CODE.USAGE);return resolved}function replaceDependencyReference(value,references){if(typeof value!="string")return value;const resolvedValue=value.replace(MUTATION_DEPENDENCY_REFERENCE_PATTERN,(_match,prefix,reference)=>{const resolved=references[reference];if(resolved===void 0)throw new PmCliError(`Unknown mutation reference "@${reference}".`,EXIT_CODE.USAGE);return`${prefix}id=${resolved}`});if(/(^|,)id=@/u.test(resolvedValue))throw new PmCliError(`Malformed mutation reference in dependency "${value}".`,EXIT_CODE.USAGE);return resolvedValue}function referencedAliases(value){return typeof value!="string"?[]:value.startsWith("@")?[value.slice(1)]:[...value.matchAll(MUTATION_DEPENDENCY_REFERENCE_PATTERN)].map(match=>match[1]).filter(reference=>reference!==void 0)}function assertAcyclicCreateReferences(rows,inputReferences){const graph=new Map;for(const[index,row]of rows.entries()){const reference=inputReferences[index];if(reference===void 0)continue;const mutationOptions=isPlainObject(row.options)?row.options:{},dependencies=Array.isArray(mutationOptions.dep)?mutationOptions.dep:mutationOptions.dep===void 0?[]:[mutationOptions.dep];graph.set(reference,[mutationOptions.parent,mutationOptions.blockedBy,...dependencies].flatMap(referencedAliases))}const visiting=new Set,visited=new Set,visit=reference=>{if(visiting.has(reference))throw new PmCliError(`Mutation reference cycle includes "@${reference}".`,EXIT_CODE.USAGE);if(!visited.has(reference)){visiting.add(reference);for(const dependency of graph.get(reference))graph.has(dependency)&&visit(dependency);visiting.delete(reference),visited.add(reference)}};for(const reference of graph.keys())visit(reference)}function parseJsonLinesRows(input){const candidates=input.split(/\r?\n/u).map((line,index)=>({line:line.trim(),number:index+1})).filter(entry=>entry.line.length>0);if(candidates.length<2)return null;const parsed=candidates.map(entry=>{try{return{...entry,ok:!0,value:JSON.parse(entry.line)}}catch(error){return{...entry,ok:!1,error}}}),first=parsed[0];if(!first.ok&&(first.line.startsWith("[")||first.line==="{"||parsed.at(-1).line==="}")||!parsed.some(entry=>entry.ok&&isPlainObject(entry.value)))return null;const rows=[];for(const entry of parsed){if(!entry.ok)throw new PmCliError(`Mutation document line ${entry.number} must be one valid JSON object: ${describeUnknownError(entry.error)}`,EXIT_CODE.USAGE,{code:"stdin_json_invalid",required:"Provide one JSON object per line (JSON Lines), a JSON array, or a {schema_version, mutations} document.",why:"Structured mutation input must parse deterministically before any tracker write begins."});if(!isPlainObject(entry.value))throw new PmCliError(`Mutation document line ${entry.number} must be a JSON object.`,EXIT_CODE.USAGE);rows.push(entry.value)}return rows}function isMutationEnvelope(value){return Object.hasOwn(value,"mutations")||Object.hasOwn(value,"schema_version")}function parseMutationDocumentEnvelope(input){let parsed;try{parsed=parseJsonValue(input,"Mutation document")}catch(error){const rows=parseJsonLinesRows(input);if(rows===null)throw error;return{schema_version:1,mutations:rows}}return Array.isArray(parsed)?{schema_version:1,mutations:parsed}:isPlainObject(parsed)&&!isMutationEnvelope(parsed)?{schema_version:1,mutations:[parsed]}:parsed}function normalizeDocumentRow(row,index){const normalized=Object.hasOwn(row,"op")?validateOperationRow(row,index):normalizeCreateDocumentRow(row,index);if(normalized.op==="create"&&normalized.id===void 0&&isPlainObject(normalized.item)&&normalized.item.id!==void 0){if(typeof normalized.item.id!="string")throw new PmCliError(`Mutation ${index+1} item id must be a string.`,EXIT_CODE.USAGE);normalized.id=normalized.item.id}return normalized}function validateOperationRow(row,index){for(const key of Object.keys(row))if(!DOCUMENT_MUTATION_ROW_KEYS.includes(key))throw unknownKeyError(`mutation ${index+1}`,key,DOCUMENT_MUTATION_ROW_KEYS);if(row.item!==void 0&&row.op!=="create")throw new PmCliError(`Mutation ${index+1} item documents are only valid for create operations.`,EXIT_CODE.USAGE);if(row.item!==void 0&&row.options!==void 0)throw new PmCliError(`Mutation ${index+1} must declare either item or options, not both.`,EXIT_CODE.USAGE);return{...row}}function normalizeCreateDocumentRow(row,index){const{ref,id,item,...fields}=row,document=item!==void 0?item:fields;if(item!==void 0&&Object.keys(fields).length>0)throw new PmCliError(`Mutation ${index+1} must not mix item document keys with top-level fields.`,EXIT_CODE.USAGE);if(!isPlainObject(document))throw new PmCliError(`Mutation ${index+1} item document must be an object.`,EXIT_CODE.USAGE);return{op:"create",...ref===void 0?{}:{ref},...id===void 0?{}:{id},item:document}}function parseMutationDocumentRows(input){const envelope=parseMutationDocumentEnvelope(input);if(!isPlainObject(envelope))throw new PmCliError("Mutation document must be a JSON array or object.",EXIT_CODE.USAGE);for(const key of Object.keys(envelope))if(!MUTATION_DOCUMENT_KEYS.includes(key))throw unknownKeyError("mutation document",key,MUTATION_DOCUMENT_KEYS);if(envelope.schema_version!==void 0&&envelope.schema_version!==1)throw new PmCliError("Mutation document schema_version must be 1.",EXIT_CODE.USAGE);if(!Array.isArray(envelope.mutations)||envelope.mutations.length===0)throw new PmCliError("Mutation document requires a non-empty mutations array.",EXIT_CODE.USAGE);return envelope.mutations.map((row,index)=>{if(!isPlainObject(row))throw new PmCliError(`Mutation ${index+1} must be an object.`,EXIT_CODE.USAGE);return normalizeDocumentRow(row,index)})}function excludeOwnCreateIds(upsert,rows,options){const ownIds=new Set(Object.values(collectMutationReferences(rows,options,Object.create(null))));for(const row of rows)row.op==="create"&&typeof row.id=="string"&&row.id.trim().length>0&&ownIds.add(normalizeItemId(row.id,options.idPrefix));return{...upsert,existing:upsert.existing.filter(candidate=>!ownIds.has(candidate.id))}}function synthesizeMissingReferences(rows){const declared=new Set(rows.map(row=>row.ref).filter(ref=>typeof ref=="string"));for(const[index,row]of rows.entries()){if(row.op!=="create"||row.ref!==void 0||typeof row.id=="string"&&row.id.trim().length>0)continue;const synthesized=`${SYNTHESIZED_REFERENCE_PREFIX}${index+1}`;if(declared.has(synthesized))throw new PmCliError(`Mutation ${index+1} receives the synthesized ref "${synthesized}", but another row declares that ref. Rename it or give mutation ${index+1} its own ref; ${SYNTHESIZED_REFERENCE_PREFIX}<n> aliases are reserved for rows without one.`,EXIT_CODE.USAGE);row.ref=synthesized}}function itemDocumentToBatchOptions(item,mode,runtimeFields){const converted=itemDocumentToMutationOptions(JSON.stringify(item),mode,{},runtimeFields);return delete converted.stdinJson,delete converted.documentAnnotationSnapshot,converted}function runtimeFieldOptionKeys(op,runtimeFields){return op!=="create"&&op!=="update"?[]:runtimeFields.filter(definition=>definition.commands.includes(op)).map(definition=>runtimeFieldOptionTarget(definition))}function convertItemDocumentRows(rows,runtimeFields){for(const row of rows)isPlainObject(row.item)&&(row.options=itemDocumentToBatchOptions(row.item,"create",runtimeFields),delete row.item)}function itemDocumentMetadataKey(key,runtimeFields){return runtimeFields.some(field=>field.metadata_key===key)?key:resolveCoreUpsertMetadataKey(key)}function readUpsertKeyValue(row,key,runtimeFields){const camel=key.replaceAll(/_([a-z])/gu,(_match,letter)=>letter.toUpperCase());if(isPlainObject(row.item)){if(row.item[key]!==void 0)return row.item[key];if(itemDocumentMetadataKey(camel,runtimeFields)===key&&row.item[camel]!==void 0)return row.item[camel]}const options=isPlainObject(row.options)?row.options:{},declared=runtimeFields.find(field=>field.metadata_key===key);return declared!==void 0&&options[runtimeFieldOptionTarget(declared)]!==void 0?options[runtimeFieldOptionTarget(declared)]:options[key]!==void 0?options[key]:options[camel]!==void 0?options[camel]:(Array.isArray(options.field)?options.field:[]).map(String).find(entry=>entry.startsWith(`${key}=`))?.slice(key.length+1)}function compareCodeUnits(left,right){return left<right?-1:+(left!==right)}function canonicalizeUpsertValue(value){return Array.isArray(value)?value.map(canonicalizeUpsertValue):isPlainObject(value)?Object.fromEntries(Object.entries(value).sort(([left],[right])=>compareCodeUnits(left,right)).map(([key,nested])=>[key,canonicalizeUpsertValue(nested)])):value}function stableUpsertValue(value){return typeof value=="string"?value.trim():JSON.stringify(canonicalizeUpsertValue(value))}function applyKeyedUpsert(rows,upsert,idPrefix,runtimeFields,references){const key=upsert.key.trim();if(key.length===0)throw new PmCliError("Upsert key must be a non-empty field name.",EXIT_CODE.USAGE);const existingByValue=indexUpsertCandidates(upsert.existing),seen=new Map,upserted=new Set;for(const[index,row]of rows.entries()){if(row.op!=="create")continue;const stable=readStableUpsertKey(row,key,index,seen,runtimeFields),match=resolveUpsertMatch(existingByValue.get(stable)??[],key,stable);if(match===void 0){row.unique={key,value:readUpsertKeyValue(row,key,runtimeFields)};continue}const id=normalizeItemId(match,idPrefix);typeof row.ref=="string"&&(references[row.ref]=id),convertRowToUpsertUpdate(row,id,runtimeFields,{key,value:readUpsertKeyValue(row,key,runtimeFields)}),upserted.add(index)}return upserted}function indexUpsertCandidates(existing){const existingByValue=new Map;for(const candidate of existing){if(candidate.value===void 0||candidate.value===null)continue;const stable=stableUpsertValue(candidate.value);existingByValue.set(stable,[...existingByValue.get(stable)??[],candidate.id])}return existingByValue}function readStableUpsertKey(row,key,index,seen,runtimeFields){const value=readUpsertKeyValue(row,key,runtimeFields);if(value==null||value==="")throw new PmCliError(`Mutation ${index+1} is missing the upsert key "${key}".`,EXIT_CODE.USAGE,{code:"upsert_key_missing",required:`Every create record must carry a non-empty "${key}" value when --upsert-key ${key} is set.`,why:"Keyed upsert identifies existing items by that field; a record without it cannot be matched or safely created."});const stable=stableUpsertValue(value),previous=seen.get(stable);if(previous!==void 0)throw new PmCliError(`Mutations ${previous+1} and ${index+1} share the upsert key value ${JSON.stringify(stable)} for "${key}".`,EXIT_CODE.USAGE,{code:"upsert_key_duplicate",required:"Each record must carry a distinct upsert key value within one batch.",why:"Two records with the same key would race for the same existing item."});return seen.set(stable,index),stable}function resolveUpsertMatch(matches,key,stable){if(matches.length>1)throw new PmCliError(`Upsert key "${key}" value ${JSON.stringify(stable)} matches ${matches.length} existing items: ${matches.join(", ")}.`,EXIT_CODE.CONFLICT,{code:"upsert_key_ambiguous",required:"Resolve the duplicate existing items or choose a key that is unique per item.",why:"An ambiguous key cannot select one item to update without guessing."});return matches[0]}function convertRowToUpsertUpdate(row,id,runtimeFields,match){const updateKeys=new Set([...MUTATION_OPTION_KEYS.update,...runtimeFieldOptionKeys("update",runtimeFields)]),options=isPlainObject(row.item)?itemDocumentToBatchOptions(row.item,"update",runtimeFields):Object.fromEntries(Object.entries(row.options).filter(([optionKey])=>updateKeys.has(optionKey)));delete row.item,delete row.ref,row.op="update",row.id=id,row.options=options,row.match=match}function collectMutationReferences(rows,options,references){for(const[index,row]of rows.entries())if(row.ref!==void 0){if(row.op!=="create")throw new PmCliError(`Mutation ${index+1} ref is only valid for create operations.`,EXIT_CODE.USAGE);if(typeof row.ref!="string"||!MUTATION_REFERENCE_PATTERN.test(row.ref))throw new PmCliError(`Mutation ${index+1} ref must match ${MUTATION_REFERENCE_PATTERN.source}.`,EXIT_CODE.USAGE);if(references[row.ref]!==void 0)throw new PmCliError(`Duplicate mutation ref "${row.ref}".`,EXIT_CODE.USAGE);references[row.ref]=typeof row.id=="string"&&row.id.trim().length>0?normalizeItemId(row.id,options.idPrefix):deriveReferencedItemId(options.transactionId,row.ref,options.idPrefix)}return references}function resolveItemMutationDocument(input,options){const rows=parseMutationDocumentRows(input);synthesizeMissingReferences(rows);const inputReferences=rows.map(row=>typeof row.ref=="string"?row.ref:void 0),references=Object.create(null),upserted=options.upsert===void 0?new Set:applyKeyedUpsert(rows,excludeOwnCreateIds(options.upsert,rows,options),options.idPrefix,options.runtimeFields??[],references);convertItemDocumentRows(rows,options.runtimeFields??[]),collectMutationReferences(rows,options,references),assertAcyclicCreateReferences(rows,inputReferences);const resolvedRows=rows.map(row=>{const resolved={...row},reference=typeof resolved.ref=="string"?resolved.ref:void 0;if(delete resolved.ref,reference!==void 0?resolved.id=references[reference]:resolved.id=replaceExactMutationReference(resolved.id,references),isPlainObject(resolved.options)){const mutationOptions={...resolved.options};for(const key of["parent","blockedBy"])mutationOptions[key]!==void 0&&(mutationOptions[key]=replaceExactMutationReference(mutationOptions[key],references));Array.isArray(mutationOptions.dep)?mutationOptions.dep=mutationOptions.dep.map(entry=>replaceDependencyReference(entry,references)):mutationOptions.dep!==void 0&&(mutationOptions.dep=replaceDependencyReference(mutationOptions.dep,references)),resolved.options=mutationOptions}return resolved}),mutations=parseItemMutationBatch(JSON.stringify(resolvedRows),{runtimeFields:options.runtimeFields??[]}),createIds=mutations.filter(mutation=>mutation.op==="create").map(mutation=>mutation.id);if(new Set(createIds).size!==createIds.length)throw new PmCliError("Duplicate resolved create id in mutation document.",EXIT_CODE.USAGE);const receiptRows=mutations.map((mutation,index)=>{const reference=inputReferences[index];return{index,...typeof reference=="string"?{ref:reference}:{},id:mutation.id,op:mutation.op,...upserted.has(index)?{upserted:!0}:{}}});return{schema_version:1,mutations,references,rows:receiptRows}}function serializePairs(value,keys){return keys.filter(key=>value[key]!==void 0&&value[key]!==null).map(key=>{const rendered=String(value[key]);return`${key}=${/[",\n\r\\]/u.test(rendered)?JSON.stringify(rendered):rendered}`}).join(",")}function serializeObjectArray(value,keys,label){if(value!==void 0){if(!Array.isArray(value)||!value.every(isPlainObject))throw new PmCliError(`${label} must be an array of objects.`,EXIT_CODE.USAGE);return value.map(entry=>serializePairs(entry,keys))}}function scalarItemOption(key,value){return key==="tags"&&Array.isArray(value)&&value.every(entry=>typeof entry=="string")?JSON.stringify(value):typeof value=="number"||typeof value=="boolean"?String(value):value}function appendFacetOptions(target,source,skipPersistedAnnotations=!1){for(const[sourceKey,targetKey,keys]of ITEM_MUTATION_FACET_OPTION_MAPPINGS){const sourceValue=source[sourceKey],serialized=serializeObjectArray(skipPersistedAnnotations&&["comments","notes","learnings"].includes(sourceKey)&&Array.isArray(sourceValue)?sourceValue.filter(entry=>!isPlainObject(entry)||entry.created_at===void 0):sourceValue,keys,sourceKey);serialized!==void 0&&serialized.length>0&&(target[targetKey]=serialized)}}function validateItemDocumentKeys(parsed,envelope){for(const key of Object.keys(parsed)){if(envelope){if(!ITEM_ENVELOPE_KEYS.includes(key))throw unknownKeyError("item envelope",key,ITEM_ENVELOPE_KEYS);continue}if(!ITEM_FIELD_KEYS.has(key)&&nearestKey(key,[...ITEM_FIELD_KEYS])===void 0&&nearestKey(key,ITEM_ENVELOPE_KEYS)==="item")throw unknownKeyError("item envelope",key,ITEM_ENVELOPE_KEYS)}}function resolveItemDocument(parsed){const envelope=Object.hasOwn(parsed,"item");validateItemDocumentKeys(parsed,envelope);const item=envelope?parsed.item:parsed;if(!isPlainObject(item))throw new PmCliError("Item document item must be an object.",EXIT_CODE.USAGE);return{item,...envelope&&isPlainObject(parsed.linked)?{linked:parsed.linked}:{}}}function appendItemDocumentEntry(documentOptions,key,value,mode,runtimeFields,explicitOptions){if((mode==="update"?UPDATE_READ_ONLY_ITEM_KEYS:READ_ONLY_ITEM_KEYS).has(key))return;const definition=runtimeFields.find(field=>field.metadata_key===key&&field.commands.includes(mode));if(definition!==void 0){const explicitValue=readRuntimeFieldOptionValue(explicitOptions,definition);documentOptions[runtimeFieldOptionTarget(definition)]=explicitValue!==void 0?explicitValue:definition.type==="array"||definition.type==="object"?JSON.stringify(value):value;return}if(!ITEM_FIELD_KEYS.has(key)){if(nearestKey(key,[...ITEM_FIELD_KEYS])!==void 0)throw unknownKeyError("item document",key,[...ITEM_FIELD_KEYS]);const fields=Array.isArray(documentOptions.field)?documentOptions.field:[];fields.push(`${key}=${typeof value=="string"?value:JSON.stringify(value)}`),documentOptions.field=fields;return}["dependencies","comments","notes","learnings","files","tests","docs","reminders","events","type_options"].includes(key)||(documentOptions[key.replaceAll(/_([a-z])/gu,(_match,letter)=>letter.toUpperCase())]=scalarItemOption(key,value))}function explicitDocumentOptionKeys(explicitOptions,mode,runtimeFields){const explicitKeys=new Set(Object.entries(explicitOptions).filter(([,value])=>value!==void 0).map(([key])=>key)),contracts=mode==="create"?CREATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS:UPDATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS;for(const{target,keys}of contracts)keys.some(key=>explicitKeys.has(key))&&explicitKeys.add(target);for(const definition of runtimeFields)readRuntimeFieldOptionValue(explicitOptions,definition)!==void 0&&explicitKeys.add(runtimeFieldOptionTarget(definition));return explicitKeys}function removeOverriddenDocumentOptions(documentOptions,mode,explicitKeys){const contracts=mode==="create"?CREATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS:UPDATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS;for(const{target}of contracts)target!=="field"&&explicitKeys.has(target)&&delete documentOptions[target]}function itemDocumentToMutationOptions(input,mode,explicitOptions={},runtimeFields=[]){const parsed=parseJsonValue(input,"Item document");if(!isPlainObject(parsed))throw new PmCliError("Item document must be a JSON object.",EXIT_CODE.USAGE);const{item,linked}=resolveItemDocument(parsed),documentOptions={};for(const[key,value]of Object.entries(item)){const metadataKey=itemDocumentMetadataKey(key,runtimeFields);metadataKey!==key&&Object.hasOwn(item,metadataKey)||appendItemDocumentEntry(documentOptions,metadataKey,value,mode,runtimeFields,explicitOptions)}appendFacetOptions(documentOptions,item,mode==="update"),linked!==void 0&&appendFacetOptions(documentOptions,linked);const explicitKeys=explicitDocumentOptionKeys(explicitOptions,mode,runtimeFields);if(removeOverriddenDocumentOptions(documentOptions,mode,explicitKeys),mode==="update"){const annotations=Object.fromEntries(["comments","notes","learnings"].filter(key=>Object.hasOwn(item,key)&&!explicitKeys.has(key.slice(0,-1))).map(key=>[key,item[key].filter(entry=>isPlainObject(entry)&&entry.created_at!==void 0)]));Object.keys(annotations).length>0&&(documentOptions.documentAnnotationSnapshot=annotations)}const merged={...documentOptions,...Object.fromEntries(Object.entries(explicitOptions).filter(([,value])=>value!==void 0)),...Array.isArray(documentOptions.field)&&Array.isArray(explicitOptions.field)?{field:[...documentOptions.field,...explicitOptions.field]}:{},stdinJson:void 0},literalKeys=Object.keys(documentOptions).filter(key=>!explicitKeys.has(key));return preserveMutationStdinTokenFields(preserveLiteralMutationInputFields(merged,literalKeys),literalKeys)}function validateItemMutationRows(value){return parseItemMutationBatch(JSON.stringify(value))}export{deriveMutationTransactionId,itemDocumentToMutationOptions,parseAtomicMutationControls,parseItemMutationBatch,resolveItemMutationDocument,stableUpsertValue,validateItemMutationRows};
2
2
  //# sourceMappingURL=structured-mutations.js.map
@@ -1,3 +1,3 @@
1
- (function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="190a58ff-ffae-52cf-927f-286e10771bbc")}catch{}})();import{assertInitializedTracker}from"../environment/tracker-preflight.js";import{assertLinkedTestCommand}from"./entry.js";import{getActiveExtensionRegistrations}from"../../core/extensions/index.js";import{resolveItemTypeRegistry}from"../../core/item/type-registry.js";import{parseOptionalNumber}from"../../core/item/parse.js";import{normalizeStatusInput}from"../../core/item/status.js";import{resolveRuntimeStatusRegistry}from"../../core/schema/runtime-schema.js";import{EXIT_CODE}from"../../core/shared/constants.js";import{PmCliError}from"../../core/shared/errors.js";import{nowIso}from"../../core/shared/time.js";import{listAllItemMetadataLight}from"../../core/store/item-store.js";import{resolveGlobalPmRoot,resolvePmRoot}from"../../core/store/paths.js";import{readSettings}from"../../core/store/settings.js";import{appendTrackedTestRunSummary}from"../../core/test/item-test-run-tracking.js";import{resolveAuthor}from"../../core/shared/author.js";import{countFailureCategories,runLinkedTests,runTest,summarizeContextPreflight}from"./execution.js";const parseStatus=(raw,statusRegistry)=>{if(raw===void 0)return;const normalized=normalizeStatusInput(raw,statusRegistry);if(!normalized){const allowedStatuses=statusRegistry.definitions.map(definition=>definition.id);throw new PmCliError(`Invalid --status value "${raw}". Allowed: ${allowedStatuses.join(", ")}`,EXIT_CODE.USAGE)}return normalized},parseTimeout=raw=>{if(raw===void 0)return;const parsed=parseOptionalNumber(raw,"timeout");if(parsed<=0)throw new PmCliError("timeout must be a positive number",EXIT_CODE.USAGE);return parsed},parseNonNegativeInteger=(raw,flag)=>{if(raw===void 0)return;const parsed=Number(raw);if(!Number.isInteger(parsed)||parsed<0)throw new PmCliError(`${flag} must be a non-negative integer`,EXIT_CODE.USAGE);return parsed},formatTrackingError=error=>error instanceof Error?error.message:String(error),resolveTrackedRunId=()=>{const fromEnv=process.env.PM_BACKGROUND_TEST_RUN_ID?.trim();return fromEnv&&fromEnv.length>0?fromEnv:`test-all-local-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`},normalizeCommand=command=>command.trim().replaceAll(/\s+/g," "),normalizeEnvSetSignature=value=>!value||Object.keys(value).length===0?"{}":JSON.stringify(Object.fromEntries(Object.entries(value).sort(([left],[right])=>left.localeCompare(right)))),normalizeEnvClearSignature=value=>!value||value.length===0?"[]":JSON.stringify([...value].sort((left,right)=>left.localeCompare(right))),normalizePmContextModeSignature=value=>{const normalized=value?.trim().toLowerCase();return normalized&&normalized.length>0?normalized:"none"},normalizeWorkspaceContextModeSignature=value=>{const normalized=value?.trim().toLowerCase();return normalized&&normalized.length>0?normalized:"source"},normalizeAssertionStrings=values=>[...new Set(values??[])].sort((left,right)=>left.localeCompare(right)),normalizeAssertionMap=value=>Object.fromEntries(Object.entries(value??{}).sort(([left],[right])=>left.localeCompare(right))),normalizeAssertionLineCount=value=>typeof value=="number"?value:void 0,normalizeAssertionSignature=test=>{const normalized={assert_stdout_contains:normalizeAssertionStrings(test.assert_stdout_contains),assert_stdout_regex:normalizeAssertionStrings(test.assert_stdout_regex),assert_stderr_contains:normalizeAssertionStrings(test.assert_stderr_contains),assert_stderr_regex:normalizeAssertionStrings(test.assert_stderr_regex),assert_stdout_min_lines:normalizeAssertionLineCount(test.assert_stdout_min_lines),assert_json_field_equals:normalizeAssertionMap(test.assert_json_field_equals),assert_json_field_gte:normalizeAssertionMap(test.assert_json_field_gte)};return JSON.stringify(normalized)},resolveLinkedTestTargetSignature=test=>{const command=resolveOptionalEnvironmentValue(test.command);return command!==void 0?`command:${test.scope}:${normalizeCommand(command)}`:`path:${test.scope}:${resolveOptionalEnvironmentValue(test.path)??""}`},buildLinkedTestKey=test=>{const envSet=normalizeEnvSetSignature(test.env_set),envClear=normalizeEnvClearSignature(test.env_clear),pmContextMode=normalizePmContextModeSignature(test.pm_context_mode),workspaceContextMode=normalizeWorkspaceContextModeSignature(test.workspace_context_mode),sharedHostSafe=test.shared_host_safe===!0?"true":"false",assertions=normalizeAssertionSignature(test);return`${resolveLinkedTestTargetSignature(test)}:${envSet}:${envClear}:${pmContextMode}:${workspaceContextMode}:${sharedHostSafe}:${assertions}`},maxTimeoutSeconds=(current,candidate)=>candidate===void 0?current:current===void 0||candidate>current?candidate:current,countStatuses=runResults=>{let passed=0,failed=0,skipped=0;for(const result of runResults){if(result.status==="passed"){passed+=1;continue}if(result.status==="failed"||result.status==="refused"){failed+=1;continue}skipped+=1}return{passed,failed,skipped}},mergeFailureCategoryCounts=(target,source)=>{for(const[key,value]of Object.entries(source))target[key]+=value},emitTestAllProgress=(options,message)=>{if(options.progress===!0)try{process.stderr.write(`[pm test-all] ${message}
2
- `)}catch{}},collectTestAllItemTests=async(filteredItems,global2,pmRoot)=>{const itemTests=[];let linkedTests=0;for(const item of filteredItems){const readResult=await runTest(item.id,{run:!1},{...global2,path:pmRoot});linkedTests+=readResult.tests.length,itemTests.push({item,tests:readResult.tests})}return{itemTests,linkedTests}},selectTestAllItems=async params=>{const statusRegistry=resolveRuntimeStatusRegistry(params.settings.schema),typeRegistry=resolveItemTypeRegistry(params.settings,getActiveExtensionRegistrations()),statusFilter=parseStatus(params.options.status,statusRegistry),limitFilter=parseNonNegativeInteger(params.options.limit,"--limit"),offsetFilter=parseNonNegativeInteger(params.options.offset,"--offset")??0,statusFilteredItems=(await listAllItemMetadataLight(params.pmRoot,params.settings.item_format,typeRegistry.type_to_folder,void 0,params.settings.schema)).filter(item=>statusFilter?item.status===statusFilter:!0).sort((a,b)=>a.id.localeCompare(b.id));return{filteredItems:limitFilter===void 0?statusFilteredItems.slice(offsetFilter):statusFilteredItems.slice(offsetFilter,offsetFilter+limitFilter),statusFilter,limitFilter,offsetFilter}},buildEffectiveTimeoutByKey=itemTests=>{const effectiveTimeoutByKey=new Map;for(const{tests}of itemTests)for(const test of tests){const key=buildLinkedTestKey(test);if(!effectiveTimeoutByKey.has(key)){effectiveTimeoutByKey.set(key,test.timeout_seconds);continue}effectiveTimeoutByKey.set(key,maxTimeoutSeconds(effectiveTimeoutByKey.get(key),test.timeout_seconds))}return effectiveTimeoutByKey};function resolveTestAllCommandRefusal(test,itemId){try{assertLinkedTestCommand(test.command);return}catch(error){if(!(error instanceof PmCliError)||error.code!=="linked_test_command_not_executable")throw error;return{command:test.command,path:test.path,status:"refused",exit_code:null,failure_category:"config_refusal",error:`Linked test refused for ${itemId}: ${error.message}`}}}const runTestAllItem=async(entry,context)=>{const testsToRun=[],keyedTests=entry.tests.map(test=>{const key=buildLinkedTestKey(test),refusal=resolveTestAllCommandRefusal(test,entry.item.id);if(refusal)return{test,key,duplicate:!1,refusal};const duplicate=context.seenTestKeys.has(key);if(!duplicate){context.seenTestKeys.add(key);const effectiveTimeoutSeconds=context.effectiveTimeoutByKey.get(key);testsToRun.push(effectiveTimeoutSeconds===void 0?test:{...test,timeout_seconds:effectiveTimeoutSeconds})}return{test,key,duplicate,refusal}}),executedResults=testsToRun.length>0?await runLinkedTests(testsToRun,context.defaultTimeoutSeconds,{progress:context.options.progress,sourceRoots:context.sourceRoots,envSet:context.options.envSet,envClear:context.options.envClear,sharedHostSafe:context.options.sharedHostSafe,pmContext:context.options.pmContext,overrideLinkedPmContext:context.options.overrideLinkedPmContext,failOnContextMismatch:context.options.failOnContextMismatch,failOnEmptyTestRun:context.options.failOnEmptyTestRun,requireAssertionsForPm:context.options.requireAssertionsForPm,checkContext:context.options.checkContext,autoPmContext:context.options.autoPmContext,workspaceContext:context.options.workspaceContext,overrideLinkedWorkspaceContext:context.options.overrideLinkedWorkspaceContext,pmRoot:context.pmRoot,allowUntrustedLinkedTests:context.options.allowUntrustedLinkedTests,untrustedLinkedTestsPolicyEnabled:context.settings.testing.allow_untrusted_linked_tests}):[];let executedIndex=0;const runResults=keyedTests.map(({test,key,duplicate,refusal})=>{if(refusal)return refusal;if(!duplicate){const executed=executedResults[executedIndex];return executedIndex+=1,executed}return{command:test.command,path:test.path,status:"skipped",error:`Duplicate linked test skipped (key=${key}).`}}),summary=countStatuses(runResults),failureCategories=countFailureCategories(runResults),trackingWarnings=await appendTestAllItemTracking(entry,summary,runResults,context);return{passed:summary.passed,failed:summary.failed,skipped:summary.skipped,trackingWarnings,failureCategories,result:{ok:summary.failed===0&&!(context.options.failOnSkipped===!0&&summary.skipped>0),id:entry.item.id,status:entry.item.status,test_count:entry.tests.length,passed:summary.passed,failed:summary.failed,skipped:summary.skipped,run_results:runResults,failure_categories:failureCategories}}},trackedRunFailed=(summary,options)=>[summary.failed>0,options.failOnSkipped===!0&&summary.skipped>0].includes(!0),optionalTrue=value=>value?!0:void 0,appendTestAllItemTracking=async(entry,summary,runResults,context)=>{if(!context.trackingEnabled)return[];try{const failed=trackedRunFailed(summary,context.options);await appendTrackedTestRunSummary({pmRoot:context.pmRoot,settings:context.settings,itemId:entry.item.id,author:context.trackingAuthor,message:`Track test-all run summary (${context.trackingRunId})`,entry:{run_id:context.trackingRunId,kind:"test-all",status:failed?"failed":"passed",started_at:context.runStartedAt,finished_at:nowIso(),recorded_at:nowIso(),attempt:context.trackingAttempt,resumed_from:context.trackingResumedFrom,passed:summary.passed,failed:summary.failed,skipped:summary.skipped,items:1,linked_tests:entry.tests.length,fail_on_skipped_triggered:optionalTrue(context.options.failOnSkipped===!0&&summary.skipped>0),executions:runResults.filter(result=>result.command?.trim()).slice(0,32).map(result=>({command:result.command.trim(),requested_pm_context_mode:result.execution_context?.requested_pm_context_mode,pm_context_mode:result.execution_context?.pm_context_mode,workspace_context_mode:result.execution_context?.workspace_context_mode,trust_reason:result.execution_context?.trust.reason}))}})}catch(error){return[`test_result_tracking_failed:${entry.item.id}:${formatTrackingError(error)}`]}return[]},resolveTrackingAttempt=()=>{const raw=process.env.PM_BACKGROUND_TEST_RUN_ATTEMPT?.trim(),parsed=raw?Number.parseInt(raw,10):Number.NaN;return Number.isFinite(parsed)&&parsed>=1?parsed:void 0},resolveOptionalEnvironmentValue=value=>{const trimmed=value?.trim();return trimmed&&trimmed.length>0?trimmed:void 0},buildTestAllItemRunContext=params=>({pmRoot:params.pmRoot,settings:params.settings,options:params.options,defaultTimeoutSeconds:params.defaultTimeoutSeconds,sourceRoots:{projectPmRoot:params.pmRoot,globalPmRoot:resolveGlobalPmRoot(process.cwd())},seenTestKeys:new Set,effectiveTimeoutByKey:buildEffectiveTimeoutByKey(params.itemTests),trackingEnabled:params.settings.testing.record_results_to_items===!0,trackingAuthor:resolveAuthor(params.options.author,params.settings.author_default),trackingRunId:resolveTrackedRunId(),trackingAttempt:resolveTrackingAttempt(),trackingResumedFrom:resolveOptionalEnvironmentValue(process.env.PM_BACKGROUND_TEST_RUN_RESUMED_FROM),runStartedAt:params.runStartedAt}),initializeTestAllAccumulation=(options,linkedTests,filteredItems)=>{const accumulation={results:[],passed:0,failed:0,skipped:0,failureCategories:countFailureCategories([]),trackingWarnings:[]},failOnEmptyTestRunTriggered=options.failOnEmptyTestRun===!0&&linkedTests===0;return failOnEmptyTestRunTriggered&&(accumulation.failed+=1,accumulation.failureCategories.empty_run+=1,accumulation.trackingWarnings.push(`empty_linked_test_selection:items=${filteredItems.length};linked_tests=0;fail_on_empty_test_run=true`)),{accumulation,failOnEmptyTestRunTriggered}},runTestAllItems=async(itemTests,context,accumulation)=>{for(const[itemIndex,entry]of itemTests.entries()){emitTestAllProgress(context.options,`item ${itemIndex+1}/${itemTests.length} start id=${entry.item.id} linked_tests=${entry.tests.length}`);const execution=await runTestAllItem(entry,context);mergeFailureCategoryCounts(accumulation.failureCategories,execution.failureCategories),accumulation.passed+=execution.passed,accumulation.failed+=execution.failed,accumulation.skipped+=execution.skipped,accumulation.trackingWarnings.push(...execution.trackingWarnings),accumulation.results.push(execution.result),emitTestAllProgress(context.options,`item ${itemIndex+1}/${itemTests.length} end id=${entry.item.id} status=${execution.failed===0?"passed":"failed"} passed=${execution.passed} failed=${execution.failed} skipped=${execution.skipped}`)}},appendContextPreflightWarning=(options,accumulation)=>{if(options.checkContext!==!0)return;const allRunResults=accumulation.results.flatMap(entry=>entry.run_results),preflight=summarizeContextPreflight(allRunResults);accumulation.trackingWarnings.push(`context_preflight:checked_pm_commands=${preflight.checked_pm_commands};tracker_read_commands=${preflight.tracker_read_commands};mismatches=${preflight.mismatches};auto_remediated=${preflight.auto_remediated}`)},buildTestAllResult=params=>({ok:params.ok,totals:{items:params.filteredItems.length,linked_tests:params.linkedTests,passed:params.accumulation.passed,failed:params.accumulation.failed,skipped:params.accumulation.skipped,failure_categories:params.accumulation.failureCategories},failed:params.accumulation.failed,passed:params.accumulation.passed,skipped:params.accumulation.skipped,fail_on_skipped_triggered:params.failOnSkippedTriggered?!0:void 0,fail_on_empty_test_run_triggered:params.failOnEmptyTestRunTriggered?!0:void 0,warnings:params.accumulation.trackingWarnings.length>0?params.accumulation.trackingWarnings:void 0,results:params.accumulation.results}),buildTestAllSelectionProgress=params=>[`selection items=${params.filteredItems.length}`,`linked_tests=${params.linkedTests}`,params.statusFilter===void 0?"":`status=${params.statusFilter}`,params.limitFilter===void 0?"":`limit=${params.limitFilter}`,params.offsetFilter>0?`offset=${params.offsetFilter}`:""].filter(entry=>entry.length>0).join(" "),prepareTestAllRun=async(options,global2)=>{const pmRoot=resolvePmRoot(process.cwd(),global2.path);await assertInitializedTracker(pmRoot);const settings=await readSettings(pmRoot),selection=await selectTestAllItems({pmRoot,settings,options}),defaultTimeoutSeconds=parseTimeout(options.timeout),runStartedAt=nowIso(),collected=await collectTestAllItemTests(selection.filteredItems,global2,pmRoot);return emitTestAllProgress(options,buildTestAllSelectionProgress({...selection,linkedTests:collected.linkedTests})),{pmRoot,settings,filteredItems:selection.filteredItems,itemTests:collected.itemTests,linkedTests:collected.linkedTests,defaultTimeoutSeconds,runStartedAt}},resolveTestAllOutcome=params=>{const failOnSkippedTriggered=params.options.failOnSkipped===!0&&params.accumulation.skipped>0,ok=![params.accumulation.failed>0,failOnSkippedTriggered,params.failOnEmptyTestRunTriggered].includes(!0);return{failOnSkippedTriggered,ok}},runTestAll=async(options,global2)=>{const prepared=await prepareTestAllRun(options,global2),{accumulation,failOnEmptyTestRunTriggered}=initializeTestAllAccumulation(options,prepared.linkedTests,prepared.filteredItems),itemRunContext=buildTestAllItemRunContext({pmRoot:prepared.pmRoot,settings:prepared.settings,options,itemTests:prepared.itemTests,defaultTimeoutSeconds:prepared.defaultTimeoutSeconds,runStartedAt:prepared.runStartedAt});await runTestAllItems(prepared.itemTests,itemRunContext,accumulation),appendContextPreflightWarning(options,accumulation);const outcome=resolveTestAllOutcome({options,accumulation,failOnEmptyTestRunTriggered});return emitTestAllProgress(options,`end status=${outcome.ok?"passed":"failed"} items=${prepared.filteredItems.length} linked_tests=${prepared.linkedTests} passed=${accumulation.passed} failed=${accumulation.failed} skipped=${accumulation.skipped}`),buildTestAllResult({ok:outcome.ok,filteredItems:prepared.filteredItems,linkedTests:prepared.linkedTests,accumulation,failOnSkippedTriggered:outcome.failOnSkippedTriggered,failOnEmptyTestRunTriggered})},_testOnlyTestAll={buildLinkedTestKey,formatTrackingError};export{_testOnlyTestAll,runTestAll};
1
+ (function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="22944f9f-02a6-5fb4-b13e-d034ec4cfa7d")}catch{}})();import{assertInitializedTracker}from"../environment/tracker-preflight.js";import{assertLinkedTestCommand}from"./entry.js";import{isItemRevisionConflict}from"../lifecycle/item-revision.js";import{getActiveExtensionRegistrations}from"../../core/extensions/index.js";import{resolveItemTypeRegistry}from"../../core/item/type-registry.js";import{parseOptionalNumber}from"../../core/item/parse.js";import{normalizeStatusInput}from"../../core/item/status.js";import{resolveRuntimeStatusRegistry}from"../../core/schema/runtime-schema.js";import{EXIT_CODE}from"../../core/shared/constants.js";import{PmCliError}from"../../core/shared/errors.js";import{nowIso}from"../../core/shared/time.js";import{listAllItemMetadataLight}from"../../core/store/item-store.js";import{resolveGlobalPmRoot,resolvePmRoot}from"../../core/store/paths.js";import{readSettings}from"../../core/store/settings.js";import{appendTrackedTestRunSummary}from"../../core/test/item-test-run-tracking.js";import{resolveAuthor}from"../../core/shared/author.js";import{countFailureCategories,runLinkedTests,runTest,summarizeContextPreflight}from"./execution.js";const parseStatus=(raw,statusRegistry)=>{if(raw===void 0)return;const normalized=normalizeStatusInput(raw,statusRegistry);if(!normalized){const allowedStatuses=statusRegistry.definitions.map(definition=>definition.id);throw new PmCliError(`Invalid --status value "${raw}". Allowed: ${allowedStatuses.join(", ")}`,EXIT_CODE.USAGE)}return normalized},parseTimeout=raw=>{if(raw===void 0)return;const parsed=parseOptionalNumber(raw,"timeout");if(parsed<=0)throw new PmCliError("timeout must be a positive number",EXIT_CODE.USAGE);return parsed},parseNonNegativeInteger=(raw,flag)=>{if(raw===void 0)return;const parsed=Number(raw);if(!Number.isInteger(parsed)||parsed<0)throw new PmCliError(`${flag} must be a non-negative integer`,EXIT_CODE.USAGE);return parsed},formatTrackingError=error=>error instanceof Error?error.message:String(error),resolveTrackedRunId=()=>{const fromEnv=process.env.PM_BACKGROUND_TEST_RUN_ID?.trim();return fromEnv&&fromEnv.length>0?fromEnv:`test-all-local-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`},normalizeCommand=command=>command.trim().replaceAll(/\s+/g," "),normalizeEnvSetSignature=value=>!value||Object.keys(value).length===0?"{}":JSON.stringify(Object.fromEntries(Object.entries(value).sort(([left],[right])=>left.localeCompare(right)))),normalizeEnvClearSignature=value=>!value||value.length===0?"[]":JSON.stringify([...value].sort((left,right)=>left.localeCompare(right))),normalizePmContextModeSignature=value=>{const normalized=value?.trim().toLowerCase();return normalized&&normalized.length>0?normalized:"none"},normalizeWorkspaceContextModeSignature=value=>{const normalized=value?.trim().toLowerCase();return normalized&&normalized.length>0?normalized:"source"},normalizeAssertionStrings=values=>[...new Set(values??[])].sort((left,right)=>left.localeCompare(right)),normalizeAssertionMap=value=>Object.fromEntries(Object.entries(value??{}).sort(([left],[right])=>left.localeCompare(right))),normalizeAssertionLineCount=value=>typeof value=="number"?value:void 0,normalizeAssertionSignature=test=>{const normalized={assert_stdout_contains:normalizeAssertionStrings(test.assert_stdout_contains),assert_stdout_regex:normalizeAssertionStrings(test.assert_stdout_regex),assert_stderr_contains:normalizeAssertionStrings(test.assert_stderr_contains),assert_stderr_regex:normalizeAssertionStrings(test.assert_stderr_regex),assert_stdout_min_lines:normalizeAssertionLineCount(test.assert_stdout_min_lines),assert_json_field_equals:normalizeAssertionMap(test.assert_json_field_equals),assert_json_field_gte:normalizeAssertionMap(test.assert_json_field_gte)};return JSON.stringify(normalized)},resolveLinkedTestTargetSignature=test=>{const command=resolveOptionalEnvironmentValue(test.command);return command!==void 0?`command:${test.scope}:${normalizeCommand(command)}`:`path:${test.scope}:${resolveOptionalEnvironmentValue(test.path)??""}`},buildLinkedTestKey=test=>{const envSet=normalizeEnvSetSignature(test.env_set),envClear=normalizeEnvClearSignature(test.env_clear),pmContextMode=normalizePmContextModeSignature(test.pm_context_mode),workspaceContextMode=normalizeWorkspaceContextModeSignature(test.workspace_context_mode),sharedHostSafe=test.shared_host_safe===!0?"true":"false",assertions=normalizeAssertionSignature(test);return`${resolveLinkedTestTargetSignature(test)}:${envSet}:${envClear}:${pmContextMode}:${workspaceContextMode}:${sharedHostSafe}:${assertions}`},maxTimeoutSeconds=(current,candidate)=>candidate===void 0?current:current===void 0||candidate>current?candidate:current,countStatuses=runResults=>{let passed=0,failed=0,skipped=0;for(const result of runResults){if(result.status==="passed"){passed+=1;continue}if(result.status==="failed"||result.status==="refused"){failed+=1;continue}skipped+=1}return{passed,failed,skipped}},mergeFailureCategoryCounts=(target,source)=>{for(const[key,value]of Object.entries(source))target[key]+=value},emitTestAllProgress=(options,message)=>{if(options.progress===!0)try{process.stderr.write(`[pm test-all] ${message}
2
+ `)}catch{}},collectTestAllItemTests=async(filteredItems,global2,pmRoot)=>{const itemTests=[];let linkedTests=0;for(const item of filteredItems){const readResult=await runTest(item.id,{run:!1},{...global2,path:pmRoot});linkedTests+=readResult.tests.length,itemTests.push({item,tests:readResult.tests})}return{itemTests,linkedTests}},selectTestAllItems=async params=>{const statusRegistry=resolveRuntimeStatusRegistry(params.settings.schema),typeRegistry=resolveItemTypeRegistry(params.settings,getActiveExtensionRegistrations()),statusFilter=parseStatus(params.options.status,statusRegistry),limitFilter=parseNonNegativeInteger(params.options.limit,"--limit"),offsetFilter=parseNonNegativeInteger(params.options.offset,"--offset")??0,statusFilteredItems=(await listAllItemMetadataLight(params.pmRoot,params.settings.item_format,typeRegistry.type_to_folder,void 0,params.settings.schema)).filter(item=>statusFilter?item.status===statusFilter:!0).sort((a,b)=>a.id.localeCompare(b.id));return{filteredItems:limitFilter===void 0?statusFilteredItems.slice(offsetFilter):statusFilteredItems.slice(offsetFilter,offsetFilter+limitFilter),statusFilter,limitFilter,offsetFilter}},buildEffectiveTimeoutByKey=itemTests=>{const effectiveTimeoutByKey=new Map;for(const{tests}of itemTests)for(const test of tests){const key=buildLinkedTestKey(test);if(!effectiveTimeoutByKey.has(key)){effectiveTimeoutByKey.set(key,test.timeout_seconds);continue}effectiveTimeoutByKey.set(key,maxTimeoutSeconds(effectiveTimeoutByKey.get(key),test.timeout_seconds))}return effectiveTimeoutByKey};function resolveTestAllCommandRefusal(test,itemId){try{assertLinkedTestCommand(test.command);return}catch(error){if(!(error instanceof PmCliError)||error.code!=="linked_test_command_not_executable")throw error;return{command:test.command,path:test.path,status:"refused",exit_code:null,failure_category:"config_refusal",error:`Linked test refused for ${itemId}: ${error.message}`}}}const runTestAllItem=async(entry,context)=>{const testsToRun=[],keyedTests=entry.tests.map(test=>{const key=buildLinkedTestKey(test),refusal=resolveTestAllCommandRefusal(test,entry.item.id);if(refusal)return{test,key,duplicate:!1,refusal};const duplicate=context.seenTestKeys.has(key);if(!duplicate){context.seenTestKeys.add(key);const effectiveTimeoutSeconds=context.effectiveTimeoutByKey.get(key);testsToRun.push(effectiveTimeoutSeconds===void 0?test:{...test,timeout_seconds:effectiveTimeoutSeconds})}return{test,key,duplicate,refusal}}),executedResults=testsToRun.length>0?await runLinkedTests(testsToRun,context.defaultTimeoutSeconds,{progress:context.options.progress,sourceRoots:context.sourceRoots,envSet:context.options.envSet,envClear:context.options.envClear,sharedHostSafe:context.options.sharedHostSafe,pmContext:context.options.pmContext,overrideLinkedPmContext:context.options.overrideLinkedPmContext,failOnContextMismatch:context.options.failOnContextMismatch,failOnEmptyTestRun:context.options.failOnEmptyTestRun,requireAssertionsForPm:context.options.requireAssertionsForPm,checkContext:context.options.checkContext,autoPmContext:context.options.autoPmContext,workspaceContext:context.options.workspaceContext,overrideLinkedWorkspaceContext:context.options.overrideLinkedWorkspaceContext,pmRoot:context.pmRoot,allowUntrustedLinkedTests:context.options.allowUntrustedLinkedTests,untrustedLinkedTestsPolicyEnabled:context.settings.testing.allow_untrusted_linked_tests}):[];let executedIndex=0;const runResults=keyedTests.map(({test,key,duplicate,refusal})=>{if(refusal)return refusal;if(!duplicate){const executed=executedResults[executedIndex];return executedIndex+=1,executed}return{command:test.command,path:test.path,status:"skipped",error:`Duplicate linked test skipped (key=${key}).`}}),summary=countStatuses(runResults),failureCategories=countFailureCategories(runResults),trackingWarnings=await appendTestAllItemTracking(entry,summary,runResults,context);return{passed:summary.passed,failed:summary.failed,skipped:summary.skipped,trackingWarnings,failureCategories,result:{ok:summary.failed===0&&!(context.options.failOnSkipped===!0&&summary.skipped>0),id:entry.item.id,status:entry.item.status,test_count:entry.tests.length,passed:summary.passed,failed:summary.failed,skipped:summary.skipped,run_results:runResults,failure_categories:failureCategories}}},trackedRunFailed=(summary,options)=>[summary.failed>0,options.failOnSkipped===!0&&summary.skipped>0].includes(!0),optionalTrue=value=>value?!0:void 0,appendTestAllItemTracking=async(entry,summary,runResults,context)=>{if(!context.trackingEnabled)return[];try{const failed=trackedRunFailed(summary,context.options);await appendTrackedTestRunSummary({pmRoot:context.pmRoot,settings:context.settings,itemId:entry.item.id,author:context.trackingAuthor,message:`Track test-all run summary (${context.trackingRunId})`,entry:{run_id:context.trackingRunId,kind:"test-all",status:failed?"failed":"passed",started_at:context.runStartedAt,finished_at:nowIso(),recorded_at:nowIso(),attempt:context.trackingAttempt,resumed_from:context.trackingResumedFrom,passed:summary.passed,failed:summary.failed,skipped:summary.skipped,items:1,linked_tests:entry.tests.length,fail_on_skipped_triggered:optionalTrue(context.options.failOnSkipped===!0&&summary.skipped>0),executions:runResults.filter(result=>result.command?.trim()).slice(0,32).map(result=>({command:result.command.trim(),requested_pm_context_mode:result.execution_context?.requested_pm_context_mode,pm_context_mode:result.execution_context?.pm_context_mode,workspace_context_mode:result.execution_context?.workspace_context_mode,trust_reason:result.execution_context?.trust.reason}))}})}catch(error){return isItemRevisionConflict(error)?(context.revisionConflicts.push(error),[]):[`test_result_tracking_failed:${entry.item.id}:${formatTrackingError(error)}`]}return[]},resolveTrackingAttempt=()=>{const raw=process.env.PM_BACKGROUND_TEST_RUN_ATTEMPT?.trim(),parsed=raw?Number.parseInt(raw,10):Number.NaN;return Number.isFinite(parsed)&&parsed>=1?parsed:void 0},resolveOptionalEnvironmentValue=value=>{const trimmed=value?.trim();return trimmed&&trimmed.length>0?trimmed:void 0},buildTestAllItemRunContext=params=>({pmRoot:params.pmRoot,settings:params.settings,options:params.options,defaultTimeoutSeconds:params.defaultTimeoutSeconds,sourceRoots:{projectPmRoot:params.pmRoot,globalPmRoot:resolveGlobalPmRoot(process.cwd())},seenTestKeys:new Set,effectiveTimeoutByKey:buildEffectiveTimeoutByKey(params.itemTests),trackingEnabled:params.settings.testing.record_results_to_items===!0,trackingAuthor:resolveAuthor(params.options.author,params.settings.author_default),trackingRunId:resolveTrackedRunId(),trackingAttempt:resolveTrackingAttempt(),trackingResumedFrom:resolveOptionalEnvironmentValue(process.env.PM_BACKGROUND_TEST_RUN_RESUMED_FROM),runStartedAt:params.runStartedAt,revisionConflicts:[]}),initializeTestAllAccumulation=(options,linkedTests,filteredItems)=>{const accumulation={results:[],passed:0,failed:0,skipped:0,failureCategories:countFailureCategories([]),trackingWarnings:[]},failOnEmptyTestRunTriggered=options.failOnEmptyTestRun===!0&&linkedTests===0;return failOnEmptyTestRunTriggered&&(accumulation.failed+=1,accumulation.failureCategories.empty_run+=1,accumulation.trackingWarnings.push(`empty_linked_test_selection:items=${filteredItems.length};linked_tests=0;fail_on_empty_test_run=true`)),{accumulation,failOnEmptyTestRunTriggered}},runTestAllItems=async(itemTests,context,accumulation)=>{for(const[itemIndex,entry]of itemTests.entries()){emitTestAllProgress(context.options,`item ${itemIndex+1}/${itemTests.length} start id=${entry.item.id} linked_tests=${entry.tests.length}`);const execution=await runTestAllItem(entry,context);mergeFailureCategoryCounts(accumulation.failureCategories,execution.failureCategories),accumulation.passed+=execution.passed,accumulation.failed+=execution.failed,accumulation.skipped+=execution.skipped,accumulation.trackingWarnings.push(...execution.trackingWarnings),accumulation.results.push(execution.result),emitTestAllProgress(context.options,`item ${itemIndex+1}/${itemTests.length} end id=${entry.item.id} status=${execution.failed===0?"passed":"failed"} passed=${execution.passed} failed=${execution.failed} skipped=${execution.skipped}`)}const[conflict]=context.revisionConflicts;if(conflict!==void 0)throw conflict},appendContextPreflightWarning=(options,accumulation)=>{if(options.checkContext!==!0)return;const allRunResults=accumulation.results.flatMap(entry=>entry.run_results),preflight=summarizeContextPreflight(allRunResults);accumulation.trackingWarnings.push(`context_preflight:checked_pm_commands=${preflight.checked_pm_commands};tracker_read_commands=${preflight.tracker_read_commands};mismatches=${preflight.mismatches};auto_remediated=${preflight.auto_remediated}`)},buildTestAllResult=params=>({ok:params.ok,totals:{items:params.filteredItems.length,linked_tests:params.linkedTests,passed:params.accumulation.passed,failed:params.accumulation.failed,skipped:params.accumulation.skipped,failure_categories:params.accumulation.failureCategories},failed:params.accumulation.failed,passed:params.accumulation.passed,skipped:params.accumulation.skipped,fail_on_skipped_triggered:params.failOnSkippedTriggered?!0:void 0,fail_on_empty_test_run_triggered:params.failOnEmptyTestRunTriggered?!0:void 0,warnings:params.accumulation.trackingWarnings.length>0?params.accumulation.trackingWarnings:void 0,results:params.accumulation.results}),buildTestAllSelectionProgress=params=>[`selection items=${params.filteredItems.length}`,`linked_tests=${params.linkedTests}`,params.statusFilter===void 0?"":`status=${params.statusFilter}`,params.limitFilter===void 0?"":`limit=${params.limitFilter}`,params.offsetFilter>0?`offset=${params.offsetFilter}`:""].filter(entry=>entry.length>0).join(" "),prepareTestAllRun=async(options,global2)=>{const pmRoot=resolvePmRoot(process.cwd(),global2.path);await assertInitializedTracker(pmRoot);const settings=await readSettings(pmRoot),selection=await selectTestAllItems({pmRoot,settings,options}),defaultTimeoutSeconds=parseTimeout(options.timeout),runStartedAt=nowIso(),collected=await collectTestAllItemTests(selection.filteredItems,global2,pmRoot);return emitTestAllProgress(options,buildTestAllSelectionProgress({...selection,linkedTests:collected.linkedTests})),{pmRoot,settings,filteredItems:selection.filteredItems,itemTests:collected.itemTests,linkedTests:collected.linkedTests,defaultTimeoutSeconds,runStartedAt}},resolveTestAllOutcome=params=>{const failOnSkippedTriggered=params.options.failOnSkipped===!0&&params.accumulation.skipped>0,ok=![params.accumulation.failed>0,failOnSkippedTriggered,params.failOnEmptyTestRunTriggered].includes(!0);return{failOnSkippedTriggered,ok}},runTestAll=async(options,global2)=>{const prepared=await prepareTestAllRun(options,global2),{accumulation,failOnEmptyTestRunTriggered}=initializeTestAllAccumulation(options,prepared.linkedTests,prepared.filteredItems),itemRunContext=buildTestAllItemRunContext({pmRoot:prepared.pmRoot,settings:prepared.settings,options,itemTests:prepared.itemTests,defaultTimeoutSeconds:prepared.defaultTimeoutSeconds,runStartedAt:prepared.runStartedAt});await runTestAllItems(prepared.itemTests,itemRunContext,accumulation),appendContextPreflightWarning(options,accumulation);const outcome=resolveTestAllOutcome({options,accumulation,failOnEmptyTestRunTriggered});return emitTestAllProgress(options,`end status=${outcome.ok?"passed":"failed"} items=${prepared.filteredItems.length} linked_tests=${prepared.linkedTests} passed=${accumulation.passed} failed=${accumulation.failed} skipped=${accumulation.skipped}`),buildTestAllResult({ok:outcome.ok,filteredItems:prepared.filteredItems,linkedTests:prepared.linkedTests,accumulation,failOnSkippedTriggered:outcome.failOnSkippedTriggered,failOnEmptyTestRunTriggered})},_testOnlyTestAll={buildLinkedTestKey,formatTrackingError};export{_testOnlyTestAll,runTestAll};
3
3
  //# sourceMappingURL=batch.js.map
@@ -5,6 +5,11 @@ export declare function admitLinkedTestRequest<T>(validate:() => T):T;
5
5
  export declare function assertLinkedTestCommand(command:string | undefined):void;
6
6
  /** Refuse invalid command or tracker context before a linked-test mutation can persist it. */
7
7
  export declare function assertLinkedTestContext(test:LinkedTest):void;
8
+ /**
9
+ * Whether two linked tests are the same registration: an addition with the
10
+ * same identity is deduplicated rather than appended.
11
+ */
12
+ export declare function linkedTestsHaveSameIdentity(left:LinkedTest,right:LinkedTest):boolean;
8
13
  /** Public contract for structured linked test keys, shared by SDK and presentation-layer consumers. */
9
14
  export declare const STRUCTURED_LINKED_TEST_KEYS:readonly ["command","cmd","path","scope","timeout","timeout_seconds","pm_context_mode","workspace_context_mode","env_set","env_clear","shared_host_safe","assert_stdout_contains","assert_stdout_regex","assert_stderr_contains","assert_stderr_regex","assert_stdout_min_lines","assert_json_field_equals","assert_json_field_gte","note"];
10
15
  /** Classify linked-test plaintext through the shared structured-entry grammar. */
@@ -1,3 +1,3 @@
1
- (function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="8d14cb04-d740-5fb7-ad97-f9a39490eb87")}catch{}})();import{EXIT_CODE}from"../../core/shared/constants.js";import{PmCliError}from"../../core/shared/errors.js";import{looksLikeStructuredKeyValueEntry}from"../../core/item/parse.js";import{renderPmCommand}from"../command-line.js";function admitLinkedTestRequest(validate){try{return validate()}catch(error){throw!(error instanceof PmCliError)||error.exitCode!==EXIT_CODE.USAGE?error:new PmCliError(`${error.message} No changes were made.`,EXIT_CODE.USAGE,{...error.context,code:error.code==="linked_test_command_not_executable"?error.code:"invalid_argument_value",reason:"test_option_invalid",changed:!1,required:error.context.required??error.message})}}function quotedAssignmentValueEnd(input,start){if(input[start]==="'"){const closing=input.indexOf("'",start+1);return closing<0?void 0:closing+1}for(let offset=start+1;offset<input.length;offset+=1){if(input[offset]==='"')return offset+1;if(input[offset]==="\\"){offset+=1;continue}if(input[offset]==="`"||input.startsWith("$(",offset))return}}function assignmentValueEnd(input,start){let offset=start;for(;offset<input.length;){const character=input[offset];if(/\s/u.test(character)||";&|".includes(character))return offset;if(character==="\\"){offset+=2;continue}if(character==="'"||character==='"'){const end=quotedAssignmentValueEnd(input,offset);if(end===void 0)return;offset=end;continue}if("<>()`".includes(character))return;offset+=1}return offset===input.length?offset:void 0}function skipAssignmentTrivia(input,start){let offset=start;for(;offset<input.length;){if(/\s/u.test(input[offset])){offset+=1;continue}if(input[offset]!=="#")return offset;const newline=input.indexOf(`
2
- `,offset);if(newline<0)return input.length;offset=newline+1}return offset}function assignmentListNextOffset(input,start){let offset=skipAssignmentTrivia(input,start);const separator=input[offset];return separator===void 0||!";&|".includes(separator)?offset:(offset+=1,separator!==";"&&input[offset]===separator&&(offset+=1),skipAssignmentTrivia(input,offset))}function isAssignmentOnlyCommand(command){const input=command.trim();let offset=skipAssignmentTrivia(input,0);if(input.length===0)return!1;for(;offset<input.length;){if(!/[A-Za-z_]/u.test(input[offset]))return!1;let nameEnd=offset+1;for(;nameEnd<input.length&&/[A-Za-z0-9_]/u.test(input[nameEnd]);)nameEnd+=1;if(input[nameEnd]!=="=")return!1;const end=assignmentValueEnd(input,nameEnd+1);if(end===void 0)return!1;offset=assignmentListNextOffset(input,end)}return!0}function assertLinkedTestCommand(command){if(!(command===void 0||!isAssignmentOnlyCommand(command)))throw new PmCliError("Linked-test command contains only variable assignments or comments and has no executable command.",EXIT_CODE.USAGE,{code:"linked_test_command_not_executable",required:'Supply an actual test command with --add "command=<actual command>" or --add-json. Environment assignments may precede that command.',examples:['pm test <id> --add "command=node --version"'],nextSteps:["Remove any already-stored assignment-only entry with --remove-index, then register the actual test command."]})}function assertLinkedTestContext(test){if(assertLinkedTestCommand(test.command),!(test.pm_context_mode!=="none"||test.workspace_context_mode==="isolated"||test.workspace_context_mode==="snapshot"))throw new PmCliError("pm_context_mode=none requires workspace_context_mode=isolated or snapshot so implicit tracker discovery cannot reach the source workspace.",EXIT_CODE.USAGE,{code:"linked_test_context_invalid",required:"Set workspace_context_mode to isolated or snapshot when pm_context_mode is none.",examples:[renderPmCommand(["test","<id>","--add-json",JSON.stringify({command:test.command,pm_context_mode:"none",workspace_context_mode:"isolated"})])]})}const STRUCTURED_LINKED_TEST_KEYS=["command","cmd","path","scope","timeout","timeout_seconds","pm_context_mode","workspace_context_mode","env_set","env_clear","shared_host_safe","assert_stdout_contains","assert_stdout_regex","assert_stderr_contains","assert_stderr_regex","assert_stdout_min_lines","assert_json_field_equals","assert_json_field_gte","note"],STRUCTURED_LINKED_TEST_KEY_SET=new Set(STRUCTURED_LINKED_TEST_KEYS);function looksLikeStructuredLinkedTestEntry(raw){return looksLikeStructuredKeyValueEntry(raw,STRUCTURED_LINKED_TEST_KEYS)}function normalizeStructuredLinkedTestEntry(kv,optionName){const normalizedKv={},unknownKeys=[];for(const[key,value]of Object.entries(kv)){const normalizedKey=key.toLowerCase();if(!STRUCTURED_LINKED_TEST_KEY_SET.has(normalizedKey)){unknownKeys.push(key);continue}if(Object.hasOwn(normalizedKv,normalizedKey))throw new PmCliError(`${optionName} provides key "${key}" more than once after case normalization`,EXIT_CODE.USAGE);normalizedKv[normalizedKey]=value}if(unknownKeys.length>0)throw new PmCliError(`${optionName} does not recognize key${unknownKeys.length>1?"s":""} ${unknownKeys.map(key=>`"${key}"`).join(", ")}. Allowed keys: ${STRUCTURED_LINKED_TEST_KEYS.join(", ")}.`,EXIT_CODE.USAGE);if(normalizedKv.cmd!==void 0){if(normalizedKv.command!==void 0&&normalizedKv.command.trim()!==normalizedKv.cmd.trim())throw new PmCliError(`${optionName} command and cmd must match when both are provided`,EXIT_CODE.USAGE);const{cmd,...rest}=normalizedKv;return{...rest,command:rest.command??cmd}}return normalizedKv}export{STRUCTURED_LINKED_TEST_KEYS,admitLinkedTestRequest,assertLinkedTestCommand,assertLinkedTestContext,looksLikeStructuredLinkedTestEntry,normalizeStructuredLinkedTestEntry};
1
+ (function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="ccb1b39b-3dde-511b-8133-d4747bb6e55e")}catch{}})();import{EXIT_CODE}from"../../core/shared/constants.js";import{PmCliError}from"../../core/shared/errors.js";import{looksLikeStructuredKeyValueEntry}from"../../core/item/parse.js";import{renderPmCommand}from"../command-line.js";function admitLinkedTestRequest(validate){try{return validate()}catch(error){throw!(error instanceof PmCliError)||error.exitCode!==EXIT_CODE.USAGE?error:new PmCliError(`${error.message} No changes were made.`,EXIT_CODE.USAGE,{...error.context,code:error.code==="linked_test_command_not_executable"?error.code:"invalid_argument_value",reason:"test_option_invalid",changed:!1,required:error.context.required??error.message})}}function quotedAssignmentValueEnd(input,start){if(input[start]==="'"){const closing=input.indexOf("'",start+1);return closing<0?void 0:closing+1}for(let offset=start+1;offset<input.length;offset+=1){if(input[offset]==='"')return offset+1;if(input[offset]==="\\"){offset+=1;continue}if(input[offset]==="`"||input.startsWith("$(",offset))return}}function assignmentValueEnd(input,start){let offset=start;for(;offset<input.length;){const character=input[offset];if(/\s/u.test(character)||";&|".includes(character))return offset;if(character==="\\"){offset+=2;continue}if(character==="'"||character==='"'){const end=quotedAssignmentValueEnd(input,offset);if(end===void 0)return;offset=end;continue}if("<>()`".includes(character))return;offset+=1}return offset===input.length?offset:void 0}function skipAssignmentTrivia(input,start){let offset=start;for(;offset<input.length;){if(/\s/u.test(input[offset])){offset+=1;continue}if(input[offset]!=="#")return offset;const newline=input.indexOf(`
2
+ `,offset);if(newline<0)return input.length;offset=newline+1}return offset}function assignmentListNextOffset(input,start){let offset=skipAssignmentTrivia(input,start);const separator=input[offset];return separator===void 0||!";&|".includes(separator)?offset:(offset+=1,separator!==";"&&input[offset]===separator&&(offset+=1),skipAssignmentTrivia(input,offset))}function isAssignmentOnlyCommand(command){const input=command.trim();let offset=skipAssignmentTrivia(input,0);if(input.length===0)return!1;for(;offset<input.length;){if(!/[A-Za-z_]/u.test(input[offset]))return!1;let nameEnd=offset+1;for(;nameEnd<input.length&&/[A-Za-z0-9_]/u.test(input[nameEnd]);)nameEnd+=1;if(input[nameEnd]!=="=")return!1;const end=assignmentValueEnd(input,nameEnd+1);if(end===void 0)return!1;offset=assignmentListNextOffset(input,end)}return!0}function assertLinkedTestCommand(command){if(!(command===void 0||!isAssignmentOnlyCommand(command)))throw new PmCliError("Linked-test command contains only variable assignments or comments and has no executable command.",EXIT_CODE.USAGE,{code:"linked_test_command_not_executable",required:'Supply an actual test command with --add "command=<actual command>" or --add-json. Environment assignments may precede that command.',examples:['pm test <id> --add "command=node --version"'],nextSteps:["Remove any already-stored assignment-only entry with --remove-index, then register the actual test command."]})}function assertLinkedTestContext(test){if(assertLinkedTestCommand(test.command),!(test.pm_context_mode!=="none"||test.workspace_context_mode==="isolated"||test.workspace_context_mode==="snapshot"))throw new PmCliError("pm_context_mode=none requires workspace_context_mode=isolated or snapshot so implicit tracker discovery cannot reach the source workspace.",EXIT_CODE.USAGE,{code:"linked_test_context_invalid",required:"Set workspace_context_mode to isolated or snapshot when pm_context_mode is none.",examples:[renderPmCommand(["test","<id>","--add-json",JSON.stringify({command:test.command,pm_context_mode:"none",workspace_context_mode:"isolated"})])]})}function linkedTestsHaveSameIdentity(left,right){return left.command===right.command&&left.path===right.path&&left.scope===right.scope&&left.pm_context_mode===right.pm_context_mode&&left.workspace_context_mode===right.workspace_context_mode}const STRUCTURED_LINKED_TEST_KEYS=["command","cmd","path","scope","timeout","timeout_seconds","pm_context_mode","workspace_context_mode","env_set","env_clear","shared_host_safe","assert_stdout_contains","assert_stdout_regex","assert_stderr_contains","assert_stderr_regex","assert_stdout_min_lines","assert_json_field_equals","assert_json_field_gte","note"],STRUCTURED_LINKED_TEST_KEY_SET=new Set(STRUCTURED_LINKED_TEST_KEYS);function looksLikeStructuredLinkedTestEntry(raw){return looksLikeStructuredKeyValueEntry(raw,STRUCTURED_LINKED_TEST_KEYS)}function normalizeStructuredLinkedTestEntry(kv,optionName){const normalizedKv={},unknownKeys=[];for(const[key,value]of Object.entries(kv)){const normalizedKey=key.toLowerCase();if(!STRUCTURED_LINKED_TEST_KEY_SET.has(normalizedKey)){unknownKeys.push(key);continue}if(Object.hasOwn(normalizedKv,normalizedKey))throw new PmCliError(`${optionName} provides key "${key}" more than once after case normalization`,EXIT_CODE.USAGE);normalizedKv[normalizedKey]=value}if(unknownKeys.length>0)throw new PmCliError(`${optionName} does not recognize key${unknownKeys.length>1?"s":""} ${unknownKeys.map(key=>`"${key}"`).join(", ")}. Allowed keys: ${STRUCTURED_LINKED_TEST_KEYS.join(", ")}.`,EXIT_CODE.USAGE);if(normalizedKv.cmd!==void 0){if(normalizedKv.command!==void 0&&normalizedKv.command.trim()!==normalizedKv.cmd.trim())throw new PmCliError(`${optionName} command and cmd must match when both are provided`,EXIT_CODE.USAGE);const{cmd,...rest}=normalizedKv;return{...rest,command:rest.command??cmd}}return normalizedKv}export{STRUCTURED_LINKED_TEST_KEYS,admitLinkedTestRequest,assertLinkedTestCommand,assertLinkedTestContext,linkedTestsHaveSameIdentity,looksLikeStructuredLinkedTestEntry,normalizeStructuredLinkedTestEntry};
3
3
  //# sourceMappingURL=entry.js.map
@@ -234,7 +234,7 @@ executionContext:NonNullable<TestRunResult["execution_context"]>;
234
234
  runLevelPmContextMode:LinkedTestPmContextMode;
235
235
  linkedOverridePmContextMode:LinkedTestPmContextMode | undefined;
236
236
  }):string;
237
- import { extractPmInvocationArgsFromSegment } from "./linked-command-detection.js";
237
+ import { extractPmInvocationArgsFromSegment,segmentInvokesRecursiveTestAll } from "./linked-command-detection.js";
238
238
  export { extractReferencedPmItemIdsFromCommand } from "./linked-command-detection.js";
239
239
  declare function commandInvokesPmCli(command:string):boolean;
240
240
  declare function commandInvokesPmTrackerReadCommand(command:string):boolean;
@@ -243,7 +243,6 @@ subcommand:string;
243
243
  args:string[];
244
244
  } | null):string | undefined;
245
245
  declare function firstDirectTestRunnerSubcommand(executable:string,args:string[]):string | undefined;
246
- declare function segmentInvokesRecursiveTestAll(segment:string):boolean;
247
246
  /** Describes the SDK-owned safety policy applied when a linked command is recorded. */
248
247
  export interface LinkedTestCommandSafetyClassification {
249
248
  /** Whether intake accepts the command before provenance checks at execution time. */