@unbrained/pm-cli 2026.9.7 → 2026.9.9

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 (746) hide show
  1. package/.agents/skills/pm-developer/SKILL.md +12 -4
  2. package/.agents/skills/pm-developer/references/MULTI_AGENT_MERGE.md +19 -10
  3. package/.agents/skills/pm-extensions/SKILL.md +6 -0
  4. package/.agents/skills/pm-sdk/SKILL.md +11 -2
  5. package/.agents/skills/pm-user/SKILL.md +7 -2
  6. package/.agents/skills/pm-user/references/ECOSYSTEM_PLANNING.md +95 -0
  7. package/.claude-plugin/marketplace.json +2 -2
  8. package/CHANGELOG.md +231 -182
  9. package/dist/cli/after-command-context-usage.js +1 -48
  10. package/dist/cli/argv-utils.js +1 -40
  11. package/dist/cli/bootstrap-args.js +1 -9
  12. package/dist/cli/bundle-integrity.js +2 -110
  13. package/dist/cli/commander-usage.js +11 -771
  14. package/dist/cli/commands/activity.js +1 -9
  15. package/dist/cli/commands/aggregate.js +1 -5
  16. package/dist/cli/commands/append.js +1 -5
  17. package/dist/cli/commands/claim.js +1 -5
  18. package/dist/cli/commands/close-many.js +1 -5
  19. package/dist/cli/commands/close.js +1 -9
  20. package/dist/cli/commands/comments.js +1 -5
  21. package/dist/cli/commands/config.js +1 -9
  22. package/dist/cli/commands/context.js +1 -9
  23. package/dist/cli/commands/contracts.js +1 -5
  24. package/dist/cli/commands/copy.js +1 -9
  25. package/dist/cli/commands/create.js +1 -9
  26. package/dist/cli/commands/delete.js +1 -9
  27. package/dist/cli/commands/deps.js +1 -9
  28. package/dist/cli/commands/docs.js +1 -9
  29. package/dist/cli/commands/duplicates.js +1 -9
  30. package/dist/cli/commands/eval.js +1 -9
  31. package/dist/cli/commands/extension/describe.js +1 -5
  32. package/dist/cli/commands/extension/scaffold.js +1 -5
  33. package/dist/cli/commands/extension/shared.js +1 -5
  34. package/dist/cli/commands/extension.js +1 -9
  35. package/dist/cli/commands/files.js +1 -9
  36. package/dist/cli/commands/focus.js +1 -9
  37. package/dist/cli/commands/gc.js +1 -9
  38. package/dist/cli/commands/get.js +1 -9
  39. package/dist/cli/commands/graph.js +1 -10
  40. package/dist/cli/commands/health.js +1 -9
  41. package/dist/cli/commands/history-compact.js +1 -10
  42. package/dist/cli/commands/history-redact.js +1 -11
  43. package/dist/cli/commands/history-repair.js +1 -10
  44. package/dist/cli/commands/history.js +1 -5
  45. package/dist/cli/commands/index.js +1 -58
  46. package/dist/cli/commands/init-agent-guidance.js +1 -9
  47. package/dist/cli/commands/init.js +1 -9
  48. package/dist/cli/commands/learnings.js +1 -5
  49. package/dist/cli/commands/lifecycle-transitions.js +1 -5
  50. package/dist/cli/commands/list.js +1 -9
  51. package/dist/cli/commands/merge.js +1 -11
  52. package/dist/cli/commands/next.js +1 -9
  53. package/dist/cli/commands/notes.js +1 -5
  54. package/dist/cli/commands/plan.js +1 -9
  55. package/dist/cli/commands/profile.js +1 -9
  56. package/dist/cli/commands/restore.js +1 -9
  57. package/dist/cli/commands/scheduling-shortcuts.js +1 -9
  58. package/dist/cli/commands/schema.js +1 -10
  59. package/dist/cli/commands/search.js +1 -9
  60. package/dist/cli/commands/stats.js +1 -9
  61. package/dist/cli/commands/telemetry.js +1 -9
  62. package/dist/cli/commands/test-all.js +1 -9
  63. package/dist/cli/commands/test-runs.js +1 -9
  64. package/dist/cli/commands/test.js +1 -9
  65. package/dist/cli/commands/update-many.js +1 -5
  66. package/dist/cli/commands/update.js +1 -9
  67. package/dist/cli/commands/upgrade.js +1 -5
  68. package/dist/cli/commands/validate.js +1 -15
  69. package/dist/cli/context-intent-invocation.js +1 -20
  70. package/dist/cli/description-stdin.js +1 -17
  71. package/dist/cli/error-guidance.js +1 -1353
  72. package/dist/cli/extension-command-help.js +5 -636
  73. package/dist/cli/extension-command-options.js +1 -427
  74. package/dist/cli/extension-recovery.js +1 -126
  75. package/dist/cli/help-content.js +2 -1001
  76. package/dist/cli/help-json-payload.js +4 -570
  77. package/dist/cli/main.d.ts +4 -0
  78. package/dist/cli/main.js +5 -2573
  79. package/dist/cli/migration-gates.js +1 -289
  80. package/dist/cli/public.js +1 -20
  81. package/dist/cli/register-annotations.js +1 -270
  82. package/dist/cli/register-assurance.js +1 -62
  83. package/dist/cli/register-files-lookup.js +1 -56
  84. package/dist/cli/register-history-activity.d.ts +8 -0
  85. package/dist/cli/register-history-activity.js +2 -0
  86. package/dist/cli/register-history-author.js +1 -38
  87. package/dist/cli/register-history-maintenance.d.ts +9 -0
  88. package/dist/cli/register-history-maintenance.js +2 -0
  89. package/dist/cli/register-list-query.js +10 -943
  90. package/dist/cli/register-mutation-options.js +1 -9
  91. package/dist/cli/register-mutation.d.ts +0 -5
  92. package/dist/cli/register-mutation.js +19 -1893
  93. package/dist/cli/register-operations.js +1 -920
  94. package/dist/cli/register-setup.js +1 -716
  95. package/dist/cli/register-structured-mutation.js +1 -196
  96. package/dist/cli/registration-helpers.js +1 -5
  97. package/dist/cli/runtime-compatibility-boundary.js +4 -42
  98. package/dist/cli/schema-registration-helpers.js +1 -73
  99. package/dist/cli/search-refresh.js +1 -13
  100. package/dist/cli/stats-analytics-json.js +1 -68
  101. package/dist/cli/telemetry-flush.js +1 -10
  102. package/dist/cli-bundle/bundle-manifest.json +164 -156
  103. package/dist/cli-bundle/chunks/{chunk-NPN5I67J.js → chunk-3IPRM75M.js} +3 -3
  104. package/dist/cli-bundle/chunks/chunk-4VL5P22L.js +2 -0
  105. package/dist/cli-bundle/chunks/chunk-AAFBV3U3.js +29 -0
  106. package/dist/cli-bundle/chunks/chunk-D3YVILJJ.js +20 -0
  107. package/dist/cli-bundle/chunks/{chunk-WYRZZ5ZE.js → chunk-DEZPZOQ7.js} +2 -2
  108. package/dist/cli-bundle/chunks/chunk-ECBLPN7B.js +3 -0
  109. package/dist/cli-bundle/chunks/chunk-J6ERHBV2.js +235 -0
  110. package/dist/cli-bundle/chunks/chunk-JUNJ5EKI.js +2 -0
  111. package/dist/cli-bundle/chunks/chunk-L5RCDKQ2.js +2 -0
  112. package/dist/cli-bundle/chunks/chunk-NSAPNEYH.js +2 -0
  113. package/dist/cli-bundle/chunks/chunk-OHNLSGGV.js +79 -0
  114. package/dist/cli-bundle/chunks/chunk-WQKMSFBV.js +5 -0
  115. package/dist/cli-bundle/chunks/{chunk-BAX2BYUW.js → chunk-XZ6T7YPP.js} +256 -150
  116. package/dist/cli-bundle/chunks/{chunk-JT6XF6GE.js → chunk-Z3XVXUVF.js} +4 -4
  117. package/dist/cli-bundle/chunks/register-list-query-UIHRCS6D.js +11 -0
  118. package/dist/cli-bundle/chunks/register-mutation-WHWMGRVX.js +20 -0
  119. package/dist/cli-bundle/chunks/register-operations-64YZYTC5.js +2 -0
  120. package/dist/cli-bundle/chunks/register-setup-PERI45EM.js +2 -0
  121. package/dist/cli-bundle/focused-chunks/chunk-2W4XIYOB.js +2 -0
  122. package/dist/cli-bundle/focused-chunks/chunk-2WSBXIGF.js +12 -0
  123. package/dist/cli-bundle/focused-chunks/chunk-5FHTCOHS.js +3 -0
  124. package/dist/cli-bundle/focused-chunks/chunk-7N6DOREF.js +26 -0
  125. package/dist/cli-bundle/focused-chunks/{chunk-3BZEOXLT.js → chunk-7PC4R5QB.js} +2 -2
  126. package/dist/cli-bundle/focused-chunks/chunk-BUCJUZVG.js +6 -0
  127. package/dist/cli-bundle/focused-chunks/chunk-FE3BABLJ.js +2 -0
  128. package/dist/cli-bundle/focused-chunks/chunk-IWITF53W.js +2 -0
  129. package/dist/cli-bundle/focused-chunks/chunk-OQUGRHKV.js +10 -0
  130. package/dist/cli-bundle/focused-chunks/{chunk-M6PBRFSH.js → chunk-PNKIANFZ.js} +2 -2
  131. package/dist/cli-bundle/focused-chunks/{chunk-LIJIA4TY.js → chunk-QQQ4SAUO.js} +3 -3
  132. package/dist/cli-bundle/focused-chunks/chunk-TTYXF5YD.js +177 -0
  133. package/dist/cli-bundle/focused-chunks/chunk-XNR3DM6J.js +2 -0
  134. package/dist/cli-bundle/focused-chunks/chunk-XSS3APUF.js +9 -0
  135. package/dist/cli-bundle/focused-chunks/chunk-YCDQ2N23.js +8 -0
  136. package/dist/cli-bundle/focused-chunks/chunk-YJUXGS57.js +20 -0
  137. package/dist/cli-bundle/focused-chunks/chunk-ZTCE4UO6.js +58 -0
  138. package/dist/cli-bundle/main.js +20 -20
  139. package/dist/cli-bundle/sdk-authoring.js +1 -1
  140. package/dist/cli-bundle/sdk-contracts.js +2 -2
  141. package/dist/cli-bundle/sdk-core.js +37 -37
  142. package/dist/cli-bundle/sdk-governance.js +1 -1
  143. package/dist/cli-bundle/sdk-graph.js +1 -1
  144. package/dist/cli-bundle/sdk-merge.js +42 -42
  145. package/dist/cli-bundle/sdk-query.js +1 -1
  146. package/dist/cli-bundle/sdk-runtime.js +1 -1
  147. package/dist/cli-bundle/sdk-testing.js +1 -1
  148. package/dist/cli-bundle/sdk.js +11 -11
  149. package/dist/cli.js +1 -104
  150. package/dist/core/checkpoint/checkpoint-gc.js +1 -169
  151. package/dist/core/checkpoint/mutation-checkpoint.js +2 -133
  152. package/dist/core/config/nested-settings.js +1 -534
  153. package/dist/core/config/positional-value.js +1 -109
  154. package/dist/core/diagnostics/remediation.js +1 -506
  155. package/dist/core/extensions/activation-summary-markdown.js +2 -145
  156. package/dist/core/extensions/activation-summary.js +1 -92
  157. package/dist/core/extensions/activation-transaction.js +1 -46
  158. package/dist/core/extensions/capability-usage.js +1 -173
  159. package/dist/core/extensions/command-hook-context.js +1 -13
  160. package/dist/core/extensions/command-metadata-contract.js +1 -22
  161. package/dist/core/extensions/command-visibility-tier.js +1 -29
  162. package/dist/core/extensions/contribution-inventory.js +1 -173
  163. package/dist/core/extensions/exporter-output-contract.js +1 -66
  164. package/dist/core/extensions/extension-candidate.js +1 -18
  165. package/dist/core/extensions/extension-capability-aliases.js +1 -158
  166. package/dist/core/extensions/extension-hook-runtime.js +1 -699
  167. package/dist/core/extensions/extension-policy.js +1 -599
  168. package/dist/core/extensions/extension-registries.js +1 -62
  169. package/dist/core/extensions/extension-runtime-helpers.js +1 -33
  170. package/dist/core/extensions/extension-types.js +1 -102
  171. package/dist/core/extensions/flag-definition-validation.js +1 -52
  172. package/dist/core/extensions/flag-value-types.js +1 -64
  173. package/dist/core/extensions/index.js +1 -526
  174. package/dist/core/extensions/item-field-types.js +1 -39
  175. package/dist/core/extensions/item-fields.js +1 -261
  176. package/dist/core/extensions/loader.js +1 -2223
  177. package/dist/core/extensions/manifest-schema.js +1 -69
  178. package/dist/core/extensions/module-graph-snapshot.js +1 -33
  179. package/dist/core/extensions/preflight-ownership.js +1 -41
  180. package/dist/core/extensions/registration-validation.js +1 -82
  181. package/dist/core/extensions/registration-values.js +1 -209
  182. package/dist/core/extensions/reserved-host-flags.js +1 -36
  183. package/dist/core/extensions/runtime-registrations.js +1 -67
  184. package/dist/core/extensions/service-ownership.js +1 -19
  185. package/dist/core/extensions/version-compat.js +1 -216
  186. package/dist/core/fs/fs-utils.js +2 -158
  187. package/dist/core/fs/host-environment-errors.js +1 -141
  188. package/dist/core/fs/index.js +1 -9
  189. package/dist/core/fs/path-utils.js +1 -17
  190. package/dist/core/governance/content-fields.js +1 -160
  191. package/dist/core/governance/issue-codes.js +1 -151
  192. package/dist/core/governance/metadata-coverage.js +1 -358
  193. package/dist/core/history/drift-cache.js +3 -72
  194. package/dist/core/history/drift-scan.js +1 -342
  195. package/dist/core/history/event-classification.js +1 -109
  196. package/dist/core/history/event-index.js +8 -784
  197. package/dist/core/history/history-compact-bulk.js +1 -104
  198. package/dist/core/history/history-diff.js +1 -158
  199. package/dist/core/history/history-rewrite.d.ts +6 -1
  200. package/dist/core/history/history-rewrite.js +1 -107
  201. package/dist/core/history/history-storage-stats.js +1 -102
  202. package/dist/core/history/history-stream-policy.js +1 -62
  203. package/dist/core/history/history.js +2 -617
  204. package/dist/core/history/identity.js +1 -30
  205. package/dist/core/history/index.js +1 -9
  206. package/dist/core/history/projection.js +1 -196
  207. package/dist/core/history/read.d.ts +9 -0
  208. package/dist/core/history/read.js +1 -57
  209. package/dist/core/history/replay.js +2 -439
  210. package/dist/core/history/version-address.js +1 -32
  211. package/dist/core/history/workspace-history.js +2 -433
  212. package/dist/core/io/body-file.js +1 -62
  213. package/dist/core/io/bulk-ids-input.js +1 -112
  214. package/dist/core/item/actionability.js +1 -327
  215. package/dist/core/item/dependency-reference.js +1 -20
  216. package/dist/core/item/id.js +1 -112
  217. package/dist/core/item/index.js +1 -12
  218. package/dist/core/item/item-format-version.js +1 -78
  219. package/dist/core/item/item-format.js +5 -1473
  220. package/dist/core/item/item-record.js +1 -23
  221. package/dist/core/item/item-type-definition.js +1 -133
  222. package/dist/core/item/parent-reference-policy.js +1 -57
  223. package/dist/core/item/parse.js +2 -603
  224. package/dist/core/item/plan-lifecycle.js +1 -19
  225. package/dist/core/item/priority.js +1 -61
  226. package/dist/core/item/sprint-release-format.js +1 -38
  227. package/dist/core/item/status-filter.js +1 -115
  228. package/dist/core/item/status.js +1 -43
  229. package/dist/core/item/toon-decode.js +1 -29
  230. package/dist/core/item/type-registry.js +1 -715
  231. package/dist/core/item/type-synonyms.js +1 -38
  232. package/dist/core/lock/index.js +1 -9
  233. package/dist/core/lock/lock-gc.js +1 -240
  234. package/dist/core/lock/lock.js +3 -590
  235. package/dist/core/output/mutation-projection.js +1 -217
  236. package/dist/core/output/output-control.js +1 -25
  237. package/dist/core/output/output.js +11 -494
  238. package/dist/core/output/query-summary.js +1 -58
  239. package/dist/core/output/tabular.js +1 -77
  240. package/dist/core/packages/manifest.js +1 -244
  241. package/dist/core/packages/root.js +1 -84
  242. package/dist/core/policy/workflow-policy-schema.d.ts +312 -0
  243. package/dist/core/policy/workflow-policy-schema.js +2 -0
  244. package/dist/core/policy/workflow-policy-store.d.ts +24 -0
  245. package/dist/core/policy/workflow-policy-store.js +2 -0
  246. package/dist/core/policy/workflow-policy.d.ts +139 -0
  247. package/dist/core/policy/workflow-policy.js +2 -0
  248. package/dist/core/profile/profile-describe.js +1 -83
  249. package/dist/core/profile/profile-lint.js +1 -415
  250. package/dist/core/profile/profile-plan.js +0 -0
  251. package/dist/core/profile/profile-presets.js +1 -370
  252. package/dist/core/reproducibility/context.js +1 -82
  253. package/dist/core/schema/fields-file.js +2 -288
  254. package/dist/core/schema/item-types-file.js +2 -296
  255. package/dist/core/schema/runtime-field-filters.js +1 -49
  256. package/dist/core/schema/runtime-field-values.js +1 -313
  257. package/dist/core/schema/runtime-schema.js +2 -826
  258. package/dist/core/schema/status-defs-file.js +2 -227
  259. package/dist/core/schema/status-token.js +1 -31
  260. package/dist/core/schema/type-inference.js +1 -95
  261. package/dist/core/schema/type-presets.js +1 -87
  262. package/dist/core/schema/type-workflows.js +1 -104
  263. package/dist/core/search/background-refresh.js +2 -286
  264. package/dist/core/search/bm25.js +1 -146
  265. package/dist/core/search/cache.js +2 -534
  266. package/dist/core/search/corpus.js +1 -311
  267. package/dist/core/search/embedding-batches.js +1 -163
  268. package/dist/core/search/eval.js +1 -225
  269. package/dist/core/search/http-client.js +1 -75
  270. package/dist/core/search/providers.js +1 -242
  271. package/dist/core/search/relevance.js +1 -244
  272. package/dist/core/search/semantic-defaults.js +1 -199
  273. package/dist/core/search/staleness.js +1 -30
  274. package/dist/core/search/vector-stores.js +2 -664
  275. package/dist/core/search/vectorization-metadata.js +1 -81
  276. package/dist/core/sentry/helpers.js +1 -272
  277. package/dist/core/sentry/instrument.js +1 -387
  278. package/dist/core/session/session-state.js +1 -260
  279. package/dist/core/shared/agent-session-context.js +1 -133
  280. package/dist/core/shared/author.js +1 -1172
  281. package/dist/core/shared/command-types.js +1 -4
  282. package/dist/core/shared/conflict-markers.js +1 -31
  283. package/dist/core/shared/constants.js +1 -405
  284. package/dist/core/shared/errors.js +1 -20
  285. package/dist/core/shared/html-entity-decode.js +1 -131
  286. package/dist/core/shared/index.js +1 -12
  287. package/dist/core/shared/item-metadata-contract.js +1 -89
  288. package/dist/core/shared/lazy-module.js +1 -16
  289. package/dist/core/shared/levenshtein.js +1 -61
  290. package/dist/core/shared/memo.js +1 -19
  291. package/dist/core/shared/numeric-parsers.js +1 -20
  292. package/dist/core/shared/option-alias-visibility.js +1 -67
  293. package/dist/core/shared/primitives.js +1 -127
  294. package/dist/core/shared/serial-queue.js +1 -79
  295. package/dist/core/shared/serialization.js +1 -210
  296. package/dist/core/shared/split-comma-list.js +1 -30
  297. package/dist/core/shared/text-normalization.js +1 -38
  298. package/dist/core/shared/time.js +1 -306
  299. package/dist/core/store/index.js +1 -12
  300. package/dist/core/store/item-format-migration.js +1 -125
  301. package/dist/core/store/item-metadata-cache.js +1 -1116
  302. package/dist/core/store/item-metadata-query-index.js +9 -394
  303. package/dist/core/store/item-metadata-read-work.js +1 -43
  304. package/dist/core/store/item-store.js +1 -693
  305. package/dist/core/store/paths.d.ts +1 -1
  306. package/dist/core/store/paths.js +1 -214
  307. package/dist/core/store/settings-read-cache.js +1 -85
  308. package/dist/core/store/settings-validator.d.ts +1 -0
  309. package/dist/core/store/settings-validator.js +1 -421
  310. package/dist/core/store/settings.js +3 -1309
  311. package/dist/core/store/tracker-preflight.js +1 -141
  312. package/dist/core/telemetry/consent.js +5 -108
  313. package/dist/core/telemetry/observability.js +1 -246
  314. package/dist/core/telemetry/runtime.js +4 -1988
  315. package/dist/core/test/background-runs.js +4 -945
  316. package/dist/core/test/item-test-run-tracking.js +1 -63
  317. package/dist/core/test/run-selectors.js +1 -120
  318. package/dist/core/validate/estimate-defaults.js +1 -89
  319. package/dist/core/validate/fix-planning.js +1 -189
  320. package/dist/core/validate/linked-artifact-reference.js +1 -36
  321. package/dist/core/validate/missing-by-type.js +1 -34
  322. package/dist/core/validate/missing-link-owners.js +1 -95
  323. package/dist/core/validate/stale-file-classification.js +1 -82
  324. package/dist/mcp/http-server.js +5 -448
  325. package/dist/mcp/legacy-adapter.js +1 -77
  326. package/dist/mcp/runtime-capabilities.js +1 -200
  327. package/dist/mcp/server.js +4 -1233
  328. package/dist/mcp/tool-definitions.js +1 -804
  329. package/dist/sdk/actionability.js +1 -13
  330. package/dist/sdk/agent/closed-domain-contracts.js +1 -161
  331. package/dist/sdk/agent/command-recovery.js +1 -59
  332. package/dist/sdk/agent/command-suggestions.js +1 -66
  333. package/dist/sdk/agent/create-option-policy.js +1 -31
  334. package/dist/sdk/agent/identity-config.js +1 -106
  335. package/dist/sdk/agent/item-addressing.js +1 -207
  336. package/dist/sdk/agent/refusal-closure-census.js +1 -151
  337. package/dist/sdk/agent/refusal-closure.js +1 -133
  338. package/dist/sdk/agent/refusal-corpus-contracts.js +1 -193
  339. package/dist/sdk/agent/refusal-reachability.js +1 -593
  340. package/dist/sdk/agent/subcommand-recovery.js +1 -83
  341. package/dist/sdk/agent/task-transcript-contracts.js +1 -197
  342. package/dist/sdk/agent/tracker-preflight-contracts.js +1 -126
  343. package/dist/sdk/agent-capability-contracts.js +1 -428
  344. package/dist/sdk/agent-session-context.js +1 -9
  345. package/dist/sdk/annotations.js +1 -448
  346. package/dist/sdk/author-attribution.js +1 -468
  347. package/dist/sdk/authoring.js +1 -20
  348. package/dist/sdk/cli-bootstrap.js +1 -838
  349. package/dist/sdk/cli-contracts/agent-output-contracts.d.ts +1 -1
  350. package/dist/sdk/cli-contracts/agent-output-contracts.js +4 -476
  351. package/dist/sdk/cli-contracts/bootstrap-command-scanner.js +1 -79
  352. package/dist/sdk/cli-contracts/command-aliases.d.ts +4 -0
  353. package/dist/sdk/cli-contracts/command-aliases.js +1 -107
  354. package/dist/sdk/cli-contracts/command-exit-contracts.js +1 -151
  355. package/dist/sdk/cli-contracts/commander-mutation-options.js +1 -1081
  356. package/dist/sdk/cli-contracts/commander-types.js +1 -159
  357. package/dist/sdk/cli-contracts/completeness.js +1 -393
  358. package/dist/sdk/cli-contracts/enum-contracts.d.ts +1 -1
  359. package/dist/sdk/cli-contracts/enum-contracts.js +1 -222
  360. package/dist/sdk/cli-contracts/flag-contracts.js +1 -1947
  361. package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +1 -347
  362. package/dist/sdk/cli-contracts/grammar-contracts.js +1 -986
  363. package/dist/sdk/cli-contracts/registration-helpers.js +7 -990
  364. package/dist/sdk/cli-contracts/runtime-contracts.d.ts +5 -0
  365. package/dist/sdk/cli-contracts/runtime-contracts.js +1 -2090
  366. package/dist/sdk/cli-contracts/schemas/assurance-definition.js +1 -324
  367. package/dist/sdk/cli-contracts/string-lists.js +1 -16
  368. package/dist/sdk/cli-contracts/tool-option-contracts.js +1 -461
  369. package/dist/sdk/cli-contracts/tool-parameter-tables.js +1 -2167
  370. package/dist/sdk/cli-contracts/tool-schema.d.ts +3 -1
  371. package/dist/sdk/cli-contracts/tool-schema.js +1 -1664
  372. package/dist/sdk/cli-contracts/typed-action-inputs.js +1 -4
  373. package/dist/sdk/cli-contracts.d.ts +1 -1
  374. package/dist/sdk/cli-contracts.js +1 -17
  375. package/dist/sdk/cli-program.js +1 -49
  376. package/dist/sdk/command-line.d.ts +2 -5
  377. package/dist/sdk/command-line.js +1 -78
  378. package/dist/sdk/comments.js +1 -133
  379. package/dist/sdk/compile-cache.js +1 -73
  380. package/dist/sdk/completion.js +174 -839
  381. package/dist/sdk/compose.js +1 -1090
  382. package/dist/sdk/config.js +1 -1204
  383. package/dist/sdk/context/recency.js +1 -33
  384. package/dist/sdk/context/semantic-session-attribution.js +1 -82
  385. package/dist/sdk/context/usage-egress.js +1 -29
  386. package/dist/sdk/context/usage-ledger.js +3 -185
  387. package/dist/sdk/context-intent-contracts.js +1 -709
  388. package/dist/sdk/context-intent-runtime.js +1 -115
  389. package/dist/sdk/context-packing.js +1 -218
  390. package/dist/sdk/context-relevance.js +1 -503
  391. package/dist/sdk/context-signal-store.js +2 -426
  392. package/dist/sdk/context-usage.js +1 -367
  393. package/dist/sdk/contracts.js +1 -23
  394. package/dist/sdk/core-governance.js +1 -14
  395. package/dist/sdk/core.js +1 -14
  396. package/dist/sdk/corpus-shape.js +1 -401
  397. package/dist/sdk/define.js +1 -220
  398. package/dist/sdk/dependencies.js +1 -718
  399. package/dist/sdk/dependency-flag-validation.js +1 -156
  400. package/dist/sdk/dependency-provenance.js +1 -135
  401. package/dist/sdk/docs.js +1 -14
  402. package/dist/sdk/duplicates.js +1 -40
  403. package/dist/sdk/environment/agent-environment.js +1 -466
  404. package/dist/sdk/environment/host-environment-errors.js +1 -8
  405. package/dist/sdk/environment/project-runtime-compatibility.js +1 -481
  406. package/dist/sdk/environment/source-context.js +1 -28
  407. package/dist/sdk/environment/tracker-preflight.js +1 -9
  408. package/dist/sdk/error-code-catalog.js +1 -153
  409. package/dist/sdk/error-runtime.js +1 -58
  410. package/dist/sdk/errors.js +1 -58
  411. package/dist/sdk/eval.js +1 -190
  412. package/dist/sdk/extension/author-manifest.js +1 -92
  413. package/dist/sdk/extension/bundled-catalog.js +1 -332
  414. package/dist/sdk/extension/concurrency.js +1 -25
  415. package/dist/sdk/extension/copy-scope.d.ts +2 -0
  416. package/dist/sdk/extension/copy-scope.js +2 -0
  417. package/dist/sdk/extension/custom-field-collisions.js +1 -30
  418. package/dist/sdk/extension/describe.js +3 -189
  419. package/dist/sdk/extension/doctor.js +1 -606
  420. package/dist/sdk/extension/install-plan.d.ts +69 -0
  421. package/dist/sdk/extension/install-plan.js +2 -0
  422. package/dist/sdk/extension/install-receipts.d.ts +7 -0
  423. package/dist/sdk/extension/install-receipts.js +2 -0
  424. package/dist/sdk/extension/install-runtime.js +3 -313
  425. package/dist/sdk/extension/install-snapshot.js +1 -66
  426. package/dist/sdk/extension/install-sources.js +5 -1057
  427. package/dist/sdk/extension/managed-state.js +2 -252
  428. package/dist/sdk/extension/migrations.js +2 -174
  429. package/dist/sdk/extension/output-ownership.js +1 -25
  430. package/dist/sdk/extension/runtime-summary.js +1 -18
  431. package/dist/sdk/extension/scaffold.js +4 -2308
  432. package/dist/sdk/extension/shared.js +1 -147
  433. package/dist/sdk/extension/source-resolution.js +1 -65
  434. package/dist/sdk/extension/update-check.js +1 -67
  435. package/dist/sdk/extension-command-context.js +1 -44
  436. package/dist/sdk/extension-contracts.js +1 -73
  437. package/dist/sdk/extension.d.ts +7 -2
  438. package/dist/sdk/extension.js +1 -2196
  439. package/dist/sdk/files.js +1 -535
  440. package/dist/sdk/flag-invocation-contracts.d.ts +0 -5
  441. package/dist/sdk/flag-invocation-contracts.js +1 -344
  442. package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1 -2224
  443. package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -2236
  444. package/dist/sdk/generated-error-code-catalog.js +1 -16
  445. package/dist/sdk/governance/assurance-action-contracts.js +1 -4
  446. package/dist/sdk/governance/assurance-action.js +1 -411
  447. package/dist/sdk/governance/assurance-limits.js +1 -10
  448. package/dist/sdk/governance/assurance-mutation-error.js +1 -81
  449. package/dist/sdk/governance/assurance-presets.js +1 -135
  450. package/dist/sdk/governance/assurance-runtime.js +1 -238
  451. package/dist/sdk/governance/assurance.js +4 -1182
  452. package/dist/sdk/governance/boundary-fixtures.js +1 -200
  453. package/dist/sdk/governance/coverage-assurance.js +1 -60
  454. package/dist/sdk/governance/defect-recurrence-coverage.js +1 -188
  455. package/dist/sdk/governance/defect-recurrence-graph.js +1 -120
  456. package/dist/sdk/governance/defect-recurrence-signals.js +1 -24
  457. package/dist/sdk/governance/defect-recurrence.js +1 -623
  458. package/dist/sdk/governance/extension-host-version.js +1 -115
  459. package/dist/sdk/governance/gc.js +1 -368
  460. package/dist/sdk/governance/health.js +1 -2367
  461. package/dist/sdk/governance/hierarchy-validation.js +1 -108
  462. package/dist/sdk/governance/linked-file-report.js +1 -71
  463. package/dist/sdk/governance/merge-receipt-history.js +1 -206
  464. package/dist/sdk/governance/provenance-health.js +1 -282
  465. package/dist/sdk/governance/reindex.js +4 -761
  466. package/dist/sdk/governance/stale-work.js +1 -82
  467. package/dist/sdk/governance/status-role-diagnostics.js +1 -35
  468. package/dist/sdk/governance/storage-integrity.js +1 -280
  469. package/dist/sdk/governance/tracked-runtime-cache.js +1 -106
  470. package/dist/sdk/governance/upgrade.js +2 -327
  471. package/dist/sdk/governance/validate-history-drift.js +1 -81
  472. package/dist/sdk/governance/validate-item-reader.js +1 -17
  473. package/dist/sdk/governance/validate-normalization.js +1 -36
  474. package/dist/sdk/governance/validate.d.ts +3 -1
  475. package/dist/sdk/governance/validate.js +1 -2261
  476. package/dist/sdk/governance/workflow-completeness.d.ts +32 -0
  477. package/dist/sdk/governance/workflow-completeness.js +2 -0
  478. package/dist/sdk/governance/workflow-policy.d.ts +47 -0
  479. package/dist/sdk/governance/workflow-policy.js +4 -0
  480. package/dist/sdk/governance/workspace-position.js +1 -163
  481. package/dist/sdk/governance.d.ts +2 -0
  482. package/dist/sdk/governance.js +1 -31
  483. package/dist/sdk/graph/adapter.js +1 -181
  484. package/dist/sdk/graph/analytics.js +1 -474
  485. package/dist/sdk/graph/assembly.js +1 -377
  486. package/dist/sdk/graph/cache.js +1 -160
  487. package/dist/sdk/graph/centrality.js +1 -258
  488. package/dist/sdk/graph/conformance.js +1 -130
  489. package/dist/sdk/graph/deadline-scheduling.d.ts +90 -0
  490. package/dist/sdk/graph/deadline-scheduling.js +2 -0
  491. package/dist/sdk/graph/durable-cache.d.ts +1 -1
  492. package/dist/sdk/graph/durable-cache.js +1 -361
  493. package/dist/sdk/graph/governance-contracts.js +1 -34
  494. package/dist/sdk/graph/governance.d.ts +13 -1
  495. package/dist/sdk/graph/governance.js +1 -735
  496. package/dist/sdk/graph/hierarchy-integrity.js +1 -310
  497. package/dist/sdk/graph/index.d.ts +3 -2
  498. package/dist/sdk/graph/index.js +1 -26
  499. package/dist/sdk/graph/lifecycle-coverage.d.ts +32 -0
  500. package/dist/sdk/graph/lifecycle-coverage.js +2 -0
  501. package/dist/sdk/graph/mutation-advisory.js +1 -176
  502. package/dist/sdk/graph/remediation.js +1 -197
  503. package/dist/sdk/graph/run.d.ts +15 -1
  504. package/dist/sdk/graph/run.js +1 -768
  505. package/dist/sdk/graph/scheduling.js +1 -124
  506. package/dist/sdk/graph/traversal.js +1 -284
  507. package/dist/sdk/graph/workspace-relationship-kind-registry.js +1 -27
  508. package/dist/sdk/graph.js +1 -15
  509. package/dist/sdk/guide-topics.js +1 -707
  510. package/dist/sdk/guide.js +1 -279
  511. package/dist/sdk/history/maintenance.d.ts +71 -0
  512. package/dist/sdk/history/maintenance.js +2 -0
  513. package/dist/sdk/history/salvage.js +2 -247
  514. package/dist/sdk/history/subject.d.ts +19 -0
  515. package/dist/sdk/history/subject.js +2 -0
  516. package/dist/sdk/history-analytics.js +1 -282
  517. package/dist/sdk/history-compact.js +1 -527
  518. package/dist/sdk/history-mcp.js +1 -68
  519. package/dist/sdk/history-provenance.js +1 -182
  520. package/dist/sdk/history-read.js +1 -96
  521. package/dist/sdk/history-redact.d.ts +1 -14
  522. package/dist/sdk/history-redact.js +1 -643
  523. package/dist/sdk/history-repair.d.ts +5 -0
  524. package/dist/sdk/history-repair.js +1 -657
  525. package/dist/sdk/improvement-ledger-validation.js +1 -62
  526. package/dist/sdk/improvement-ledger.js +2 -257
  527. package/dist/sdk/index.d.ts +4 -1
  528. package/dist/sdk/index.js +1 -183
  529. package/dist/sdk/init-agent-guidance.js +2 -496
  530. package/dist/sdk/init.js +2 -820
  531. package/dist/sdk/invocation-author.js +1 -39
  532. package/dist/sdk/item-children.js +1 -90
  533. package/dist/sdk/item-metadata-index.js +1 -15
  534. package/dist/sdk/item-schedule.js +1 -27
  535. package/dist/sdk/item-transaction.js +1 -396
  536. package/dist/sdk/learnings.js +1 -29
  537. package/dist/sdk/lifecycle/append.js +2 -53
  538. package/dist/sdk/lifecycle/claim.d.ts +2 -0
  539. package/dist/sdk/lifecycle/claim.js +1 -242
  540. package/dist/sdk/lifecycle/close-many.js +1 -438
  541. package/dist/sdk/lifecycle/close.js +1 -468
  542. package/dist/sdk/lifecycle/copy.js +1 -212
  543. package/dist/sdk/lifecycle/create.js +1 -1949
  544. package/dist/sdk/lifecycle/delete.js +1 -45
  545. package/dist/sdk/lifecycle/event-validation-messages.js +1 -91
  546. package/dist/sdk/lifecycle/focus.js +1 -91
  547. package/dist/sdk/lifecycle/hierarchy-mutation-lock.js +1 -24
  548. package/dist/sdk/lifecycle/legacy-none-tokens.js +1 -149
  549. package/dist/sdk/lifecycle/lifecycle-transitions.js +1 -40
  550. package/dist/sdk/lifecycle/mcp-actions.d.ts +2 -0
  551. package/dist/sdk/lifecycle/mcp-actions.js +1 -51
  552. package/dist/sdk/lifecycle/metadata-normalizers.js +1 -46
  553. package/dist/sdk/lifecycle/mutation-command-options.js +1 -9
  554. package/dist/sdk/lifecycle/plan.js +1 -1606
  555. package/dist/sdk/lifecycle/recurrence-parsers.d.ts +1 -1
  556. package/dist/sdk/lifecycle/recurrence-parsers.js +1 -147
  557. package/dist/sdk/lifecycle/reopen.js +1 -68
  558. package/dist/sdk/lifecycle/repeatable-metadata-parsers.js +1 -143
  559. package/dist/sdk/lifecycle/restore.d.ts +1 -0
  560. package/dist/sdk/lifecycle/restore.js +1 -330
  561. package/dist/sdk/lifecycle/shared-unset-fields.js +1 -295
  562. package/dist/sdk/lifecycle/update-many.js +1 -861
  563. package/dist/sdk/lifecycle/update.js +1 -2136
  564. package/dist/sdk/lifecycle-completion.js +1 -92
  565. package/dist/sdk/lifecycle-policy.js +1 -120
  566. package/dist/sdk/linked-artifacts.js +1 -530
  567. package/dist/sdk/mcp/apps.js +4 -133
  568. package/dist/sdk/mcp/authorization.js +1 -404
  569. package/dist/sdk/mcp/discovery.js +1 -494
  570. package/dist/sdk/mcp/interactions.js +1 -336
  571. package/dist/sdk/mcp/protocol.d.ts +7 -0
  572. package/dist/sdk/mcp/protocol.js +1 -184
  573. package/dist/sdk/mcp/skills.js +1 -389
  574. package/dist/sdk/mcp/subscriptions.js +1 -211
  575. package/dist/sdk/mcp/tasks.js +2 -430
  576. package/dist/sdk/mcp/transport.js +1 -260
  577. package/dist/sdk/merge/abandoned-receipts.js +1 -46
  578. package/dist/sdk/merge/driver.js +1 -212
  579. package/dist/sdk/merge/index.js +1 -16
  580. package/dist/sdk/merge/install.js +3 -561
  581. package/dist/sdk/merge/receipt-file-boundary.js +1 -46
  582. package/dist/sdk/merge/receipt-operation.js +1 -96
  583. package/dist/sdk/merge/receipt-schema.js +1 -397
  584. package/dist/sdk/merge/receipts.js +4 -525
  585. package/dist/sdk/merge/reconcile.js +1 -352
  586. package/dist/sdk/merge/three-way.js +3 -775
  587. package/dist/sdk/merge.js +1 -10
  588. package/dist/sdk/mutation-events.js +1 -292
  589. package/dist/sdk/mutation-guard.js +1 -216
  590. package/dist/sdk/notes.js +1 -139
  591. package/dist/sdk/output-contracts.js +1 -172
  592. package/dist/sdk/output-projection.js +1 -430
  593. package/dist/sdk/output-token-accounting.js +1 -140
  594. package/dist/sdk/output.js +1 -64
  595. package/dist/sdk/ownership-source.js +1 -21
  596. package/dist/sdk/package-import-adapters.js +1 -442
  597. package/dist/sdk/package-migrations.js +1 -20
  598. package/dist/sdk/package-runtime-options.js +1 -80
  599. package/dist/sdk/pagination.js +1 -162
  600. package/dist/sdk/profile.js +1 -454
  601. package/dist/sdk/provenance.js +1 -258
  602. package/dist/sdk/public-surface.json +1 -1
  603. package/dist/sdk/query/activity.js +1 -401
  604. package/dist/sdk/query/aggregate.d.ts +16 -0
  605. package/dist/sdk/query/aggregate.js +1 -390
  606. package/dist/sdk/query/calendar.js +1 -964
  607. package/dist/sdk/query/complete-list.js +1 -215
  608. package/dist/sdk/query/context.js +1 -1702
  609. package/dist/sdk/query/duplicate-candidates.js +1 -70
  610. package/dist/sdk/query/get.js +1 -450
  611. package/dist/sdk/query/history.js +1 -186
  612. package/dist/sdk/query/item-filter-options.js +1 -9
  613. package/dist/sdk/query/light-metadata.js +1 -18
  614. package/dist/sdk/query/list-filter-shared.js +1 -81
  615. package/dist/sdk/query/list.js +1 -1304
  616. package/dist/sdk/query/multi-value-filters.js +1 -78
  617. package/dist/sdk/query/next.js +1 -513
  618. package/dist/sdk/query/parsers.js +1 -44
  619. package/dist/sdk/query/projection-contracts.js +1 -184
  620. package/dist/sdk/query/search-contracts.d.ts +27 -0
  621. package/dist/sdk/query/search-contracts.js +1 -230
  622. package/dist/sdk/query/search-pagination.js +1 -35
  623. package/dist/sdk/query/search-rendering.js +1 -105
  624. package/dist/sdk/query/search.d.ts +6 -4
  625. package/dist/sdk/query/search.js +2 -1987
  626. package/dist/sdk/query.js +1 -35
  627. package/dist/sdk/read-output/continuation.js +1 -194
  628. package/dist/sdk/read-output-budget.js +1 -135
  629. package/dist/sdk/read-output-contracts.d.ts +1 -1
  630. package/dist/sdk/read-output-contracts.js +1 -1225
  631. package/dist/sdk/read-output-rows.js +1 -186
  632. package/dist/sdk/read-output-session.js +1 -208
  633. package/dist/sdk/relationship-analytics.js +1 -410
  634. package/dist/sdk/relationship-context.js +1 -284
  635. package/dist/sdk/relationship-history.js +4 -519
  636. package/dist/sdk/relationship-kinds/contract.js +1 -22
  637. package/dist/sdk/relationship-migration.js +1 -77
  638. package/dist/sdk/relationships.js +1 -579
  639. package/dist/sdk/reproducibility/process.js +1 -87
  640. package/dist/sdk/runtime-action-aliases.js +1 -59
  641. package/dist/sdk/runtime-extended-actions.js +1 -177
  642. package/dist/sdk/runtime-input.js +1 -614
  643. package/dist/sdk/runtime-primitives.js +1 -84
  644. package/dist/sdk/runtime-public-contracts.d.ts +2 -1
  645. package/dist/sdk/runtime-public-contracts.js +1 -4
  646. package/dist/sdk/runtime-stats-options.js +1 -38
  647. package/dist/sdk/runtime.d.ts +4 -0
  648. package/dist/sdk/runtime.js +1 -1928
  649. package/dist/sdk/scheduling-shortcuts.js +1 -63
  650. package/dist/sdk/schema-migration.js +3 -856
  651. package/dist/sdk/schema.d.ts +2 -1
  652. package/dist/sdk/schema.js +1 -1376
  653. package/dist/sdk/search-refresh-worker.js +1 -18
  654. package/dist/sdk/similarity-scoring.js +1 -53
  655. package/dist/sdk/similarity.js +1 -326
  656. package/dist/sdk/start-task-status.js +1 -14
  657. package/dist/sdk/stats.js +1 -270
  658. package/dist/sdk/structured-mutations.js +1 -580
  659. package/dist/sdk/telemetry-flush.js +1 -13
  660. package/dist/sdk/telemetry.js +1 -405
  661. package/dist/sdk/templates.js +2 -292
  662. package/dist/sdk/test/batch.js +2 -509
  663. package/dist/sdk/test/entry.js +1 -70
  664. package/dist/sdk/test/execution.js +6 -2211
  665. package/dist/sdk/test/linked-command-detection.js +1 -546
  666. package/dist/sdk/test/measurements.js +1 -91
  667. package/dist/sdk/test/parsers.js +1 -545
  668. package/dist/sdk/test/runs.js +1 -193
  669. package/dist/sdk/test/trust.js +2 -206
  670. package/dist/sdk/testing.js +4 -1391
  671. package/dist/sdk/traceability/runtime-files-lookup.js +1 -32
  672. package/dist/sdk/traceability/source-traceability.js +1 -292
  673. package/dist/sdk/tracker-root-discovery.js +1 -9
  674. package/dist/sdk/workspace-contracts-cache.js +1 -28
  675. package/dist/sdk/workspace-contracts.js +1 -33
  676. package/dist/sdk/workspace-memory.js +2 -318
  677. package/dist/sdk/workspace-recipe.js +1 -71
  678. package/dist/sdk/workspace-snapshot.js +4 -613
  679. package/dist/sdk/workspace-transaction-gc.js +1 -149
  680. package/dist/sdk/workspace-transaction.js +2 -363
  681. package/dist/sdk/workspace.js +3 -127
  682. package/dist/types/index.js +1 -9
  683. package/dist/types.d.ts +4 -0
  684. package/dist/types.js +1 -245
  685. package/docs/AGENT_GUIDE.md +1 -1
  686. package/docs/COMMANDS.md +10 -0
  687. package/docs/CONFIGURATION.md +12 -1
  688. package/docs/CONTEXT_ALGORITHM_PORTFOLIO.md +167 -0
  689. package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +9 -3
  690. package/docs/EXTENSIONS.md +1 -0
  691. package/docs/HISTORY_MAINTENANCE.md +125 -0
  692. package/docs/MCP_2026_07_28_CONFORMANCE.md +20 -10
  693. package/docs/PACKAGE_EVIDENCE.md +92 -0
  694. package/docs/PLANNING_MEASUREMENTS.md +183 -0
  695. package/docs/README.md +4 -0
  696. package/docs/READ_OUTPUT_CONTRACTS.md +5 -0
  697. package/docs/SCRIPTING.md +21 -0
  698. package/docs/TESTING.md +33 -0
  699. package/docs/WORKFLOW_POLICIES.md +129 -0
  700. package/docs/generated/FLAG_LEXICON_BUDGETS.md +7 -7
  701. package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +11 -5
  702. package/marketplace.json +2 -2
  703. package/package.json +5 -5
  704. package/packages/pm-beads/package.json +1 -1
  705. package/packages/pm-calendar/package.json +1 -1
  706. package/packages/pm-command-kit/package.json +1 -1
  707. package/packages/pm-digital-twin/package.json +1 -1
  708. package/packages/pm-governance-audit/package.json +1 -1
  709. package/packages/pm-guide-shell/package.json +1 -1
  710. package/packages/pm-kanban/package.json +1 -1
  711. package/packages/pm-lifecycle-hooks/package.json +1 -1
  712. package/packages/pm-linked-test-adapters/package.json +1 -1
  713. package/packages/pm-search-advanced/package.json +1 -1
  714. package/packages/pm-templates/package.json +1 -1
  715. package/packages/pm-todos/package.json +1 -1
  716. package/packages/pm-vcs/package.json +1 -1
  717. package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
  718. package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
  719. package/scripts/finalize-build.mjs +45 -3
  720. package/dist/cli-bundle/chunks/chunk-AZDFJGH6.js +0 -9
  721. package/dist/cli-bundle/chunks/chunk-CKOL5U7J.js +0 -77
  722. package/dist/cli-bundle/chunks/chunk-JX4DH4WC.js +0 -3
  723. package/dist/cli-bundle/chunks/chunk-OF76PSDQ.js +0 -5
  724. package/dist/cli-bundle/chunks/chunk-QUWFABDM.js +0 -232
  725. package/dist/cli-bundle/chunks/chunk-QWRRFYK3.js +0 -2
  726. package/dist/cli-bundle/chunks/chunk-RWWBOWJ5.js +0 -2
  727. package/dist/cli-bundle/chunks/chunk-WGAOYSYH.js +0 -40
  728. package/dist/cli-bundle/chunks/chunk-WI2AYPA7.js +0 -2
  729. package/dist/cli-bundle/chunks/register-list-query-5JL52D33.js +0 -11
  730. package/dist/cli-bundle/chunks/register-mutation-ZPG7KMVP.js +0 -20
  731. package/dist/cli-bundle/chunks/register-operations-I5W3KMGB.js +0 -2
  732. package/dist/cli-bundle/chunks/register-setup-H4SVAVX7.js +0 -2
  733. package/dist/cli-bundle/focused-chunks/chunk-AL5ON6K6.js +0 -2
  734. package/dist/cli-bundle/focused-chunks/chunk-CHC2IDXA.js +0 -6
  735. package/dist/cli-bundle/focused-chunks/chunk-CK6QFAPZ.js +0 -20
  736. package/dist/cli-bundle/focused-chunks/chunk-EZR3GHFE.js +0 -2
  737. package/dist/cli-bundle/focused-chunks/chunk-H2WJWK7L.js +0 -56
  738. package/dist/cli-bundle/focused-chunks/chunk-NTPY5GSO.js +0 -3
  739. package/dist/cli-bundle/focused-chunks/chunk-P5O7MP5Y.js +0 -2
  740. package/dist/cli-bundle/focused-chunks/chunk-PDMW2E36.js +0 -177
  741. package/dist/cli-bundle/focused-chunks/chunk-PEFABF7E.js +0 -26
  742. package/dist/cli-bundle/focused-chunks/chunk-QTVCLMSZ.js +0 -6
  743. package/dist/cli-bundle/focused-chunks/chunk-QTZRBUYA.js +0 -8
  744. package/dist/cli-bundle/focused-chunks/chunk-SGQST3PQ.js +0 -12
  745. package/dist/cli-bundle/focused-chunks/chunk-UKHASMMP.js +0 -10
  746. package/dist/cli-bundle/focused-chunks/chunk-ZPEKQHOC.js +0 -2
