@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,1058 +1,6 @@
1
- /**
2
- * @module sdk/extension/install-sources
3
- *
4
- * Implements extension package-management support for Install Sources.
5
- */
6
-
7
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="05f56edb-c08d-570c-b8b5-641fc694331e")}catch(e){}}();
8
- import { execFile } from "node:child_process";
9
- import fs from "node:fs/promises";
10
- import os from "node:os";
11
- import path from "node:path";
12
- import { fileURLToPath } from "node:url";
13
- import { promisify } from "node:util";
14
- import npa from "npm-package-arg";
15
- import { extract as extractTar, list as listTar } from "tar";
16
- import { collectPackageExtensionDirectories } from "../../core/packages/manifest.js";
17
- import { resolvePmPackageRootFromModule } from "../../core/packages/root.js";
18
- import { pathExists } from "../../core/fs/fs-utils.js";
19
- import { isPathWithinDirectory } from "../../core/fs/path-utils.js";
20
- import { EXIT_CODE } from "../../core/shared/constants.js";
21
- import { PmCliError, } from "../../core/shared/errors.js";
22
- import { listBundledPackageAliases } from "./bundled-catalog.js";
23
- const execFileAsync = promisify(execFile);
24
- const PM_CLI_PACKAGE_NAME = "@unbrained/pm-cli";
25
- const LOCAL_PACKAGE_ARCHIVE_LIMITS = {
26
- maxArchiveBytes: 64 * 1024 * 1024,
27
- maxEntries: 4096,
28
- maxExpandedBytes: 256 * 1024 * 1024,
29
- maxEntryBytes: 64 * 1024 * 1024,
30
- };
31
- let bundledPackageAliasesCache;
32
- /** Resolve an already-installed npm package without executing package code. */
33
- export async function findInstalledNpmPackageCandidate(packageName, cwd = process.cwd()) {
34
- const normalized = packageName.trim();
35
- if (!/^(@[^/\\\s]+\/[^/\\\s]+|[^@/\\\s][^/\\\s]*)$/u.test(normalized)) {
36
- return null;
37
- }
38
- let current = path.resolve(cwd);
39
- while (true) {
40
- const directory = path.join(current, "node_modules", ...normalized.split("/"));
41
- const manifestPath = path.join(directory, "package.json");
42
- if (await pathExists(manifestPath)) {
43
- try {
44
- const manifest = JSON.parse(await fs.readFile(manifestPath, "utf8"));
45
- if (manifest.name === normalized) {
46
- return {
47
- package: normalized,
48
- ...(typeof manifest.version === "string"
49
- ? { version: manifest.version }
50
- : {}),
51
- directory,
52
- };
53
- }
54
- }
55
- catch {
56
- return null;
57
- }
58
- }
59
- const parent = path.dirname(current);
60
- if (parent === current)
61
- return null;
62
- current = parent;
63
- }
64
- }
65
- function parseGithubPathSpec(pathSpec, input, refOverride) {
66
- const segments = pathSpec
67
- .split("/")
68
- .map((segment) => segment.trim())
69
- .filter((segment) => segment.length > 0);
70
- if (segments.length < 2) {
71
- return null;
72
- }
73
- const owner = segments[0];
74
- const repo = segments[1].replace(/\.git$/i, "");
75
- if (owner.length === 0 || repo.length === 0) {
76
- return null;
77
- }
78
- const tail = segments.slice(2);
79
- let ref;
80
- let subpath;
81
- if (tail[0] === "tree" && tail.length >= 2) {
82
- ref = tail[1];
83
- subpath = tail.slice(2).join("/");
84
- }
85
- else if (tail.length > 0) {
86
- subpath = tail.join("/");
87
- }
88
- if (typeof refOverride === "string" && refOverride.trim().length > 0) {
89
- ref = refOverride.trim();
90
- }
91
- return {
92
- kind: "github",
93
- input,
94
- owner,
95
- repo,
96
- repository: `https://github.com/${owner}/${repo}.git`,
97
- ref,
98
- subpath: subpath && subpath.length > 0 ? subpath : undefined,
99
- };
100
- }
101
- function parseNpmInstallSource(normalizedInput, forceGithub, refOverride) {
102
- const spec = normalizedInput.slice("npm:".length).trim();
103
- if (spec.length === 0) {
104
- throw new PmCliError('npm package source must include a package spec after "npm:".', EXIT_CODE.USAGE);
105
- }
106
- if (forceGithub) {
107
- throw new PmCliError('Options "--gh/--github" cannot be combined with npm: package sources.', EXIT_CODE.USAGE);
108
- }
109
- if (refOverride) {
110
- throw new PmCliError('Option "--ref" cannot be combined with npm: package sources.', EXIT_CODE.USAGE);
111
- }
112
- return {
113
- kind: "npm",
114
- input: normalizedInput,
115
- spec,
116
- };
117
- }
118
- /** Implements parse extension install source for the public runtime surface of this module. */
119
- export function parseExtensionInstallSource(input, options = {}) {
120
- const normalizedInput = input.trim();
121
- if (normalizedInput.length === 0) {
122
- throw new PmCliError("Extension source is required for --install.", EXIT_CODE.USAGE);
123
- }
124
- const refOverride = typeof options.ref === "string" && options.ref.trim().length > 0
125
- ? options.ref.trim()
126
- : undefined;
127
- if (normalizedInput.startsWith("npm:")) {
128
- return parseNpmInstallSource(normalizedInput, options.forceGithub === true, refOverride);
129
- }
130
- const maybeGithubByUrl = (() => {
131
- try {
132
- const parsed = new URL(normalizedInput);
133
- if (parsed.hostname !== "github.com") {
134
- return null;
135
- }
136
- const pathSpec = parsed.pathname.replace(/^\/+/, "");
137
- return parseGithubPathSpec(pathSpec, normalizedInput, refOverride);
138
- }
139
- catch {
140
- return null;
141
- }
142
- })();
143
- if (maybeGithubByUrl) {
144
- return maybeGithubByUrl;
145
- }
146
- const strippedDomainInput = normalizedInput.startsWith("github.com/")
147
- ? normalizedInput.slice("github.com/".length)
148
- : null;
149
- if (strippedDomainInput) {
150
- const parsed = parseGithubPathSpec(strippedDomainInput, normalizedInput, refOverride);
151
- if (!parsed) {
152
- throw new PmCliError(`Invalid GitHub source "${normalizedInput}".`, EXIT_CODE.USAGE);
153
- }
154
- return parsed;
155
- }
156
- if (options.forceGithub) {
157
- const parsed = parseGithubPathSpec(normalizedInput, normalizedInput, refOverride);
158
- if (!parsed) {
159
- throw new PmCliError(`Invalid GitHub shorthand "${normalizedInput}".`, EXIT_CODE.USAGE);
160
- }
161
- return parsed;
162
- }
163
- if (/^https?:\/\//i.test(normalizedInput)) {
164
- throw new PmCliError(`Unsupported extension source URL "${normalizedInput}". Supported remote source host: github.com.`, EXIT_CODE.USAGE);
165
- }
166
- return {
167
- kind: "local",
168
- input: normalizedInput,
169
- absolute_path: path.resolve(process.cwd(), normalizedInput),
170
- };
171
- }
172
- /** Implements run git command for the public runtime surface of this module. */
173
- export async function runGitCommand(args, execRunner = execFileAsync, timeoutMs) {
174
- try {
175
- const result = await execRunner("git", args, {
176
- encoding: "utf8",
177
- timeout: timeoutMs,
178
- });
179
- return (result.stdout ?? "").trim();
180
- }
181
- catch (error) {
182
- /* c8 ignore start -- stderr-vs-error-message precedence is validated in integration command-runner paths */
183
- const stderr = typeof error === "object" && error !== null && "stderr" in error
184
- ? String(error.stderr)
185
- : "";
186
- const message = stderr.trim().length > 0
187
- ? stderr.trim()
188
- : error instanceof Error
189
- ? error.message
190
- : String(error);
191
- /* c8 ignore stop */
192
- throw new PmCliError(`Git command failed: git ${args.join(" ")}\n${message}`, EXIT_CODE.GENERIC_FAILURE);
193
- }
194
- }
195
- /** Implements resolve npm command name for the public runtime surface of this module. */
196
- export function resolveNpmCommandName(platform = process.platform) {
197
- return platform === "win32" ? "npm.cmd" : "npm";
198
- }
199
- /** Implements should run npm command in shell for the public runtime surface of this module. */
200
- export function shouldRunNpmCommandInShell(platform = process.platform) {
201
- return platform === "win32";
202
- }
203
- async function runNpmCommand(args, cwd, execRunner = execFileAsync, platform = process.platform, environment = process.env) {
204
- const npmCommand = resolveNpmCommandName(platform);
205
- const env = Object.fromEntries(Object.entries(environment).filter(([key]) => key.toLowerCase() !== "npm_config_allow_scripts"));
206
- env.NPM_CONFIG_ALLOW_SCRIPTS = "";
207
- try {
208
- const result = await execRunner(npmCommand, args, {
209
- cwd,
210
- encoding: "utf8",
211
- env,
212
- shell: shouldRunNpmCommandInShell(platform),
213
- });
214
- return (result.stdout ?? "").trim();
215
- }
216
- catch (error) {
217
- const stderr = typeof error === "object" && error !== null && "stderr" in error
218
- ? String(error.stderr)
219
- : "";
220
- const message = stderr.trim().length > 0
221
- ? stderr.trim()
222
- : error instanceof Error
223
- ? error.message
224
- : String(error);
225
- throw new PmCliError(`npm command failed: ${npmCommand} ${args.join(" ")}\n${message}`, EXIT_CODE.GENERIC_FAILURE);
226
- }
227
- }
228
- function npmPackageNameFromSpec(spec) {
229
- const trimmed = spec.trim();
230
- const withoutAlias = trimmed.includes("@file:")
231
- ? trimmed.slice(0, trimmed.lastIndexOf("@file:"))
232
- : trimmed;
233
- if (withoutAlias.startsWith("@")) {
234
- const scoped = withoutAlias.match(/^(@[^/@\s]+\/[^/@\s]+)/);
235
- return scoped?.[1] ?? withoutAlias;
236
- }
237
- const unscoped = withoutAlias.match(/^([^/@\s]+)/);
238
- return unscoped?.[1] ?? withoutAlias;
239
- }
240
- /** Return whether an npm spec is a complete local-file alias, including unchanged UNC targets. */
241
- function isNpmLocalFileAliasSpec(spec) {
242
- const marker = "@file:";
243
- const markerIndex = spec.lastIndexOf(marker);
244
- return (markerIndex > 0 &&
245
- spec.slice(0, markerIndex).trim().length > 0 &&
246
- spec.slice(markerIndex + marker.length).trim().length > 0);
247
- }
248
- /** Implements check whether npm not found error for the public runtime surface of this module. */
249
- export function isNpmNotFoundError(error) {
250
- const message = error instanceof Error ? error.message : String(error);
251
- const normalized = message.toLowerCase();
252
- return (normalized.includes("npm err! code e404") ||
253
- normalized.includes("404 not found") ||
254
- normalized.includes("is not in this registry"));
255
- }
256
- /** Implements check whether npm pack not found error for the public runtime surface of this module. */
257
- export function isNpmPackNotFoundError(error) {
258
- const message = error instanceof Error ? error.message : String(error);
259
- const normalized = message.toLowerCase();
260
- return isNpmNotFoundError(error) || normalized.includes("not found");
261
- }
262
- function isFirstPartyPmPackageName(packageName) {
263
- const normalized = packageName.trim().toLowerCase();
264
- return (normalized.startsWith("@unbrained/pm-") || normalized.startsWith("pm-"));
265
- }
266
- /** Implements build npm not found recovery for the public runtime surface of this module. */
267
- export function buildNpmNotFoundRecovery(spec) {
268
- const packageName = npmPackageNameFromSpec(spec);
269
- const isFirstPartyPackage = isFirstPartyPmPackageName(packageName);
270
- const repoName = packageName.replace(/^.*\//, "");
271
- const githubSource = isFirstPartyPackage
272
- ? `github.com/unbraind/${repoName}`
273
- : undefined;
274
- const nextBestCommand = githubSource
275
- ? `pm install --project ${githubSource}`
276
- : undefined;
277
- return {
278
- message: isFirstPartyPackage
279
- ? `npm package "${spec}" was not found in the registry. If this is an unpublished first-party pm package, install its GitHub repository instead.`
280
- : `npm package "${spec}" was not found in the registry.`,
281
- context: {
282
- code: "npm_package_not_found",
283
- required: "Use an install source that exists, or publish the npm package before installing it with npm:<name>.",
284
- why: "Classifying npm 404s avoids repeated registry retries and gives agents a deterministic fallback path.",
285
- examples: nextBestCommand
286
- ? [nextBestCommand, `pm package catalog --project --json`]
287
- : [`npm view ${packageName}`, `pm package catalog --project --json`],
288
- nextSteps: nextBestCommand
289
- ? [
290
- `Try ${nextBestCommand} if the repository exists.`,
291
- "Use pm package catalog --project --json to inspect bundled package aliases before installing.",
292
- ]
293
- : [
294
- `Verify ${packageName} exists in the npm registry and that you have access to it.`,
295
- "Use pm package catalog --project --json to inspect bundled package aliases before installing.",
296
- ],
297
- recovery: {
298
- attempted_command: `pm install --project npm:${spec}`,
299
- normalized_args: ["install", "--project", `npm:${spec}`],
300
- ...(githubSource && nextBestCommand
301
- ? {
302
- fallback_candidates: [
303
- {
304
- source: githubSource,
305
- command: nextBestCommand,
306
- reason: "canonical first-party GitHub repository fallback for unpublished pm packages",
307
- },
308
- ],
309
- next_best_command: nextBestCommand,
310
- }
311
- : {}),
312
- },
313
- },
314
- };
315
- }
316
- /** Implements wrap npm pack resolution error for the public runtime surface of this module. */
317
- export function wrapNpmPackResolutionError(spec, error) {
318
- if (!isNpmPackNotFoundError(error)) {
319
- return null;
320
- }
321
- const recovery = buildNpmNotFoundRecovery(spec);
322
- return new PmCliError(recovery.message, EXIT_CODE.NOT_FOUND, recovery.context);
323
- }
324
- async function resolveLocalNpmPackagePath(spec) {
325
- if (path.isAbsolute(spec) || spec.startsWith(".") || spec.startsWith("..")) {
326
- const absolutePath = path.resolve(process.cwd(), spec);
327
- return (await pathExists(absolutePath)) ? absolutePath : null;
328
- }
329
- try {
330
- const parsed = new URL(spec);
331
- if (parsed.protocol === "file:") {
332
- const absolutePath = fileURLToPath(parsed);
333
- return (await pathExists(absolutePath)) ? absolutePath : null;
334
- }
335
- }
336
- catch {
337
- // Registry package specs are not URLs.
338
- }
339
- if (!/^[a-z][a-z0-9+.-]*:/i.test(spec)) {
340
- const absolutePath = path.resolve(process.cwd(), spec);
341
- if (await pathExists(absolutePath)) {
342
- return absolutePath;
343
- }
344
- }
345
- return null;
346
- }
347
- async function resolveNpmPackSpec(spec) {
348
- const localPath = await resolveLocalNpmPackagePath(spec);
349
- if (localPath) {
350
- // Hand npm pack a NATIVE filesystem path, never a percent-encoded file URL:
351
- // npm opens the spec literally, so spaces (`%20`) or a Windows 8.3 `~` short
352
- // name (`%7E`) escaped by pathToFileURL make pack fail ENOENT on every
353
- // platform (GH-363). resolveLocalNpmPackagePath already decoded the path.
354
- return localPath;
355
- }
356
- const localFileAlias = normalizeNpmLocalFileAliasSpec(spec);
357
- if (localFileAlias !== spec) {
358
- return localFileAlias;
359
- }
360
- if (/^[a-z][a-z0-9+.-]*:/i.test(spec)) {
361
- return spec;
362
- }
363
- return spec;
364
- }
365
- /** Implements normalize npm local file alias spec for the public runtime surface of this module. */
366
- export function normalizeNpmLocalFileAliasSpec(spec, cwd = process.cwd()) {
367
- const marker = "@file:";
368
- const markerIndex = spec.lastIndexOf(marker);
369
- if (!isNpmLocalFileAliasSpec(spec)) {
370
- return spec;
371
- }
372
- const packageName = spec.slice(0, markerIndex);
373
- const target = spec.slice(markerIndex + marker.length);
374
- // `file://host/share` (exactly two leading slashes) is a UNC / network spec,
375
- // not a local path — leave it for npm to resolve.
376
- if (target.startsWith("//") && !target.startsWith("///")) {
377
- return spec;
378
- }
379
- // A bare relative target resolves against cwd.
380
- if (!target.startsWith("/")) {
381
- return `${packageName}@${path.resolve(cwd, target)}`;
382
- }
383
- // Resolve an absolute `file:` URL target to a NATIVE, percent-DECODED path
384
- // (never an encoded file URL): npm opens the alias target literally, so an
385
- // escaped path — spaces (`%20`) or a Windows 8.3 `~` short name escaped to
386
- // `%7E` — fails ENOENT on every platform (GH-363). Decode via URL +
387
- // decodeURIComponent rather than fileURLToPath, which throws
388
- // ERR_INVALID_FILE_URL_PATH for a driveless absolute path supplied on Windows;
389
- // strip the leading slash before a Windows drive letter (`/C:/x` -> `C:/x`).
390
- let decodedPath;
391
- try {
392
- decodedPath = decodeURIComponent(new URL(`file:${target}`).pathname);
393
- }
394
- catch {
395
- // Malformed percent-encoding (e.g. `%ZZ`) makes decodeURIComponent throw a
396
- // URIError; leave the spec untouched so npm surfaces a clear error instead
397
- // of crashing the CLI on an uncaught exception.
398
- return spec;
399
- }
400
- const nativePath = /^\/[A-Za-z]:/.test(decodedPath)
401
- ? decodedPath.slice(1)
402
- : decodedPath;
403
- return `${packageName}@${nativePath}`;
404
- }
405
- /**
406
- * Parse npm pack output and bind the reported artifact to its isolated target.
407
- *
408
- * Supports current JSON metadata and the legacy filename-only form while
409
- * refusing absolute or traversing results before the filesystem is consulted.
410
- */
411
- function resolvePackedTarball(packDirectory, filename) {
412
- const tarball = path.resolve(packDirectory, filename);
413
- const relativeTarball = path.relative(packDirectory, tarball);
414
- if (relativeTarball.length === 0 ||
415
- relativeTarball === ".." ||
416
- relativeTarball.startsWith(`..${path.sep}`) ||
417
- path.isAbsolute(relativeTarball)) {
418
- throw new PmCliError("npm pack reported a package archive outside its isolated destination.", EXIT_CODE.GENERIC_FAILURE, {
419
- code: "npm_package_archive_unsafe",
420
- required: "Retry with a trusted npm client that writes its archive inside the requested pack destination.",
421
- why: "pm will not read a package-manager artifact outside the isolated directory created for this install.",
422
- });
423
- }
424
- return tarball;
425
- }
426
- function decodePackedNpmCandidate(value, key) {
427
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
428
- return undefined;
429
- }
430
- const record = value;
431
- if (typeof record.filename !== "string" ||
432
- record.filename.trim().length === 0) {
433
- return undefined;
434
- }
435
- return {
436
- ...(key === undefined ? {} : { key }),
437
- filename: record.filename,
438
- ...(typeof record.name === "string" ? { name: record.name } : {}),
439
- ...(typeof record.version === "string" ? { version: record.version } : {}),
440
- };
441
- }
442
- function collectPackedNpmCandidates(parsed) {
443
- const entries = Array.isArray(parsed)
444
- ? parsed.map((value) => ({ value }))
445
- : typeof parsed === "object" && parsed !== null
446
- ? Object.entries(parsed).map(([key, value]) => ({ key, value }))
447
- : [];
448
- return entries.flatMap(({ key, value }) => {
449
- const candidate = decodePackedNpmCandidate(value, key);
450
- return candidate ? [candidate] : [];
451
- });
452
- }
453
- function selectPackedNpmCandidate(candidates, expectedPackage) {
454
- const normalizedExpected = expectedPackage?.trim().toLowerCase();
455
- const matchingCandidates = normalizedExpected
456
- ? candidates.filter((candidate) => {
457
- const normalizedName = candidate.name?.trim().toLowerCase();
458
- return normalizedName !== undefined
459
- ? normalizedName === normalizedExpected
460
- : candidate.key?.trim().toLowerCase() === normalizedExpected;
461
- })
462
- : [];
463
- if (matchingCandidates.length === 1)
464
- return matchingCandidates[0];
465
- if (candidates.length !== 1)
466
- return undefined;
467
- const soleCandidate = candidates[0];
468
- const soleIdentity = soleCandidate.name ?? soleCandidate.key;
469
- return normalizedExpected &&
470
- soleIdentity !== undefined &&
471
- soleIdentity.trim().toLowerCase() !== normalizedExpected
472
- ? undefined
473
- : soleCandidate;
474
- }
475
- function parsePackedNpmPackage(stdout, packDirectory, expectedPackage) {
476
- let parsed;
477
- try {
478
- parsed = JSON.parse(stdout);
479
- }
480
- catch {
481
- const filename = stdout
482
- .split(/\r?\n/)
483
- .map((line) => line.trim())
484
- .filter((line) => line.length > 0)
485
- .at(-1);
486
- if (!filename) {
487
- throw new PmCliError("npm pack did not report a tarball filename.", EXIT_CODE.GENERIC_FAILURE);
488
- }
489
- return { tarball: resolvePackedTarball(packDirectory, filename) };
490
- }
491
- const candidates = collectPackedNpmCandidates(parsed);
492
- const selected = selectPackedNpmCandidate(candidates, expectedPackage);
493
- if (!selected) {
494
- throw new PmCliError("npm pack --json returned an unsupported or ambiguous package receipt.", EXIT_CODE.GENERIC_FAILURE, {
495
- code: "npm_pack_json_shape_unsupported",
496
- required: "Use an npm client that returns an array of package receipts or an object keyed by package name, with exactly one requested package entry containing filename.",
497
- why: `Well-formed JSON contained ${candidates.length} usable package receipt(s), but pm could not select ${expectedPackage ?? "one package"} deterministically.`,
498
- });
499
- }
500
- return {
501
- tarball: resolvePackedTarball(packDirectory, selected.filename),
502
- package: selected.name ?? selected.key,
503
- version: selected.version,
504
- };
505
- }
506
- async function resolveNpmSourceDirectory(source) {
507
- return resolveNpmSourceDirectoryWithRunner(source, runNpmCommand);
508
- }
509
- /**
510
- * Resolve an npm source with an injectable, argv-safe package-manager runner.
511
- *
512
- * Local package directories remain in place, while local and registry archives
513
- * share the same bounded validation, dependency installation, and cleanup
514
- * contract. Registry artifacts must also exist inside the requested pack root.
515
- */
516
- async function resolveNpmSourceDirectoryWithRunner(source, npmRunner) {
517
- const localPackageRoot = await resolveLocalNpmPackagePath(source.spec);
518
- if (localPackageRoot) {
519
- const localStats = await fs.stat(localPackageRoot);
520
- if (localStats.isFile() && isLocalPackageArchive(localPackageRoot)) {
521
- return extractLocalPackageArchive(localPackageRoot);
522
- }
523
- const packageJsonPath = path.join(localPackageRoot, "package.json");
524
- const packageJson = (await pathExists(packageJsonPath))
525
- ? JSON.parse(await fs.readFile(packageJsonPath, "utf8"))
526
- : {};
527
- return {
528
- directory: await resolvePackageExtensionDirectory(localPackageRoot, source.input),
529
- package: typeof packageJson.name === "string" ? packageJson.name : undefined,
530
- version: typeof packageJson.version === "string"
531
- ? packageJson.version
532
- : undefined,
533
- cleanup: async () => { },
534
- };
535
- }
536
- const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "pm-npm-package-source-"));
537
- const packDirectory = path.join(tempRoot, "pack");
538
- await fs.mkdir(packDirectory, { recursive: true });
539
- try {
540
- const packSpec = await resolveNpmPackSpec(source.spec);
541
- const packStdout = await npmRunner([
542
- "pack",
543
- packSpec,
544
- "--json",
545
- "--pack-destination",
546
- packDirectory,
547
- ]);
548
- const packed = parsePackedNpmPackage(packStdout, packDirectory, isNpmLocalFileAliasSpec(source.spec)
549
- ? undefined
550
- : npmPackageNameFromSpec(source.spec));
551
- if (!(await pathExists(packed.tarball))) {
552
- throw new PmCliError("npm pack did not create its reported package archive.", EXIT_CODE.GENERIC_FAILURE, {
553
- code: "npm_package_archive_missing",
554
- required: "Retry the npm package install with a healthy registry and writable temporary directory.",
555
- why: "The package manager reported a tarball filename that was absent before validation, so pm cannot safely extract or install it.",
556
- });
557
- }
558
- const extracted = await extractLocalPackageArchive(packed.tarball);
559
- return {
560
- directory: extracted.directory,
561
- package: packed.package ?? extracted.package,
562
- version: packed.version ?? extracted.version,
563
- cleanup: async () => {
564
- try {
565
- await extracted.cleanup();
566
- }
567
- finally {
568
- await fs.rm(tempRoot, { recursive: true, force: true });
569
- }
570
- },
571
- };
572
- }
573
- catch (error) {
574
- await fs.rm(tempRoot, { recursive: true, force: true });
575
- const wrappedError = wrapNpmPackResolutionError(source.spec, error);
576
- if (wrappedError) {
577
- throw wrappedError;
578
- }
579
- throw error;
580
- }
581
- }
582
- /** Return whether a filesystem path names one supported npm package archive. */
583
- function isLocalPackageArchive(candidate) {
584
- const normalized = candidate.toLowerCase();
585
- return normalized.endsWith(".tgz") || normalized.endsWith(".tar.gz");
586
- }
587
- function failLocalPackageArchive(message) {
588
- throw new PmCliError(message, EXIT_CODE.USAGE, {
589
- code: "local_package_archive_unsafe",
590
- required: "Use a bounded npm .tgz or .tar.gz archive with one package/ root and no links or escaping paths.",
591
- why: "Package archives are untrusted input and must be validated before any entry reaches the filesystem.",
592
- });
593
- }
594
- function validateLocalPackageArchiveEntry(entry, limits, state) {
595
- if (entry.meta)
596
- return;
597
- state.entries += 1;
598
- if (state.entries > limits.maxEntries) {
599
- failLocalPackageArchive(`Local package archive exceeds the ${limits.maxEntries} entry limit.`);
600
- }
601
- const archivePath = entry.path;
602
- const segments = archivePath.split("/");
603
- if (archivePath.includes("\\") ||
604
- archivePath.startsWith("/") ||
605
- /^[A-Za-z]:/u.test(archivePath) ||
606
- segments.some((segment) => segment === "..")) {
607
- failLocalPackageArchive(`Local package archive contains an escaping path: "${archivePath}".`);
608
- }
609
- if (segments[0] !== "package") {
610
- failLocalPackageArchive(`Local package archive entry "${archivePath}" is outside the required package/ root.`);
611
- }
612
- if (entry.type === "SymbolicLink" || entry.type === "Link") {
613
- failLocalPackageArchive(`Local package archive link "${archivePath}" is not supported.`);
614
- }
615
- if (entry.type !== "File" &&
616
- entry.type !== "OldFile" &&
617
- entry.type !== "Directory") {
618
- failLocalPackageArchive(`Local package archive entry "${archivePath}" uses unsupported type "${entry.type}".`);
619
- }
620
- if (entry.size > limits.maxEntryBytes) {
621
- failLocalPackageArchive(`Local package archive entry "${archivePath}" exceeds the ${limits.maxEntryBytes} byte entry limit.`);
622
- }
623
- state.expandedBytes += entry.size;
624
- if (state.expandedBytes > limits.maxExpandedBytes) {
625
- failLocalPackageArchive(`Local package archive exceeds the ${limits.maxExpandedBytes} expanded byte limit.`);
626
- }
627
- if (archivePath === "package/package.json") {
628
- state.packageJsonEntries += 1;
629
- }
630
- }
631
- /** Validate and extract one local npm package archive into an isolated temporary root. */
632
- async function extractLocalPackageArchive(archivePath, limits = LOCAL_PACKAGE_ARCHIVE_LIMITS) {
633
- const archiveStats = await fs.stat(archivePath);
634
- if (archiveStats.size > limits.maxArchiveBytes) {
635
- failLocalPackageArchive(`Local package archive exceeds the ${limits.maxArchiveBytes} archive byte limit.`);
636
- }
637
- const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "pm-local-package-archive-"));
638
- const extractDirectory = path.join(tempRoot, "extract");
639
- await fs.mkdir(extractDirectory, { recursive: true });
640
- const state = { entries: 0, expandedBytes: 0, packageJsonEntries: 0 };
641
- let validationError;
642
- try {
643
- await listTar({
644
- file: archivePath,
645
- strict: true,
646
- maxDecompressionRatio: 100,
647
- onReadEntry: (entry) => {
648
- if (validationError !== undefined)
649
- return;
650
- try {
651
- validateLocalPackageArchiveEntry(entry, limits, state);
652
- }
653
- catch (error) {
654
- validationError = error;
655
- }
656
- },
657
- });
658
- if (validationError !== undefined)
659
- throw validationError;
660
- if (state.packageJsonEntries !== 1) {
661
- failLocalPackageArchive(`Local package archive must contain exactly one package/package.json entry; found ${state.packageJsonEntries}.`);
662
- }
663
- await extractTar({
664
- file: archivePath,
665
- cwd: extractDirectory,
666
- strict: true,
667
- preservePaths: false,
668
- preserveOwner: false,
669
- noMtime: true,
670
- unlink: true,
671
- maxDepth: 64,
672
- maxDecompressionRatio: 100,
673
- });
674
- const packageRoot = path.join(extractDirectory, "package");
675
- const packageJsonPath = path.join(packageRoot, "package.json");
676
- const packageJson = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
677
- await installNpmPackageRuntimeDependencies(packageRoot);
678
- return {
679
- directory: await resolvePackageExtensionDirectory(packageRoot, archivePath),
680
- package: typeof packageJson.name === "string" ? packageJson.name : undefined,
681
- version: typeof packageJson.version === "string"
682
- ? packageJson.version
683
- : undefined,
684
- cleanup: async () => {
685
- await fs.rm(tempRoot, { recursive: true, force: true });
686
- },
687
- };
688
- }
689
- catch (error) {
690
- await fs.rm(tempRoot, { recursive: true, force: true });
691
- throw error;
692
- }
693
- }
694
- async function installNpmPackageRuntimeDependencies(packageRoot, npmRunner = runNpmCommand) {
695
- const packageJsonPath = path.join(packageRoot, "package.json");
696
- if (!(await pathExists(packageJsonPath))) {
697
- return;
698
- }
699
- let parsed;
700
- try {
701
- parsed = JSON.parse(await fs.readFile(packageJsonPath, "utf8"));
702
- }
703
- catch {
704
- return;
705
- }
706
- if (typeof parsed !== "object" || parsed === null) {
707
- return;
708
- }
709
- const manifest = parsed;
710
- const dependencySpecs = runtimeDependencyInstallSpecs(manifest);
711
- const shouldLinkHostedPmCli = hasHostedPmCliDependency(manifest);
712
- if (dependencySpecs.length === 0 && !shouldLinkHostedPmCli) {
713
- return;
714
- }
715
- const runtimeOnlyManifest = { ...parsed };
716
- delete runtimeOnlyManifest.devDependencies;
717
- const installManifest = { ...runtimeOnlyManifest };
718
- removeHostedPmCliDependency(installManifest);
719
- await fs.writeFile(packageJsonPath, `${JSON.stringify(installManifest, null, 2)}\n`, "utf8");
720
- try {
721
- await Promise.all([
722
- fs.rm(path.join(packageRoot, "package-lock.json"), { force: true }),
723
- fs.rm(path.join(packageRoot, "npm-shrinkwrap.json"), { force: true }),
724
- ]);
725
- if (dependencySpecs.length > 0) {
726
- await npmRunner([
727
- "install",
728
- "--ignore-scripts",
729
- "--no-audit",
730
- "--fund=false",
731
- "--package-lock=false",
732
- "--no-save",
733
- "--omit=peer",
734
- "--",
735
- ], packageRoot);
736
- }
737
- if (shouldLinkHostedPmCli) {
738
- await linkHostedPmCliDependency(packageRoot);
739
- }
740
- }
741
- finally {
742
- await fs.writeFile(packageJsonPath, `${JSON.stringify(runtimeOnlyManifest, null, 2)}\n`, "utf8");
743
- }
744
- }
745
- function hasHostedPmCliDependency(manifest) {
746
- for (const dependencyMap of [
747
- manifest.dependencies,
748
- manifest.optionalDependencies,
749
- manifest.peerDependencies,
750
- ]) {
751
- if (typeof dependencyMap === "object" &&
752
- dependencyMap !== null &&
753
- PM_CLI_PACKAGE_NAME in dependencyMap) {
754
- return true;
755
- }
756
- }
757
- return false;
758
- }
759
- function removeHostedPmCliDependency(manifest) {
760
- for (const field of [
761
- "dependencies",
762
- "optionalDependencies",
763
- "peerDependencies",
764
- ]) {
765
- const dependencyMap = manifest[field];
766
- if (typeof dependencyMap !== "object" || dependencyMap === null) {
767
- continue;
768
- }
769
- const nextMap = { ...dependencyMap };
770
- delete nextMap[PM_CLI_PACKAGE_NAME];
771
- if (Object.keys(nextMap).length === 0) {
772
- delete manifest[field];
773
- }
774
- else {
775
- manifest[field] = nextMap;
776
- }
777
- }
778
- }
779
- async function linkHostedPmCliDependency(packageRoot) {
780
- const hostPackageRoot = resolvePmPackageRootFromModule(import.meta.url, [
781
- "../../..",
782
- ]);
783
- const [scope, packageName] = PM_CLI_PACKAGE_NAME.split("/");
784
- const scopedDirectory = path.join(packageRoot, "node_modules", scope);
785
- const linkPath = path.join(scopedDirectory, packageName);
786
- await fs.mkdir(scopedDirectory, { recursive: true });
787
- await fs.rm(linkPath, { recursive: true, force: true });
788
- await fs.symlink(hostPackageRoot, linkPath, resolveDirectorySymlinkType(process.platform));
789
- }
790
- function resolveDirectorySymlinkType(platform) {
791
- return platform === "win32" ? "junction" : "dir";
792
- }
793
- function validateRuntimeDependencySpec(name, version) {
794
- if (name.startsWith("-")) {
795
- throw new PmCliError(`Extension runtime dependency name "${name}" is unsafe because npm could interpret it as a command-line option.`, EXIT_CODE.USAGE, {
796
- code: "extension_dependency_name_unsafe",
797
- required: "Use a valid npm package name that does not begin with a dash.",
798
- why: "Extension manifests are untrusted input and dependency names must never become npm options.",
799
- });
800
- }
801
- const hasUnsafeControlOrShellCharacter = [...version].some((character) => {
802
- const codePoint = character.charCodeAt(0);
803
- return (codePoint <= 31 || codePoint === 127 || "&|;()`\"'".includes(character));
804
- });
805
- if (hasUnsafeControlOrShellCharacter) {
806
- throw new PmCliError(`Extension runtime dependency "${name}" has an unsafe version specifier.`, EXIT_CODE.USAGE, {
807
- code: "extension_dependency_version_unsafe",
808
- required: "Use an npm version, range, dist-tag, URL, or file specifier without shell metacharacters.",
809
- why: "npm.cmd requires a command shell on Windows, so untrusted shell metacharacters cannot be forwarded.",
810
- });
811
- }
812
- try {
813
- npa.resolve(name, version);
814
- }
815
- catch {
816
- throw new PmCliError(`Extension runtime dependency "${name}@${version}" is not a valid npm dependency specifier.`, EXIT_CODE.USAGE, {
817
- code: "extension_dependency_spec_invalid",
818
- required: "Use a valid npm package name and npm-supported version, range, dist-tag, URL, or file specifier.",
819
- why: "Only grammar-validated dependency specs may be written to the isolated runtime install manifest.",
820
- });
821
- }
822
- return `${name}@${version}`;
823
- }
824
- function runtimeDependencyInstallSpecs(manifest) {
825
- const specs = new Map();
826
- for (const dependencyMap of [
827
- manifest.dependencies,
828
- manifest.optionalDependencies,
829
- manifest.peerDependencies,
830
- ]) {
831
- if (typeof dependencyMap !== "object" || dependencyMap === null) {
832
- continue;
833
- }
834
- for (const [name, version] of Object.entries(dependencyMap)) {
835
- if (name === PM_CLI_PACKAGE_NAME ||
836
- typeof version !== "string" ||
837
- version.trim().length === 0 ||
838
- specs.has(name)) {
839
- continue;
840
- }
841
- const normalizedVersion = version.trim();
842
- specs.set(name, validateRuntimeDependencySpec(name, normalizedVersion));
843
- }
844
- }
845
- return [...specs.values()];
846
- }
847
- async function resolvePackageExtensionDirectory(packageRoot, sourceLabel) {
848
- const discovered = await collectPackageExtensionDirectories(packageRoot);
849
- if (discovered.length === 1) {
850
- return discovered[0];
851
- }
852
- if (discovered.length > 1) {
853
- const choices = discovered
854
- .map((entry) => path.relative(packageRoot, entry).replaceAll(path.sep, "/"))
855
- .sort((left, right) => left.localeCompare(right));
856
- throw new PmCliError(`Package source "${sourceLabel}" contains multiple extension manifests. Provide an explicit extension path. Candidates: ${choices.join(", ")}`, EXIT_CODE.USAGE);
857
- }
858
- throw new PmCliError(`Unable to locate a pm extension manifest in package source "${sourceLabel}". Package installs currently activate only extension resources, so add package.json pm.extensions or an extensions/ directory. Metadata-only resources like pm.docs/pm.examples are catalog metadata and do not activate commands.`, EXIT_CODE.USAGE);
859
- }
860
- async function resolveGithubSourceDirectory(cloneDirectory, source) {
861
- const candidatePaths = [];
862
- /* c8 ignore start -- subpath candidate expansion permutations are covered by source-resolution integration suites */
863
- if (source.subpath) {
864
- candidatePaths.push(source.subpath);
865
- candidatePaths.push(path.posix.join(".agents/pm/extensions", source.subpath));
866
- candidatePaths.push(path.posix.join(".custom/pm-extensions", source.subpath));
867
- candidatePaths.push(path.posix.join(".custom/pm-extension", source.subpath));
868
- }
869
- /* c8 ignore stop */
870
- for (const candidate of candidatePaths) {
871
- const absolute = path.resolve(cloneDirectory, candidate);
872
- if (!isPathWithinDirectory(cloneDirectory, absolute)) {
873
- // source.subpath is user-controlled; never resolve a manifest outside the
874
- // cloned repository (path-traversal guard).
875
- continue;
876
- }
877
- if (await pathExists(path.join(absolute, "manifest.json"))) {
878
- return { directory: absolute, resolved_subpath: candidate };
879
- }
880
- }
881
- if (await pathExists(path.join(cloneDirectory, "manifest.json"))) {
882
- return { directory: cloneDirectory, resolved_subpath: "." };
883
- }
884
- const discoveredDirectory = await resolvePackageExtensionDirectory(cloneDirectory, source.input);
885
- return {
886
- directory: discoveredDirectory,
887
- resolved_subpath: path
888
- .relative(cloneDirectory, discoveredDirectory)
889
- .replaceAll(path.sep, "/"),
890
- };
891
- }
892
- /** Bare package-ish names (no path separators, or a single-scope npm name) that miss local resolution are almost always intended as npm or bundled installs, so the not-found error must route agents to those sources instead of dead-ending. */
893
- function looksLikeBarePackageName(input) {
894
- const trimmed = input.trim();
895
- if (trimmed.length === 0 ||
896
- trimmed.startsWith(".") ||
897
- trimmed.startsWith("~")) {
898
- return false;
899
- }
900
- if (trimmed.startsWith("@")) {
901
- return trimmed.split("/").length === 2;
902
- }
903
- return !trimmed.includes("/") && !trimmed.includes("\\");
904
- }
905
- async function buildLocalSourceNotFoundError(source) {
906
- const baseMessage = `Local extension source does not exist: "${source.absolute_path}".`;
907
- const input = source.input.trim();
908
- if (!looksLikeBarePackageName(input)) {
909
- return new PmCliError(baseMessage, EXIT_CODE.NOT_FOUND);
910
- }
911
- let bundledAliases = [];
912
- try {
913
- const envPackageRoot = process.env.PM_CLI_PACKAGE_ROOT;
914
- const cacheKey = typeof envPackageRoot === "string" && envPackageRoot.trim().length > 0
915
- ? path.resolve(envPackageRoot.trim())
916
- : "";
917
- if (bundledPackageAliasesCache?.key !== cacheKey) {
918
- bundledPackageAliasesCache = {
919
- key: cacheKey,
920
- aliases: await listBundledPackageAliases(),
921
- };
922
- }
923
- bundledAliases = bundledPackageAliasesCache.aliases;
924
- }
925
- catch {
926
- // Alias discovery is best-effort; the npm: hint alone still unblocks agents.
927
- }
928
- const nextSteps = [
929
- `Retry with pm install npm:${input} if the package is published to npm.`,
930
- `Or inspect bundled packages with pm package catalog --project --json before installing by alias. Known aliases (blank means none found): ${bundledAliases.join(", ")}`,
931
- ];
932
- return new PmCliError(`${baseMessage} "${input}" did not match a local directory, bundled package alias, or bundled package name; if you meant an npm package, install it as "npm:${input}".`, EXIT_CODE.NOT_FOUND, {
933
- code: "local_source_not_found_bare_name",
934
- required: `Use "npm:${input}" for npm registry packages, a bundled catalog alias, or an existing local directory path.`,
935
- why: "Bare names resolve as local paths only after bundled aliases, so unmatched names need an explicit npm: source.",
936
- examples: [
937
- `pm install npm:${input}`,
938
- "pm package catalog --project --json",
939
- ],
940
- nextSteps,
941
- recovery: {
942
- attempted_command: `pm install ${input}`,
943
- normalized_args: ["install", input],
944
- next_best_command: `pm install npm:${input}`,
945
- },
946
- });
947
- }
948
- /** Implements resolve install source for the public runtime surface of this module. */
949
- export async function resolveInstallSource(source) {
950
- if (source.kind === "local") {
951
- let localStats;
952
- try {
953
- localStats = await fs.stat(source.absolute_path);
954
- }
955
- catch {
956
- throw await buildLocalSourceNotFoundError(source);
957
- }
958
- if (localStats.isFile() && isLocalPackageArchive(source.absolute_path)) {
959
- const resolved = await extractLocalPackageArchive(source.absolute_path);
960
- return {
961
- source,
962
- directory: resolved.directory,
963
- source_root: path.dirname(resolved.directory),
964
- resolved_subpath: path
965
- .relative(path.dirname(resolved.directory), resolved.directory)
966
- .replaceAll(path.sep, "/"),
967
- npm_package: resolved.package,
968
- npm_version: resolved.version,
969
- cleanup: resolved.cleanup,
970
- };
971
- }
972
- if (!localStats.isDirectory()) {
973
- throw new PmCliError(`Local extension source must be a directory or npm .tgz/.tar.gz archive: "${source.absolute_path}".`, EXIT_CODE.USAGE);
974
- }
975
- const directory = await resolvePackageExtensionDirectory(source.absolute_path, source.input);
976
- return {
977
- source,
978
- directory,
979
- source_root: source.absolute_path,
980
- };
981
- }
982
- if (source.kind === "npm") {
983
- const resolved = await resolveNpmSourceDirectory(source);
984
- return {
985
- source,
986
- directory: resolved.directory,
987
- source_root: path.dirname(resolved.directory),
988
- cleanup: resolved.cleanup,
989
- resolved_subpath: path
990
- .relative(path.dirname(resolved.directory), resolved.directory)
991
- .replaceAll(path.sep, "/"),
992
- npm_package: resolved.package,
993
- npm_version: resolved.version,
994
- };
995
- }
996
- const cloneDirectory = await fs.mkdtemp(path.join(os.tmpdir(), "pm-extension-source-"));
997
- const cloneArgs = ["clone", "--depth", "1"];
998
- if (source.ref) {
999
- cloneArgs.push("--branch", source.ref);
1000
- }
1001
- cloneArgs.push(source.repository, cloneDirectory);
1002
- try {
1003
- await runGitCommand(cloneArgs);
1004
- const commit = await runGitCommand([
1005
- "-C",
1006
- cloneDirectory,
1007
- "rev-parse",
1008
- "HEAD",
1009
- ]);
1010
- const resolved = await resolveGithubSourceDirectory(cloneDirectory, source);
1011
- return {
1012
- source,
1013
- directory: resolved.directory,
1014
- source_root: cloneDirectory,
1015
- resolved_subpath: resolved.resolved_subpath,
1016
- commit,
1017
- cleanup: async () => {
1018
- await fs.rm(cloneDirectory, { recursive: true, force: true });
1019
- },
1020
- };
1021
- }
1022
- catch (error) {
1023
- await fs.rm(cloneDirectory, { recursive: true, force: true });
1024
- throw error;
1025
- }
1026
- }
1027
- /** Implements are directories equivalent for the public runtime surface of this module. */
1028
- export async function areDirectoriesEquivalent(left, right) {
1029
- if (!(await pathExists(left)) || !(await pathExists(right))) {
1030
- return false;
1031
- }
1032
- const [leftRealPath, rightRealPath] = await Promise.all([
1033
- fs.realpath(left),
1034
- fs.realpath(right),
1035
- ]);
1036
- return leftRealPath === rightRealPath;
1037
- }
1038
- /** Public contract for test only install sources, shared by SDK and presentation-layer consumers. */
1039
- export const _testOnlyInstallSources = {
1040
- extractLocalPackageArchive,
1041
- validateLocalPackageArchiveEntry,
1042
- installNpmPackageRuntimeDependencies,
1043
- npmPackageNameFromSpec,
1044
- parsePackedNpmPackage,
1045
- resolveNpmSourceDirectoryWithRunner,
1046
- resolveNpmSourceDirectory,
1047
- resolveNpmPackSpec,
1048
- findInstalledNpmPackageCandidate,
1049
- resolvePackageExtensionDirectory,
1050
- runtimeDependencyInstallSpecs,
1051
- hasHostedPmCliDependency,
1052
- removeHostedPmCliDependency,
1053
- linkHostedPmCliDependency,
1054
- resolveDirectorySymlinkType,
1055
- runNpmCommand,
1056
- };
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]="68a37ea1-3571-59ab-b72c-0195efa84e3c")}catch(e2){}})();import{execFile}from"node:child_process";import fs from"node:fs/promises";import os from"node:os";import path from"node:path";import{fileURLToPath}from"node:url";import{promisify}from"node:util";import npa from"npm-package-arg";import{extract as extractTar,list as listTar}from"tar";import{collectPackageExtensionDirectories}from"../../core/packages/manifest.js";import{resolvePmPackageRootFromModule}from"../../core/packages/root.js";import{pathExists}from"../../core/fs/fs-utils.js";import{isPathWithinDirectory}from"../../core/fs/path-utils.js";import{EXIT_CODE}from"../../core/shared/constants.js";import{PmCliError}from"../../core/shared/errors.js";import{listBundledPackageAliases}from"./bundled-catalog.js";const execFileAsync=promisify(execFile);const PM_CLI_PACKAGE_NAME="@unbrained/pm-cli";const LOCAL_PACKAGE_ARCHIVE_LIMITS={maxArchiveBytes:64*1024*1024,maxEntries:4096,maxExpandedBytes:256*1024*1024,maxEntryBytes:64*1024*1024};let bundledPackageAliasesCache;async function findInstalledNpmPackageCandidate(packageName,cwd=process.cwd()){const normalized=packageName.trim();if(!/^(@[^/\\\s]+\/[^/\\\s]+|[^@/\\\s][^/\\\s]*)$/u.test(normalized)){return null}let current=path.resolve(cwd);while(true){const directory=path.join(current,"node_modules",...normalized.split("/"));const manifestPath=path.join(directory,"package.json");if(await pathExists(manifestPath)){try{const manifest=JSON.parse(await fs.readFile(manifestPath,"utf8"));if(manifest.name===normalized){return{package:normalized,...typeof manifest.version==="string"?{version:manifest.version}:{},directory}}}catch{return null}}const parent=path.dirname(current);if(parent===current)return null;current=parent}}function parseGithubPathSpec(pathSpec,input,refOverride){const segments=pathSpec.split("/").map(segment=>segment.trim()).filter(segment=>segment.length>0);if(segments.length<2){return null}const owner=segments[0];const repo=segments[1].replace(/\.git$/i,"");if(owner.length===0||repo.length===0){return null}const tail=segments.slice(2);let ref;let subpath;if(tail[0]==="tree"&&tail.length>=2){ref=tail[1];subpath=tail.slice(2).join("/")}else if(tail.length>0){subpath=tail.join("/")}if(typeof refOverride==="string"&&refOverride.trim().length>0){ref=refOverride.trim()}return{kind:"github",input,owner,repo,repository:`https://github.com/${owner}/${repo}.git`,ref,subpath:subpath&&subpath.length>0?subpath:void 0}}function parseNpmInstallSource(normalizedInput,forceGithub,refOverride){const spec=normalizedInput.slice("npm:".length).trim();if(spec.length===0){throw new PmCliError('npm package source must include a package spec after "npm:".',EXIT_CODE.USAGE)}if(forceGithub){throw new PmCliError('Options "--gh/--github" cannot be combined with npm: package sources.',EXIT_CODE.USAGE)}if(refOverride){throw new PmCliError('Option "--ref" cannot be combined with npm: package sources.',EXIT_CODE.USAGE)}return{kind:"npm",input:normalizedInput,spec}}function parseExtensionInstallSource(input,options={}){const normalizedInput=input.trim();if(normalizedInput.length===0){throw new PmCliError("Extension source is required for --install.",EXIT_CODE.USAGE)}const refOverride=typeof options.ref==="string"&&options.ref.trim().length>0?options.ref.trim():void 0;if(normalizedInput.startsWith("npm:")){return parseNpmInstallSource(normalizedInput,options.forceGithub===true,refOverride)}const maybeGithubByUrl=(()=>{try{const parsed=new URL(normalizedInput);if(parsed.hostname!=="github.com"){return null}const pathSpec=parsed.pathname.replace(/^\/+/,"");return parseGithubPathSpec(pathSpec,normalizedInput,refOverride)}catch{return null}})();if(maybeGithubByUrl){return maybeGithubByUrl}const strippedDomainInput=normalizedInput.startsWith("github.com/")?normalizedInput.slice("github.com/".length):null;if(strippedDomainInput){const parsed=parseGithubPathSpec(strippedDomainInput,normalizedInput,refOverride);if(!parsed){throw new PmCliError(`Invalid GitHub source "${normalizedInput}".`,EXIT_CODE.USAGE)}return parsed}if(options.forceGithub){const parsed=parseGithubPathSpec(normalizedInput,normalizedInput,refOverride);if(!parsed){throw new PmCliError(`Invalid GitHub shorthand "${normalizedInput}".`,EXIT_CODE.USAGE)}return parsed}if(/^https?:\/\//i.test(normalizedInput)){throw new PmCliError(`Unsupported extension source URL "${normalizedInput}". Supported remote source host: github.com.`,EXIT_CODE.USAGE)}return{kind:"local",input:normalizedInput,absolute_path:path.resolve(process.cwd(),normalizedInput)}}async function runGitCommand(args,execRunner=execFileAsync,timeoutMs){try{const result=await execRunner("git",args,{encoding:"utf8",timeout:timeoutMs});return(result.stdout??"").trim()}catch(error){const stderr=typeof error==="object"&&error!==null&&"stderr"in error?String(error.stderr):"";const message=stderr.trim().length>0?stderr.trim():error instanceof Error?error.message:String(error);throw new PmCliError(`Git command failed: git ${args.join(" ")}
2
+ ${message}`,EXIT_CODE.GENERIC_FAILURE)}}function resolveNpmCommandName(platform=process.platform){return platform==="win32"?"npm.cmd":"npm"}function shouldRunNpmCommandInShell(platform=process.platform){return platform==="win32"}async function runNpmCommand(args,cwd,execRunner=execFileAsync,platform=process.platform,environment=process.env){const npmCommand=resolveNpmCommandName(platform);const env=Object.fromEntries(Object.entries(environment).filter(([key])=>key.toLowerCase()!=="npm_config_allow_scripts"));env.NPM_CONFIG_ALLOW_SCRIPTS="";try{const result=await execRunner(npmCommand,args,{cwd,encoding:"utf8",env,shell:shouldRunNpmCommandInShell(platform)});return(result.stdout??"").trim()}catch(error){const stderr=typeof error==="object"&&error!==null&&"stderr"in error?String(error.stderr):"";const message=stderr.trim().length>0?stderr.trim():error instanceof Error?error.message:String(error);throw new PmCliError(`npm command failed: ${npmCommand} ${args.join(" ")}
3
+ ${message}`,EXIT_CODE.GENERIC_FAILURE)}}function npmPackageNameFromSpec(spec){const trimmed=spec.trim();const withoutAlias=trimmed.includes("@file:")?trimmed.slice(0,trimmed.lastIndexOf("@file:")):trimmed;if(withoutAlias.startsWith("@")){const scoped=withoutAlias.match(/^(@[^/@\s]+\/[^/@\s]+)/);return scoped?.[1]??withoutAlias}const unscoped=withoutAlias.match(/^([^/@\s]+)/);return unscoped?.[1]??withoutAlias}function isNpmLocalFileAliasSpec(spec){const marker="@file:";const markerIndex=spec.lastIndexOf(marker);return markerIndex>0&&spec.slice(0,markerIndex).trim().length>0&&spec.slice(markerIndex+marker.length).trim().length>0}function isNpmNotFoundError(error){const message=error instanceof Error?error.message:String(error);const normalized=message.toLowerCase();return normalized.includes("npm err! code e404")||normalized.includes("404 not found")||normalized.includes("is not in this registry")}function isNpmPackNotFoundError(error){const message=error instanceof Error?error.message:String(error);const normalized=message.toLowerCase();return isNpmNotFoundError(error)||normalized.includes("not found")}function isFirstPartyPmPackageName(packageName){const normalized=packageName.trim().toLowerCase();return normalized.startsWith("@unbrained/pm-")||normalized.startsWith("pm-")}function buildNpmNotFoundRecovery(spec){const packageName=npmPackageNameFromSpec(spec);const isFirstPartyPackage=isFirstPartyPmPackageName(packageName);const repoName=packageName.replace(/^.*\//,"");const githubSource=isFirstPartyPackage?`github.com/unbraind/${repoName}`:void 0;const nextBestCommand=githubSource?`pm install --project ${githubSource}`:void 0;return{message:isFirstPartyPackage?`npm package "${spec}" was not found in the registry. If this is an unpublished first-party pm package, install its GitHub repository instead.`:`npm package "${spec}" was not found in the registry.`,context:{code:"npm_package_not_found",required:"Use an install source that exists, or publish the npm package before installing it with npm:<name>.",why:"Classifying npm 404s avoids repeated registry retries and gives agents a deterministic fallback path.",examples:nextBestCommand?[nextBestCommand,`pm package catalog --project --json`]:[`npm view ${packageName}`,`pm package catalog --project --json`],nextSteps:nextBestCommand?[`Try ${nextBestCommand} if the repository exists.`,"Use pm package catalog --project --json to inspect bundled package aliases before installing."]:[`Verify ${packageName} exists in the npm registry and that you have access to it.`,"Use pm package catalog --project --json to inspect bundled package aliases before installing."],recovery:{attempted_command:`pm install --project npm:${spec}`,normalized_args:["install","--project",`npm:${spec}`],...githubSource&&nextBestCommand?{fallback_candidates:[{source:githubSource,command:nextBestCommand,reason:"canonical first-party GitHub repository fallback for unpublished pm packages"}],next_best_command:nextBestCommand}:{}}}}}function wrapNpmPackResolutionError(spec,error){if(!isNpmPackNotFoundError(error)){return null}const recovery=buildNpmNotFoundRecovery(spec);return new PmCliError(recovery.message,EXIT_CODE.NOT_FOUND,recovery.context)}async function resolveLocalNpmPackagePath(spec){if(path.isAbsolute(spec)||spec.startsWith(".")||spec.startsWith("..")){const absolutePath=path.resolve(process.cwd(),spec);return await pathExists(absolutePath)?absolutePath:null}try{const parsed=new URL(spec);if(parsed.protocol==="file:"){const absolutePath=fileURLToPath(parsed);return await pathExists(absolutePath)?absolutePath:null}}catch{}if(!/^[a-z][a-z0-9+.-]*:/i.test(spec)){const absolutePath=path.resolve(process.cwd(),spec);if(await pathExists(absolutePath)){return absolutePath}}return null}async function resolveNpmPackSpec(spec){const localPath=await resolveLocalNpmPackagePath(spec);if(localPath){return localPath}const localFileAlias=normalizeNpmLocalFileAliasSpec(spec);if(localFileAlias!==spec){return localFileAlias}if(/^[a-z][a-z0-9+.-]*:/i.test(spec)){return spec}return spec}function normalizeNpmLocalFileAliasSpec(spec,cwd=process.cwd()){const marker="@file:";const markerIndex=spec.lastIndexOf(marker);if(!isNpmLocalFileAliasSpec(spec)){return spec}const packageName=spec.slice(0,markerIndex);const target=spec.slice(markerIndex+marker.length);if(target.startsWith("//")&&!target.startsWith("///")){return spec}if(!target.startsWith("/")){return`${packageName}@${path.resolve(cwd,target)}`}let decodedPath;try{decodedPath=decodeURIComponent(new URL(`file:${target}`).pathname)}catch{return spec}const nativePath=/^\/[A-Za-z]:/.test(decodedPath)?decodedPath.slice(1):decodedPath;return`${packageName}@${nativePath}`}function resolvePackedTarball(packDirectory,filename){const tarball=path.resolve(packDirectory,filename);const relativeTarball=path.relative(packDirectory,tarball);if(relativeTarball.length===0||relativeTarball===".."||relativeTarball.startsWith(`..${path.sep}`)||path.isAbsolute(relativeTarball)){throw new PmCliError("npm pack reported a package archive outside its isolated destination.",EXIT_CODE.GENERIC_FAILURE,{code:"npm_package_archive_unsafe",required:"Retry with a trusted npm client that writes its archive inside the requested pack destination.",why:"pm will not read a package-manager artifact outside the isolated directory created for this install."})}return tarball}function decodePackedNpmCandidate(value,key){if(typeof value!=="object"||value===null||Array.isArray(value)){return void 0}const record=value;if(typeof record.filename!=="string"||record.filename.trim().length===0){return void 0}return{...key===void 0?{}:{key},filename:record.filename,...typeof record.name==="string"?{name:record.name}:{},...typeof record.version==="string"?{version:record.version}:{}}}function collectPackedNpmCandidates(parsed){const entries=Array.isArray(parsed)?parsed.map(value=>({value})):typeof parsed==="object"&&parsed!==null?Object.entries(parsed).map(([key,value])=>({key,value})):[];return entries.flatMap(({key,value})=>{const candidate=decodePackedNpmCandidate(value,key);return candidate?[candidate]:[]})}function selectPackedNpmCandidate(candidates,expectedPackage){const normalizedExpected=expectedPackage?.trim().toLowerCase();const matchingCandidates=normalizedExpected?candidates.filter(candidate=>{const normalizedName=candidate.name?.trim().toLowerCase();return normalizedName!==void 0?normalizedName===normalizedExpected:candidate.key?.trim().toLowerCase()===normalizedExpected}):[];if(matchingCandidates.length===1)return matchingCandidates[0];if(candidates.length!==1)return void 0;const soleCandidate=candidates[0];const soleIdentity=soleCandidate.name??soleCandidate.key;return normalizedExpected&&soleIdentity!==void 0&&soleIdentity.trim().toLowerCase()!==normalizedExpected?void 0:soleCandidate}function parsePackedNpmPackage(stdout,packDirectory,expectedPackage){let parsed;try{parsed=JSON.parse(stdout)}catch{const filename=stdout.split(/\r?\n/).map(line=>line.trim()).filter(line=>line.length>0).at(-1);if(!filename){throw new PmCliError("npm pack did not report a tarball filename.",EXIT_CODE.GENERIC_FAILURE)}return{tarball:resolvePackedTarball(packDirectory,filename)}}const candidates=collectPackedNpmCandidates(parsed);const selected=selectPackedNpmCandidate(candidates,expectedPackage);if(!selected){throw new PmCliError("npm pack --json returned an unsupported or ambiguous package receipt.",EXIT_CODE.GENERIC_FAILURE,{code:"npm_pack_json_shape_unsupported",required:"Use an npm client that returns an array of package receipts or an object keyed by package name, with exactly one requested package entry containing filename.",why:`Well-formed JSON contained ${candidates.length} usable package receipt(s), but pm could not select ${expectedPackage??"one package"} deterministically.`})}return{tarball:resolvePackedTarball(packDirectory,selected.filename),package:selected.name??selected.key,version:selected.version}}async function resolveNpmSourceDirectory(source){return resolveNpmSourceDirectoryWithRunner(source,runNpmCommand)}async function resolveNpmSourceDirectoryWithRunner(source,npmRunner){const localPackageRoot=await resolveLocalNpmPackagePath(source.spec);if(localPackageRoot){const localStats=await fs.stat(localPackageRoot);if(localStats.isFile()&&isLocalPackageArchive(localPackageRoot)){return extractLocalPackageArchive(localPackageRoot)}const packageJsonPath=path.join(localPackageRoot,"package.json");const packageJson=await pathExists(packageJsonPath)?JSON.parse(await fs.readFile(packageJsonPath,"utf8")):{};return{directory:await resolvePackageExtensionDirectory(localPackageRoot,source.input),package:typeof packageJson.name==="string"?packageJson.name:void 0,version:typeof packageJson.version==="string"?packageJson.version:void 0,cleanup:async()=>{}}}const tempRoot=await fs.mkdtemp(path.join(os.tmpdir(),"pm-npm-package-source-"));const packDirectory=path.join(tempRoot,"pack");await fs.mkdir(packDirectory,{recursive:true});try{const packSpec=await resolveNpmPackSpec(source.spec);const packStdout=await npmRunner(["pack",packSpec,"--json","--pack-destination",packDirectory]);const packed=parsePackedNpmPackage(packStdout,packDirectory,isNpmLocalFileAliasSpec(source.spec)?void 0:npmPackageNameFromSpec(source.spec));if(!await pathExists(packed.tarball)){throw new PmCliError("npm pack did not create its reported package archive.",EXIT_CODE.GENERIC_FAILURE,{code:"npm_package_archive_missing",required:"Retry the npm package install with a healthy registry and writable temporary directory.",why:"The package manager reported a tarball filename that was absent before validation, so pm cannot safely extract or install it."})}const extracted=await extractLocalPackageArchive(packed.tarball);return{directory:extracted.directory,package:packed.package??extracted.package,version:packed.version??extracted.version,cleanup:async()=>{try{await extracted.cleanup()}finally{await fs.rm(tempRoot,{recursive:true,force:true})}}}}catch(error){await fs.rm(tempRoot,{recursive:true,force:true});const wrappedError=wrapNpmPackResolutionError(source.spec,error);if(wrappedError){throw wrappedError}throw error}}function isLocalPackageArchive(candidate){const normalized=candidate.toLowerCase();return normalized.endsWith(".tgz")||normalized.endsWith(".tar.gz")}function failLocalPackageArchive(message){throw new PmCliError(message,EXIT_CODE.USAGE,{code:"local_package_archive_unsafe",required:"Use a bounded npm .tgz or .tar.gz archive with one package/ root and no links or escaping paths.",why:"Package archives are untrusted input and must be validated before any entry reaches the filesystem."})}function validateLocalPackageArchiveEntry(entry,limits,state){if(entry.meta)return;state.entries+=1;if(state.entries>limits.maxEntries){failLocalPackageArchive(`Local package archive exceeds the ${limits.maxEntries} entry limit.`)}const archivePath=entry.path;const segments=archivePath.split("/");if(archivePath.includes("\\")||archivePath.startsWith("/")||/^[A-Za-z]:/u.test(archivePath)||segments.some(segment=>segment==="..")){failLocalPackageArchive(`Local package archive contains an escaping path: "${archivePath}".`)}if(segments[0]!=="package"){failLocalPackageArchive(`Local package archive entry "${archivePath}" is outside the required package/ root.`)}if(entry.type==="SymbolicLink"||entry.type==="Link"){failLocalPackageArchive(`Local package archive link "${archivePath}" is not supported.`)}if(entry.type!=="File"&&entry.type!=="OldFile"&&entry.type!=="Directory"){failLocalPackageArchive(`Local package archive entry "${archivePath}" uses unsupported type "${entry.type}".`)}if(entry.size>limits.maxEntryBytes){failLocalPackageArchive(`Local package archive entry "${archivePath}" exceeds the ${limits.maxEntryBytes} byte entry limit.`)}state.expandedBytes+=entry.size;if(state.expandedBytes>limits.maxExpandedBytes){failLocalPackageArchive(`Local package archive exceeds the ${limits.maxExpandedBytes} expanded byte limit.`)}if(archivePath==="package/package.json"){state.packageJsonEntries+=1}}async function extractLocalPackageArchive(archivePath,limits=LOCAL_PACKAGE_ARCHIVE_LIMITS){const archiveStats=await fs.stat(archivePath);if(archiveStats.size>limits.maxArchiveBytes){failLocalPackageArchive(`Local package archive exceeds the ${limits.maxArchiveBytes} archive byte limit.`)}const tempRoot=await fs.mkdtemp(path.join(os.tmpdir(),"pm-local-package-archive-"));const extractDirectory=path.join(tempRoot,"extract");await fs.mkdir(extractDirectory,{recursive:true});const state={entries:0,expandedBytes:0,packageJsonEntries:0};let validationError;try{await listTar({file:archivePath,strict:true,maxDecompressionRatio:100,onReadEntry:entry=>{if(validationError!==void 0)return;try{validateLocalPackageArchiveEntry(entry,limits,state)}catch(error){validationError=error}}});if(validationError!==void 0)throw validationError;if(state.packageJsonEntries!==1){failLocalPackageArchive(`Local package archive must contain exactly one package/package.json entry; found ${state.packageJsonEntries}.`)}await extractTar({file:archivePath,cwd:extractDirectory,strict:true,preservePaths:false,preserveOwner:false,noMtime:true,unlink:true,maxDepth:64,maxDecompressionRatio:100});const packageRoot=path.join(extractDirectory,"package");const packageJsonPath=path.join(packageRoot,"package.json");const packageJson=JSON.parse(await fs.readFile(packageJsonPath,"utf8"));await installNpmPackageRuntimeDependencies(packageRoot);return{directory:await resolvePackageExtensionDirectory(packageRoot,archivePath),package:typeof packageJson.name==="string"?packageJson.name:void 0,version:typeof packageJson.version==="string"?packageJson.version:void 0,cleanup:async()=>{await fs.rm(tempRoot,{recursive:true,force:true})}}}catch(error){await fs.rm(tempRoot,{recursive:true,force:true});throw error}}async function installNpmPackageRuntimeDependencies(packageRoot,npmRunner=runNpmCommand){const packageJsonPath=path.join(packageRoot,"package.json");if(!await pathExists(packageJsonPath)){return}let parsed;try{parsed=JSON.parse(await fs.readFile(packageJsonPath,"utf8"))}catch{return}if(typeof parsed!=="object"||parsed===null){return}const manifest=parsed;const dependencySpecs=runtimeDependencyInstallSpecs(manifest);const shouldLinkHostedPmCli=hasHostedPmCliDependency(manifest);if(dependencySpecs.length===0&&!shouldLinkHostedPmCli){return}const runtimeOnlyManifest={...parsed};delete runtimeOnlyManifest.devDependencies;const installManifest={...runtimeOnlyManifest};removeHostedPmCliDependency(installManifest);await fs.writeFile(packageJsonPath,`${JSON.stringify(installManifest,null,2)}
4
+ `,"utf8");try{await Promise.all([fs.rm(path.join(packageRoot,"package-lock.json"),{force:true}),fs.rm(path.join(packageRoot,"npm-shrinkwrap.json"),{force:true})]);if(dependencySpecs.length>0){await npmRunner(["install","--ignore-scripts","--no-audit","--fund=false","--package-lock=false","--no-save","--omit=peer","--"],packageRoot)}if(shouldLinkHostedPmCli){await linkHostedPmCliDependency(packageRoot)}}finally{await fs.writeFile(packageJsonPath,`${JSON.stringify(runtimeOnlyManifest,null,2)}
5
+ `,"utf8")}}function hasHostedPmCliDependency(manifest){for(const dependencyMap of[manifest.dependencies,manifest.optionalDependencies,manifest.peerDependencies]){if(typeof dependencyMap==="object"&&dependencyMap!==null&&PM_CLI_PACKAGE_NAME in dependencyMap){return true}}return false}function removeHostedPmCliDependency(manifest){for(const field of["dependencies","optionalDependencies","peerDependencies"]){const dependencyMap=manifest[field];if(typeof dependencyMap!=="object"||dependencyMap===null){continue}const nextMap={...dependencyMap};delete nextMap[PM_CLI_PACKAGE_NAME];if(Object.keys(nextMap).length===0){delete manifest[field]}else{manifest[field]=nextMap}}}async function linkHostedPmCliDependency(packageRoot){const hostPackageRoot=resolvePmPackageRootFromModule(import.meta.url,["../../.."]);const[scope,packageName]=PM_CLI_PACKAGE_NAME.split("/");const scopedDirectory=path.join(packageRoot,"node_modules",scope);const linkPath=path.join(scopedDirectory,packageName);await fs.mkdir(scopedDirectory,{recursive:true});await fs.rm(linkPath,{recursive:true,force:true});await fs.symlink(hostPackageRoot,linkPath,resolveDirectorySymlinkType(process.platform))}function resolveDirectorySymlinkType(platform){return platform==="win32"?"junction":"dir"}function validateRuntimeDependencySpec(name,version){if(name.startsWith("-")){throw new PmCliError(`Extension runtime dependency name "${name}" is unsafe because npm could interpret it as a command-line option.`,EXIT_CODE.USAGE,{code:"extension_dependency_name_unsafe",required:"Use a valid npm package name that does not begin with a dash.",why:"Extension manifests are untrusted input and dependency names must never become npm options."})}const hasUnsafeControlOrShellCharacter=[...version].some(character=>{const codePoint=character.charCodeAt(0);return codePoint<=31||codePoint===127||"&|;()`\"'".includes(character)});if(hasUnsafeControlOrShellCharacter){throw new PmCliError(`Extension runtime dependency "${name}" has an unsafe version specifier.`,EXIT_CODE.USAGE,{code:"extension_dependency_version_unsafe",required:"Use an npm version, range, dist-tag, URL, or file specifier without shell metacharacters.",why:"npm.cmd requires a command shell on Windows, so untrusted shell metacharacters cannot be forwarded."})}try{npa.resolve(name,version)}catch{throw new PmCliError(`Extension runtime dependency "${name}@${version}" is not a valid npm dependency specifier.`,EXIT_CODE.USAGE,{code:"extension_dependency_spec_invalid",required:"Use a valid npm package name and npm-supported version, range, dist-tag, URL, or file specifier.",why:"Only grammar-validated dependency specs may be written to the isolated runtime install manifest."})}return`${name}@${version}`}function runtimeDependencyInstallSpecs(manifest){const specs=new Map;for(const dependencyMap of[manifest.dependencies,manifest.optionalDependencies,manifest.peerDependencies]){if(typeof dependencyMap!=="object"||dependencyMap===null){continue}for(const[name,version]of Object.entries(dependencyMap)){if(name===PM_CLI_PACKAGE_NAME||typeof version!=="string"||version.trim().length===0||specs.has(name)){continue}const normalizedVersion=version.trim();specs.set(name,validateRuntimeDependencySpec(name,normalizedVersion))}}return[...specs.values()]}async function resolvePackageExtensionDirectory(packageRoot,sourceLabel){const discovered=await collectPackageExtensionDirectories(packageRoot);if(discovered.length===1){return discovered[0]}if(discovered.length>1){const choices=discovered.map(entry=>path.relative(packageRoot,entry).replaceAll(path.sep,"/")).sort((left,right)=>left.localeCompare(right));throw new PmCliError(`Package source "${sourceLabel}" contains multiple extension manifests. Provide an explicit extension path. Candidates: ${choices.join(", ")}`,EXIT_CODE.USAGE)}throw new PmCliError(`Unable to locate a pm extension manifest in package source "${sourceLabel}". Package installs currently activate only extension resources, so add package.json pm.extensions or an extensions/ directory. Metadata-only resources like pm.docs/pm.examples are catalog metadata and do not activate commands.`,EXIT_CODE.USAGE)}async function resolveGithubSourceDirectory(cloneDirectory,source){const candidatePaths=[];if(source.subpath){candidatePaths.push(source.subpath);candidatePaths.push(path.posix.join(".agents/pm/extensions",source.subpath));candidatePaths.push(path.posix.join(".custom/pm-extensions",source.subpath));candidatePaths.push(path.posix.join(".custom/pm-extension",source.subpath))}for(const candidate of candidatePaths){const absolute=path.resolve(cloneDirectory,candidate);if(!isPathWithinDirectory(cloneDirectory,absolute)){continue}if(await pathExists(path.join(absolute,"manifest.json"))){return{directory:absolute,resolved_subpath:candidate}}}if(await pathExists(path.join(cloneDirectory,"manifest.json"))){return{directory:cloneDirectory,resolved_subpath:"."}}const discoveredDirectory=await resolvePackageExtensionDirectory(cloneDirectory,source.input);return{directory:discoveredDirectory,resolved_subpath:path.relative(cloneDirectory,discoveredDirectory).replaceAll(path.sep,"/")}}function looksLikeBarePackageName(input){const trimmed=input.trim();if(trimmed.length===0||trimmed.startsWith(".")||trimmed.startsWith("~")){return false}if(trimmed.startsWith("@")){return trimmed.split("/").length===2}return!trimmed.includes("/")&&!trimmed.includes("\\")}async function buildLocalSourceNotFoundError(source){const baseMessage=`Local extension source does not exist: "${source.absolute_path}".`;const input=source.input.trim();if(!looksLikeBarePackageName(input)){return new PmCliError(baseMessage,EXIT_CODE.NOT_FOUND)}let bundledAliases=[];try{const envPackageRoot=process.env.PM_CLI_PACKAGE_ROOT;const cacheKey=typeof envPackageRoot==="string"&&envPackageRoot.trim().length>0?path.resolve(envPackageRoot.trim()):"";if(bundledPackageAliasesCache?.key!==cacheKey){bundledPackageAliasesCache={key:cacheKey,aliases:await listBundledPackageAliases()}}bundledAliases=bundledPackageAliasesCache.aliases}catch{}const nextSteps=[`Retry with pm install npm:${input} if the package is published to npm.`,`Or inspect bundled packages with pm package catalog --project --json before installing by alias. Known aliases (blank means none found): ${bundledAliases.join(", ")}`];return new PmCliError(`${baseMessage} "${input}" did not match a local directory, bundled package alias, or bundled package name; if you meant an npm package, install it as "npm:${input}".`,EXIT_CODE.NOT_FOUND,{code:"local_source_not_found_bare_name",required:`Use "npm:${input}" for npm registry packages, a bundled catalog alias, or an existing local directory path.`,why:"Bare names resolve as local paths only after bundled aliases, so unmatched names need an explicit npm: source.",examples:[`pm install npm:${input}`,"pm package catalog --project --json"],nextSteps,recovery:{attempted_command:`pm install ${input}`,normalized_args:["install",input],next_best_command:`pm install npm:${input}`}})}async function resolveInstallSource(source){if(source.kind==="local"){let localStats;try{localStats=await fs.stat(source.absolute_path)}catch{throw await buildLocalSourceNotFoundError(source)}if(localStats.isFile()&&isLocalPackageArchive(source.absolute_path)){const resolved=await extractLocalPackageArchive(source.absolute_path);return{source,directory:resolved.directory,source_root:path.dirname(resolved.directory),resolved_subpath:path.relative(path.dirname(resolved.directory),resolved.directory).replaceAll(path.sep,"/"),npm_package:resolved.package,npm_version:resolved.version,cleanup:resolved.cleanup}}if(!localStats.isDirectory()){throw new PmCliError(`Local extension source must be a directory or npm .tgz/.tar.gz archive: "${source.absolute_path}".`,EXIT_CODE.USAGE)}const directory=await resolvePackageExtensionDirectory(source.absolute_path,source.input);return{source,directory,source_root:source.absolute_path}}if(source.kind==="npm"){const resolved=await resolveNpmSourceDirectory(source);return{source,directory:resolved.directory,source_root:path.dirname(resolved.directory),cleanup:resolved.cleanup,resolved_subpath:path.relative(path.dirname(resolved.directory),resolved.directory).replaceAll(path.sep,"/"),npm_package:resolved.package,npm_version:resolved.version}}const cloneDirectory=await fs.mkdtemp(path.join(os.tmpdir(),"pm-extension-source-"));const cloneArgs=["clone","--depth","1"];if(source.ref){cloneArgs.push("--branch",source.ref)}cloneArgs.push(source.repository,cloneDirectory);try{await runGitCommand(cloneArgs);const commit=await runGitCommand(["-C",cloneDirectory,"rev-parse","HEAD"]);const resolved=await resolveGithubSourceDirectory(cloneDirectory,source);return{source,directory:resolved.directory,source_root:cloneDirectory,resolved_subpath:resolved.resolved_subpath,commit,cleanup:async()=>{await fs.rm(cloneDirectory,{recursive:true,force:true})}}}catch(error){await fs.rm(cloneDirectory,{recursive:true,force:true});throw error}}async function areDirectoriesEquivalent(left,right){if(!await pathExists(left)||!await pathExists(right)){return false}const[leftRealPath,rightRealPath]=await Promise.all([fs.realpath(left),fs.realpath(right)]);return leftRealPath===rightRealPath}const _testOnlyInstallSources={extractLocalPackageArchive,validateLocalPackageArchiveEntry,installNpmPackageRuntimeDependencies,npmPackageNameFromSpec,parsePackedNpmPackage,resolveNpmSourceDirectoryWithRunner,resolveNpmSourceDirectory,resolveNpmPackSpec,findInstalledNpmPackageCandidate,resolvePackageExtensionDirectory,runtimeDependencyInstallSpecs,hasHostedPmCliDependency,removeHostedPmCliDependency,linkHostedPmCliDependency,resolveDirectorySymlinkType,runNpmCommand};export{_testOnlyInstallSources,areDirectoriesEquivalent,buildNpmNotFoundRecovery,findInstalledNpmPackageCandidate,isNpmNotFoundError,isNpmPackNotFoundError,normalizeNpmLocalFileAliasSpec,parseExtensionInstallSource,resolveInstallSource,resolveNpmCommandName,runGitCommand,shouldRunNpmCommandInShell,wrapNpmPackResolutionError};
1057
6
  //# sourceMappingURL=install-sources.js.map
1058
- //# debugId=05f56edb-c08d-570c-b8b5-641fc694331e