@@ -1,1392 +1,5 @@
1
-
2
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a09f5e0d-fccc-5a22-a6f3-0a37cbeea3b0")}catch(e){}}();
3
- import { activateExtensions, deactivateExtensions, runAfterCommandHooks, runBeforeCommandHooks, runBeforeMutationHooks, runCommandHandler, runCommandOverride, runOnIndexHooks, runOnReadHooks, runOnWriteHooks, runParserOverride, runPreflightOverride, runRendererOverride, runServiceOverride, } from "../core/extensions/loader.js";
4
- import { createDefaultExtensionGovernancePolicy } from "../core/extensions/extension-types.js";
5
- import { getMigrationRuntimeDefinition, resolveRegisteredSearchProvider, resolveRegisteredVectorStoreAdapter, } from "../core/extensions/runtime-registrations.js";
6
- import { collectUsedExtensionCapabilities } from "../core/extensions/capability-usage.js";
7
- import { normalizeKnownExtensionCapability } from "../core/extensions/extension-capability-aliases.js";
8
- import { checkExtensionManifestCompatibility, describeExtensionBlueprint, lintExtensionBlueprint, preflightExtension, } from "./compose.js";
9
- import { describeExtensionActivation } from "../core/extensions/activation-summary.js";
10
- import { lintProjectProfile, } from "../core/profile/profile-lint.js";
11
- import { renderExtensionSurfaceMarkdown } from "../core/extensions/activation-summary-markdown.js";
12
- import { asPropertyRecord, resolveActivatablePropertyRecord, } from "../core/shared/primitives.js";
13
- import { createExtensionCommandSdk } from "./extension-command-context.js";
14
- import { PmClient } from "./runtime.js";
15
- // `describeExtensionActivation` is the `describe` (enumerate-all) verb that
16
- // pairs with the `assert*` (verify-one) and `run*` (invoke-one) helpers below.
17
- // It lives in core (it walks the same registries the loader populates) and is
18
- // surfaced here so package authors get the whole testing surface from the
19
- // `@unbrained/pm-cli/sdk/testing` subpath.
20
- export { describeExtensionActivation, renderExtensionSurfaceMarkdown };
21
- // `composeExtension`'s author-time companions: describe a blueprint's surface map
22
- // and preflight it for capability drift / duplicate / empty-surface footguns
23
- // without activating. Surfaced through the `@unbrained/pm-cli/sdk/testing` subpath
24
- // so a package author gets the full author → describe → preflight → test loop here,
25
- // alongside the assert*/run* helpers; `assertExtensionBlueprint` below is the
26
- // throwing assertion that pairs with the non-throwing `lintExtensionBlueprint`.
27
- export { describeExtensionBlueprint, lintExtensionBlueprint };
28
- function registeredExpectationName(expectation, legacyValue) {
29
- return expectation.name ?? legacyValue ?? "";
30
- }
31
- const HOOK_KIND_TO_REGISTRY_FIELD = {
32
- before_command: "beforeCommand",
33
- before_mutation: "beforeMutation",
34
- after_command: "afterCommand",
35
- on_read: "onRead",
36
- on_write: "onWrite",
37
- on_index: "onIndex",
38
- };
39
- const RUNNABLE_HOOK_KIND_TO_REGISTRY_FIELD = {
40
- before_command: "beforeCommand",
41
- after_command: "afterCommand",
42
- on_read: "onRead",
43
- on_write: "onWrite",
44
- on_index: "onIndex",
45
- };
46
- function normalizeSdkIdentifier(value) {
47
- return value.trim().toLowerCase();
48
- }
49
- /**
50
- * Match key for profile-name assertions. Extends {@link normalizeSdkIdentifier}
51
- * with hyphen→underscore folding so the assertion mirrors the runtime profile
52
- * resolution (`pm profile`), which treats `my-flow` and `my_flow` as the same
53
- * archetype. Profiles are the one registration surface that resolves
54
- * hyphen-insensitively (item types resolve by alias, migrations by exact id), so
55
- * — unlike the other `assertRegistered*` helpers — this one folds the separator
56
- * to stay in lockstep with how a profile is actually looked up by name.
57
- */
58
- function normalizeSdkProfileMatchKey(value) {
59
- return normalizeSdkIdentifier(value).replaceAll("-", "_");
60
- }
61
- function extensionNameSuffix(extensionName) {
62
- return extensionName ? ` from extension "${extensionName}"` : "";
63
- }
64
- function sortedUnique(values) {
65
- return [...new Set(values)].sort((left, right) => left.localeCompare(right));
66
- }
67
- function normalizeSdkCommandName(command) {
68
- if (typeof command !== "string") {
69
- // Positional misuse like runRegisteredCommandForTest(activation, "name", opts)
70
- // reaches here with `undefined` at runtime; guide instead of crashing on .trim().
71
- throw new Error('A command name string is required. Pass it via the options object, e.g. runRegisteredCommandForTest(activation, { command: "my command" }) — positional command arguments are not supported.');
72
- }
73
- return command
74
- .trim()
75
- .toLowerCase()
76
- .split(/\s+/)
77
- .filter((part) => part.length > 0)
78
- .join(" ");
79
- }
80
- function formatAvailable(values) {
81
- return values.length > 0 ? values.join(", ") : "(none)";
82
- }
83
- function assertStringSetIncludes(actual, expected, label) {
84
- const actualValues = new Set(actual ?? []);
85
- const missing = sortedUnique(expected.filter((value) => !actualValues.has(value)));
86
- if (missing.length > 0) {
87
- throw new Error(`Expected package manifest ${label} to include ${missing.join(", ")}; available: ${formatAvailable(sortedUnique(actual ?? []))}`);
88
- }
89
- }
90
- function collectFlagLabels(flags) {
91
- const labels = new Set();
92
- for (const flag of flags) {
93
- if (typeof flag.long === "string" && flag.long.trim().length > 0) {
94
- labels.add(flag.long.trim());
95
- }
96
- if (typeof flag.short === "string" && flag.short.trim().length > 0) {
97
- labels.add(flag.short.trim());
98
- }
99
- }
100
- return labels;
101
- }
102
- function readTestExtensionManifest(module) {
103
- const moduleRecord = asPropertyRecord(module);
104
- if (!moduleRecord) {
105
- return {};
106
- }
107
- const manifest = asPropertyRecord(moduleRecord.manifest);
108
- if (manifest) {
109
- return manifest;
110
- }
111
- const defaultExport = asPropertyRecord(moduleRecord.default);
112
- const defaultManifest = asPropertyRecord(defaultExport?.manifest);
113
- if (defaultManifest) {
114
- return defaultManifest;
115
- }
116
- if (defaultExport &&
117
- typeof moduleRecord.default !== "function" &&
118
- ("name" in defaultExport || "capabilities" in defaultExport)) {
119
- return defaultExport;
120
- }
121
- if (typeof module !== "function" &&
122
- ("name" in moduleRecord || "capabilities" in moduleRecord)) {
123
- return moduleRecord;
124
- }
125
- return {};
126
- }
127
- function resolveTestExtensionName(manifest, explicitName) {
128
- return (explicitName ??
129
- (typeof manifest.name === "string" && manifest.name.trim().length > 0
130
- ? manifest.name.trim()
131
- : "test-extension"));
132
- }
133
- function readTestExtensionCapabilities(manifest, options) {
134
- if (Array.isArray(options.capabilities)) {
135
- return [...options.capabilities];
136
- }
137
- if (Array.isArray(manifest.capabilities)) {
138
- return manifest.capabilities.filter((capability) => typeof capability === "string");
139
- }
140
- return [];
141
- }
142
- /**
143
- * Build the synthetic single-extension {@link ExtensionLoadResult} shared by the
144
- * activate/deactivate test helpers, so both stay aligned with the loader's load
145
- * contract as it evolves. The `loaded` entry mirrors the real on-disk shape
146
- * (including `capabilities` and the compatibility fields) while leaving
147
- * filesystem paths empty, since the module is supplied in memory.
148
- */
149
- function buildSingleExtensionLoadResult(module, manifest, identity) {
150
- return {
151
- disabled_by_flag: false,
152
- roots: { global: "", project: "" },
153
- configured_enabled: [],
154
- configured_disabled: [],
155
- discovered: [],
156
- effective: [],
157
- warnings: [],
158
- policy: identity.policy,
159
- failed: [],
160
- loaded: [
161
- {
162
- layer: identity.layer,
163
- directory: "",
164
- manifest_path: "",
165
- name: identity.name,
166
- version: typeof manifest.version === "string" ? manifest.version : "0.0.0",
167
- entry: typeof manifest.entry === "string" ? manifest.entry : "./index.js",
168
- priority: typeof manifest.priority === "number" ? manifest.priority : 0,
169
- entry_path: "",
170
- capabilities: identity.capabilities,
171
- manifest_version: typeof manifest.manifest_version === "number"
172
- ? manifest.manifest_version
173
- : undefined,
174
- pm_min_version: typeof manifest.pm_min_version === "string"
175
- ? manifest.pm_min_version
176
- : undefined,
177
- pm_max_version: typeof manifest.pm_max_version === "string"
178
- ? manifest.pm_max_version
179
- : undefined,
180
- engines: manifest.engines,
181
- trusted: manifest.trusted,
182
- provenance: manifest.provenance,
183
- sandbox_profile: manifest.sandbox_profile,
184
- permissions: manifest.permissions,
185
- activation: manifest.activation,
186
- module,
187
- },
188
- ],
189
- };
190
- }
191
- /**
192
- * Activate one in-memory extension module for package tests.
193
- *
194
- * This uses pm's real registration validation and activation engine while
195
- * avoiding private loader imports, filesystem manifests, or workspace setup.
196
- */
197
- export async function activateExtensionForTest(module, options = {}) {
198
- const manifest = readTestExtensionManifest(module);
199
- return activateExtensions(buildSingleExtensionLoadResult(module, manifest, {
200
- name: resolveTestExtensionName(manifest, options.name),
201
- layer: options.layer ?? "project",
202
- capabilities: readTestExtensionCapabilities(manifest, options),
203
- policy: options.policy ?? createDefaultExtensionGovernancePolicy(),
204
- }));
205
- }
206
- /**
207
- * Deactivate one in-memory extension module for package tests — the teardown
208
- * counterpart to {@link activateExtensionForTest}.
209
- *
210
- * Runs pm's real `deactivateExtensions` engine (including its bounded per-hook
211
- * timeout and best-effort failure capture) over a single synthetic load entry,
212
- * so authors can prove an extension's `deactivate` releases the resources its
213
- * `activate` opened — without importing private loader internals or staging a
214
- * workspace. Resolve `name`/`layer` the same way {@link activateExtensionForTest}
215
- * does so a forwarded `activation` result skips a failed extension correctly.
216
- */
217
- export async function deactivateExtensionForTest(module, options = {}) {
218
- const manifest = readTestExtensionManifest(module);
219
- return deactivateExtensions(buildSingleExtensionLoadResult(module, manifest, {
220
- name: resolveTestExtensionName(manifest, options.name),
221
- layer: options.layer ?? "project",
222
- capabilities: readTestExtensionCapabilities(manifest, {}),
223
- policy: createDefaultExtensionGovernancePolicy(),
224
- }), options.activation, options.deactivateTimeoutMs === undefined
225
- ? {}
226
- : { deactivate_timeout_ms: options.deactivateTimeoutMs });
227
- }
228
- /**
229
- * Invoke a registered extension command handler and return its real
230
- * {@link CommandHandlerResult} so package tests can assert on behavior — not
231
- * just that the command was registered.
232
- *
233
- * This is the "invoke" verb that completes the package-author testing loop:
234
- * `activateExtensionForTest` → `assertRegisteredCommandContract` → **run** →
235
- * `deactivateExtensionForTest`. It runs pm's real handler-dispatch engine
236
- * (`runCommandHandler`) over `activation.commands`, building the
237
- * `CommandHandlerContext` with agent-safe global defaults
238
- * (`{ json: true, quiet: true, noPager: true }`) that callers may override.
239
- *
240
- * Because `registerImporter`/`registerExporter` register their handlers under
241
- * the `"<name> import"` / `"<name> export"` command paths, this same helper
242
- * exercises importer and exporter handlers too.
243
- *
244
- * Throws a descriptive error (listing the available handler command paths) when
245
- * no handler is registered for `command`, since that is a wiring/typo bug in the
246
- * test rather than a behavior under test. When a handler is found, the result is
247
- * returned verbatim: a clean run yields `{ handled: true, result, warnings: [] }`,
248
- * while a handler that throws a non-exit error yields
249
- * `{ handled: false, warnings: [code], errorMessage }` so the failure can be
250
- * asserted. A handler that throws an error carrying a numeric `exitCode`
251
- * propagates the throw, matching runtime semantics.
252
- */
253
- export async function runRegisteredCommandForTest(commands, options) {
254
- const command = normalizeSdkCommandName(options.command);
255
- if (command.length === 0) {
256
- throw new Error("Expected command name must be a non-empty string");
257
- }
258
- const hasHandler = commands.handlers.some((entry) => entry.command === command);
259
- if (!hasHandler) {
260
- const available = sortedUnique(commands.handlers.map((entry) => entry.command));
261
- throw new Error(`Expected a registered command handler for "${command}" to invoke. Available command handlers: ${formatAvailable(available)}`);
262
- }
263
- if (options.sdk !== undefined && options.sdkFactory !== undefined) {
264
- throw new TypeError("runRegisteredCommandForTest accepts sdk or sdkFactory, not both");
265
- }
266
- const pmRoot = options.pmRoot ?? "";
267
- const global = { json: true, quiet: true, noPager: true, ...options.global };
268
- const sdk = options.sdk ??
269
- options.sdkFactory?.({ pmRoot, global }) ??
270
- (pmRoot.length > 0
271
- ? createExtensionCommandSdk(pmRoot, new PmClient({ pmRoot }))
272
- : undefined);
273
- return runCommandHandler(commands, {
274
- command,
275
- args: options.args ? [...options.args] : [],
276
- options: options.options ? { ...options.options } : {},
277
- global,
278
- pm_root: pmRoot,
279
- ...(sdk === undefined ? {} : { sdk }),
280
- });
281
- }
282
- /** Invoke registered transactional mutation guards through the same fail-closed runtime used by real writes. */
283
- export async function runRegisteredMutationGuardForTest(hooks, options) {
284
- if ((hooks.beforeMutation?.length ?? 0) === 0) {
285
- throw new Error("Expected a registered before_mutation hook to invoke");
286
- }
287
- await runBeforeMutationHooks(hooks, options.context);
288
- }
289
- /**
290
- * Fire every registered lifecycle hook of a given `kind` through pm's real hook
291
- * runner and return the warnings array so package tests can assert on behavior —
292
- * not just that a hook was registered.
293
- *
294
- * This is the hook counterpart to {@link runRegisteredCommandForTest}, extending
295
- * the package-author "invoke" verb to the `api.hooks.*` surface. Pass the
296
- * `ExtensionHookRegistry` from `activateExtensionForTest(...).hooks` together with
297
- * the lifecycle `kind` and a synthetic context. Hooks observe their inputs via a
298
- * cloned context snapshot (mutations never leak back to the caller), so the
299
- * observable signal is twofold: any side effects the hook performs, and the
300
- * returned warnings. A clean run returns `[]`; a hook that throws contributes one
301
- * `extension_hook_failed:<layer>:<name>:<hookName>` warning, mirroring runtime
302
- * dispatch which isolates a failing hook without aborting the others.
303
- *
304
- * Throws a descriptive error (listing the hook kinds that do have registrations)
305
- * when no hook of `kind` is registered, since firing a hook the extension never
306
- * registered is a wiring/typo bug in the test rather than a behavior under test.
307
- */
308
- export async function runRegisteredHookForTest(hooks, options) {
309
- const kind = options.kind;
310
- if (kind === "before_mutation") {
311
- throw new Error("Invoke before_mutation hooks with runRegisteredMutationGuardForTest so denials and failures retain fail-closed semantics.");
312
- }
313
- if ((hooks[RUNNABLE_HOOK_KIND_TO_REGISTRY_FIELD[kind]]?.length ?? 0) === 0) {
314
- const populatedKinds = sortedUnique(Object.keys(RUNNABLE_HOOK_KIND_TO_REGISTRY_FIELD).filter((candidateKind) => (hooks[RUNNABLE_HOOK_KIND_TO_REGISTRY_FIELD[candidateKind]]
315
- ?.length ?? 0) > 0));
316
- throw new Error(`Expected a registered "${kind}" hook to invoke. Hook kinds with registrations: ${formatAvailable(populatedKinds)}`);
317
- }
318
- switch (options.kind) {
319
- case "before_command":
320
- return runBeforeCommandHooks(hooks, options.context);
321
- case "after_command":
322
- return runAfterCommandHooks(hooks, options.context);
323
- case "on_read":
324
- return runOnReadHooks(hooks, options.context);
325
- case "on_write":
326
- return runOnWriteHooks(hooks, options.context);
327
- case "on_index":
328
- return runOnIndexHooks(hooks, options.context);
329
- }
330
- }
331
- /**
332
- * Invoke a registered parser override through pm's real runner and return the
333
- * resolved {@link ParserOverrideResult}, so package tests can assert the rewritten
334
- * args/options/global an override produces for a command before dispatch.
335
- *
336
- * Guards that a parser override is registered for the (normalized) target command
337
- * before delegating: without a match `runParserOverride` would silently return
338
- * `overridden: false`, hiding a typo'd command name in the test. When a match
339
- * exists the result is returned verbatim — `overridden: true` with the rewritten
340
- * context on success, or `overridden: false` with an
341
- * `extension_parser_override_failed:*` warning when the override throws.
342
- */
343
- export async function runRegisteredParserOverrideForTest(parsers, context) {
344
- const command = normalizeSdkCommandName(context.command);
345
- if (!parsers.overrides.some((entry) => entry.command === command)) {
346
- throw new Error(`Expected a registered parser override for command "${command}" to invoke. Available parser override commands: ${formatAvailable(sortedUnique(parsers.overrides.map((entry) => entry.command)))}`);
347
- }
348
- return runParserOverride(parsers, context);
349
- }
350
- /**
351
- * Invoke the active preflight override through pm's real runner and return the
352
- * resolved {@link PreflightOverrideResult}, so package tests can assert the
353
- * migration/format gate decision an override yields.
354
- *
355
- * Unlike command-scoped overrides, the runtime applies the **last** registered
356
- * preflight override regardless of command, so this helper guards only that at
357
- * least one preflight override is registered before delegating. The result is
358
- * returned verbatim — `overridden: true` with the adjusted decision on success,
359
- * or `overridden: false` with an `extension_preflight_override_failed:*` warning
360
- * when the override throws.
361
- */
362
- export async function runRegisteredPreflightOverrideForTest(preflight, context) {
363
- if (preflight.overrides.length === 0) {
364
- throw new Error("Expected a registered preflight override to invoke, but none are registered.");
365
- }
366
- return runPreflightOverride(preflight, context);
367
- }
368
- /**
369
- * Invoke a registered command-result override through pm's real runner and return
370
- * the resolved {@link CommandOverrideResult}, so package tests can assert how an
371
- * override transforms a command's result payload.
372
- *
373
- * Accepts the same `ExtensionCommandRegistry` exposed as
374
- * `activateExtensionForTest(...).commands` (it carries both handlers and
375
- * overrides). Guards that an override is registered for the (normalized) target
376
- * command before delegating, so a typo'd command name surfaces as a clear error
377
- * rather than a silent `overridden: false`. The result is returned verbatim —
378
- * including the `extension_command_override_async_unsupported:*` warning the
379
- * runtime emits when an override returns a Promise (command overrides are
380
- * synchronous), or an `extension_command_override_failed:*` warning on throw.
381
- */
382
- export async function runRegisteredCommandOverrideForTest(commands, context) {
383
- const command = normalizeSdkCommandName(context.command);
384
- if (!commands.overrides.some((entry) => entry.command === command)) {
385
- throw new Error(`Expected a registered command override for command "${command}" to invoke. Available command override commands: ${formatAvailable(sortedUnique(commands.overrides.map((entry) => entry.command)))}`);
386
- }
387
- return runCommandOverride(commands, context);
388
- }
389
- /**
390
- * Invoke a registered renderer override through pm's real runner and return the
391
- * resolved {@link RendererOverrideResult}, so package tests can assert the custom
392
- * string an override renders for a given output `format`.
393
- *
394
- * Guards that a renderer override is registered for `context.format` before
395
- * delegating, so a wrong format surfaces as a clear error rather than a silent
396
- * `overridden: false`. The result is returned verbatim — `overridden: true` with
397
- * the rendered string on success, or `overridden: false` (with an
398
- * `extension_renderer_invalid_result:*` / `extension_renderer_failed:*` warning
399
- * where applicable) when the override returns a non-string or throws.
400
- */
401
- export async function runRegisteredRendererOverrideForTest(renderers, context) {
402
- if (!renderers.overrides.some((entry) => entry.format === context.format)) {
403
- throw new Error(`Expected a registered renderer override for format "${context.format}" to invoke. Available renderer override formats: ${formatAvailable(sortedUnique(renderers.overrides.map((entry) => entry.format)))}`);
404
- }
405
- return runRendererOverride(renderers, context);
406
- }
407
- /**
408
- * Invoke a registered service override through pm's real runner and return the
409
- * resolved {@link ServiceOverrideResult}, so package tests can assert how an
410
- * override handles an internal service payload (e.g. `output_format`).
411
- *
412
- * Guards that a service override is registered for `context.service` before
413
- * delegating, so a wrong service name surfaces as a clear error rather than a
414
- * silent `handled: false`. The result is returned verbatim — `handled: true` with
415
- * the override's result when it claims the payload, or `handled: false` with the
416
- * original payload (and any `extension_service_override_*` warnings) otherwise.
417
- */
418
- export async function runRegisteredServiceOverrideForTest(services, context) {
419
- if (!services.overrides.some((entry) => entry.service === context.service)) {
420
- throw new Error(`Expected a registered service override for service "${context.service}" to invoke. Available service override services: ${formatAvailable(sortedUnique(services.overrides.map((entry) => entry.service)))}`);
421
- }
422
- return runServiceOverride(services, context);
423
- }
424
- /** Maps each search-provider operation to the runtime-definition keys that may hold its function, in priority order. The host accepts both camelCase and snake_case spellings for the multi-word operations, so this helper mirrors that by trying `embedBatch` before `embed_batch` and `queryExpansion` before `query_expansion`. */
425
- const SEARCH_PROVIDER_OPERATION_DEFINITION_KEYS = {
426
- query: ["query"],
427
- embed: ["embed"],
428
- embedBatch: ["embedBatch", "embed_batch"],
429
- queryExpansion: ["queryExpansion", "query_expansion"],
430
- rerank: ["rerank"],
431
- };
432
- /**
433
- * Invoke an operation of a registered search provider through the same name
434
- * resolution the host uses and return the operation's result, so package tests
435
- * can assert a custom provider's runtime behavior — not just that it registered.
436
- *
437
- * This is the search-provider counterpart to {@link runRegisteredCommandForTest},
438
- * extending the package-author "invoke" verb to the `api.registerSearchProvider`
439
- * surface. Pass the `ExtensionRegistrationRegistry` from
440
- * `activateExtensionForTest(...).registrations`, the registered provider name, the
441
- * `operation` to exercise (`query`, `embed`, `embedBatch`, `queryExpansion`, or
442
- * `rerank`), and a synthetic context. The provider is resolved via
443
- * {@link resolveRegisteredSearchProvider} (case-insensitive, last registration
444
- * wins) and the operation is invoked on its `runtime_definition` — the clone that
445
- * preserves live functions, matching what the runtime dispatches.
446
- *
447
- * Throws a descriptive error listing the available providers when the name is not
448
- * registered, and a separate error when the resolved provider does not implement
449
- * the requested operation, since invoking an absent provider/operation is a
450
- * wiring bug in the test rather than a behavior under test.
451
- */
452
- export async function runRegisteredSearchProviderForTest(registrations, options) {
453
- const registration = resolveRegisteredSearchProvider(registrations, options.provider);
454
- if (!registration) {
455
- const available = sortedUnique(registrations.search_providers.map((entry) => entry.definition.name));
456
- throw new Error(`Expected a registered search provider "${options.provider}" to invoke. Available search providers: ${formatAvailable(available)}`);
457
- }
458
- const runtimeDefinition = registration.runtime_definition;
459
- const operationFn = SEARCH_PROVIDER_OPERATION_DEFINITION_KEYS[options.operation]
460
- .map((key) => runtimeDefinition[key])
461
- .find((value) => typeof value === "function");
462
- if (typeof operationFn !== "function") {
463
- throw new Error(`Registered search provider "${options.provider}" does not implement the "${options.operation}" operation.`);
464
- }
465
- return (await operationFn(options.context));
466
- }
467
- /**
468
- * Invoke an operation of a registered vector store adapter through the same name
469
- * resolution the host uses and return the operation's result, so package tests
470
- * can assert a custom adapter's runtime behavior — not just that it registered.
471
- *
472
- * This is the vector-store counterpart to {@link runRegisteredSearchProviderForTest}.
473
- * Pass the `ExtensionRegistrationRegistry` from
474
- * `activateExtensionForTest(...).registrations`, the registered adapter name, the
475
- * `operation` to exercise (`query`, `upsert`, or `delete`), and a synthetic
476
- * context. The adapter is resolved via {@link resolveRegisteredVectorStoreAdapter}
477
- * (case-insensitive, last registration wins) and the operation is invoked on its
478
- * `runtime_definition` — the clone that preserves live functions, matching what
479
- * the runtime dispatches.
480
- *
481
- * Throws a descriptive error listing the available adapters when the name is not
482
- * registered, and a separate error when the resolved adapter does not implement
483
- * the requested operation.
484
- */
485
- export async function runRegisteredVectorStoreAdapterForTest(registrations, options) {
486
- const registration = resolveRegisteredVectorStoreAdapter(registrations, options.adapter);
487
- if (!registration) {
488
- const available = sortedUnique(registrations.vector_store_adapters.map((entry) => entry.definition.name));
489
- throw new Error(`Expected a registered vector store adapter "${options.adapter}" to invoke. Available vector store adapters: ${formatAvailable(available)}`);
490
- }
491
- const operationFn = registration.runtime_definition[options.operation];
492
- if (typeof operationFn !== "function") {
493
- throw new Error(`Registered vector store adapter "${options.adapter}" does not implement the "${options.operation}" operation.`);
494
- }
495
- return (await operationFn(options.context));
496
- }
497
- /**
498
- * Invoke a registered schema migration's `run` function through the same runtime
499
- * definition the host executes and return its result, so package tests can assert
500
- * a migration's behavior — not just that it registered.
501
- *
502
- * This completes the package-author "invoke" verb across every executable
503
- * registration surface. The migration is resolved by id via
504
- * {@link assertRegisteredMigration} (which throws a descriptive "available
505
- * migrations" error when absent), then `run` is invoked on its
506
- * `runtime_definition` with a context mirroring the one
507
- * `executeRegisteredRuntimeMigrations` builds at runtime: the resolved id,
508
- * `command: "migration"`, the registering extension's layer/name, the supplied
509
- * `pmRoot`, and the migration's normalized status. Unlike the runtime — which
510
- * skips already-applied migrations and folds a throw into a warning — this helper
511
- * always invokes `run` and lets a throw propagate, so authors can assert both the
512
- * success result and failure via rejection.
513
- *
514
- * Throws when the resolved migration declares no `run` function, since invoking a
515
- * runless migration is a wiring bug in the test rather than a behavior under test.
516
- */
517
- export async function runRegisteredMigrationForTest(registrations, options) {
518
- const migration = assertRegisteredMigration(registrations, {
519
- migration: options.migration,
520
- extensionName: options.extensionName,
521
- });
522
- const run = getMigrationRuntimeDefinition(migration).run;
523
- if (typeof run !== "function") {
524
- throw new Error(`Registered migration "${options.migration}" does not implement a run function to invoke.`);
525
- }
526
- const declaredStatus = migration.definition.status;
527
- const context = {
528
- id: migration.definition.id,
529
- command: "migration",
530
- layer: migration.layer,
531
- extension: migration.name,
532
- pm_root: options.pmRoot ?? "",
533
- status: (typeof declaredStatus === "string"
534
- ? declaredStatus.trim().toLowerCase()
535
- : "") || "pending",
536
- };
537
- return await run(context);
538
- }
539
- /**
540
- * Invoke a registered extension importer through pm's real handler-dispatch
541
- * engine and return its {@link CommandHandlerResult}, so package tests can assert
542
- * an importer's behavior — not just that it registered.
543
- *
544
- * This is the importer counterpart to {@link runRegisteredCommandForTest},
545
- * extending the package-author "invoke" verb to the `api.registerImporter`
546
- * surface. Because `registerImporter(name, fn)` wraps `fn` into a command handler
547
- * at the `"<name> import"` path, invoking it through `runRegisteredCommandForTest`
548
- * requires the author to know that naming convention and to remember that an
549
- * importer is reachable as a command at all. This helper closes both gaps: it
550
- * accepts the registered importer name directly, validates via
551
- * {@link assertRegisteredImporter} that it is genuinely a registered importer
552
- * (not merely some command parked at that path), derives the command path, and
553
- * dispatches through the same engine.
554
- *
555
- * The full activation result is required because importer execution spans two
556
- * sub-registries: `registrations.importers` proves the importer exists, while
557
- * `commands` holds the wrapped handler. The result is returned verbatim from the
558
- * command engine: a clean run yields `{ handled: true, result, warnings: [] }`
559
- * (where `result` is the importer's return value), a non-exit throw yields
560
- * `{ handled: false, warnings: [code], errorMessage }`, and an error carrying a
561
- * numeric `exitCode` propagates — matching runtime import semantics.
562
- *
563
- * Throws a descriptive "available importers" error (via `assertRegisteredImporter`)
564
- * when no importer matches, since that is a wiring/typo bug in the test rather
565
- * than a behavior under test.
566
- */
567
- export async function runRegisteredImporterForTest(activation, options) {
568
- const importer = assertRegisteredImporter(activation.registrations, {
569
- importer: options.importer,
570
- extensionName: options.extensionName,
571
- });
572
- return runRegisteredCommandForTest(activation.commands, {
573
- command: `${importer.importer} import`,
574
- args: options.args,
575
- options: options.options,
576
- global: options.global,
577
- pmRoot: options.pmRoot,
578
- });
579
- }
580
- /**
581
- * Invoke a registered extension exporter through pm's real handler-dispatch
582
- * engine and return its {@link CommandHandlerResult}, so package tests can assert
583
- * an exporter's behavior — not just that it registered.
584
- *
585
- * This is the exporter counterpart to {@link runRegisteredImporterForTest} and
586
- * the final surface in the package-author "invoke" verb. Because
587
- * `registerExporter(name, fn)` wraps `fn` into a command handler at the
588
- * `"<name> export"` path, this helper accepts the registered exporter name
589
- * directly, validates via {@link assertRegisteredExporter} that it is genuinely a
590
- * registered exporter, derives the command path, and dispatches through the same
591
- * engine. See {@link runRegisteredImporterForTest} for the full activation
592
- * rationale and return semantics (which apply identically here).
593
- *
594
- * Throws a descriptive "available exporters" error (via `assertRegisteredExporter`)
595
- * when no exporter matches, since that is a wiring/typo bug in the test rather
596
- * than a behavior under test.
597
- */
598
- export async function runRegisteredExporterForTest(activation, options) {
599
- const exporter = assertRegisteredExporter(activation.registrations, {
600
- exporter: options.exporter,
601
- extensionName: options.extensionName,
602
- });
603
- return runRegisteredCommandForTest(activation.commands, {
604
- command: `${exporter.exporter} export`,
605
- args: options.args,
606
- options: options.options,
607
- global: options.global,
608
- pmRoot: options.pmRoot,
609
- });
610
- }
611
- /**
612
- * Assert that an {@link ExtensionDeactivationResult} reports the expected clean
613
- * teardown counts, throwing a descriptive error otherwise. Defaults assert the
614
- * single-extension happy path — exactly one extension deactivated and none
615
- * failed. Returns the result so assertions can chain.
616
- */
617
- export function assertExtensionDeactivated(result, expectation = {}) {
618
- const expectedDeactivated = expectation.deactivated ?? 1;
619
- if (result.deactivated !== expectedDeactivated) {
620
- throw new Error(`Expected ${expectedDeactivated} extension${expectedDeactivated === 1 ? "" : "s"} to deactivate cleanly, ` +
621
- `but ${result.deactivated} did.`);
622
- }
623
- const expectedFailed = expectation.failed ?? 0;
624
- if (result.failed.length !== expectedFailed) {
625
- const detail = result.failed
626
- .map((failure) => `${failure.layer}:${failure.name} (${failure.error})`)
627
- .join(", ");
628
- throw new Error(`Expected ${expectedFailed} teardown failure${expectedFailed === 1 ? "" : "s"}, ` +
629
- `but observed ${result.failed.length}${detail.length > 0 ? `: ${detail}` : ""}.`);
630
- }
631
- return result;
632
- }
633
- /** Assert that a normalized package manifest advertises expected package resources. Pair with `readPmPackageManifest(packageRoot)` in package tests. */
634
- export function assertPackageManifest(manifest, expectation) {
635
- if (expectation.packageName !== undefined &&
636
- manifest.package_name !== expectation.packageName) {
637
- throw new Error(`Expected package manifest package_name to be "${expectation.packageName}"; received "${manifest.package_name ?? "(none)"}"`);
638
- }
639
- if (expectation.aliases !== undefined) {
640
- assertStringSetIncludes(manifest.aliases, expectation.aliases, "aliases");
641
- }
642
- if (expectation.resources !== undefined) {
643
- for (const [kind, expectedPaths] of Object.entries(expectation.resources)) {
644
- assertStringSetIncludes(manifest.resources[kind], expectedPaths, `pm.${kind}`);
645
- }
646
- }
647
- return manifest;
648
- }
649
- /** Assert that an activated extension registration registry contains a command contract with the expected public metadata. */
650
- export function assertRegisteredCommandContract(registrations, expectation) {
651
- const expectedCommand = normalizeSdkCommandName(registeredExpectationName(expectation, expectation.command));
652
- if (expectedCommand.length === 0) {
653
- throw new Error("Expected command name must be a non-empty string");
654
- }
655
- const commandCandidates = registrations.commands.filter((entry) => entry.command === expectedCommand);
656
- const command = expectation.extensionName
657
- ? commandCandidates.find((entry) => entry.name === expectation.extensionName)
658
- : commandCandidates[0];
659
- if (!command) {
660
- const available = registrations.commands
661
- .map((entry) => entry.command)
662
- .sort((left, right) => left.localeCompare(right));
663
- const extensionSuffix = expectation.extensionName
664
- ? ` from extension "${expectation.extensionName}"`
665
- : "";
666
- throw new Error(`Expected extension command "${expectedCommand}"${extensionSuffix} to be registered. Available commands: ${formatAvailable(available)}`);
667
- }
668
- if (expectation.action !== undefined &&
669
- command.action !== expectation.action) {
670
- throw new Error(`Expected extension command "${expectedCommand}" action "${expectation.action}", received "${command.action}"`);
671
- }
672
- if (expectation.arguments !== undefined) {
673
- const actualArguments = (command.arguments ?? []).map((argument) => argument.name);
674
- const missingArguments = expectation.arguments.filter((argument) => !actualArguments.includes(argument));
675
- if (missingArguments.length > 0) {
676
- throw new Error(`Expected extension command "${expectedCommand}" arguments ${formatAvailable(expectation.arguments)}; missing ${formatAvailable(missingArguments)}; available ${formatAvailable(actualArguments)}`);
677
- }
678
- }
679
- const flags = registrations.flags
680
- .filter((entry) => entry.target_command === expectedCommand &&
681
- (expectation.extensionName === undefined ||
682
- entry.name === expectation.extensionName))
683
- .flatMap((entry) => entry.flags);
684
- if (expectation.flags !== undefined) {
685
- const actualFlagLabels = collectFlagLabels(flags);
686
- const missingFlags = expectation.flags.filter((flag) => !actualFlagLabels.has(flag));
687
- if (missingFlags.length > 0) {
688
- throw new Error(`Expected extension command "${expectedCommand}" flags ${formatAvailable(expectation.flags)}; missing ${formatAvailable(missingFlags)}; available ${formatAvailable([...actualFlagLabels].sort((left, right) => left.localeCompare(right)))}`);
689
- }
690
- }
691
- return { command, flags };
692
- }
693
- /** Assert that an activated extension registration registry contains flags injected into an existing command through `api.registerFlags(...)`. */
694
- export function assertRegisteredFlags(registrations, expectation) {
695
- const expectedCommand = normalizeSdkCommandName(registeredExpectationName(expectation, expectation.targetCommand));
696
- if (expectedCommand.length === 0) {
697
- throw new Error("Expected target command name must be a non-empty string");
698
- }
699
- const candidates = registrations.flags.filter((entry) => entry.target_command === expectedCommand);
700
- let registration;
701
- if (expectation.extensionName) {
702
- registration = candidates.find((entry) => entry.name === expectation.extensionName);
703
- }
704
- else if (candidates.length === 1) {
705
- registration = candidates[0];
706
- }
707
- else if (candidates.length > 1) {
708
- const availableExtensions = sortedUnique(candidates.map((entry) => entry.name));
709
- throw new Error(`Expected flags for target command "${expectedCommand}" matched multiple extensions: ${formatAvailable(availableExtensions)}. Specify extensionName to choose one registration.`);
710
- }
711
- if (!registration) {
712
- const available = sortedUnique(registrations.flags.map((entry) => entry.target_command));
713
- const availableExtensions = sortedUnique(candidates.map((entry) => entry.name));
714
- throw new Error(`Expected flags for target command "${expectedCommand}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available flag target commands: ${formatAvailable(available)}; matching extensions: ${formatAvailable(availableExtensions)}`);
715
- }
716
- if (expectation.flags !== undefined) {
717
- const actualFlagLabels = collectFlagLabels(registration.flags);
718
- const missingFlags = expectation.flags.filter((flag) => !actualFlagLabels.has(flag));
719
- if (missingFlags.length > 0) {
720
- throw new Error(`Expected flags for target command "${expectedCommand}" to include ${formatAvailable(expectation.flags)}; missing ${formatAvailable(missingFlags)}; available ${formatAvailable([...actualFlagLabels].sort((left, right) => left.localeCompare(right)))}`);
721
- }
722
- }
723
- return registration;
724
- }
725
- /**
726
- * Assert that an activated extension hook registry contains a hook of the
727
- * expected lifecycle kind (optionally scoped to a specific extension).
728
- *
729
- * Hooks are surfaced via `ExtensionActivationResult.hooks`, not the command
730
- * registration registry, so this helper accepts an `ExtensionHookRegistry`.
731
- */
732
- export function assertRegisteredHook(hooks, expectation) {
733
- const field = HOOK_KIND_TO_REGISTRY_FIELD[expectation.kind];
734
- const candidates = (hooks[field] ?? []);
735
- const hook = expectation.extensionName
736
- ? candidates.find((entry) => entry.name === expectation.extensionName)
737
- : candidates[0];
738
- if (!hook) {
739
- const available = sortedUnique(candidates.map((entry) => entry.name));
740
- throw new Error(`Expected a "${expectation.kind}" hook${extensionNameSuffix(expectation.extensionName)} to be registered. Available "${expectation.kind}" hooks: ${formatAvailable(available)}`);
741
- }
742
- return hook;
743
- }
744
- /** Assert that an activated extension registration registry contains a search provider with the expected name (optionally scoped to a specific extension). */
745
- export function assertRegisteredSearchProvider(registrations, expectation) {
746
- const expectedProvider = normalizeSdkIdentifier(registeredExpectationName(expectation, expectation.provider));
747
- if (expectedProvider.length === 0) {
748
- throw new Error("Expected search provider name must be a non-empty string");
749
- }
750
- const candidates = registrations.search_providers.filter((entry) => normalizeSdkIdentifier(entry.definition.name) === expectedProvider);
751
- const provider = expectation.extensionName
752
- ? candidates.find((entry) => entry.name === expectation.extensionName)
753
- : candidates[0];
754
- if (!provider) {
755
- const available = sortedUnique(registrations.search_providers.map((entry) => entry.definition.name));
756
- throw new Error(`Expected search provider "${expectedProvider}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available search providers: ${formatAvailable(available)}`);
757
- }
758
- return provider;
759
- }
760
- /** Assert that an activated extension registration registry contains a vector store adapter with the expected name (optionally scoped to a specific extension). */
761
- export function assertRegisteredVectorStoreAdapter(registrations, expectation) {
762
- const expectedAdapter = normalizeSdkIdentifier(registeredExpectationName(expectation, expectation.adapter));
763
- if (expectedAdapter.length === 0) {
764
- throw new Error("Expected vector store adapter name must be a non-empty string");
765
- }
766
- const candidates = registrations.vector_store_adapters.filter((entry) => normalizeSdkIdentifier(entry.definition.name) === expectedAdapter);
767
- const adapter = expectation.extensionName
768
- ? candidates.find((entry) => entry.name === expectation.extensionName)
769
- : candidates[0];
770
- if (!adapter) {
771
- const available = sortedUnique(registrations.vector_store_adapters.map((entry) => entry.definition.name));
772
- throw new Error(`Expected vector store adapter "${expectedAdapter}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available vector store adapters: ${formatAvailable(available)}`);
773
- }
774
- return adapter;
775
- }
776
- /** Assert that an activated extension registration registry contains an importer for the expected format/name (optionally scoped to a specific extension). */
777
- export function assertRegisteredImporter(registrations, expectation) {
778
- const expectedImporter = normalizeSdkIdentifier(registeredExpectationName(expectation, expectation.importer));
779
- if (expectedImporter.length === 0) {
780
- throw new Error("Expected importer name must be a non-empty string");
781
- }
782
- const candidates = registrations.importers.filter((entry) => normalizeSdkIdentifier(entry.importer) === expectedImporter);
783
- const importer = expectation.extensionName
784
- ? candidates.find((entry) => entry.name === expectation.extensionName)
785
- : candidates[0];
786
- if (!importer) {
787
- const available = sortedUnique(registrations.importers.map((entry) => entry.importer));
788
- throw new Error(`Expected importer "${expectedImporter}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available importers: ${formatAvailable(available)}`);
789
- }
790
- return importer;
791
- }
792
- /** Assert that an activated extension registration registry contains an exporter for the expected format/name (optionally scoped to a specific extension). */
793
- export function assertRegisteredExporter(registrations, expectation) {
794
- const expectedExporter = normalizeSdkIdentifier(registeredExpectationName(expectation, expectation.exporter));
795
- if (expectedExporter.length === 0) {
796
- throw new Error("Expected exporter name must be a non-empty string");
797
- }
798
- const candidates = registrations.exporters.filter((entry) => normalizeSdkIdentifier(entry.exporter) === expectedExporter);
799
- const exporter = expectation.extensionName
800
- ? candidates.find((entry) => entry.name === expectation.extensionName)
801
- : candidates[0];
802
- if (!exporter) {
803
- const available = sortedUnique(registrations.exporters.map((entry) => entry.exporter));
804
- throw new Error(`Expected exporter "${expectedExporter}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available exporters: ${formatAvailable(available)}`);
805
- }
806
- return exporter;
807
- }
808
- /** Assert that an activated extension registration registry contains a custom item field definition (optionally scoped to a specific extension). */
809
- export function assertRegisteredItemField(registrations, expectation) {
810
- const expectedField = normalizeSdkIdentifier(registeredExpectationName(expectation, expectation.field));
811
- if (expectedField.length === 0) {
812
- throw new Error("Expected item field name must be a non-empty string");
813
- }
814
- const candidates = registrations.item_fields
815
- .filter((entry) => expectation.extensionName === undefined ||
816
- entry.name === expectation.extensionName)
817
- .map((registration) => ({
818
- registration,
819
- field: registration.fields.find((field) => normalizeSdkIdentifier(field.name) === expectedField),
820
- }))
821
- .filter((entry) => entry.field !== undefined);
822
- const match = candidates.find((entry) => expectation.type === undefined || entry.field.type === expectation.type);
823
- if (!match) {
824
- const available = sortedUnique(registrations.item_fields.flatMap((entry) => entry.fields.map((field) => `${field.name}:${field.type}`)));
825
- throw new Error(`Expected item field "${expectedField}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available item fields: ${formatAvailable(available)}`);
826
- }
827
- return match;
828
- }
829
- /** Assert that an activated extension registration registry contains a custom item type definition (optionally scoped to a specific extension). */
830
- export function assertRegisteredItemType(registrations, expectation) {
831
- const expectedType = normalizeSdkIdentifier(registeredExpectationName(expectation, expectation.itemType));
832
- if (expectedType.length === 0) {
833
- throw new Error("Expected item type name must be a non-empty string");
834
- }
835
- const candidates = registrations.item_types
836
- .filter((entry) => expectation.extensionName === undefined ||
837
- entry.name === expectation.extensionName)
838
- .map((registration) => ({
839
- registration,
840
- itemType: registration.types.find((itemType) => normalizeSdkIdentifier(itemType.name) === expectedType),
841
- }))
842
- .filter((entry) => entry.itemType !== undefined);
843
- const match = candidates.find((entry) => expectation.folder === undefined ||
844
- entry.itemType.folder === expectation.folder);
845
- if (!match) {
846
- const available = sortedUnique(registrations.item_types.flatMap((entry) => entry.types.map((itemType) => `${itemType.name}:${itemType.folder}`)));
847
- throw new Error(`Expected item type "${expectedType}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available item types: ${formatAvailable(available)}`);
848
- }
849
- return match;
850
- }
851
- /**
852
- * Assert that an activated extension registration registry contains a project
853
- * profile registered via `api.registerProfile(profile)` (optionally scoped to a
854
- * specific extension).
855
- *
856
- * This is the test-time counterpart to the declarative `defineProjectProfile`
857
- * authoring helper and the `pm profile list/show/apply` runtime surface: it
858
- * proves a package's archetype reached the registry so a downstream consumer can
859
- * resolve and apply it by name. Like the other declarative-surface assertions
860
- * (item types, item fields), a profile is verified by presence — it is staged,
861
- * not executed — so there is no `runRegisteredProfileForTest` counterpart.
862
- */
863
- export function assertRegisteredProfile(registrations, expectation) {
864
- const expectedProfile = normalizeSdkProfileMatchKey(registeredExpectationName(expectation, expectation.profile));
865
- if (expectedProfile.length === 0) {
866
- throw new Error("Expected profile name must be a non-empty string");
867
- }
868
- const match = registrations.profiles
869
- .filter((entry) => expectation.extensionName === undefined ||
870
- entry.name === expectation.extensionName)
871
- .find((entry) => normalizeSdkProfileMatchKey(entry.profile.name) === expectedProfile);
872
- if (!match) {
873
- const available = sortedUnique(registrations.profiles.map((entry) => entry.profile.name));
874
- throw new Error(`Expected profile "${expectedProfile}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available profiles: ${formatAvailable(available)}`);
875
- }
876
- return { registration: match, profile: match.profile };
877
- }
878
- /**
879
- * Assert that an activated extension command registry contains a command
880
- * override registered via `api.registerCommand(command, override)` (optionally
881
- * scoped to a specific extension).
882
- *
883
- * Command overrides are surfaced via `ExtensionActivationResult.commands`, not
884
- * the command registration registry, so this helper accepts an
885
- * `ExtensionCommandRegistry`.
886
- */
887
- export function assertRegisteredCommandOverride(commands, expectation) {
888
- const expectedCommand = normalizeSdkCommandName(registeredExpectationName(expectation, expectation.command));
889
- if (expectedCommand.length === 0) {
890
- throw new Error("Expected command name must be a non-empty string");
891
- }
892
- const candidates = commands.overrides.filter((entry) => entry.command === expectedCommand);
893
- const override = expectation.extensionName
894
- ? candidates.find((entry) => entry.name === expectation.extensionName)
895
- : candidates[0];
896
- if (!override) {
897
- const available = sortedUnique(commands.overrides.map((entry) => entry.command));
898
- throw new Error(`Expected command override "${expectedCommand}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available command overrides: ${formatAvailable(available)}`);
899
- }
900
- return override;
901
- }
902
- /**
903
- * Assert that an activated extension parser registry contains a parser override
904
- * registered via `api.registerParser(command, override)` (optionally scoped to
905
- * a specific extension).
906
- *
907
- * Parser overrides are surfaced via `ExtensionActivationResult.parsers`, not the
908
- * command registration registry, so this helper accepts an
909
- * `ExtensionParserRegistry`.
910
- */
911
- export function assertRegisteredParserOverride(parsers, expectation) {
912
- const expectedCommand = normalizeSdkCommandName(registeredExpectationName(expectation, expectation.command));
913
- if (expectedCommand.length === 0) {
914
- throw new Error("Expected command name must be a non-empty string");
915
- }
916
- const candidates = parsers.overrides.filter((entry) => entry.command === expectedCommand);
917
- const override = expectation.extensionName
918
- ? candidates.find((entry) => entry.name === expectation.extensionName)
919
- : candidates[0];
920
- if (!override) {
921
- const available = sortedUnique(parsers.overrides.map((entry) => entry.command));
922
- throw new Error(`Expected parser override "${expectedCommand}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available parser overrides: ${formatAvailable(available)}`);
923
- }
924
- return override;
925
- }
926
- /**
927
- * Assert that an activated extension preflight registry contains a preflight
928
- * override registered via `api.registerPreflight(override)` (optionally scoped
929
- * to a specific extension).
930
- *
931
- * Preflight overrides are global (they run for every command and carry no
932
- * `command` field), so the expectation only accepts an optional
933
- * `extensionName`. Preflight overrides are surfaced via
934
- * `ExtensionActivationResult.preflight`.
935
- */
936
- export function assertRegisteredPreflightOverride(preflight, expectation = {}) {
937
- const override = expectation.extensionName
938
- ? preflight.overrides.find((entry) => entry.name === expectation.extensionName)
939
- : preflight.overrides[0];
940
- if (!override) {
941
- const available = sortedUnique(preflight.overrides.map((entry) => entry.name));
942
- throw new Error(`Expected a preflight override${extensionNameSuffix(expectation.extensionName)} to be registered. Available preflight overrides: ${formatAvailable(available)}`);
943
- }
944
- return override;
945
- }
946
- /**
947
- * Assert that an activated extension renderer registry contains a renderer
948
- * override registered via `api.registerRenderer(format, renderer)` for the
949
- * expected output format (optionally scoped to a specific extension).
950
- *
951
- * Renderer overrides are surfaced via `ExtensionActivationResult.renderers`.
952
- */
953
- export function assertRegisteredRendererOverride(renderers, expectation) {
954
- const expectedFormat = normalizeSdkIdentifier(registeredExpectationName(expectation, expectation.format));
955
- if (expectedFormat.length === 0) {
956
- throw new Error("Expected renderer format must be a non-empty string");
957
- }
958
- const candidates = renderers.overrides.filter((entry) => entry.format === expectedFormat);
959
- const override = expectation.extensionName
960
- ? candidates.find((entry) => entry.name === expectation.extensionName)
961
- : candidates[0];
962
- if (!override) {
963
- const available = sortedUnique(renderers.overrides.map((entry) => entry.format));
964
- throw new Error(`Expected renderer override "${expectedFormat}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available renderer overrides: ${formatAvailable(available)}`);
965
- }
966
- return override;
967
- }
968
- /**
969
- * Assert that an activated extension service registry contains a service override
970
- * registered via `api.registerService(service, override)` for the expected
971
- * service name (optionally scoped to a specific extension).
972
- *
973
- * Service overrides are surfaced via `ExtensionActivationResult.services`, not the
974
- * command registration registry, so this helper accepts an
975
- * `ExtensionServiceRegistry`.
976
- */
977
- export function assertRegisteredServiceOverride(services, expectation) {
978
- const expectedService = normalizeSdkIdentifier(registeredExpectationName(expectation, expectation.service));
979
- if (expectedService.length === 0) {
980
- throw new Error("Expected service name must be a non-empty string");
981
- }
982
- const candidates = services.overrides.filter((entry) => normalizeSdkIdentifier(entry.service) === expectedService);
983
- const override = expectation.extensionName
984
- ? candidates.find((entry) => entry.name === expectation.extensionName)
985
- : candidates[0];
986
- if (!override) {
987
- const available = sortedUnique(services.overrides.map((entry) => entry.service));
988
- throw new Error(`Expected service override "${expectedService}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available service overrides: ${formatAvailable(available)}`);
989
- }
990
- return override;
991
- }
992
- /**
993
- * Assert that an activated extension registration registry contains a schema
994
- * migration registered via `api.registerMigration(definition)` with the expected
995
- * id (optionally scoped to a specific extension and asserting the `mandatory`
996
- * governance flag, where an unset flag is treated as non-mandatory).
997
- *
998
- * Migrations are surfaced via `ExtensionActivationResult.registrations.migrations`.
999
- */
1000
- export function assertRegisteredMigration(registrations, expectation) {
1001
- const expectedMigration = normalizeSdkIdentifier(registeredExpectationName(expectation, expectation.migration));
1002
- if (expectedMigration.length === 0) {
1003
- throw new Error("Expected migration id must be a non-empty string");
1004
- }
1005
- const candidates = registrations.migrations.filter((entry) => (expectation.extensionName === undefined ||
1006
- entry.name === expectation.extensionName) &&
1007
- typeof entry.definition.id === "string" &&
1008
- normalizeSdkIdentifier(entry.definition.id) === expectedMigration);
1009
- const match = candidates.find((entry) => expectation.mandatory === undefined ||
1010
- (entry.definition.mandatory ?? false) === expectation.mandatory);
1011
- if (match) {
1012
- return match;
1013
- }
1014
- // The id (and any extension scope) matched but the `mandatory` flag did not:
1015
- // report the mismatch directly rather than the misleading "not registered"
1016
- // listing. Reaching here with a candidate implies `expectation.mandatory` was
1017
- // set, since an unset flag matches any candidate above.
1018
- const idMatch = candidates[0];
1019
- if (idMatch !== undefined) {
1020
- throw new Error(`Expected migration "${expectedMigration}"${extensionNameSuffix(expectation.extensionName)} to have ` +
1021
- `mandatory=${expectation.mandatory}, but it is mandatory=${idMatch.definition.mandatory ?? false}.`);
1022
- }
1023
- const available = sortedUnique(registrations.migrations.map((entry) => {
1024
- const id = typeof entry.definition.id === "string" &&
1025
- entry.definition.id.trim().length > 0
1026
- ? entry.definition.id.trim()
1027
- : "(unnamed)";
1028
- return `${id}:${entry.definition.mandatory === true}`;
1029
- }));
1030
- throw new Error(`Expected migration "${expectedMigration}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available migrations: ${formatAvailable(available)}`);
1031
- }
1032
- /**
1033
- * Assert that an activated extension declares no capability it never uses
1034
- * (least privilege). Pass the same capabilities as `manifest.capabilities` via
1035
- * `expectation.declared`; the helper computes what the extension actually
1036
- * registered against and throws when any declared capability is unused.
1037
- *
1038
- * This is the package-test counterpart of the advisory
1039
- * `extension_capability_unused` warning `pm package doctor` emits, letting an
1040
- * author catch an over-broad manifest at `npm test` time. Returns the
1041
- * declared/used/unused breakdown for further assertions.
1042
- */
1043
- export function assertExtensionCapabilityUsage(activation, expectation) {
1044
- const toKnownCapabilitySet = (capabilities, field) => {
1045
- const known = new Set();
1046
- for (const capability of capabilities) {
1047
- const normalized = normalizeKnownExtensionCapability(capability);
1048
- if (normalized === null) {
1049
- throw new Error(`Expected ${field} capability "${capability}" to be a known extension capability. ` +
1050
- "Use canonical capability names (see manifest.capabilities).");
1051
- }
1052
- known.add(normalized);
1053
- }
1054
- return known;
1055
- };
1056
- const declared = [
1057
- ...toKnownCapabilitySet(expectation.declared, "declared"),
1058
- ].sort((left, right) => left.localeCompare(right));
1059
- const allowUnused = toKnownCapabilitySet(expectation.allowUnused ?? [], "allowUnused");
1060
- const used = collectUsedExtensionCapabilities(activation, {
1061
- extensionName: expectation.extensionName,
1062
- });
1063
- const usedSet = new Set(used);
1064
- const unused = declared.filter((capability) => !usedSet.has(capability) && !allowUnused.has(capability));
1065
- if (unused.length > 0) {
1066
- const scopeSuffix = extensionNameSuffix(expectation.extensionName);
1067
- throw new Error(`Expected every declared capability${scopeSuffix} to be exercised, but [${unused.join(", ")}] ${unused.length === 1 ? "is" : "are"} declared yet never registered against. ` +
1068
- `Remove ${unused.length === 1 ? "it" : "them"} from manifest.capabilities for least privilege, ` +
1069
- "or pass allowUnused for capabilities registered only behind a runtime flag.");
1070
- }
1071
- return { declared, used, unused };
1072
- }
1073
- /**
1074
- * Preflight a declarative {@link ExtensionBlueprint} in a test, throwing if it has
1075
- * any `error`-severity issue (today: capability the blueprint exercises but the
1076
- * declared set omits, which would fail activation with `extension_capability_missing`).
1077
- *
1078
- * The throwing counterpart to {@link lintExtensionBlueprint} and the `assert*`
1079
- * family member for declarative authoring: drop `assertExtensionBlueprint(blueprint)`
1080
- * into a package's `node:test`/Vitest suite to fail CI before the blueprint is
1081
- * ever activated. The full {@link ExtensionBlueprintLintResult} is returned on
1082
- * success so a test can still inspect advisory warnings (unused capability,
1083
- * duplicate command, empty surface) without failing on them.
1084
- */
1085
- export function assertExtensionBlueprint(blueprint, options = {}) {
1086
- const result = lintExtensionBlueprint(blueprint, options);
1087
- if (!result.ok) {
1088
- const errors = result.findings.filter((finding) => finding.severity === "error");
1089
- throw new Error(`Extension blueprint failed preflight with ${errors.length} ${errors.length === 1 ? "error" : "errors"}:\n` +
1090
- errors
1091
- .map((finding) => ` - [${finding.code}] ${finding.message}`)
1092
- .join("\n"));
1093
- }
1094
- return result;
1095
- }
1096
- /**
1097
- * Assert a {@link ProjectProfileDefinition} is internally consistent in a test,
1098
- * throwing on any `error`-severity finding (and on `warning`-severity findings
1099
- * too when `strict` is set). The author-time counterpart to `defineProjectProfile`
1100
- * and the project-profile analogue of {@link assertExtensionBlueprint}: drop
1101
- * `assertProjectProfile(myProfile)` into a package's `node:test`/Vitest suite to
1102
- * fail CI before the profile is ever registered via `api.registerProfile` or
1103
- * applied via `pm profile apply`. The full {@link ProjectProfileLintReport} is
1104
- * returned on success so a test can still inspect advisory warnings without
1105
- * failing on them.
1106
- */
1107
- export function assertProjectProfile(profile, options = {}) {
1108
- const report = lintProjectProfile(profile);
1109
- const blocking = report.findings.filter((finding) => finding.severity === "error" ||
1110
- (options.strict === true && finding.severity === "warning"));
1111
- if (blocking.length > 0) {
1112
- throw new Error(`Project profile "${report.profile}" failed lint with ${blocking.length} ${blocking.length === 1 ? "issue" : "issues"}:\n` +
1113
- blocking
1114
- .map((finding) => ` - ${finding.severity} [${finding.code}] ${finding.message}`)
1115
- .join("\n"));
1116
- }
1117
- return report;
1118
- }
1119
- /**
1120
- * Strictly assert a manifest's `capabilities` equal the least-privilege set a
1121
- * declarative {@link ExtensionBlueprint} exercises, throwing on any drift in
1122
- * either direction.
1123
- *
1124
- * This is the strict bookend to the lenient {@link assertExtensionBlueprint}:
1125
- * where that helper fails only on an *undeclared* capability (the `error`-severity
1126
- * `extension_capability_missing` activation crash) and merely *warns* on an unused
1127
- * one, this assertion fails on **both** — an undeclared capability (`missing`) and
1128
- * a declared-but-unused one (`unused`) — so a hand-maintained `manifest.json` stays
1129
- * exactly the set the blueprint requires. Drop it into a package's
1130
- * `node:test`/Vitest suite to guard against capability drift in CI, the natural
1131
- * companion to {@link ../sdk/compose.js#synthesizeExtensionManifest} (assert what
1132
- * you would otherwise generate). Only `capabilities` are reconciled because that is
1133
- * the one manifest field a blueprint determines.
1134
- *
1135
- * The reconciliation is returned on success so a test can still inspect advisory
1136
- * warnings (duplicate command, empty surface) without failing on them.
1137
- */
1138
- export function assertExtensionManifestMatchesBlueprint(manifest, blueprint) {
1139
- // Coerce a malformed/absent capabilities field to an explicit empty declared set
1140
- // so an untyped `.js` caller gets a deterministic `missing` list rather than the
1141
- // lint silently falling back to the blueprint's in-module manifest mirror.
1142
- const declaredCapabilities = Array.isArray(manifest.capabilities)
1143
- ? manifest.capabilities
1144
- : [];
1145
- const result = lintExtensionBlueprint(blueprint, { declaredCapabilities });
1146
- // `declared` is guaranteed non-null here: we always hand lint an array, so it
1147
- // never takes its "no declared set" branch. The cast drops the unreachable null.
1148
- const declared = result.declared;
1149
- const declaredSet = new Set(declared);
1150
- const usedSet = new Set(result.used);
1151
- const missing = result.used.filter((capability) => !declaredSet.has(capability));
1152
- const unused = declared.filter((capability) => !usedSet.has(capability));
1153
- if (missing.length > 0 || unused.length > 0) {
1154
- const parts = [];
1155
- if (missing.length > 0) {
1156
- parts.push(`missing [${missing.join(", ")}] (the blueprint registers ${missing.length === 1 ? "a surface" : "surfaces"} requiring ${missing.length === 1 ? "it" : "them"}; activation throws extension_capability_missing)`);
1157
- }
1158
- if (unused.length > 0) {
1159
- parts.push(`unused [${unused.join(", ")}] (declared but no surface exercises ${unused.length === 1 ? "it" : "them"}; drop for least privilege)`);
1160
- }
1161
- throw new Error(`Manifest capabilities do not match the blueprint: ${parts.join("; ")}. ` +
1162
- "Set capabilities to synthesizeExtensionManifest(blueprint, identity).capabilities to stay in sync.");
1163
- }
1164
- return {
1165
- used: result.used,
1166
- declared,
1167
- missing,
1168
- unused,
1169
- findings: result.findings,
1170
- };
1171
- }
1172
- /**
1173
- * Assert an extension manifest's declared version bounds permit it to load on a
1174
- * target pm CLI version, throwing when a bound blocks the load.
1175
- *
1176
- * This is the throwing CI/test counterpart to
1177
- * {@link ../sdk/compose.js#checkExtensionManifestCompatibility}: it runs the same
1178
- * author-time version-bound analysis and fails on any blocking incompatibility — a
1179
- * malformed bound (`*_invalid`), a `pm_min_version` the target is below
1180
- * (`pm_min_version_unmet`), or a `block`-mode `pm_max_version` the target exceeds
1181
- * (`pm_max_version_exceeded`). Advisory `warning` findings (`*_unchecked`, or a
1182
- * `warn`-mode `pm_max_version_exceeded_warn`) never throw, because the loader
1183
- * would still load the extension. Pin it to the pm version a package commits to
1184
- * supporting so a too-tight or malformed bound fails the package's own suite, not
1185
- * a user's install. The full compatibility result is returned on success so a test
1186
- * can still inspect advisory warnings.
1187
- */
1188
- export function assertExtensionManifestCompatible(manifest, target) {
1189
- const result = checkExtensionManifestCompatibility(manifest, target);
1190
- const blocking = result.findings.filter((finding) => finding.severity === "error");
1191
- if (blocking.length > 0) {
1192
- throw new Error(`Extension manifest is not compatible with pm ${result.pmVersion}: ${blocking
1193
- .map((finding) => finding.message)
1194
- .join("; ")}`);
1195
- }
1196
- return result;
1197
- }
1198
- /**
1199
- * Preflight a declarative {@link ExtensionBlueprint} through every author-time
1200
- * check in one test, throwing if any stage produced an `error`-severity finding.
1201
- *
1202
- * This is the throwing CI/test bookend over
1203
- * {@link ../sdk/compose.js#preflightExtension} — the single guard that replaces
1204
- * chaining {@link assertExtensionBlueprint}, {@link assertExtensionManifestMatchesBlueprint},
1205
- * and {@link assertExtensionManifestCompatible} in a package's
1206
- * `node:test`/Vitest suite. It runs the same consolidated analysis (always lints
1207
- * the blueprint; synthesizes the manifest when `options.identity` is given; checks
1208
- * version bounds when `options.target` is given) and throws one error listing every
1209
- * blocking finding tagged by its `source:code`. Advisory `warning` findings (an
1210
- * unused capability, a duplicate command, an `*_unchecked` bound) never throw,
1211
- * matching the underlying stages. The full {@link ExtensionPreflightReport} is
1212
- * returned on success so a test can still inspect those warnings, the synthesized
1213
- * manifest, and the derived capability set without failing on them.
1214
- */
1215
- export function assertExtensionPreflight(blueprint, options = {}) {
1216
- const report = preflightExtension(blueprint, options);
1217
- if (!report.ok) {
1218
- const errors = report.findings.filter((finding) => finding.severity === "error");
1219
- throw new Error(`Extension failed preflight with ${errors.length} ${errors.length === 1 ? "error" : "errors"}:\n` +
1220
- errors
1221
- .map((finding) => ` - [${finding.source}:${finding.code}] ${finding.message}`)
1222
- .join("\n"));
1223
- }
1224
- return report;
1225
- }
1226
- /** Reject obviously wrong harness input (e.g. an options object passed as the module) instead of silently producing an empty activation. Mirrors the loader's activatable-extension shapes: an `activate` function on the module or on its default export. */
1227
- function assertTestModuleHasActivateExport(module) {
1228
- if (resolveActivatablePropertyRecord(module)) {
1229
- return;
1230
- }
1231
- throw new Error("createExtensionTestHarness received a module with no activate export. Pass the extension module (with an activate(api) function on the module or its default export) as the first argument, and options second.");
1232
- }
1233
- /**
1234
- * Activate one in-memory extension module and return a fluent
1235
- * {@link ExtensionTestHarness} that binds every SDK testing helper to the right
1236
- * sub-registry of the resulting activation.
1237
- *
1238
- * This is the ergonomic capstone over the standalone helpers: instead of
1239
- * `activateExtensionForTest(module)` followed by repeatedly threading
1240
- * `activation.registrations` / `activation.commands` / `activation.hooks` into
1241
- * each `assertRegistered*` / `runRegistered*` call, an author writes
1242
- * `const ext = await createExtensionTestHarness(module, { capabilities });` and
1243
- * then `ext.assertCommandContract(...)`, `await ext.runCommand(...)`,
1244
- * `await ext.deactivate()` — never needing to know pm's internal registry layout.
1245
- *
1246
- * `name` and `layer` are resolved exactly as {@link activateExtensionForTest}
1247
- * resolves them, and captured so {@link ExtensionTestHarness.deactivate} forwards
1248
- * a matching skip-key. Activation runs pm's real validation/activation engine, so
1249
- * every bound helper exercises real wiring and dispatch — not mocks.
1250
- *
1251
- * Fails fast: if the module does not activate cleanly (e.g. a registration is
1252
- * dropped because the manifest omits the required capability), this throws a
1253
- * descriptive error listing each failure instead of returning a harness whose
1254
- * registries are empty — which would otherwise surface later as the confusing
1255
- * `available: (none)` assertion error this helper exists to prevent. Tests that
1256
- * deliberately exercise a *failed* activation should call
1257
- * {@link activateExtensionForTest} directly and inspect `activation.failed`.
1258
- */
1259
- export async function createExtensionTestHarness(module, options = {}) {
1260
- assertTestModuleHasActivateExport(module);
1261
- const manifest = readTestExtensionManifest(module);
1262
- const name = resolveTestExtensionName(manifest, options.name);
1263
- const layer = options.layer ?? "project";
1264
- const activation = await activateExtensionForTest(module, options);
1265
- if (activation.failed.length > 0) {
1266
- const detail = activation.failed
1267
- .map((failure) => {
1268
- const missingCapability = failure.trace?.missing_capability;
1269
- const reason = missingCapability
1270
- ? `${failure.error}; missing capability "${missingCapability}"`
1271
- : failure.error;
1272
- return `${failure.layer}:${failure.name} (${reason})`;
1273
- })
1274
- .join(", ");
1275
- throw new Error(`createExtensionTestHarness could not activate the extension cleanly: ${detail}. ` +
1276
- "Declare the required capability in the manifest (or pass it via options.capabilities), " +
1277
- "or use activateExtensionForTest directly to inspect a failed activation.");
1278
- }
1279
- return {
1280
- module,
1281
- name,
1282
- layer,
1283
- activation,
1284
- activationSummary(describeOptions) {
1285
- return describeExtensionActivation(activation, describeOptions);
1286
- },
1287
- renderMarkdown(markdownOptions = {}) {
1288
- const { extensionName, ...renderOptions } = markdownOptions ?? {};
1289
- return renderExtensionSurfaceMarkdown(describeExtensionActivation(activation, { extensionName }), renderOptions);
1290
- },
1291
- assertCommandContract(expectation) {
1292
- return assertRegisteredCommandContract(activation.registrations, expectation);
1293
- },
1294
- assertFlags(expectation) {
1295
- return assertRegisteredFlags(activation.registrations, expectation);
1296
- },
1297
- assertItemField(expectation) {
1298
- return assertRegisteredItemField(activation.registrations, expectation);
1299
- },
1300
- assertItemType(expectation) {
1301
- return assertRegisteredItemType(activation.registrations, expectation);
1302
- },
1303
- assertProfile(expectation) {
1304
- return assertRegisteredProfile(activation.registrations, expectation);
1305
- },
1306
- assertHook(expectation) {
1307
- return assertRegisteredHook(activation.hooks, expectation);
1308
- },
1309
- assertCommandOverride(expectation) {
1310
- return assertRegisteredCommandOverride(activation.commands, expectation);
1311
- },
1312
- assertParserOverride(expectation) {
1313
- return assertRegisteredParserOverride(activation.parsers, expectation);
1314
- },
1315
- assertPreflightOverride(expectation) {
1316
- return assertRegisteredPreflightOverride(activation.preflight, expectation);
1317
- },
1318
- assertRendererOverride(expectation) {
1319
- return assertRegisteredRendererOverride(activation.renderers, expectation);
1320
- },
1321
- assertServiceOverride(expectation) {
1322
- return assertRegisteredServiceOverride(activation.services, expectation);
1323
- },
1324
- assertSearchProvider(expectation) {
1325
- return assertRegisteredSearchProvider(activation.registrations, expectation);
1326
- },
1327
- assertVectorStoreAdapter(expectation) {
1328
- return assertRegisteredVectorStoreAdapter(activation.registrations, expectation);
1329
- },
1330
- assertImporter(expectation) {
1331
- return assertRegisteredImporter(activation.registrations, expectation);
1332
- },
1333
- assertExporter(expectation) {
1334
- return assertRegisteredExporter(activation.registrations, expectation);
1335
- },
1336
- assertMigration(expectation) {
1337
- return assertRegisteredMigration(activation.registrations, expectation);
1338
- },
1339
- assertCapabilityUsage(expectation) {
1340
- return assertExtensionCapabilityUsage(activation, expectation);
1341
- },
1342
- runCommand(runOptions) {
1343
- return runRegisteredCommandForTest(activation.commands, runOptions);
1344
- },
1345
- runHook(runOptions) {
1346
- return runRegisteredHookForTest(activation.hooks, runOptions);
1347
- },
1348
- runMutationGuard(runOptions) {
1349
- return runRegisteredMutationGuardForTest(activation.hooks, runOptions);
1350
- },
1351
- runCommandOverride(context) {
1352
- return runRegisteredCommandOverrideForTest(activation.commands, context);
1353
- },
1354
- runParserOverride(context) {
1355
- return runRegisteredParserOverrideForTest(activation.parsers, context);
1356
- },
1357
- runPreflightOverride(context) {
1358
- return runRegisteredPreflightOverrideForTest(activation.preflight, context);
1359
- },
1360
- runRendererOverride(context) {
1361
- return runRegisteredRendererOverrideForTest(activation.renderers, context);
1362
- },
1363
- runServiceOverride(context) {
1364
- return runRegisteredServiceOverrideForTest(activation.services, context);
1365
- },
1366
- runSearchProvider(runOptions) {
1367
- return runRegisteredSearchProviderForTest(activation.registrations, runOptions);
1368
- },
1369
- runVectorStoreAdapter(runOptions) {
1370
- return runRegisteredVectorStoreAdapterForTest(activation.registrations, runOptions);
1371
- },
1372
- runMigration(runOptions) {
1373
- return runRegisteredMigrationForTest(activation.registrations, runOptions);
1374
- },
1375
- runImporter(runOptions) {
1376
- return runRegisteredImporterForTest(activation, runOptions);
1377
- },
1378
- runExporter(runOptions) {
1379
- return runRegisteredExporterForTest(activation, runOptions);
1380
- },
1381
- deactivate(deactivateOptions = {}) {
1382
- return deactivateExtensionForTest(module, {
1383
- name,
1384
- layer,
1385
- activation,
1386
- deactivateTimeoutMs: deactivateOptions.deactivateTimeoutMs,
1387
- });
1388
- },
1389
- };
1390
- }
1
+ !(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="fa9e95e5-7782-509d-96af-093a47daaed7")}catch(e2){}})();import{activateExtensions,deactivateExtensions,runAfterCommandHooks,runBeforeCommandHooks,runBeforeMutationHooks,runCommandHandler,runCommandOverride,runOnIndexHooks,runOnReadHooks,runOnWriteHooks,runParserOverride,runPreflightOverride,runRendererOverride,runServiceOverride}from"../core/extensions/loader.js";import{createDefaultExtensionGovernancePolicy}from"../core/extensions/extension-types.js";import{getMigrationRuntimeDefinition,resolveRegisteredSearchProvider,resolveRegisteredVectorStoreAdapter}from"../core/extensions/runtime-registrations.js";import{collectUsedExtensionCapabilities}from"../core/extensions/capability-usage.js";import{normalizeKnownExtensionCapability}from"../core/extensions/extension-capability-aliases.js";import{checkExtensionManifestCompatibility,describeExtensionBlueprint,lintExtensionBlueprint,preflightExtension}from"./compose.js";import{describeExtensionActivation}from"../core/extensions/activation-summary.js";import{lintProjectProfile}from"../core/profile/profile-lint.js";import{renderExtensionSurfaceMarkdown}from"../core/extensions/activation-summary-markdown.js";import{asPropertyRecord,resolveActivatablePropertyRecord}from"../core/shared/primitives.js";import{createExtensionCommandSdk}from"./extension-command-context.js";import{PmClient}from"./runtime.js";function registeredExpectationName(expectation,legacyValue){return expectation.name??legacyValue??""}const HOOK_KIND_TO_REGISTRY_FIELD={before_command:"beforeCommand",before_mutation:"beforeMutation",after_command:"afterCommand",on_read:"onRead",on_write:"onWrite",on_index:"onIndex"};const RUNNABLE_HOOK_KIND_TO_REGISTRY_FIELD={before_command:"beforeCommand",after_command:"afterCommand",on_read:"onRead",on_write:"onWrite",on_index:"onIndex"};function normalizeSdkIdentifier(value){return value.trim().toLowerCase()}function normalizeSdkProfileMatchKey(value){return normalizeSdkIdentifier(value).replaceAll("-","_")}function extensionNameSuffix(extensionName){return extensionName?` from extension "${extensionName}"`:""}function sortedUnique(values){return[...new Set(values)].sort((left,right)=>left.localeCompare(right))}function normalizeSdkCommandName(command){if(typeof command!=="string"){throw new Error('A command name string is required. Pass it via the options object, e.g. runRegisteredCommandForTest(activation, { command: "my command" }) \u2014 positional command arguments are not supported.')}return command.trim().toLowerCase().split(/\s+/).filter(part=>part.length>0).join(" ")}function formatAvailable(values){return values.length>0?values.join(", "):"(none)"}function assertStringSetIncludes(actual,expected,label){const actualValues=new Set(actual??[]);const missing=sortedUnique(expected.filter(value=>!actualValues.has(value)));if(missing.length>0){throw new Error(`Expected package manifest ${label} to include ${missing.join(", ")}; available: ${formatAvailable(sortedUnique(actual??[]))}`)}}function collectFlagLabels(flags){const labels=new Set;for(const flag of flags){if(typeof flag.long==="string"&&flag.long.trim().length>0){labels.add(flag.long.trim())}if(typeof flag.short==="string"&&flag.short.trim().length>0){labels.add(flag.short.trim())}}return labels}function readTestExtensionManifest(module){const moduleRecord=asPropertyRecord(module);if(!moduleRecord){return{}}const manifest=asPropertyRecord(moduleRecord.manifest);if(manifest){return manifest}const defaultExport=asPropertyRecord(moduleRecord.default);const defaultManifest=asPropertyRecord(defaultExport?.manifest);if(defaultManifest){return defaultManifest}if(defaultExport&&typeof moduleRecord.default!=="function"&&("name"in defaultExport||"capabilities"in defaultExport)){return defaultExport}if(typeof module!=="function"&&("name"in moduleRecord||"capabilities"in moduleRecord)){return moduleRecord}return{}}function resolveTestExtensionName(manifest,explicitName){return explicitName??(typeof manifest.name==="string"&&manifest.name.trim().length>0?manifest.name.trim():"test-extension")}function readTestExtensionCapabilities(manifest,options){if(Array.isArray(options.capabilities)){return[...options.capabilities]}if(Array.isArray(manifest.capabilities)){return manifest.capabilities.filter(capability=>typeof capability==="string")}return[]}function buildSingleExtensionLoadResult(module,manifest,identity){return{disabled_by_flag:false,roots:{global:"",project:""},configured_enabled:[],configured_disabled:[],discovered:[],effective:[],warnings:[],policy:identity.policy,failed:[],loaded:[{layer:identity.layer,directory:"",manifest_path:"",name:identity.name,version:typeof manifest.version==="string"?manifest.version:"0.0.0",entry:typeof manifest.entry==="string"?manifest.entry:"./index.js",priority:typeof manifest.priority==="number"?manifest.priority:0,entry_path:"",capabilities:identity.capabilities,manifest_version:typeof manifest.manifest_version==="number"?manifest.manifest_version:void 0,pm_min_version:typeof manifest.pm_min_version==="string"?manifest.pm_min_version:void 0,pm_max_version:typeof manifest.pm_max_version==="string"?manifest.pm_max_version:void 0,engines:manifest.engines,trusted:manifest.trusted,provenance:manifest.provenance,sandbox_profile:manifest.sandbox_profile,permissions:manifest.permissions,activation:manifest.activation,module}]}}async function activateExtensionForTest(module,options={}){const manifest=readTestExtensionManifest(module);return activateExtensions(buildSingleExtensionLoadResult(module,manifest,{name:resolveTestExtensionName(manifest,options.name),layer:options.layer??"project",capabilities:readTestExtensionCapabilities(manifest,options),policy:options.policy??createDefaultExtensionGovernancePolicy()}))}async function deactivateExtensionForTest(module,options={}){const manifest=readTestExtensionManifest(module);return deactivateExtensions(buildSingleExtensionLoadResult(module,manifest,{name:resolveTestExtensionName(manifest,options.name),layer:options.layer??"project",capabilities:readTestExtensionCapabilities(manifest,{}),policy:createDefaultExtensionGovernancePolicy()}),options.activation,options.deactivateTimeoutMs===void 0?{}:{deactivate_timeout_ms:options.deactivateTimeoutMs})}async function runRegisteredCommandForTest(commands,options){const command=normalizeSdkCommandName(options.command);if(command.length===0){throw new Error("Expected command name must be a non-empty string")}const hasHandler=commands.handlers.some(entry=>entry.command===command);if(!hasHandler){const available=sortedUnique(commands.handlers.map(entry=>entry.command));throw new Error(`Expected a registered command handler for "${command}" to invoke. Available command handlers: ${formatAvailable(available)}`)}if(options.sdk!==void 0&&options.sdkFactory!==void 0){throw new TypeError("runRegisteredCommandForTest accepts sdk or sdkFactory, not both")}const pmRoot=options.pmRoot??"";const global2={json:true,quiet:true,noPager:true,...options.global};const sdk=options.sdk??options.sdkFactory?.({pmRoot,global:global2})??(pmRoot.length>0?createExtensionCommandSdk(pmRoot,new PmClient({pmRoot})):void 0);return runCommandHandler(commands,{command,args:options.args?[...options.args]:[],options:options.options?{...options.options}:{},global:global2,pm_root:pmRoot,...sdk===void 0?{}:{sdk}})}async function runRegisteredMutationGuardForTest(hooks,options){if((hooks.beforeMutation?.length??0)===0){throw new Error("Expected a registered before_mutation hook to invoke")}await runBeforeMutationHooks(hooks,options.context)}async function runRegisteredHookForTest(hooks,options){const kind=options.kind;if(kind==="before_mutation"){throw new Error("Invoke before_mutation hooks with runRegisteredMutationGuardForTest so denials and failures retain fail-closed semantics.")}if((hooks[RUNNABLE_HOOK_KIND_TO_REGISTRY_FIELD[kind]]?.length??0)===0){const populatedKinds=sortedUnique(Object.keys(RUNNABLE_HOOK_KIND_TO_REGISTRY_FIELD).filter(candidateKind=>(hooks[RUNNABLE_HOOK_KIND_TO_REGISTRY_FIELD[candidateKind]]?.length??0)>0));throw new Error(`Expected a registered "${kind}" hook to invoke. Hook kinds with registrations: ${formatAvailable(populatedKinds)}`)}switch(options.kind){case"before_command":return runBeforeCommandHooks(hooks,options.context);case"after_command":return runAfterCommandHooks(hooks,options.context);case"on_read":return runOnReadHooks(hooks,options.context);case"on_write":return runOnWriteHooks(hooks,options.context);case"on_index":return runOnIndexHooks(hooks,options.context)}}async function runRegisteredParserOverrideForTest(parsers,context){const command=normalizeSdkCommandName(context.command);if(!parsers.overrides.some(entry=>entry.command===command)){throw new Error(`Expected a registered parser override for command "${command}" to invoke. Available parser override commands: ${formatAvailable(sortedUnique(parsers.overrides.map(entry=>entry.command)))}`)}return runParserOverride(parsers,context)}async function runRegisteredPreflightOverrideForTest(preflight,context){if(preflight.overrides.length===0){throw new Error("Expected a registered preflight override to invoke, but none are registered.")}return runPreflightOverride(preflight,context)}async function runRegisteredCommandOverrideForTest(commands,context){const command=normalizeSdkCommandName(context.command);if(!commands.overrides.some(entry=>entry.command===command)){throw new Error(`Expected a registered command override for command "${command}" to invoke. Available command override commands: ${formatAvailable(sortedUnique(commands.overrides.map(entry=>entry.command)))}`)}return runCommandOverride(commands,context)}async function runRegisteredRendererOverrideForTest(renderers,context){if(!renderers.overrides.some(entry=>entry.format===context.format)){throw new Error(`Expected a registered renderer override for format "${context.format}" to invoke. Available renderer override formats: ${formatAvailable(sortedUnique(renderers.overrides.map(entry=>entry.format)))}`)}return runRendererOverride(renderers,context)}async function runRegisteredServiceOverrideForTest(services,context){if(!services.overrides.some(entry=>entry.service===context.service)){throw new Error(`Expected a registered service override for service "${context.service}" to invoke. Available service override services: ${formatAvailable(sortedUnique(services.overrides.map(entry=>entry.service)))}`)}return runServiceOverride(services,context)}const SEARCH_PROVIDER_OPERATION_DEFINITION_KEYS={query:["query"],embed:["embed"],embedBatch:["embedBatch","embed_batch"],queryExpansion:["queryExpansion","query_expansion"],rerank:["rerank"]};async function runRegisteredSearchProviderForTest(registrations,options){const registration=resolveRegisteredSearchProvider(registrations,options.provider);if(!registration){const available=sortedUnique(registrations.search_providers.map(entry=>entry.definition.name));throw new Error(`Expected a registered search provider "${options.provider}" to invoke. Available search providers: ${formatAvailable(available)}`)}const runtimeDefinition=registration.runtime_definition;const operationFn=SEARCH_PROVIDER_OPERATION_DEFINITION_KEYS[options.operation].map(key=>runtimeDefinition[key]).find(value=>typeof value==="function");if(typeof operationFn!=="function"){throw new Error(`Registered search provider "${options.provider}" does not implement the "${options.operation}" operation.`)}return await operationFn(options.context)}async function runRegisteredVectorStoreAdapterForTest(registrations,options){const registration=resolveRegisteredVectorStoreAdapter(registrations,options.adapter);if(!registration){const available=sortedUnique(registrations.vector_store_adapters.map(entry=>entry.definition.name));throw new Error(`Expected a registered vector store adapter "${options.adapter}" to invoke. Available vector store adapters: ${formatAvailable(available)}`)}const operationFn=registration.runtime_definition[options.operation];if(typeof operationFn!=="function"){throw new Error(`Registered vector store adapter "${options.adapter}" does not implement the "${options.operation}" operation.`)}return await operationFn(options.context)}async function runRegisteredMigrationForTest(registrations,options){const migration=assertRegisteredMigration(registrations,{migration:options.migration,extensionName:options.extensionName});const run=getMigrationRuntimeDefinition(migration).run;if(typeof run!=="function"){throw new Error(`Registered migration "${options.migration}" does not implement a run function to invoke.`)}const declaredStatus=migration.definition.status;const context={id:migration.definition.id,command:"migration",layer:migration.layer,extension:migration.name,pm_root:options.pmRoot??"",status:(typeof declaredStatus==="string"?declaredStatus.trim().toLowerCase():"")||"pending"};return await run(context)}async function runRegisteredImporterForTest(activation,options){const importer=assertRegisteredImporter(activation.registrations,{importer:options.importer,extensionName:options.extensionName});return runRegisteredCommandForTest(activation.commands,{command:`${importer.importer} import`,args:options.args,options:options.options,global:options.global,pmRoot:options.pmRoot})}async function runRegisteredExporterForTest(activation,options){const exporter=assertRegisteredExporter(activation.registrations,{exporter:options.exporter,extensionName:options.extensionName});return runRegisteredCommandForTest(activation.commands,{command:`${exporter.exporter} export`,args:options.args,options:options.options,global:options.global,pmRoot:options.pmRoot})}function assertExtensionDeactivated(result,expectation={}){const expectedDeactivated=expectation.deactivated??1;if(result.deactivated!==expectedDeactivated){throw new Error(`Expected ${expectedDeactivated} extension${expectedDeactivated===1?"":"s"} to deactivate cleanly, but ${result.deactivated} did.`)}const expectedFailed=expectation.failed??0;if(result.failed.length!==expectedFailed){const detail=result.failed.map(failure=>`${failure.layer}:${failure.name} (${failure.error})`).join(", ");throw new Error(`Expected ${expectedFailed} teardown failure${expectedFailed===1?"":"s"}, but observed ${result.failed.length}${detail.length>0?`: ${detail}`:""}.`)}return result}function assertPackageManifest(manifest,expectation){if(expectation.packageName!==void 0&&manifest.package_name!==expectation.packageName){throw new Error(`Expected package manifest package_name to be "${expectation.packageName}"; received "${manifest.package_name??"(none)"}"`)}if(expectation.aliases!==void 0){assertStringSetIncludes(manifest.aliases,expectation.aliases,"aliases")}if(expectation.resources!==void 0){for(const[kind,expectedPaths]of Object.entries(expectation.resources)){assertStringSetIncludes(manifest.resources[kind],expectedPaths,`pm.${kind}`)}}return manifest}function assertRegisteredCommandContract(registrations,expectation){const expectedCommand=normalizeSdkCommandName(registeredExpectationName(expectation,expectation.command));if(expectedCommand.length===0){throw new Error("Expected command name must be a non-empty string")}const commandCandidates=registrations.commands.filter(entry=>entry.command===expectedCommand);const command=expectation.extensionName?commandCandidates.find(entry=>entry.name===expectation.extensionName):commandCandidates[0];if(!command){const available=registrations.commands.map(entry=>entry.command).sort((left,right)=>left.localeCompare(right));const extensionSuffix=expectation.extensionName?` from extension "${expectation.extensionName}"`:"";throw new Error(`Expected extension command "${expectedCommand}"${extensionSuffix} to be registered. Available commands: ${formatAvailable(available)}`)}if(expectation.action!==void 0&&command.action!==expectation.action){throw new Error(`Expected extension command "${expectedCommand}" action "${expectation.action}", received "${command.action}"`)}if(expectation.arguments!==void 0){const actualArguments=(command.arguments??[]).map(argument=>argument.name);const missingArguments=expectation.arguments.filter(argument=>!actualArguments.includes(argument));if(missingArguments.length>0){throw new Error(`Expected extension command "${expectedCommand}" arguments ${formatAvailable(expectation.arguments)}; missing ${formatAvailable(missingArguments)}; available ${formatAvailable(actualArguments)}`)}}const flags=registrations.flags.filter(entry=>entry.target_command===expectedCommand&&(expectation.extensionName===void 0||entry.name===expectation.extensionName)).flatMap(entry=>entry.flags);if(expectation.flags!==void 0){const actualFlagLabels=collectFlagLabels(flags);const missingFlags=expectation.flags.filter(flag=>!actualFlagLabels.has(flag));if(missingFlags.length>0){throw new Error(`Expected extension command "${expectedCommand}" flags ${formatAvailable(expectation.flags)}; missing ${formatAvailable(missingFlags)}; available ${formatAvailable([...actualFlagLabels].sort((left,right)=>left.localeCompare(right)))}`)}}return{command,flags}}function assertRegisteredFlags(registrations,expectation){const expectedCommand=normalizeSdkCommandName(registeredExpectationName(expectation,expectation.targetCommand));if(expectedCommand.length===0){throw new Error("Expected target command name must be a non-empty string")}const candidates=registrations.flags.filter(entry=>entry.target_command===expectedCommand);let registration;if(expectation.extensionName){registration=candidates.find(entry=>entry.name===expectation.extensionName)}else if(candidates.length===1){registration=candidates[0]}else if(candidates.length>1){const availableExtensions=sortedUnique(candidates.map(entry=>entry.name));throw new Error(`Expected flags for target command "${expectedCommand}" matched multiple extensions: ${formatAvailable(availableExtensions)}. Specify extensionName to choose one registration.`)}if(!registration){const available=sortedUnique(registrations.flags.map(entry=>entry.target_command));const availableExtensions=sortedUnique(candidates.map(entry=>entry.name));throw new Error(`Expected flags for target command "${expectedCommand}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available flag target commands: ${formatAvailable(available)}; matching extensions: ${formatAvailable(availableExtensions)}`)}if(expectation.flags!==void 0){const actualFlagLabels=collectFlagLabels(registration.flags);const missingFlags=expectation.flags.filter(flag=>!actualFlagLabels.has(flag));if(missingFlags.length>0){throw new Error(`Expected flags for target command "${expectedCommand}" to include ${formatAvailable(expectation.flags)}; missing ${formatAvailable(missingFlags)}; available ${formatAvailable([...actualFlagLabels].sort((left,right)=>left.localeCompare(right)))}`)}}return registration}function assertRegisteredHook(hooks,expectation){const field=HOOK_KIND_TO_REGISTRY_FIELD[expectation.kind];const candidates=hooks[field]??[];const hook=expectation.extensionName?candidates.find(entry=>entry.name===expectation.extensionName):candidates[0];if(!hook){const available=sortedUnique(candidates.map(entry=>entry.name));throw new Error(`Expected a "${expectation.kind}" hook${extensionNameSuffix(expectation.extensionName)} to be registered. Available "${expectation.kind}" hooks: ${formatAvailable(available)}`)}return hook}function assertRegisteredSearchProvider(registrations,expectation){const expectedProvider=normalizeSdkIdentifier(registeredExpectationName(expectation,expectation.provider));if(expectedProvider.length===0){throw new Error("Expected search provider name must be a non-empty string")}const candidates=registrations.search_providers.filter(entry=>normalizeSdkIdentifier(entry.definition.name)===expectedProvider);const provider=expectation.extensionName?candidates.find(entry=>entry.name===expectation.extensionName):candidates[0];if(!provider){const available=sortedUnique(registrations.search_providers.map(entry=>entry.definition.name));throw new Error(`Expected search provider "${expectedProvider}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available search providers: ${formatAvailable(available)}`)}return provider}function assertRegisteredVectorStoreAdapter(registrations,expectation){const expectedAdapter=normalizeSdkIdentifier(registeredExpectationName(expectation,expectation.adapter));if(expectedAdapter.length===0){throw new Error("Expected vector store adapter name must be a non-empty string")}const candidates=registrations.vector_store_adapters.filter(entry=>normalizeSdkIdentifier(entry.definition.name)===expectedAdapter);const adapter=expectation.extensionName?candidates.find(entry=>entry.name===expectation.extensionName):candidates[0];if(!adapter){const available=sortedUnique(registrations.vector_store_adapters.map(entry=>entry.definition.name));throw new Error(`Expected vector store adapter "${expectedAdapter}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available vector store adapters: ${formatAvailable(available)}`)}return adapter}function assertRegisteredImporter(registrations,expectation){const expectedImporter=normalizeSdkIdentifier(registeredExpectationName(expectation,expectation.importer));if(expectedImporter.length===0){throw new Error("Expected importer name must be a non-empty string")}const candidates=registrations.importers.filter(entry=>normalizeSdkIdentifier(entry.importer)===expectedImporter);const importer=expectation.extensionName?candidates.find(entry=>entry.name===expectation.extensionName):candidates[0];if(!importer){const available=sortedUnique(registrations.importers.map(entry=>entry.importer));throw new Error(`Expected importer "${expectedImporter}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available importers: ${formatAvailable(available)}`)}return importer}function assertRegisteredExporter(registrations,expectation){const expectedExporter=normalizeSdkIdentifier(registeredExpectationName(expectation,expectation.exporter));if(expectedExporter.length===0){throw new Error("Expected exporter name must be a non-empty string")}const candidates=registrations.exporters.filter(entry=>normalizeSdkIdentifier(entry.exporter)===expectedExporter);const exporter=expectation.extensionName?candidates.find(entry=>entry.name===expectation.extensionName):candidates[0];if(!exporter){const available=sortedUnique(registrations.exporters.map(entry=>entry.exporter));throw new Error(`Expected exporter "${expectedExporter}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available exporters: ${formatAvailable(available)}`)}return exporter}function assertRegisteredItemField(registrations,expectation){const expectedField=normalizeSdkIdentifier(registeredExpectationName(expectation,expectation.field));if(expectedField.length===0){throw new Error("Expected item field name must be a non-empty string")}const candidates=registrations.item_fields.filter(entry=>expectation.extensionName===void 0||entry.name===expectation.extensionName).map(registration=>({registration,field:registration.fields.find(field=>normalizeSdkIdentifier(field.name)===expectedField)})).filter(entry=>entry.field!==void 0);const match=candidates.find(entry=>expectation.type===void 0||entry.field.type===expectation.type);if(!match){const available=sortedUnique(registrations.item_fields.flatMap(entry=>entry.fields.map(field=>`${field.name}:${field.type}`)));throw new Error(`Expected item field "${expectedField}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available item fields: ${formatAvailable(available)}`)}return match}function assertRegisteredItemType(registrations,expectation){const expectedType=normalizeSdkIdentifier(registeredExpectationName(expectation,expectation.itemType));if(expectedType.length===0){throw new Error("Expected item type name must be a non-empty string")}const candidates=registrations.item_types.filter(entry=>expectation.extensionName===void 0||entry.name===expectation.extensionName).map(registration=>({registration,itemType:registration.types.find(itemType=>normalizeSdkIdentifier(itemType.name)===expectedType)})).filter(entry=>entry.itemType!==void 0);const match=candidates.find(entry=>expectation.folder===void 0||entry.itemType.folder===expectation.folder);if(!match){const available=sortedUnique(registrations.item_types.flatMap(entry=>entry.types.map(itemType=>`${itemType.name}:${itemType.folder}`)));throw new Error(`Expected item type "${expectedType}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available item types: ${formatAvailable(available)}`)}return match}function assertRegisteredProfile(registrations,expectation){const expectedProfile=normalizeSdkProfileMatchKey(registeredExpectationName(expectation,expectation.profile));if(expectedProfile.length===0){throw new Error("Expected profile name must be a non-empty string")}const match=registrations.profiles.filter(entry=>expectation.extensionName===void 0||entry.name===expectation.extensionName).find(entry=>normalizeSdkProfileMatchKey(entry.profile.name)===expectedProfile);if(!match){const available=sortedUnique(registrations.profiles.map(entry=>entry.profile.name));throw new Error(`Expected profile "${expectedProfile}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available profiles: ${formatAvailable(available)}`)}return{registration:match,profile:match.profile}}function assertRegisteredCommandOverride(commands,expectation){const expectedCommand=normalizeSdkCommandName(registeredExpectationName(expectation,expectation.command));if(expectedCommand.length===0){throw new Error("Expected command name must be a non-empty string")}const candidates=commands.overrides.filter(entry=>entry.command===expectedCommand);const override=expectation.extensionName?candidates.find(entry=>entry.name===expectation.extensionName):candidates[0];if(!override){const available=sortedUnique(commands.overrides.map(entry=>entry.command));throw new Error(`Expected command override "${expectedCommand}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available command overrides: ${formatAvailable(available)}`)}return override}function assertRegisteredParserOverride(parsers,expectation){const expectedCommand=normalizeSdkCommandName(registeredExpectationName(expectation,expectation.command));if(expectedCommand.length===0){throw new Error("Expected command name must be a non-empty string")}const candidates=parsers.overrides.filter(entry=>entry.command===expectedCommand);const override=expectation.extensionName?candidates.find(entry=>entry.name===expectation.extensionName):candidates[0];if(!override){const available=sortedUnique(parsers.overrides.map(entry=>entry.command));throw new Error(`Expected parser override "${expectedCommand}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available parser overrides: ${formatAvailable(available)}`)}return override}function assertRegisteredPreflightOverride(preflight,expectation={}){const override=expectation.extensionName?preflight.overrides.find(entry=>entry.name===expectation.extensionName):preflight.overrides[0];if(!override){const available=sortedUnique(preflight.overrides.map(entry=>entry.name));throw new Error(`Expected a preflight override${extensionNameSuffix(expectation.extensionName)} to be registered. Available preflight overrides: ${formatAvailable(available)}`)}return override}function assertRegisteredRendererOverride(renderers,expectation){const expectedFormat=normalizeSdkIdentifier(registeredExpectationName(expectation,expectation.format));if(expectedFormat.length===0){throw new Error("Expected renderer format must be a non-empty string")}const candidates=renderers.overrides.filter(entry=>entry.format===expectedFormat);const override=expectation.extensionName?candidates.find(entry=>entry.name===expectation.extensionName):candidates[0];if(!override){const available=sortedUnique(renderers.overrides.map(entry=>entry.format));throw new Error(`Expected renderer override "${expectedFormat}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available renderer overrides: ${formatAvailable(available)}`)}return override}function assertRegisteredServiceOverride(services,expectation){const expectedService=normalizeSdkIdentifier(registeredExpectationName(expectation,expectation.service));if(expectedService.length===0){throw new Error("Expected service name must be a non-empty string")}const candidates=services.overrides.filter(entry=>normalizeSdkIdentifier(entry.service)===expectedService);const override=expectation.extensionName?candidates.find(entry=>entry.name===expectation.extensionName):candidates[0];if(!override){const available=sortedUnique(services.overrides.map(entry=>entry.service));throw new Error(`Expected service override "${expectedService}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available service overrides: ${formatAvailable(available)}`)}return override}function assertRegisteredMigration(registrations,expectation){const expectedMigration=normalizeSdkIdentifier(registeredExpectationName(expectation,expectation.migration));if(expectedMigration.length===0){throw new Error("Expected migration id must be a non-empty string")}const candidates=registrations.migrations.filter(entry=>(expectation.extensionName===void 0||entry.name===expectation.extensionName)&&typeof entry.definition.id==="string"&&normalizeSdkIdentifier(entry.definition.id)===expectedMigration);const match=candidates.find(entry=>expectation.mandatory===void 0||(entry.definition.mandatory??false)===expectation.mandatory);if(match){return match}const idMatch=candidates[0];if(idMatch!==void 0){throw new Error(`Expected migration "${expectedMigration}"${extensionNameSuffix(expectation.extensionName)} to have mandatory=${expectation.mandatory}, but it is mandatory=${idMatch.definition.mandatory??false}.`)}const available=sortedUnique(registrations.migrations.map(entry=>{const id=typeof entry.definition.id==="string"&&entry.definition.id.trim().length>0?entry.definition.id.trim():"(unnamed)";return`${id}:${entry.definition.mandatory===true}`}));throw new Error(`Expected migration "${expectedMigration}"${extensionNameSuffix(expectation.extensionName)} to be registered. Available migrations: ${formatAvailable(available)}`)}function assertExtensionCapabilityUsage(activation,expectation){const toKnownCapabilitySet=(capabilities,field)=>{const known=new Set;for(const capability of capabilities){const normalized=normalizeKnownExtensionCapability(capability);if(normalized===null){throw new Error(`Expected ${field} capability "${capability}" to be a known extension capability. Use canonical capability names (see manifest.capabilities).`)}known.add(normalized)}return known};const declared=[...toKnownCapabilitySet(expectation.declared,"declared")].sort((left,right)=>left.localeCompare(right));const allowUnused=toKnownCapabilitySet(expectation.allowUnused??[],"allowUnused");const used=collectUsedExtensionCapabilities(activation,{extensionName:expectation.extensionName});const usedSet=new Set(used);const unused=declared.filter(capability=>!usedSet.has(capability)&&!allowUnused.has(capability));if(unused.length>0){const scopeSuffix=extensionNameSuffix(expectation.extensionName);throw new Error(`Expected every declared capability${scopeSuffix} to be exercised, but [${unused.join(", ")}] ${unused.length===1?"is":"are"} declared yet never registered against. Remove ${unused.length===1?"it":"them"} from manifest.capabilities for least privilege, or pass allowUnused for capabilities registered only behind a runtime flag.`)}return{declared,used,unused}}function assertExtensionBlueprint(blueprint,options={}){const result=lintExtensionBlueprint(blueprint,options);if(!result.ok){const errors=result.findings.filter(finding=>finding.severity==="error");throw new Error(`Extension blueprint failed preflight with ${errors.length} ${errors.length===1?"error":"errors"}:
2
+ `+errors.map(finding=>` - [${finding.code}] ${finding.message}`).join("\n"))}return result}function assertProjectProfile(profile,options={}){const report=lintProjectProfile(profile);const blocking=report.findings.filter(finding=>finding.severity==="error"||options.strict===true&&finding.severity==="warning");if(blocking.length>0){throw new Error(`Project profile "${report.profile}" failed lint with ${blocking.length} ${blocking.length===1?"issue":"issues"}:
3
+ `+blocking.map(finding=>` - ${finding.severity} [${finding.code}] ${finding.message}`).join("\n"))}return report}function assertExtensionManifestMatchesBlueprint(manifest,blueprint){const declaredCapabilities=Array.isArray(manifest.capabilities)?manifest.capabilities:[];const result=lintExtensionBlueprint(blueprint,{declaredCapabilities});const declared=result.declared;const declaredSet=new Set(declared);const usedSet=new Set(result.used);const missing=result.used.filter(capability=>!declaredSet.has(capability));const unused=declared.filter(capability=>!usedSet.has(capability));if(missing.length>0||unused.length>0){const parts=[];if(missing.length>0){parts.push(`missing [${missing.join(", ")}] (the blueprint registers ${missing.length===1?"a surface":"surfaces"} requiring ${missing.length===1?"it":"them"}; activation throws extension_capability_missing)`)}if(unused.length>0){parts.push(`unused [${unused.join(", ")}] (declared but no surface exercises ${unused.length===1?"it":"them"}; drop for least privilege)`)}throw new Error(`Manifest capabilities do not match the blueprint: ${parts.join("; ")}. Set capabilities to synthesizeExtensionManifest(blueprint, identity).capabilities to stay in sync.`)}return{used:result.used,declared,missing,unused,findings:result.findings}}function assertExtensionManifestCompatible(manifest,target){const result=checkExtensionManifestCompatibility(manifest,target);const blocking=result.findings.filter(finding=>finding.severity==="error");if(blocking.length>0){throw new Error(`Extension manifest is not compatible with pm ${result.pmVersion}: ${blocking.map(finding=>finding.message).join("; ")}`)}return result}function assertExtensionPreflight(blueprint,options={}){const report=preflightExtension(blueprint,options);if(!report.ok){const errors=report.findings.filter(finding=>finding.severity==="error");throw new Error(`Extension failed preflight with ${errors.length} ${errors.length===1?"error":"errors"}:
4
+ `+errors.map(finding=>` - [${finding.source}:${finding.code}] ${finding.message}`).join("\n"))}return report}function assertTestModuleHasActivateExport(module){if(resolveActivatablePropertyRecord(module)){return}throw new Error("createExtensionTestHarness received a module with no activate export. Pass the extension module (with an activate(api) function on the module or its default export) as the first argument, and options second.")}async function createExtensionTestHarness(module,options={}){assertTestModuleHasActivateExport(module);const manifest=readTestExtensionManifest(module);const name=resolveTestExtensionName(manifest,options.name);const layer=options.layer??"project";const activation=await activateExtensionForTest(module,options);if(activation.failed.length>0){const detail=activation.failed.map(failure=>{const missingCapability=failure.trace?.missing_capability;const reason=missingCapability?`${failure.error}; missing capability "${missingCapability}"`:failure.error;return`${failure.layer}:${failure.name} (${reason})`}).join(", ");throw new Error(`createExtensionTestHarness could not activate the extension cleanly: ${detail}. Declare the required capability in the manifest (or pass it via options.capabilities), or use activateExtensionForTest directly to inspect a failed activation.`)}return{module,name,layer,activation,activationSummary(describeOptions){return describeExtensionActivation(activation,describeOptions)},renderMarkdown(markdownOptions={}){const{extensionName,...renderOptions}=markdownOptions??{};return renderExtensionSurfaceMarkdown(describeExtensionActivation(activation,{extensionName}),renderOptions)},assertCommandContract(expectation){return assertRegisteredCommandContract(activation.registrations,expectation)},assertFlags(expectation){return assertRegisteredFlags(activation.registrations,expectation)},assertItemField(expectation){return assertRegisteredItemField(activation.registrations,expectation)},assertItemType(expectation){return assertRegisteredItemType(activation.registrations,expectation)},assertProfile(expectation){return assertRegisteredProfile(activation.registrations,expectation)},assertHook(expectation){return assertRegisteredHook(activation.hooks,expectation)},assertCommandOverride(expectation){return assertRegisteredCommandOverride(activation.commands,expectation)},assertParserOverride(expectation){return assertRegisteredParserOverride(activation.parsers,expectation)},assertPreflightOverride(expectation){return assertRegisteredPreflightOverride(activation.preflight,expectation)},assertRendererOverride(expectation){return assertRegisteredRendererOverride(activation.renderers,expectation)},assertServiceOverride(expectation){return assertRegisteredServiceOverride(activation.services,expectation)},assertSearchProvider(expectation){return assertRegisteredSearchProvider(activation.registrations,expectation)},assertVectorStoreAdapter(expectation){return assertRegisteredVectorStoreAdapter(activation.registrations,expectation)},assertImporter(expectation){return assertRegisteredImporter(activation.registrations,expectation)},assertExporter(expectation){return assertRegisteredExporter(activation.registrations,expectation)},assertMigration(expectation){return assertRegisteredMigration(activation.registrations,expectation)},assertCapabilityUsage(expectation){return assertExtensionCapabilityUsage(activation,expectation)},runCommand(runOptions){return runRegisteredCommandForTest(activation.commands,runOptions)},runHook(runOptions){return runRegisteredHookForTest(activation.hooks,runOptions)},runMutationGuard(runOptions){return runRegisteredMutationGuardForTest(activation.hooks,runOptions)},runCommandOverride(context){return runRegisteredCommandOverrideForTest(activation.commands,context)},runParserOverride(context){return runRegisteredParserOverrideForTest(activation.parsers,context)},runPreflightOverride(context){return runRegisteredPreflightOverrideForTest(activation.preflight,context)},runRendererOverride(context){return runRegisteredRendererOverrideForTest(activation.renderers,context)},runServiceOverride(context){return runRegisteredServiceOverrideForTest(activation.services,context)},runSearchProvider(runOptions){return runRegisteredSearchProviderForTest(activation.registrations,runOptions)},runVectorStoreAdapter(runOptions){return runRegisteredVectorStoreAdapterForTest(activation.registrations,runOptions)},runMigration(runOptions){return runRegisteredMigrationForTest(activation.registrations,runOptions)},runImporter(runOptions){return runRegisteredImporterForTest(activation,runOptions)},runExporter(runOptions){return runRegisteredExporterForTest(activation,runOptions)},deactivate(deactivateOptions={}){return deactivateExtensionForTest(module,{name,layer,activation,deactivateTimeoutMs:deactivateOptions.deactivateTimeoutMs})}}}export{activateExtensionForTest,assertExtensionBlueprint,assertExtensionCapabilityUsage,assertExtensionDeactivated,assertExtensionManifestCompatible,assertExtensionManifestMatchesBlueprint,assertExtensionPreflight,assertPackageManifest,assertProjectProfile,assertRegisteredCommandContract,assertRegisteredCommandOverride,assertRegisteredExporter,assertRegisteredFlags,assertRegisteredHook,assertRegisteredImporter,assertRegisteredItemField,assertRegisteredItemType,assertRegisteredMigration,assertRegisteredParserOverride,assertRegisteredPreflightOverride,assertRegisteredProfile,assertRegisteredRendererOverride,assertRegisteredSearchProvider,assertRegisteredServiceOverride,assertRegisteredVectorStoreAdapter,createExtensionTestHarness,deactivateExtensionForTest,describeExtensionActivation,describeExtensionBlueprint,lintExtensionBlueprint,renderExtensionSurfaceMarkdown,runRegisteredCommandForTest,runRegisteredCommandOverrideForTest,runRegisteredExporterForTest,runRegisteredHookForTest,runRegisteredImporterForTest,runRegisteredMigrationForTest,runRegisteredMutationGuardForTest,runRegisteredParserOverrideForTest,runRegisteredPreflightOverrideForTest,runRegisteredRendererOverrideForTest,runRegisteredSearchProviderForTest,runRegisteredServiceOverrideForTest,runRegisteredVectorStoreAdapterForTest};
1391
5
  //# sourceMappingURL=testing.js.map
1392
- //# debugId=a09f5e0d-fccc-5a22-a6f3-0a37cbeea3b0