@unbrained/pm-cli 2026.9.7 → 2026.9.8
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.
- package/.agents/skills/pm-developer/SKILL.md +12 -4
- package/.agents/skills/pm-developer/references/MULTI_AGENT_MERGE.md +19 -10
- package/.agents/skills/pm-extensions/SKILL.md +6 -0
- package/.agents/skills/pm-sdk/SKILL.md +11 -2
- package/.agents/skills/pm-user/SKILL.md +5 -0
- package/.agents/skills/pm-user/references/ECOSYSTEM_PLANNING.md +95 -0
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +211 -181
- package/dist/cli/after-command-context-usage.js +1 -48
- package/dist/cli/argv-utils.js +1 -40
- package/dist/cli/bootstrap-args.js +1 -9
- package/dist/cli/bundle-integrity.js +2 -110
- package/dist/cli/commander-usage.js +11 -771
- package/dist/cli/commands/activity.js +1 -9
- package/dist/cli/commands/aggregate.js +1 -5
- package/dist/cli/commands/append.js +1 -5
- package/dist/cli/commands/claim.js +1 -5
- package/dist/cli/commands/close-many.js +1 -5
- package/dist/cli/commands/close.js +1 -9
- package/dist/cli/commands/comments.js +1 -5
- package/dist/cli/commands/config.js +1 -9
- package/dist/cli/commands/context.js +1 -9
- package/dist/cli/commands/contracts.js +1 -5
- package/dist/cli/commands/copy.js +1 -9
- package/dist/cli/commands/create.js +1 -9
- package/dist/cli/commands/delete.js +1 -9
- package/dist/cli/commands/deps.js +1 -9
- package/dist/cli/commands/docs.js +1 -9
- package/dist/cli/commands/duplicates.js +1 -9
- package/dist/cli/commands/eval.js +1 -9
- package/dist/cli/commands/extension/describe.js +1 -5
- package/dist/cli/commands/extension/scaffold.js +1 -5
- package/dist/cli/commands/extension/shared.js +1 -5
- package/dist/cli/commands/extension.js +1 -9
- package/dist/cli/commands/files.js +1 -9
- package/dist/cli/commands/focus.js +1 -9
- package/dist/cli/commands/gc.js +1 -9
- package/dist/cli/commands/get.js +1 -9
- package/dist/cli/commands/graph.js +1 -10
- package/dist/cli/commands/health.js +1 -9
- package/dist/cli/commands/history-compact.js +1 -10
- package/dist/cli/commands/history-redact.js +1 -11
- package/dist/cli/commands/history-repair.js +1 -10
- package/dist/cli/commands/history.js +1 -5
- package/dist/cli/commands/index.js +1 -58
- package/dist/cli/commands/init-agent-guidance.js +1 -9
- package/dist/cli/commands/init.js +1 -9
- package/dist/cli/commands/learnings.js +1 -5
- package/dist/cli/commands/lifecycle-transitions.js +1 -5
- package/dist/cli/commands/list.js +1 -9
- package/dist/cli/commands/merge.js +1 -11
- package/dist/cli/commands/next.js +1 -9
- package/dist/cli/commands/notes.js +1 -5
- package/dist/cli/commands/plan.js +1 -9
- package/dist/cli/commands/profile.js +1 -9
- package/dist/cli/commands/restore.js +1 -9
- package/dist/cli/commands/scheduling-shortcuts.js +1 -9
- package/dist/cli/commands/schema.js +1 -10
- package/dist/cli/commands/search.js +1 -9
- package/dist/cli/commands/stats.js +1 -9
- package/dist/cli/commands/telemetry.js +1 -9
- package/dist/cli/commands/test-all.js +1 -9
- package/dist/cli/commands/test-runs.js +1 -9
- package/dist/cli/commands/test.js +1 -9
- package/dist/cli/commands/update-many.js +1 -5
- package/dist/cli/commands/update.js +1 -9
- package/dist/cli/commands/upgrade.js +1 -5
- package/dist/cli/commands/validate.js +1 -15
- package/dist/cli/context-intent-invocation.js +1 -20
- package/dist/cli/description-stdin.js +1 -17
- package/dist/cli/error-guidance.js +1 -1353
- package/dist/cli/extension-command-help.js +5 -636
- package/dist/cli/extension-command-options.js +1 -427
- package/dist/cli/extension-recovery.js +1 -126
- package/dist/cli/help-content.js +2 -1001
- package/dist/cli/help-json-payload.js +4 -570
- package/dist/cli/main.d.ts +4 -0
- package/dist/cli/main.js +5 -2573
- package/dist/cli/migration-gates.js +1 -289
- package/dist/cli/public.js +1 -20
- package/dist/cli/register-annotations.js +1 -270
- package/dist/cli/register-assurance.js +1 -62
- package/dist/cli/register-files-lookup.js +1 -56
- package/dist/cli/register-history-activity.d.ts +8 -0
- package/dist/cli/register-history-activity.js +2 -0
- package/dist/cli/register-history-author.js +1 -38
- package/dist/cli/register-history-maintenance.d.ts +9 -0
- package/dist/cli/register-history-maintenance.js +2 -0
- package/dist/cli/register-list-query.js +10 -943
- package/dist/cli/register-mutation-options.js +1 -9
- package/dist/cli/register-mutation.js +19 -1893
- package/dist/cli/register-operations.js +1 -920
- package/dist/cli/register-setup.js +1 -716
- package/dist/cli/register-structured-mutation.js +1 -196
- package/dist/cli/registration-helpers.js +1 -5
- package/dist/cli/runtime-compatibility-boundary.js +4 -42
- package/dist/cli/schema-registration-helpers.js +1 -73
- package/dist/cli/search-refresh.js +1 -13
- package/dist/cli/stats-analytics-json.js +1 -68
- package/dist/cli/telemetry-flush.js +1 -10
- package/dist/cli-bundle/bundle-manifest.json +164 -156
- package/dist/cli-bundle/chunks/chunk-3BZZA6A3.js +5 -0
- package/dist/cli-bundle/chunks/chunk-AMRDVX36.js +235 -0
- package/dist/cli-bundle/chunks/chunk-DAM4CBBR.js +2202 -0
- package/dist/cli-bundle/chunks/{chunk-WYRZZ5ZE.js → chunk-DEZPZOQ7.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-FLDWYEND.js +77 -0
- package/dist/cli-bundle/chunks/{chunk-NPN5I67J.js → chunk-G5ADGQ2D.js} +3 -3
- package/dist/cli-bundle/chunks/chunk-JAAEYHUA.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-JX4DH4WC.js → chunk-KR3RP4FH.js} +3 -3
- package/dist/cli-bundle/chunks/chunk-LEZOUXG6.js +2 -0
- package/dist/cli-bundle/chunks/chunk-NSAPNEYH.js +2 -0
- package/dist/cli-bundle/chunks/chunk-QOEKOECV.js +29 -0
- package/dist/cli-bundle/chunks/chunk-RHSFOMHU.js +2 -0
- package/dist/cli-bundle/chunks/chunk-XOD2PCB6.js +20 -0
- package/dist/cli-bundle/chunks/{chunk-JT6XF6GE.js → chunk-YVEQ2AMO.js} +4 -4
- package/dist/cli-bundle/chunks/register-list-query-KSK3R63M.js +11 -0
- package/dist/cli-bundle/chunks/register-mutation-IQ5C7U6O.js +20 -0
- package/dist/cli-bundle/chunks/{register-operations-I5W3KMGB.js → register-operations-DWVHR2NC.js} +2 -2
- package/dist/cli-bundle/chunks/register-setup-BQ5SVD4B.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-3WRPWLA7.js +3 -0
- package/dist/cli-bundle/focused-chunks/chunk-7MBUII7U.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-COPBO5HW.js +8 -0
- package/dist/cli-bundle/focused-chunks/chunk-DUN4IXYN.js +20 -0
- package/dist/cli-bundle/focused-chunks/{chunk-LIJIA4TY.js → chunk-EE5QSM4Z.js} +3 -3
- package/dist/cli-bundle/focused-chunks/chunk-HJVARYM3.js +6 -0
- package/dist/cli-bundle/focused-chunks/chunk-IAUOUGVR.js +177 -0
- package/dist/cli-bundle/focused-chunks/chunk-KOOMJ54F.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-MZDXX7JY.js +56 -0
- package/dist/cli-bundle/focused-chunks/{chunk-M6PBRFSH.js → chunk-OPFHFGDD.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-QHNETP77.js +9 -0
- package/dist/cli-bundle/focused-chunks/{chunk-3BZEOXLT.js → chunk-RMWES4M6.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-RXT4P5QH.js +10 -0
- package/dist/cli-bundle/focused-chunks/chunk-SDOL6FM2.js +12 -0
- package/dist/cli-bundle/focused-chunks/chunk-SQV4AAUC.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-PEFABF7E.js → chunk-WE3IUNIW.js} +3 -3
- package/dist/cli-bundle/focused-chunks/chunk-YALOUBWJ.js +2 -0
- package/dist/cli-bundle/main.js +20 -20
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +2 -2
- package/dist/cli-bundle/sdk-core.js +29 -29
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +42 -42
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +11 -11
- package/dist/cli.js +1 -104
- package/dist/core/checkpoint/checkpoint-gc.js +1 -169
- package/dist/core/checkpoint/mutation-checkpoint.js +2 -133
- package/dist/core/config/nested-settings.js +1 -534
- package/dist/core/config/positional-value.js +1 -109
- package/dist/core/diagnostics/remediation.js +1 -506
- package/dist/core/extensions/activation-summary-markdown.js +2 -145
- package/dist/core/extensions/activation-summary.js +1 -92
- package/dist/core/extensions/activation-transaction.js +1 -46
- package/dist/core/extensions/capability-usage.js +1 -173
- package/dist/core/extensions/command-hook-context.js +1 -13
- package/dist/core/extensions/command-metadata-contract.js +1 -22
- package/dist/core/extensions/command-visibility-tier.js +1 -29
- package/dist/core/extensions/contribution-inventory.js +1 -173
- package/dist/core/extensions/exporter-output-contract.js +1 -66
- package/dist/core/extensions/extension-candidate.js +1 -18
- package/dist/core/extensions/extension-capability-aliases.js +1 -158
- package/dist/core/extensions/extension-hook-runtime.js +1 -699
- package/dist/core/extensions/extension-policy.js +1 -599
- package/dist/core/extensions/extension-registries.js +1 -62
- package/dist/core/extensions/extension-runtime-helpers.js +1 -33
- package/dist/core/extensions/extension-types.js +1 -102
- package/dist/core/extensions/flag-definition-validation.js +1 -52
- package/dist/core/extensions/flag-value-types.js +1 -64
- package/dist/core/extensions/index.js +1 -526
- package/dist/core/extensions/item-field-types.js +1 -39
- package/dist/core/extensions/item-fields.js +1 -261
- package/dist/core/extensions/loader.js +1 -2223
- package/dist/core/extensions/manifest-schema.js +1 -69
- package/dist/core/extensions/module-graph-snapshot.js +1 -33
- package/dist/core/extensions/preflight-ownership.js +1 -41
- package/dist/core/extensions/registration-validation.js +1 -82
- package/dist/core/extensions/registration-values.js +1 -209
- package/dist/core/extensions/reserved-host-flags.js +1 -36
- package/dist/core/extensions/runtime-registrations.js +1 -67
- package/dist/core/extensions/service-ownership.js +1 -19
- package/dist/core/extensions/version-compat.js +1 -216
- package/dist/core/fs/fs-utils.js +2 -158
- package/dist/core/fs/host-environment-errors.js +1 -141
- package/dist/core/fs/index.js +1 -9
- package/dist/core/fs/path-utils.js +1 -17
- package/dist/core/governance/content-fields.js +1 -160
- package/dist/core/governance/issue-codes.js +1 -151
- package/dist/core/governance/metadata-coverage.js +1 -358
- package/dist/core/history/drift-cache.js +3 -72
- package/dist/core/history/drift-scan.js +1 -342
- package/dist/core/history/event-classification.js +1 -109
- package/dist/core/history/event-index.js +8 -784
- package/dist/core/history/history-compact-bulk.js +1 -104
- package/dist/core/history/history-diff.js +1 -158
- package/dist/core/history/history-rewrite.d.ts +6 -1
- package/dist/core/history/history-rewrite.js +1 -107
- package/dist/core/history/history-storage-stats.js +1 -102
- package/dist/core/history/history-stream-policy.js +1 -62
- package/dist/core/history/history.js +2 -617
- package/dist/core/history/identity.js +1 -30
- package/dist/core/history/index.js +1 -9
- package/dist/core/history/projection.js +1 -196
- package/dist/core/history/read.d.ts +9 -0
- package/dist/core/history/read.js +1 -57
- package/dist/core/history/replay.js +2 -439
- package/dist/core/history/version-address.js +1 -32
- package/dist/core/history/workspace-history.js +2 -433
- package/dist/core/io/body-file.js +1 -62
- package/dist/core/io/bulk-ids-input.js +1 -112
- package/dist/core/item/actionability.js +1 -327
- package/dist/core/item/dependency-reference.js +1 -20
- package/dist/core/item/id.js +1 -112
- package/dist/core/item/index.js +1 -12
- package/dist/core/item/item-format-version.js +1 -78
- package/dist/core/item/item-format.js +5 -1473
- package/dist/core/item/item-record.js +1 -23
- package/dist/core/item/item-type-definition.js +1 -133
- package/dist/core/item/parent-reference-policy.js +1 -57
- package/dist/core/item/parse.js +2 -603
- package/dist/core/item/plan-lifecycle.js +1 -19
- package/dist/core/item/priority.js +1 -61
- package/dist/core/item/sprint-release-format.js +1 -38
- package/dist/core/item/status-filter.js +1 -115
- package/dist/core/item/status.js +1 -43
- package/dist/core/item/toon-decode.js +1 -29
- package/dist/core/item/type-registry.js +1 -715
- package/dist/core/item/type-synonyms.js +1 -38
- package/dist/core/lock/index.js +1 -9
- package/dist/core/lock/lock-gc.js +1 -240
- package/dist/core/lock/lock.js +3 -590
- package/dist/core/output/mutation-projection.js +1 -217
- package/dist/core/output/output-control.js +1 -25
- package/dist/core/output/output.js +11 -494
- package/dist/core/output/query-summary.js +1 -58
- package/dist/core/output/tabular.js +1 -77
- package/dist/core/packages/manifest.js +1 -244
- package/dist/core/packages/root.js +1 -84
- package/dist/core/profile/profile-describe.js +1 -83
- package/dist/core/profile/profile-lint.js +1 -415
- package/dist/core/profile/profile-plan.js +0 -0
- package/dist/core/profile/profile-presets.js +1 -370
- package/dist/core/reproducibility/context.js +1 -82
- package/dist/core/schema/fields-file.js +2 -288
- package/dist/core/schema/item-types-file.js +2 -296
- package/dist/core/schema/runtime-field-filters.js +1 -49
- package/dist/core/schema/runtime-field-values.js +1 -313
- package/dist/core/schema/runtime-schema.js +2 -826
- package/dist/core/schema/status-defs-file.js +2 -227
- package/dist/core/schema/status-token.js +1 -31
- package/dist/core/schema/type-inference.js +1 -95
- package/dist/core/schema/type-presets.js +1 -87
- package/dist/core/schema/type-workflows.js +1 -104
- package/dist/core/search/background-refresh.js +2 -286
- package/dist/core/search/bm25.js +1 -146
- package/dist/core/search/cache.js +2 -534
- package/dist/core/search/corpus.js +1 -311
- package/dist/core/search/embedding-batches.js +1 -163
- package/dist/core/search/eval.js +1 -225
- package/dist/core/search/http-client.js +1 -75
- package/dist/core/search/providers.js +1 -242
- package/dist/core/search/relevance.js +1 -244
- package/dist/core/search/semantic-defaults.js +1 -199
- package/dist/core/search/staleness.js +1 -30
- package/dist/core/search/vector-stores.js +2 -664
- package/dist/core/search/vectorization-metadata.js +1 -81
- package/dist/core/sentry/helpers.js +1 -272
- package/dist/core/sentry/instrument.js +1 -387
- package/dist/core/session/session-state.js +1 -260
- package/dist/core/shared/agent-session-context.js +1 -133
- package/dist/core/shared/author.js +1 -1172
- package/dist/core/shared/command-types.js +1 -4
- package/dist/core/shared/conflict-markers.js +1 -31
- package/dist/core/shared/constants.js +1 -405
- package/dist/core/shared/errors.js +1 -20
- package/dist/core/shared/html-entity-decode.js +1 -131
- package/dist/core/shared/index.js +1 -12
- package/dist/core/shared/item-metadata-contract.js +1 -89
- package/dist/core/shared/lazy-module.js +1 -16
- package/dist/core/shared/levenshtein.js +1 -61
- package/dist/core/shared/memo.js +1 -19
- package/dist/core/shared/numeric-parsers.js +1 -20
- package/dist/core/shared/option-alias-visibility.js +1 -67
- package/dist/core/shared/primitives.js +1 -127
- package/dist/core/shared/serial-queue.js +1 -79
- package/dist/core/shared/serialization.js +1 -210
- package/dist/core/shared/split-comma-list.js +1 -30
- package/dist/core/shared/text-normalization.js +1 -38
- package/dist/core/shared/time.js +1 -306
- package/dist/core/store/index.js +1 -12
- package/dist/core/store/item-format-migration.js +1 -125
- package/dist/core/store/item-metadata-cache.js +1 -1116
- package/dist/core/store/item-metadata-query-index.js +9 -394
- package/dist/core/store/item-metadata-read-work.js +1 -43
- package/dist/core/store/item-store.js +1 -693
- package/dist/core/store/paths.d.ts +1 -1
- package/dist/core/store/paths.js +1 -214
- package/dist/core/store/settings-read-cache.js +1 -85
- package/dist/core/store/settings-validator.js +1 -421
- package/dist/core/store/settings.js +3 -1309
- package/dist/core/store/tracker-preflight.js +1 -141
- package/dist/core/telemetry/consent.js +5 -108
- package/dist/core/telemetry/observability.js +1 -246
- package/dist/core/telemetry/runtime.js +4 -1988
- package/dist/core/test/background-runs.js +4 -945
- package/dist/core/test/item-test-run-tracking.js +1 -63
- package/dist/core/test/run-selectors.js +1 -120
- package/dist/core/validate/estimate-defaults.js +1 -89
- package/dist/core/validate/fix-planning.js +1 -189
- package/dist/core/validate/linked-artifact-reference.js +1 -36
- package/dist/core/validate/missing-by-type.js +1 -34
- package/dist/core/validate/missing-link-owners.js +1 -95
- package/dist/core/validate/stale-file-classification.js +1 -82
- package/dist/mcp/http-server.js +5 -448
- package/dist/mcp/legacy-adapter.js +1 -77
- package/dist/mcp/runtime-capabilities.js +1 -200
- package/dist/mcp/server.js +4 -1233
- package/dist/mcp/tool-definitions.js +1 -804
- package/dist/sdk/actionability.js +1 -13
- package/dist/sdk/agent/closed-domain-contracts.js +1 -161
- package/dist/sdk/agent/command-recovery.js +1 -59
- package/dist/sdk/agent/command-suggestions.js +1 -66
- package/dist/sdk/agent/create-option-policy.js +1 -31
- package/dist/sdk/agent/identity-config.js +1 -106
- package/dist/sdk/agent/item-addressing.js +1 -207
- package/dist/sdk/agent/refusal-closure-census.js +1 -151
- package/dist/sdk/agent/refusal-closure.js +1 -133
- package/dist/sdk/agent/refusal-corpus-contracts.js +1 -193
- package/dist/sdk/agent/refusal-reachability.js +1 -593
- package/dist/sdk/agent/subcommand-recovery.js +1 -83
- package/dist/sdk/agent/task-transcript-contracts.js +1 -197
- package/dist/sdk/agent/tracker-preflight-contracts.js +1 -126
- package/dist/sdk/agent-capability-contracts.js +1 -428
- package/dist/sdk/agent-session-context.js +1 -9
- package/dist/sdk/annotations.js +1 -448
- package/dist/sdk/author-attribution.js +1 -468
- package/dist/sdk/authoring.js +1 -20
- package/dist/sdk/cli-bootstrap.js +1 -838
- package/dist/sdk/cli-contracts/agent-output-contracts.d.ts +1 -1
- package/dist/sdk/cli-contracts/agent-output-contracts.js +4 -476
- package/dist/sdk/cli-contracts/bootstrap-command-scanner.js +1 -79
- package/dist/sdk/cli-contracts/command-aliases.d.ts +4 -0
- package/dist/sdk/cli-contracts/command-aliases.js +1 -107
- package/dist/sdk/cli-contracts/command-exit-contracts.js +1 -151
- package/dist/sdk/cli-contracts/commander-mutation-options.js +1 -1081
- package/dist/sdk/cli-contracts/commander-types.js +1 -159
- package/dist/sdk/cli-contracts/completeness.js +1 -393
- package/dist/sdk/cli-contracts/enum-contracts.js +1 -222
- package/dist/sdk/cli-contracts/flag-contracts.js +1 -1947
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +1 -347
- package/dist/sdk/cli-contracts/grammar-contracts.js +1 -986
- package/dist/sdk/cli-contracts/registration-helpers.js +7 -990
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +5 -0
- package/dist/sdk/cli-contracts/runtime-contracts.js +1 -2090
- package/dist/sdk/cli-contracts/schemas/assurance-definition.js +1 -324
- package/dist/sdk/cli-contracts/string-lists.js +1 -16
- package/dist/sdk/cli-contracts/tool-option-contracts.js +1 -461
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +1 -2167
- package/dist/sdk/cli-contracts/tool-schema.d.ts +3 -1
- package/dist/sdk/cli-contracts/tool-schema.js +1 -1664
- package/dist/sdk/cli-contracts/typed-action-inputs.js +1 -4
- package/dist/sdk/cli-contracts.d.ts +1 -1
- package/dist/sdk/cli-contracts.js +1 -17
- package/dist/sdk/cli-program.js +1 -49
- package/dist/sdk/command-line.d.ts +2 -5
- package/dist/sdk/command-line.js +1 -78
- package/dist/sdk/comments.js +1 -133
- package/dist/sdk/compile-cache.js +1 -73
- package/dist/sdk/completion.js +157 -837
- package/dist/sdk/compose.js +1 -1090
- package/dist/sdk/config.js +1 -1204
- package/dist/sdk/context/recency.js +1 -33
- package/dist/sdk/context/semantic-session-attribution.js +1 -82
- package/dist/sdk/context/usage-egress.js +1 -29
- package/dist/sdk/context/usage-ledger.js +3 -185
- package/dist/sdk/context-intent-contracts.js +1 -709
- package/dist/sdk/context-intent-runtime.js +1 -115
- package/dist/sdk/context-packing.js +1 -218
- package/dist/sdk/context-relevance.js +1 -503
- package/dist/sdk/context-signal-store.js +2 -426
- package/dist/sdk/context-usage.js +1 -367
- package/dist/sdk/contracts.js +1 -23
- package/dist/sdk/core-governance.js +1 -14
- package/dist/sdk/core.js +1 -14
- package/dist/sdk/corpus-shape.js +1 -401
- package/dist/sdk/define.js +1 -220
- package/dist/sdk/dependencies.js +1 -718
- package/dist/sdk/dependency-flag-validation.js +1 -156
- package/dist/sdk/dependency-provenance.js +1 -135
- package/dist/sdk/docs.js +1 -14
- package/dist/sdk/duplicates.js +1 -40
- package/dist/sdk/environment/agent-environment.js +1 -466
- package/dist/sdk/environment/host-environment-errors.js +1 -8
- package/dist/sdk/environment/project-runtime-compatibility.js +1 -481
- package/dist/sdk/environment/source-context.js +1 -28
- package/dist/sdk/environment/tracker-preflight.js +1 -9
- package/dist/sdk/error-code-catalog.js +1 -153
- package/dist/sdk/error-runtime.js +1 -58
- package/dist/sdk/errors.js +1 -58
- package/dist/sdk/eval.js +1 -190
- package/dist/sdk/extension/author-manifest.js +1 -92
- package/dist/sdk/extension/bundled-catalog.js +1 -332
- package/dist/sdk/extension/concurrency.js +1 -25
- package/dist/sdk/extension/copy-scope.d.ts +2 -0
- package/dist/sdk/extension/copy-scope.js +2 -0
- package/dist/sdk/extension/custom-field-collisions.js +1 -30
- package/dist/sdk/extension/describe.js +3 -189
- package/dist/sdk/extension/doctor.js +1 -606
- package/dist/sdk/extension/install-plan.d.ts +69 -0
- package/dist/sdk/extension/install-plan.js +2 -0
- package/dist/sdk/extension/install-receipts.d.ts +7 -0
- package/dist/sdk/extension/install-receipts.js +2 -0
- package/dist/sdk/extension/install-runtime.js +3 -313
- package/dist/sdk/extension/install-snapshot.js +1 -66
- package/dist/sdk/extension/install-sources.js +5 -1057
- package/dist/sdk/extension/managed-state.js +2 -252
- package/dist/sdk/extension/migrations.js +2 -174
- package/dist/sdk/extension/output-ownership.js +1 -25
- package/dist/sdk/extension/runtime-summary.js +1 -18
- package/dist/sdk/extension/scaffold.js +4 -2308
- package/dist/sdk/extension/shared.js +1 -147
- package/dist/sdk/extension/source-resolution.js +1 -65
- package/dist/sdk/extension/update-check.js +1 -67
- package/dist/sdk/extension-command-context.js +1 -44
- package/dist/sdk/extension-contracts.js +1 -73
- package/dist/sdk/extension.d.ts +7 -2
- package/dist/sdk/extension.js +1 -2196
- package/dist/sdk/files.js +1 -535
- package/dist/sdk/flag-invocation-contracts.d.ts +0 -5
- package/dist/sdk/flag-invocation-contracts.js +1 -344
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1 -2224
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -2236
- package/dist/sdk/generated-error-code-catalog.js +1 -16
- package/dist/sdk/governance/assurance-action-contracts.js +1 -4
- package/dist/sdk/governance/assurance-action.js +1 -411
- package/dist/sdk/governance/assurance-limits.js +1 -10
- package/dist/sdk/governance/assurance-mutation-error.js +1 -81
- package/dist/sdk/governance/assurance-presets.js +1 -135
- package/dist/sdk/governance/assurance-runtime.js +1 -238
- package/dist/sdk/governance/assurance.js +4 -1182
- package/dist/sdk/governance/boundary-fixtures.js +1 -200
- package/dist/sdk/governance/coverage-assurance.js +1 -60
- package/dist/sdk/governance/defect-recurrence-coverage.js +1 -188
- package/dist/sdk/governance/defect-recurrence-graph.js +1 -120
- package/dist/sdk/governance/defect-recurrence-signals.js +1 -24
- package/dist/sdk/governance/defect-recurrence.js +1 -623
- package/dist/sdk/governance/extension-host-version.js +1 -115
- package/dist/sdk/governance/gc.js +1 -368
- package/dist/sdk/governance/health.js +1 -2367
- package/dist/sdk/governance/hierarchy-validation.js +1 -108
- package/dist/sdk/governance/linked-file-report.js +1 -71
- package/dist/sdk/governance/merge-receipt-history.js +1 -206
- package/dist/sdk/governance/provenance-health.js +1 -282
- package/dist/sdk/governance/reindex.js +4 -761
- package/dist/sdk/governance/stale-work.js +1 -82
- package/dist/sdk/governance/status-role-diagnostics.js +1 -35
- package/dist/sdk/governance/storage-integrity.js +1 -280
- package/dist/sdk/governance/tracked-runtime-cache.js +1 -106
- package/dist/sdk/governance/upgrade.js +2 -327
- package/dist/sdk/governance/validate-history-drift.js +1 -81
- package/dist/sdk/governance/validate-item-reader.js +1 -17
- package/dist/sdk/governance/validate-normalization.js +1 -36
- package/dist/sdk/governance/validate.js +1 -2261
- package/dist/sdk/governance/workspace-position.js +1 -163
- package/dist/sdk/governance.d.ts +1 -0
- package/dist/sdk/governance.js +1 -31
- package/dist/sdk/graph/adapter.js +1 -181
- package/dist/sdk/graph/analytics.js +1 -474
- package/dist/sdk/graph/assembly.js +1 -377
- package/dist/sdk/graph/cache.js +1 -160
- package/dist/sdk/graph/centrality.js +1 -258
- package/dist/sdk/graph/conformance.js +1 -130
- package/dist/sdk/graph/deadline-scheduling.d.ts +90 -0
- package/dist/sdk/graph/deadline-scheduling.js +2 -0
- package/dist/sdk/graph/durable-cache.d.ts +1 -1
- package/dist/sdk/graph/durable-cache.js +1 -361
- package/dist/sdk/graph/governance-contracts.js +1 -34
- package/dist/sdk/graph/governance.d.ts +13 -1
- package/dist/sdk/graph/governance.js +1 -735
- package/dist/sdk/graph/hierarchy-integrity.js +1 -310
- package/dist/sdk/graph/index.d.ts +3 -2
- package/dist/sdk/graph/index.js +1 -26
- package/dist/sdk/graph/lifecycle-coverage.d.ts +32 -0
- package/dist/sdk/graph/lifecycle-coverage.js +2 -0
- package/dist/sdk/graph/mutation-advisory.js +1 -176
- package/dist/sdk/graph/remediation.js +1 -197
- package/dist/sdk/graph/run.d.ts +15 -1
- package/dist/sdk/graph/run.js +1 -768
- package/dist/sdk/graph/scheduling.js +1 -124
- package/dist/sdk/graph/traversal.js +1 -284
- package/dist/sdk/graph/workspace-relationship-kind-registry.js +1 -27
- package/dist/sdk/graph.js +1 -15
- package/dist/sdk/guide-topics.js +1 -707
- package/dist/sdk/guide.js +1 -279
- package/dist/sdk/history/maintenance.d.ts +71 -0
- package/dist/sdk/history/maintenance.js +2 -0
- package/dist/sdk/history/salvage.js +2 -247
- package/dist/sdk/history/subject.d.ts +19 -0
- package/dist/sdk/history/subject.js +2 -0
- package/dist/sdk/history-analytics.js +1 -282
- package/dist/sdk/history-compact.js +1 -527
- package/dist/sdk/history-mcp.js +1 -68
- package/dist/sdk/history-provenance.js +1 -182
- package/dist/sdk/history-read.js +1 -96
- package/dist/sdk/history-redact.d.ts +1 -14
- package/dist/sdk/history-redact.js +1 -643
- package/dist/sdk/history-repair.d.ts +5 -0
- package/dist/sdk/history-repair.js +1 -657
- package/dist/sdk/improvement-ledger-validation.js +1 -62
- package/dist/sdk/improvement-ledger.js +2 -257
- package/dist/sdk/index.d.ts +4 -0
- package/dist/sdk/index.js +1 -183
- package/dist/sdk/init-agent-guidance.js +2 -496
- package/dist/sdk/init.js +2 -820
- package/dist/sdk/invocation-author.js +1 -39
- package/dist/sdk/item-children.js +1 -90
- package/dist/sdk/item-metadata-index.js +1 -15
- package/dist/sdk/item-schedule.js +1 -27
- package/dist/sdk/item-transaction.js +1 -396
- package/dist/sdk/learnings.js +1 -29
- package/dist/sdk/lifecycle/append.js +2 -53
- package/dist/sdk/lifecycle/claim.d.ts +2 -0
- package/dist/sdk/lifecycle/claim.js +1 -242
- package/dist/sdk/lifecycle/close-many.js +1 -438
- package/dist/sdk/lifecycle/close.js +1 -468
- package/dist/sdk/lifecycle/copy.js +1 -212
- package/dist/sdk/lifecycle/create.js +1 -1949
- package/dist/sdk/lifecycle/delete.js +1 -45
- package/dist/sdk/lifecycle/event-validation-messages.js +1 -91
- package/dist/sdk/lifecycle/focus.js +1 -91
- package/dist/sdk/lifecycle/hierarchy-mutation-lock.js +1 -24
- package/dist/sdk/lifecycle/legacy-none-tokens.js +1 -149
- package/dist/sdk/lifecycle/lifecycle-transitions.js +1 -40
- package/dist/sdk/lifecycle/mcp-actions.d.ts +2 -0
- package/dist/sdk/lifecycle/mcp-actions.js +1 -51
- package/dist/sdk/lifecycle/metadata-normalizers.js +1 -46
- package/dist/sdk/lifecycle/mutation-command-options.js +1 -9
- package/dist/sdk/lifecycle/plan.js +1 -1606
- package/dist/sdk/lifecycle/recurrence-parsers.js +1 -147
- package/dist/sdk/lifecycle/reopen.js +1 -68
- package/dist/sdk/lifecycle/repeatable-metadata-parsers.js +1 -143
- package/dist/sdk/lifecycle/restore.d.ts +1 -0
- package/dist/sdk/lifecycle/restore.js +1 -330
- package/dist/sdk/lifecycle/shared-unset-fields.js +1 -295
- package/dist/sdk/lifecycle/update-many.js +1 -861
- package/dist/sdk/lifecycle/update.js +1 -2136
- package/dist/sdk/lifecycle-completion.js +1 -92
- package/dist/sdk/lifecycle-policy.js +1 -120
- package/dist/sdk/linked-artifacts.js +1 -530
- package/dist/sdk/mcp/apps.js +4 -133
- package/dist/sdk/mcp/authorization.js +1 -404
- package/dist/sdk/mcp/discovery.js +1 -494
- package/dist/sdk/mcp/interactions.js +1 -336
- package/dist/sdk/mcp/protocol.d.ts +7 -0
- package/dist/sdk/mcp/protocol.js +1 -184
- package/dist/sdk/mcp/skills.js +1 -389
- package/dist/sdk/mcp/subscriptions.js +1 -211
- package/dist/sdk/mcp/tasks.js +2 -430
- package/dist/sdk/mcp/transport.js +1 -260
- package/dist/sdk/merge/abandoned-receipts.js +1 -46
- package/dist/sdk/merge/driver.js +1 -212
- package/dist/sdk/merge/index.js +1 -16
- package/dist/sdk/merge/install.js +3 -561
- package/dist/sdk/merge/receipt-file-boundary.js +1 -46
- package/dist/sdk/merge/receipt-operation.js +1 -96
- package/dist/sdk/merge/receipt-schema.js +1 -397
- package/dist/sdk/merge/receipts.js +4 -525
- package/dist/sdk/merge/reconcile.js +1 -352
- package/dist/sdk/merge/three-way.js +3 -775
- package/dist/sdk/merge.js +1 -10
- package/dist/sdk/mutation-events.js +1 -292
- package/dist/sdk/mutation-guard.js +1 -216
- package/dist/sdk/notes.js +1 -139
- package/dist/sdk/output-contracts.js +1 -172
- package/dist/sdk/output-projection.js +1 -430
- package/dist/sdk/output-token-accounting.js +1 -140
- package/dist/sdk/output.js +1 -64
- package/dist/sdk/ownership-source.js +1 -21
- package/dist/sdk/package-import-adapters.js +1 -442
- package/dist/sdk/package-migrations.js +1 -20
- package/dist/sdk/package-runtime-options.js +1 -80
- package/dist/sdk/pagination.js +1 -162
- package/dist/sdk/profile.js +1 -454
- package/dist/sdk/provenance.js +1 -258
- package/dist/sdk/public-surface.json +1 -1
- package/dist/sdk/query/activity.js +1 -401
- package/dist/sdk/query/aggregate.d.ts +16 -0
- package/dist/sdk/query/aggregate.js +1 -390
- package/dist/sdk/query/calendar.js +1 -964
- package/dist/sdk/query/complete-list.js +1 -215
- package/dist/sdk/query/context.js +1 -1702
- package/dist/sdk/query/duplicate-candidates.js +1 -70
- package/dist/sdk/query/get.js +1 -450
- package/dist/sdk/query/history.js +1 -186
- package/dist/sdk/query/item-filter-options.js +1 -9
- package/dist/sdk/query/light-metadata.js +1 -18
- package/dist/sdk/query/list-filter-shared.js +1 -81
- package/dist/sdk/query/list.js +1 -1304
- package/dist/sdk/query/multi-value-filters.js +1 -78
- package/dist/sdk/query/next.js +1 -513
- package/dist/sdk/query/parsers.js +1 -44
- package/dist/sdk/query/projection-contracts.js +1 -184
- package/dist/sdk/query/search-contracts.js +1 -230
- package/dist/sdk/query/search-pagination.js +1 -35
- package/dist/sdk/query/search-rendering.js +1 -105
- package/dist/sdk/query/search.js +2 -1987
- package/dist/sdk/query.js +1 -35
- package/dist/sdk/read-output/continuation.js +1 -194
- package/dist/sdk/read-output-budget.js +1 -135
- package/dist/sdk/read-output-contracts.js +1 -1225
- package/dist/sdk/read-output-rows.js +1 -186
- package/dist/sdk/read-output-session.js +1 -208
- package/dist/sdk/relationship-analytics.js +1 -410
- package/dist/sdk/relationship-context.js +1 -284
- package/dist/sdk/relationship-history.js +4 -519
- package/dist/sdk/relationship-kinds/contract.js +1 -22
- package/dist/sdk/relationship-migration.js +1 -77
- package/dist/sdk/relationships.js +1 -579
- package/dist/sdk/reproducibility/process.js +1 -87
- package/dist/sdk/runtime-action-aliases.js +1 -59
- package/dist/sdk/runtime-extended-actions.js +1 -177
- package/dist/sdk/runtime-input.js +1 -614
- package/dist/sdk/runtime-primitives.js +1 -84
- package/dist/sdk/runtime-public-contracts.js +1 -4
- package/dist/sdk/runtime-stats-options.js +1 -38
- package/dist/sdk/runtime.js +1 -1928
- package/dist/sdk/scheduling-shortcuts.js +1 -63
- package/dist/sdk/schema-migration.js +3 -856
- package/dist/sdk/schema.js +1 -1376
- package/dist/sdk/search-refresh-worker.js +1 -18
- package/dist/sdk/similarity-scoring.js +1 -53
- package/dist/sdk/similarity.js +1 -326
- package/dist/sdk/start-task-status.js +1 -14
- package/dist/sdk/stats.js +1 -270
- package/dist/sdk/structured-mutations.js +1 -580
- package/dist/sdk/telemetry-flush.js +1 -13
- package/dist/sdk/telemetry.js +1 -405
- package/dist/sdk/templates.js +2 -292
- package/dist/sdk/test/batch.js +2 -509
- package/dist/sdk/test/entry.js +1 -70
- package/dist/sdk/test/execution.js +6 -2211
- package/dist/sdk/test/linked-command-detection.js +1 -546
- package/dist/sdk/test/measurements.js +1 -91
- package/dist/sdk/test/parsers.js +1 -545
- package/dist/sdk/test/runs.js +1 -193
- package/dist/sdk/test/trust.js +2 -206
- package/dist/sdk/testing.js +4 -1391
- package/dist/sdk/traceability/runtime-files-lookup.js +1 -32
- package/dist/sdk/traceability/source-traceability.js +1 -292
- package/dist/sdk/tracker-root-discovery.js +1 -9
- package/dist/sdk/workspace-contracts-cache.js +1 -28
- package/dist/sdk/workspace-contracts.js +1 -33
- package/dist/sdk/workspace-memory.js +2 -318
- package/dist/sdk/workspace-recipe.js +1 -71
- package/dist/sdk/workspace-snapshot.js +4 -613
- package/dist/sdk/workspace-transaction-gc.js +1 -149
- package/dist/sdk/workspace-transaction.js +2 -363
- package/dist/sdk/workspace.js +3 -127
- package/dist/types/index.js +1 -9
- package/dist/types.js +1 -245
- package/docs/AGENT_GUIDE.md +1 -1
- package/docs/CONTEXT_ALGORITHM_PORTFOLIO.md +167 -0
- package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +9 -3
- package/docs/EXTENSIONS.md +1 -0
- package/docs/HISTORY_MAINTENANCE.md +125 -0
- package/docs/MCP_2026_07_28_CONFORMANCE.md +20 -10
- package/docs/PACKAGE_EVIDENCE.md +92 -0
- package/docs/PLANNING_MEASUREMENTS.md +183 -0
- package/docs/README.md +3 -0
- package/docs/SCRIPTING.md +21 -0
- package/docs/TESTING.md +23 -0
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +5 -5
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +2 -2
- package/marketplace.json +2 -2
- package/package.json +1 -1
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/scripts/finalize-build.mjs +45 -3
- package/dist/cli-bundle/chunks/chunk-AZDFJGH6.js +0 -9
- package/dist/cli-bundle/chunks/chunk-BAX2BYUW.js +0 -2111
- package/dist/cli-bundle/chunks/chunk-CKOL5U7J.js +0 -77
- package/dist/cli-bundle/chunks/chunk-OF76PSDQ.js +0 -5
- package/dist/cli-bundle/chunks/chunk-QUWFABDM.js +0 -232
- package/dist/cli-bundle/chunks/chunk-QWRRFYK3.js +0 -2
- package/dist/cli-bundle/chunks/chunk-RWWBOWJ5.js +0 -2
- package/dist/cli-bundle/chunks/chunk-WGAOYSYH.js +0 -40
- package/dist/cli-bundle/chunks/chunk-WI2AYPA7.js +0 -2
- package/dist/cli-bundle/chunks/register-list-query-5JL52D33.js +0 -11
- package/dist/cli-bundle/chunks/register-mutation-ZPG7KMVP.js +0 -20
- package/dist/cli-bundle/chunks/register-setup-H4SVAVX7.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-AL5ON6K6.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-CHC2IDXA.js +0 -6
- package/dist/cli-bundle/focused-chunks/chunk-CK6QFAPZ.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-EZR3GHFE.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-H2WJWK7L.js +0 -56
- package/dist/cli-bundle/focused-chunks/chunk-NTPY5GSO.js +0 -3
- package/dist/cli-bundle/focused-chunks/chunk-P5O7MP5Y.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-PDMW2E36.js +0 -177
- package/dist/cli-bundle/focused-chunks/chunk-QTVCLMSZ.js +0 -6
- package/dist/cli-bundle/focused-chunks/chunk-QTZRBUYA.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-SGQST3PQ.js +0 -12
- package/dist/cli-bundle/focused-chunks/chunk-UKHASMMP.js +0 -10
- package/dist/cli-bundle/focused-chunks/chunk-ZPEKQHOC.js +0 -2
|
@@ -1,2224 +1,2 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module core/extensions/loader
|
|
3
|
-
*
|
|
4
|
-
* Implements extension runtime contracts and governance for Loader.
|
|
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]="e4e1b7c2-6551-5e56-b26a-30062aed5b97")}catch(e){}}();
|
|
8
|
-
import fs from "node:fs/promises";
|
|
9
|
-
import path from "node:path";
|
|
10
|
-
import { pathToFileURL } from "node:url";
|
|
11
|
-
import { pathExists } from "../fs/fs-utils.js";
|
|
12
|
-
import { isPathWithinDirectory } from "../fs/path-utils.js";
|
|
13
|
-
import { isHostOutputSuppressed, suppressHostOutput, } from "../output/output-control.js";
|
|
14
|
-
import { resolvePmPackageRootFromModule } from "../packages/root.js";
|
|
15
|
-
import { resolveGlobalPmRoot } from "../store/paths.js";
|
|
16
|
-
import { asRecordLoose, resolveActivatablePropertyRecord, } from "../shared/primitives.js";
|
|
17
|
-
import { flattenFlagListValue, isFlagDefaultValueCoercible, resolveFlagValueKind, } from "./flag-value-types.js";
|
|
18
|
-
import { KNOWN_ITEM_FIELD_TYPES, normalizeItemFieldType, suggestKnownItemFieldType, } from "./item-field-types.js";
|
|
19
|
-
import { snapshotExtensionModuleGraph } from "./module-graph-snapshot.js";
|
|
20
|
-
import { captureExtensionActivationRollback } from "./activation-transaction.js";
|
|
21
|
-
import { collectPreflightCollisionWarnings, normalizePreflightOverride, } from "./preflight-ownership.js";
|
|
22
|
-
import { normalizeServiceOverrideOwnership } from "./service-ownership.js";
|
|
23
|
-
import { assertCommandDefinitionMetadataStrings } from "./command-visibility-tier.js";
|
|
24
|
-
import { buildImportExportContext, resolveImportExportArtifactOutput, } from "./exporter-output-contract.js";
|
|
25
|
-
import { asRegistrationRecord, assertOptionalBooleanField, assertOptionalFlagDefaultField, assertOptionalStringArrayField, assertOptionalStringField, normalizeOptionalStringArrayField, } from "./registration-validation.js";
|
|
26
|
-
import { describeExtensionLongFlagFailure, findExtensionFlagTokenFailure, } from "./flag-definition-validation.js";
|
|
27
|
-
import { compareComparableVersions, evaluatePmMaxVersionBound, evaluatePmMinVersionBound, parseComparableVersion, } from "./version-compat.js";
|
|
28
|
-
import { createRelationshipKindRegistry, } from "../../sdk/relationships.js";
|
|
29
|
-
import { normalizeNames, isKnownExtensionCapability, collectUnknownExtensionCapabilities, normalizeManifestCapabilities, formatUnknownExtensionCapabilityWarning, formatLegacyExtensionCapabilityAliasWarning, } from "./extension-capability-aliases.js";
|
|
30
|
-
import { normalizeExtensionPolicy, serializeExtensionPolicy, hydrateExtensionPolicy, normalizePolicySandboxProfile, evaluateExtensionPolicyForExtension, evaluateExtensionPolicyForCapability, evaluateExtensionPolicyForRegistration, } from "./extension-policy.js";
|
|
31
|
-
import { createEmptyExtensionHookRegistry, createEmptyExtensionCommandRegistry, createEmptyExtensionParserRegistry, createEmptyExtensionPreflightRegistry, createEmptyExtensionServiceRegistry, createEmptyExtensionRendererRegistry, createEmptyExtensionRegistrationRegistry, } from "./extension-registries.js";
|
|
32
|
-
import { normalizeCommandName } from "./extension-runtime-helpers.js";
|
|
33
|
-
import { normalizeExtensionContributionInventory } from "./contribution-inventory.js";
|
|
34
|
-
import { formatExtensionManifestSchemaWarnings } from "./manifest-schema.js";
|
|
35
|
-
import { attachRuntimeDefinition, assertHookHandler, assertNonEmptyRegistrationString, assertRegistrationFunction, cloneRuntimeRegistrationValue, createRegistrationValidationError, extractRegistrationValidationTrace, isExtensionServiceName, isOutputRendererFormat, normalizeRegistrationRecord, normalizeRegistrationRecordList, normalizeRuntimeRegistrationRecord, normalizeRegistrationName, sanitizeRegistrationValue, toRegistrationCommandPath, validateAssuranceMeasurementProviderDefinition, } from "./registration-values.js";
|
|
36
|
-
import { buildReadyExtensionCandidate, } from "./extension-candidate.js";
|
|
37
|
-
export { parseUnknownExtensionCapabilityWarning, parseLegacyExtensionCapabilityAliasWarning, } from "./extension-capability-aliases.js";
|
|
38
|
-
export { createEmptyExtensionHookRegistry, createEmptyExtensionCommandRegistry, createEmptyExtensionParserRegistry, createEmptyExtensionPreflightRegistry, createEmptyExtensionServiceRegistry, createEmptyExtensionRendererRegistry, createEmptyExtensionRegistrationRegistry, } from "./extension-registries.js";
|
|
39
|
-
export { runBeforeCommandHooks, runBeforeMutationHooks, runAfterCommandHooks, runOnWriteHooks, runOnReadHooks, runOnIndexHooks, runCommandHandler, runParserOverride, runPreflightOverride, runServiceOverrideSync, runServiceOverride, runCommandOverride, runRendererOverride, } from "./extension-hook-runtime.js";
|
|
40
|
-
import { KNOWN_EXTENSION_CAPABILITIES, KNOWN_EXTENSION_SERVICE_NAMES, createDefaultExtensionGovernancePolicy, } from "./extension-types.js";
|
|
41
|
-
export * from "./extension-types.js";
|
|
42
|
-
/** Fallback extension priority used when callers do not provide an override. */
|
|
43
|
-
export const DEFAULT_EXTENSION_PRIORITY = 100;
|
|
44
|
-
let currentPmCliVersionPromise = null;
|
|
45
|
-
const DEFAULT_EXTENSION_POLICY = Object.freeze(createDefaultExtensionGovernancePolicy());
|
|
46
|
-
let extensionReloadEpoch = 0;
|
|
47
|
-
/** Implements next extension reload token for the public runtime surface of this module. */
|
|
48
|
-
export function nextExtensionReloadToken(seed = Date.now()) {
|
|
49
|
-
extensionReloadEpoch += 1;
|
|
50
|
-
return `${extensionReloadEpoch}-${seed}`;
|
|
51
|
-
}
|
|
52
|
-
function parseOptionalManifestString(candidate, field) {
|
|
53
|
-
const value = candidate[field];
|
|
54
|
-
if (value === undefined || value === null) {
|
|
55
|
-
return undefined;
|
|
56
|
-
}
|
|
57
|
-
if (typeof value !== "string" || value.trim().length === 0) {
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
return value.trim();
|
|
61
|
-
}
|
|
62
|
-
function parseManifestEngines(value) {
|
|
63
|
-
if (value === undefined || value === null) {
|
|
64
|
-
return undefined;
|
|
65
|
-
}
|
|
66
|
-
const enginesRecord = asRecordLoose(value);
|
|
67
|
-
if (!enginesRecord) {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
const engines = {};
|
|
71
|
-
for (const key of Object.keys(enginesRecord).sort((left, right) => left.localeCompare(right))) {
|
|
72
|
-
if (key.trim().length === 0) {
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
const engineValue = enginesRecord[key];
|
|
76
|
-
if (typeof engineValue !== "string" || engineValue.trim().length === 0) {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
engines[key.trim()] = engineValue.trim();
|
|
80
|
-
}
|
|
81
|
-
return Object.keys(engines).length > 0 ? engines : undefined;
|
|
82
|
-
}
|
|
83
|
-
/** Parse a required manifest string field, returning `null` when it is absent, non-string, or blank. */
|
|
84
|
-
function parseRequiredManifestString(candidate, field) {
|
|
85
|
-
const value = candidate[field];
|
|
86
|
-
if (typeof value !== "string" || value.trim().length === 0) {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
return value.trim();
|
|
90
|
-
}
|
|
91
|
-
/** Parse an optional integer value (`undefined` when absent, `null` when present but not an integer). */
|
|
92
|
-
function parseOptionalIntegerValue(value) {
|
|
93
|
-
if (value === undefined || value === null) {
|
|
94
|
-
return undefined;
|
|
95
|
-
}
|
|
96
|
-
if (typeof value !== "number" || !Number.isInteger(value)) {
|
|
97
|
-
return null;
|
|
98
|
-
}
|
|
99
|
-
return value;
|
|
100
|
-
}
|
|
101
|
-
/** Parse an optional boolean value (`undefined` when absent, `null` when present but not a boolean). */
|
|
102
|
-
function parseOptionalBooleanValue(value) {
|
|
103
|
-
if (value === undefined || value === null) {
|
|
104
|
-
return undefined;
|
|
105
|
-
}
|
|
106
|
-
if (typeof value !== "boolean") {
|
|
107
|
-
return null;
|
|
108
|
-
}
|
|
109
|
-
return value;
|
|
110
|
-
}
|
|
111
|
-
/** Parse the optional integer `priority`, defaulting to {@link DEFAULT_EXTENSION_PRIORITY} when absent and rejecting (`null`) a non-integer. */
|
|
112
|
-
function parseManifestPriority(candidate) {
|
|
113
|
-
const value = parseOptionalIntegerValue(candidate.priority);
|
|
114
|
-
return value === undefined ? DEFAULT_EXTENSION_PRIORITY : value;
|
|
115
|
-
}
|
|
116
|
-
/** Parse the optional `sandbox_profile`, rejecting (`null`) any value that does not round-trip through {@link normalizePolicySandboxProfile}. */
|
|
117
|
-
function parseManifestSandboxProfile(candidate) {
|
|
118
|
-
const value = candidate.sandbox_profile;
|
|
119
|
-
if (value === undefined || value === null) {
|
|
120
|
-
return undefined;
|
|
121
|
-
}
|
|
122
|
-
if (typeof value !== "string") {
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
const normalizedProfile = normalizePolicySandboxProfile(value);
|
|
126
|
-
if (normalizedProfile !== value.trim().toLowerCase()) {
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
return normalizedProfile;
|
|
130
|
-
}
|
|
131
|
-
/** Return the trimmed string when `value` is a non-blank string, otherwise `undefined`. */
|
|
132
|
-
function optionalTrimmedString(value) {
|
|
133
|
-
return typeof value === "string" && value.trim().length > 0
|
|
134
|
-
? value.trim()
|
|
135
|
-
: undefined;
|
|
136
|
-
}
|
|
137
|
-
/** Parse the optional `provenance` record (`undefined` absent, `null` malformed), keeping only the present trimmed string fields and a boolean `verified`. */
|
|
138
|
-
function parseManifestProvenance(value) {
|
|
139
|
-
if (value === undefined || value === null) {
|
|
140
|
-
return undefined;
|
|
141
|
-
}
|
|
142
|
-
const provenanceRecord = asRecordLoose(value);
|
|
143
|
-
if (!provenanceRecord) {
|
|
144
|
-
return null;
|
|
145
|
-
}
|
|
146
|
-
const source = optionalTrimmedString(provenanceRecord.source);
|
|
147
|
-
const signature = optionalTrimmedString(provenanceRecord.signature);
|
|
148
|
-
const attestation = optionalTrimmedString(provenanceRecord.attestation);
|
|
149
|
-
const verified = provenanceRecord.verified === undefined ||
|
|
150
|
-
provenanceRecord.verified === null
|
|
151
|
-
? undefined
|
|
152
|
-
: typeof provenanceRecord.verified === "boolean"
|
|
153
|
-
? provenanceRecord.verified
|
|
154
|
-
: null;
|
|
155
|
-
if (verified === null) {
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
return {
|
|
159
|
-
...(source ? { source } : {}),
|
|
160
|
-
...(signature ? { signature } : {}),
|
|
161
|
-
...(attestation ? { attestation } : {}),
|
|
162
|
-
...(typeof verified === "boolean" ? { verified } : {}),
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
/** Parse the optional `permissions` record (`undefined` absent, `null` malformed), keeping only the boolean grants that are present. */
|
|
166
|
-
function parseManifestPermissions(value) {
|
|
167
|
-
if (value === undefined || value === null) {
|
|
168
|
-
return undefined;
|
|
169
|
-
}
|
|
170
|
-
const permissionsRecord = asRecordLoose(value);
|
|
171
|
-
if (!permissionsRecord) {
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
const fsRead = parseOptionalBooleanValue(permissionsRecord.fs_read);
|
|
175
|
-
const fsWrite = parseOptionalBooleanValue(permissionsRecord.fs_write);
|
|
176
|
-
const network = parseOptionalBooleanValue(permissionsRecord.network);
|
|
177
|
-
const envRead = parseOptionalBooleanValue(permissionsRecord.env_read);
|
|
178
|
-
const envWrite = parseOptionalBooleanValue(permissionsRecord.env_write);
|
|
179
|
-
const processSpawn = parseOptionalBooleanValue(permissionsRecord.process_spawn);
|
|
180
|
-
if ([fsRead, fsWrite, network, envRead, envWrite, processSpawn].includes(null)) {
|
|
181
|
-
return null;
|
|
182
|
-
}
|
|
183
|
-
return {
|
|
184
|
-
...(typeof fsRead === "boolean" ? { fs_read: fsRead } : {}),
|
|
185
|
-
...(typeof fsWrite === "boolean" ? { fs_write: fsWrite } : {}),
|
|
186
|
-
...(typeof network === "boolean" ? { network } : {}),
|
|
187
|
-
...(typeof envRead === "boolean" ? { env_read: envRead } : {}),
|
|
188
|
-
...(typeof envWrite === "boolean" ? { env_write: envWrite } : {}),
|
|
189
|
-
...(typeof processSpawn === "boolean"
|
|
190
|
-
? { process_spawn: processSpawn }
|
|
191
|
-
: {}),
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
/** Parse the optional `capabilities` array, normalizing legacy aliases; returns empty lists when absent and `null` when the field is not a string array. */
|
|
195
|
-
function parseManifestCapabilities(value) {
|
|
196
|
-
if (value === undefined || value === null) {
|
|
197
|
-
return { capabilities: [], legacy_aliases: [] };
|
|
198
|
-
}
|
|
199
|
-
if (!Array.isArray(value) ||
|
|
200
|
-
value.some((entry) => typeof entry !== "string")) {
|
|
201
|
-
return null;
|
|
202
|
-
}
|
|
203
|
-
const normalizedCapabilities = normalizeManifestCapabilities(value);
|
|
204
|
-
return {
|
|
205
|
-
capabilities: normalizedCapabilities.capabilities,
|
|
206
|
-
legacy_aliases: normalizedCapabilities.legacy_aliases,
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
/** Parse the optional `activation` block, returning the de-duplicated sorted `commands` set, `undefined` when no command activation is declared, and `null` when the block is malformed. */
|
|
210
|
-
function parseManifestActivation(value) {
|
|
211
|
-
if (value === undefined || value === null) {
|
|
212
|
-
return undefined;
|
|
213
|
-
}
|
|
214
|
-
const activationRecord = asRecordLoose(value);
|
|
215
|
-
if (!activationRecord) {
|
|
216
|
-
return null;
|
|
217
|
-
}
|
|
218
|
-
const rawCommands = activationRecord.commands;
|
|
219
|
-
if (rawCommands === undefined || rawCommands === null) {
|
|
220
|
-
return undefined;
|
|
221
|
-
}
|
|
222
|
-
if (!Array.isArray(rawCommands) ||
|
|
223
|
-
rawCommands.some((entry) => typeof entry !== "string")) {
|
|
224
|
-
return null;
|
|
225
|
-
}
|
|
226
|
-
const commands = [
|
|
227
|
-
...new Set(rawCommands
|
|
228
|
-
.map((entry) => normalizeCommandName(entry))
|
|
229
|
-
.filter((entry) => entry.length > 0)),
|
|
230
|
-
].sort((left, right) => left.localeCompare(right));
|
|
231
|
-
return commands.length > 0 ? { commands } : undefined;
|
|
232
|
-
}
|
|
233
|
-
/** Parse every optional manifest metadata field, returning `null` as soon as any one is malformed. */
|
|
234
|
-
function parseManifestMetadata(candidate) {
|
|
235
|
-
const manifestVersion = parseOptionalIntegerValue(candidate.manifest_version);
|
|
236
|
-
if (manifestVersion === null) {
|
|
237
|
-
return null;
|
|
238
|
-
}
|
|
239
|
-
const pmMinVersion = parseOptionalManifestString(candidate, "pm_min_version");
|
|
240
|
-
if (pmMinVersion === null) {
|
|
241
|
-
return null;
|
|
242
|
-
}
|
|
243
|
-
const pmMaxVersion = parseOptionalManifestString(candidate, "pm_max_version");
|
|
244
|
-
if (pmMaxVersion === null) {
|
|
245
|
-
return null;
|
|
246
|
-
}
|
|
247
|
-
const engines = parseManifestEngines(candidate.engines);
|
|
248
|
-
if (engines === null) {
|
|
249
|
-
return null;
|
|
250
|
-
}
|
|
251
|
-
const trusted = parseOptionalBooleanValue(candidate.trusted);
|
|
252
|
-
if (trusted === null) {
|
|
253
|
-
return null;
|
|
254
|
-
}
|
|
255
|
-
const sandboxProfile = parseManifestSandboxProfile(candidate);
|
|
256
|
-
if (sandboxProfile === null) {
|
|
257
|
-
return null;
|
|
258
|
-
}
|
|
259
|
-
const provenance = parseManifestProvenance(candidate.provenance);
|
|
260
|
-
if (provenance === null) {
|
|
261
|
-
return null;
|
|
262
|
-
}
|
|
263
|
-
const permissions = parseManifestPermissions(candidate.permissions);
|
|
264
|
-
if (permissions === null) {
|
|
265
|
-
return null;
|
|
266
|
-
}
|
|
267
|
-
const capabilities = parseManifestCapabilities(candidate.capabilities);
|
|
268
|
-
if (capabilities === null) {
|
|
269
|
-
return null;
|
|
270
|
-
}
|
|
271
|
-
const activation = parseManifestActivation(candidate.activation);
|
|
272
|
-
if (activation === null) {
|
|
273
|
-
return null;
|
|
274
|
-
}
|
|
275
|
-
const contributions = normalizeExtensionContributionInventory(candidate.contributions);
|
|
276
|
-
if (contributions === null) {
|
|
277
|
-
return null;
|
|
278
|
-
}
|
|
279
|
-
return {
|
|
280
|
-
manifest_version: manifestVersion,
|
|
281
|
-
pm_min_version: pmMinVersion,
|
|
282
|
-
pm_max_version: pmMaxVersion,
|
|
283
|
-
engines,
|
|
284
|
-
trusted,
|
|
285
|
-
sandbox_profile: sandboxProfile,
|
|
286
|
-
provenance,
|
|
287
|
-
permissions,
|
|
288
|
-
capabilities: capabilities.capabilities,
|
|
289
|
-
legacy_capability_aliases: capabilities.legacy_aliases,
|
|
290
|
-
activation,
|
|
291
|
-
contributions,
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
/** Parse and normalize one complete on-disk extension manifest contract. */
|
|
295
|
-
export function parseExtensionManifestDocument(raw) {
|
|
296
|
-
if (typeof raw !== "object" || raw === null) {
|
|
297
|
-
return null;
|
|
298
|
-
}
|
|
299
|
-
const candidate = raw;
|
|
300
|
-
const name = parseRequiredManifestString(candidate, "name");
|
|
301
|
-
if (name === null) {
|
|
302
|
-
return null;
|
|
303
|
-
}
|
|
304
|
-
const version = parseRequiredManifestString(candidate, "version");
|
|
305
|
-
if (version === null) {
|
|
306
|
-
return null;
|
|
307
|
-
}
|
|
308
|
-
const entry = parseRequiredManifestString(candidate, "entry");
|
|
309
|
-
if (entry === null) {
|
|
310
|
-
return null;
|
|
311
|
-
}
|
|
312
|
-
const priority = parseManifestPriority(candidate);
|
|
313
|
-
if (priority === null) {
|
|
314
|
-
return null;
|
|
315
|
-
}
|
|
316
|
-
const metadata = parseManifestMetadata(candidate);
|
|
317
|
-
if (metadata === null) {
|
|
318
|
-
return null;
|
|
319
|
-
}
|
|
320
|
-
return {
|
|
321
|
-
name,
|
|
322
|
-
version,
|
|
323
|
-
entry,
|
|
324
|
-
priority,
|
|
325
|
-
manifest_version: metadata.manifest_version,
|
|
326
|
-
pm_min_version: metadata.pm_min_version,
|
|
327
|
-
pm_max_version: metadata.pm_max_version,
|
|
328
|
-
engines: metadata.engines,
|
|
329
|
-
trusted: metadata.trusted,
|
|
330
|
-
provenance: metadata.provenance,
|
|
331
|
-
sandbox_profile: metadata.sandbox_profile,
|
|
332
|
-
permissions: metadata.permissions,
|
|
333
|
-
activation: metadata.activation,
|
|
334
|
-
contributions: metadata.contributions,
|
|
335
|
-
capabilities: metadata.capabilities,
|
|
336
|
-
legacy_capability_aliases: metadata.legacy_capability_aliases.length > 0
|
|
337
|
-
? metadata.legacy_capability_aliases
|
|
338
|
-
: undefined,
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
function shouldEnable(name, enabled, disabled) {
|
|
342
|
-
if (disabled.has(name)) {
|
|
343
|
-
return false;
|
|
344
|
-
}
|
|
345
|
-
if (enabled.size === 0) {
|
|
346
|
-
return true;
|
|
347
|
-
}
|
|
348
|
-
return enabled.has(name);
|
|
349
|
-
}
|
|
350
|
-
/** Resolve symlinks on both paths before the containment check so a link inside the directory cannot escape it. */
|
|
351
|
-
export async function isCanonicalPathWithinDirectory(directory, targetPath) {
|
|
352
|
-
const [resolvedDirectory, resolvedTargetPath] = await Promise.all([
|
|
353
|
-
fs.realpath(directory),
|
|
354
|
-
fs.realpath(targetPath),
|
|
355
|
-
]);
|
|
356
|
-
return isPathWithinDirectory(resolvedDirectory, resolvedTargetPath);
|
|
357
|
-
}
|
|
358
|
-
/** Implements resolve extension roots for the public runtime surface of this module. */
|
|
359
|
-
export function resolveExtensionRoots(pmRoot, cwd = process.cwd()) {
|
|
360
|
-
return {
|
|
361
|
-
global: path.join(resolveGlobalPmRoot(cwd), "extensions"),
|
|
362
|
-
project: path.join(pmRoot, "extensions"),
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
async function listExtensionDirectories(extensionsRoot) {
|
|
366
|
-
try {
|
|
367
|
-
const entries = await fs.readdir(extensionsRoot, { withFileTypes: true });
|
|
368
|
-
return entries
|
|
369
|
-
.filter((entry) => entry.isDirectory())
|
|
370
|
-
.map((entry) => entry.name)
|
|
371
|
-
.sort((a, b) => a.localeCompare(b));
|
|
372
|
-
}
|
|
373
|
-
catch {
|
|
374
|
-
return [];
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
function summarizeCandidate(candidate) {
|
|
378
|
-
const summary = {
|
|
379
|
-
layer: candidate.layer,
|
|
380
|
-
directory: candidate.directory,
|
|
381
|
-
manifest_path: candidate.manifest_path,
|
|
382
|
-
name: candidate.manifest.name,
|
|
383
|
-
version: candidate.manifest.version,
|
|
384
|
-
entry: candidate.manifest.entry,
|
|
385
|
-
priority: candidate.manifest.priority,
|
|
386
|
-
entry_path: candidate.entry_path,
|
|
387
|
-
manifest_version: candidate.manifest.manifest_version,
|
|
388
|
-
pm_min_version: candidate.manifest.pm_min_version,
|
|
389
|
-
pm_max_version: candidate.manifest.pm_max_version,
|
|
390
|
-
engines: candidate.manifest.engines,
|
|
391
|
-
trusted: candidate.manifest.trusted,
|
|
392
|
-
provenance: candidate.manifest.provenance,
|
|
393
|
-
sandbox_profile: candidate.manifest.sandbox_profile,
|
|
394
|
-
permissions: candidate.manifest.permissions,
|
|
395
|
-
capabilities: [...candidate.manifest.capabilities],
|
|
396
|
-
activation: candidate.manifest.activation
|
|
397
|
-
? {
|
|
398
|
-
commands: [...candidate.manifest.activation.commands],
|
|
399
|
-
}
|
|
400
|
-
: undefined,
|
|
401
|
-
contributions: candidate.manifest.contributions ?? candidate.contributions,
|
|
402
|
-
};
|
|
403
|
-
if (candidate.source_package) {
|
|
404
|
-
summary.source_package = candidate.source_package;
|
|
405
|
-
}
|
|
406
|
-
if (candidate.source_aliases) {
|
|
407
|
-
summary.source_aliases = [...candidate.source_aliases];
|
|
408
|
-
}
|
|
409
|
-
return summary;
|
|
410
|
-
}
|
|
411
|
-
function normalizeManagedSourcePackage(value) {
|
|
412
|
-
return typeof value === "string" && value.trim().length > 0
|
|
413
|
-
? value.trim()
|
|
414
|
-
: undefined;
|
|
415
|
-
}
|
|
416
|
-
async function readManagedExtensionSourcePackages(extensionsRoot) {
|
|
417
|
-
const packages = new Map();
|
|
418
|
-
try {
|
|
419
|
-
const parsed = JSON.parse(await fs.readFile(path.join(extensionsRoot, ".managed-extensions.json"), "utf8"));
|
|
420
|
-
const managedExtensions = asRecordLoose(parsed);
|
|
421
|
-
const entries = managedExtensions?.entries;
|
|
422
|
-
if (!Array.isArray(entries)) {
|
|
423
|
-
return packages;
|
|
424
|
-
}
|
|
425
|
-
for (const entry of entries) {
|
|
426
|
-
if (typeof entry !== "object" || entry === null) {
|
|
427
|
-
continue;
|
|
428
|
-
}
|
|
429
|
-
const record = entry;
|
|
430
|
-
const sourcePackage = normalizeManagedSourcePackage(record.source?.package);
|
|
431
|
-
const aliases = [record.source?.input, record.source?.name, sourcePackage]
|
|
432
|
-
.map((value) => normalizeManagedSourcePackage(value))
|
|
433
|
-
.filter((value) => value !== undefined);
|
|
434
|
-
const contributions = normalizeExtensionContributionInventory(record.contributions);
|
|
435
|
-
const identity = {
|
|
436
|
-
aliases: [...new Set(aliases)],
|
|
437
|
-
...(sourcePackage ? { package_name: sourcePackage } : {}),
|
|
438
|
-
...(contributions ? { contributions } : {}),
|
|
439
|
-
};
|
|
440
|
-
if (typeof record.directory === "string" &&
|
|
441
|
-
record.directory.trim().length > 0) {
|
|
442
|
-
packages.set(`directory:${record.directory.trim()}`, identity);
|
|
443
|
-
}
|
|
444
|
-
if (typeof record.name === "string" && record.name.trim().length > 0) {
|
|
445
|
-
packages.set(`name:${record.name.trim()}`, identity);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
catch {
|
|
450
|
-
return packages;
|
|
451
|
-
}
|
|
452
|
-
return packages;
|
|
453
|
-
}
|
|
454
|
-
function sortCandidates(candidates) {
|
|
455
|
-
return [...candidates].sort((left, right) => {
|
|
456
|
-
if (left.manifest.priority !== right.manifest.priority) {
|
|
457
|
-
return left.manifest.priority - right.manifest.priority;
|
|
458
|
-
}
|
|
459
|
-
const byName = left.manifest.name.localeCompare(right.manifest.name);
|
|
460
|
-
if (byName !== 0) {
|
|
461
|
-
return byName;
|
|
462
|
-
}
|
|
463
|
-
return left.directory.localeCompare(right.directory);
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
function buildEffectiveExtensions(globalCandidates, projectCandidates) {
|
|
467
|
-
const ordered = [
|
|
468
|
-
...sortCandidates(globalCandidates),
|
|
469
|
-
...sortCandidates(projectCandidates),
|
|
470
|
-
];
|
|
471
|
-
const effective = [];
|
|
472
|
-
for (const candidate of ordered) {
|
|
473
|
-
const existingIndex = effective.findIndex((entry) => entry.manifest.name === candidate.manifest.name);
|
|
474
|
-
if (existingIndex >= 0) {
|
|
475
|
-
effective.splice(existingIndex, 1);
|
|
476
|
-
}
|
|
477
|
-
effective.push(candidate);
|
|
478
|
-
}
|
|
479
|
-
return effective;
|
|
480
|
-
}
|
|
481
|
-
async function scanExtensionLayer(layer, extensionsRoot, enabled, disabled, pmMaxVersionExceededMode) {
|
|
482
|
-
const diagnostics = [];
|
|
483
|
-
const warnings = [];
|
|
484
|
-
const candidates = [];
|
|
485
|
-
const directories = await listExtensionDirectories(extensionsRoot);
|
|
486
|
-
const managedSourcePackages = await readManagedExtensionSourcePackages(extensionsRoot);
|
|
487
|
-
for (const directory of directories) {
|
|
488
|
-
const scanned = await scanExtensionDirectory(layer, extensionsRoot, directory, enabled, disabled, managedSourcePackages, pmMaxVersionExceededMode);
|
|
489
|
-
diagnostics.push(scanned.diagnostic);
|
|
490
|
-
warnings.push(...scanned.warnings);
|
|
491
|
-
if (scanned.candidate) {
|
|
492
|
-
candidates.push(scanned.candidate);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
return { diagnostics, warnings, candidates };
|
|
496
|
-
}
|
|
497
|
-
function emptyExtensionLayerScan() {
|
|
498
|
-
return { diagnostics: [], warnings: [], candidates: [] };
|
|
499
|
-
}
|
|
500
|
-
/** Build the `warn`-status scan result for a directory whose manifest is missing or unparseable, carrying the supplied diagnostic warning and no candidate. */
|
|
501
|
-
function buildUnavailableExtensionScan(layer, directory, manifestPath, warning) {
|
|
502
|
-
return {
|
|
503
|
-
diagnostic: {
|
|
504
|
-
layer,
|
|
505
|
-
directory,
|
|
506
|
-
manifest_path: manifestPath,
|
|
507
|
-
name: null,
|
|
508
|
-
version: null,
|
|
509
|
-
entry: null,
|
|
510
|
-
priority: null,
|
|
511
|
-
entry_path: null,
|
|
512
|
-
enabled: null,
|
|
513
|
-
status: "warn",
|
|
514
|
-
},
|
|
515
|
-
warnings: [warning],
|
|
516
|
-
candidate: null,
|
|
517
|
-
};
|
|
518
|
-
}
|
|
519
|
-
/** Collect the non-fatal load warnings for a parsed extension manifest, in detection order: legacy capability aliases, unknown capabilities, an entry outside or absent from the extension directory, then the pm version floor/ceiling incompatibility warnings. */
|
|
520
|
-
function collectScannedExtensionWarnings(layer, manifest, rawManifest, entryWithinDirectory, entryExists, pmVersionCompatibility, pmMaxVersionCompatibility) {
|
|
521
|
-
const extensionWarnings = formatExtensionManifestSchemaWarnings(layer, manifest, rawManifest);
|
|
522
|
-
if (Array.isArray(manifest.legacy_capability_aliases) &&
|
|
523
|
-
manifest.legacy_capability_aliases.length > 0) {
|
|
524
|
-
extensionWarnings.push(formatLegacyExtensionCapabilityAliasWarning(layer, manifest.name, manifest.legacy_capability_aliases));
|
|
525
|
-
}
|
|
526
|
-
for (const capability of collectUnknownExtensionCapabilities(manifest.capabilities)) {
|
|
527
|
-
extensionWarnings.push(formatUnknownExtensionCapabilityWarning(layer, manifest.name, capability));
|
|
528
|
-
}
|
|
529
|
-
if (!entryWithinDirectory) {
|
|
530
|
-
extensionWarnings.push(`extension_entry_outside_extension:${layer}:${manifest.name}`);
|
|
531
|
-
}
|
|
532
|
-
else if (!entryExists) {
|
|
533
|
-
extensionWarnings.push(`extension_entry_missing:${layer}:${manifest.name}`);
|
|
534
|
-
}
|
|
535
|
-
if (pmVersionCompatibility.warning) {
|
|
536
|
-
extensionWarnings.push(pmVersionCompatibility.warning);
|
|
537
|
-
}
|
|
538
|
-
if (pmMaxVersionCompatibility.warning) {
|
|
539
|
-
extensionWarnings.push(pmMaxVersionCompatibility.warning);
|
|
540
|
-
}
|
|
541
|
-
return extensionWarnings;
|
|
542
|
-
}
|
|
543
|
-
async function scanExtensionDirectory(layer, extensionsRoot, directory, enabled, disabled, managedSourcePackages, pmMaxVersionExceededMode) {
|
|
544
|
-
const extensionDir = path.join(extensionsRoot, directory);
|
|
545
|
-
const manifestPath = path.join(extensionDir, "manifest.json");
|
|
546
|
-
if (!(await pathExists(manifestPath))) {
|
|
547
|
-
return buildUnavailableExtensionScan(layer, directory, manifestPath, `extension_manifest_missing:${layer}:${directory}`);
|
|
548
|
-
}
|
|
549
|
-
let manifest;
|
|
550
|
-
let rawManifest;
|
|
551
|
-
try {
|
|
552
|
-
const parsed = JSON.parse(await fs.readFile(manifestPath, "utf8"));
|
|
553
|
-
rawManifest = asRecordLoose(parsed);
|
|
554
|
-
manifest = parseExtensionManifestDocument(parsed);
|
|
555
|
-
}
|
|
556
|
-
catch {
|
|
557
|
-
rawManifest = null;
|
|
558
|
-
manifest = null;
|
|
559
|
-
}
|
|
560
|
-
if (!manifest || !rawManifest) {
|
|
561
|
-
return buildUnavailableExtensionScan(layer, directory, manifestPath, `extension_manifest_invalid:${layer}:${directory}`);
|
|
562
|
-
}
|
|
563
|
-
const entryPath = path.resolve(extensionDir, manifest.entry);
|
|
564
|
-
const entryWithinDirectoryByPath = isPathWithinDirectory(extensionDir, entryPath);
|
|
565
|
-
const entryExists = entryWithinDirectoryByPath
|
|
566
|
-
? await pathExists(entryPath)
|
|
567
|
-
: false;
|
|
568
|
-
const entryWithinDirectory = entryWithinDirectoryByPath && entryExists
|
|
569
|
-
? await isCanonicalPathWithinDirectory(extensionDir, entryPath)
|
|
570
|
-
: entryWithinDirectoryByPath;
|
|
571
|
-
const enabledForLoad = shouldEnable(manifest.name, enabled, disabled);
|
|
572
|
-
const pmVersionCompatibility = await evaluatePmMinVersionCompatibility(layer, manifest);
|
|
573
|
-
const pmMaxVersionCompatibility = await evaluatePmMaxVersionCompatibility(layer, manifest, pmMaxVersionExceededMode);
|
|
574
|
-
const extensionWarnings = collectScannedExtensionWarnings(layer, manifest, rawManifest, entryWithinDirectory, entryExists, pmVersionCompatibility, pmMaxVersionCompatibility);
|
|
575
|
-
const extensionReady = entryWithinDirectory &&
|
|
576
|
-
entryExists &&
|
|
577
|
-
pmVersionCompatibility.allowed &&
|
|
578
|
-
pmMaxVersionCompatibility.allowed;
|
|
579
|
-
const sourceIdentity = managedSourcePackages.get(`directory:${directory}`) ??
|
|
580
|
-
managedSourcePackages.get(`name:${manifest.name}`);
|
|
581
|
-
return {
|
|
582
|
-
diagnostic: {
|
|
583
|
-
layer,
|
|
584
|
-
directory,
|
|
585
|
-
manifest_path: manifestPath,
|
|
586
|
-
name: manifest.name,
|
|
587
|
-
version: manifest.version,
|
|
588
|
-
entry: manifest.entry,
|
|
589
|
-
priority: manifest.priority,
|
|
590
|
-
entry_path: entryPath,
|
|
591
|
-
enabled: enabledForLoad,
|
|
592
|
-
status: extensionReady ? "ok" : "warn",
|
|
593
|
-
},
|
|
594
|
-
warnings: extensionWarnings,
|
|
595
|
-
candidate: buildReadyExtensionCandidate({
|
|
596
|
-
layer,
|
|
597
|
-
directory,
|
|
598
|
-
manifestPath,
|
|
599
|
-
entryPath,
|
|
600
|
-
manifest,
|
|
601
|
-
sourceIdentity,
|
|
602
|
-
extensionReady,
|
|
603
|
-
enabledForLoad,
|
|
604
|
-
}),
|
|
605
|
-
};
|
|
606
|
-
}
|
|
607
|
-
/** Implements discover extensions for the public runtime surface of this module. */
|
|
608
|
-
export async function discoverExtensions(options) {
|
|
609
|
-
const roots = resolveExtensionRoots(options.pmRoot, options.cwd ?? process.cwd());
|
|
610
|
-
const configured_enabled = normalizeNames(options.settings.extensions.enabled);
|
|
611
|
-
const configured_disabled = normalizeNames(options.settings.extensions.disabled);
|
|
612
|
-
const policy = normalizeExtensionPolicy(options.settings);
|
|
613
|
-
const serializedPolicy = serializeExtensionPolicy(policy);
|
|
614
|
-
if (options.noExtensions) {
|
|
615
|
-
return {
|
|
616
|
-
disabled_by_flag: true,
|
|
617
|
-
roots,
|
|
618
|
-
configured_enabled,
|
|
619
|
-
configured_disabled,
|
|
620
|
-
discovered: [],
|
|
621
|
-
effective: [],
|
|
622
|
-
warnings: [...policy.warnings],
|
|
623
|
-
policy: serializedPolicy,
|
|
624
|
-
};
|
|
625
|
-
}
|
|
626
|
-
const enabled = new Set(configured_enabled);
|
|
627
|
-
const disabled = new Set(configured_disabled);
|
|
628
|
-
const globalScan = options.ignoreGlobalExtensions === true
|
|
629
|
-
? emptyExtensionLayerScan()
|
|
630
|
-
: await scanExtensionLayer("global", roots.global, enabled, disabled, policy.pmMaxVersionExceededMode.global);
|
|
631
|
-
const projectScan = await scanExtensionLayer("project", roots.project, enabled, disabled, policy.pmMaxVersionExceededMode.project);
|
|
632
|
-
const policyWarnings = [...policy.warnings];
|
|
633
|
-
const effectiveCandidates = buildEffectiveExtensions(globalScan.candidates, projectScan.candidates);
|
|
634
|
-
const effective = [];
|
|
635
|
-
for (const candidate of effectiveCandidates) {
|
|
636
|
-
const extensionRef = {
|
|
637
|
-
layer: candidate.layer,
|
|
638
|
-
name: candidate.manifest.name,
|
|
639
|
-
trusted: candidate.manifest.trusted === true,
|
|
640
|
-
provenanceVerified: candidate.manifest.provenance?.verified === true,
|
|
641
|
-
sandboxProfile: candidate.manifest.sandbox_profile,
|
|
642
|
-
permissions: candidate.manifest.permissions &&
|
|
643
|
-
typeof candidate.manifest.permissions === "object"
|
|
644
|
-
? {
|
|
645
|
-
fs_read: candidate.manifest.permissions.fs_read,
|
|
646
|
-
fs_write: candidate.manifest.permissions.fs_write,
|
|
647
|
-
network: candidate.manifest.permissions.network,
|
|
648
|
-
env_read: candidate.manifest.permissions.env_read,
|
|
649
|
-
env_write: candidate.manifest.permissions.env_write,
|
|
650
|
-
process_spawn: candidate.manifest.permissions.process_spawn,
|
|
651
|
-
}
|
|
652
|
-
: undefined,
|
|
653
|
-
};
|
|
654
|
-
const extensionDecision = evaluateExtensionPolicyForExtension(policy, extensionRef);
|
|
655
|
-
if (extensionDecision.warning) {
|
|
656
|
-
policyWarnings.push(extensionDecision.warning);
|
|
657
|
-
}
|
|
658
|
-
if (!extensionDecision.allowed) {
|
|
659
|
-
continue;
|
|
660
|
-
}
|
|
661
|
-
for (const capability of candidate.manifest.capabilities) {
|
|
662
|
-
const capabilityDecision = evaluateExtensionPolicyForCapability(policy, extensionRef, capability);
|
|
663
|
-
if (capabilityDecision.warning) {
|
|
664
|
-
policyWarnings.push(capabilityDecision.warning);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
effective.push(summarizeCandidate(candidate));
|
|
668
|
-
}
|
|
669
|
-
return {
|
|
670
|
-
disabled_by_flag: false,
|
|
671
|
-
roots,
|
|
672
|
-
configured_enabled,
|
|
673
|
-
configured_disabled,
|
|
674
|
-
discovered: [...globalScan.diagnostics, ...projectScan.diagnostics],
|
|
675
|
-
effective,
|
|
676
|
-
warnings: [
|
|
677
|
-
...new Set([
|
|
678
|
-
...globalScan.warnings,
|
|
679
|
-
...projectScan.warnings,
|
|
680
|
-
...policyWarnings,
|
|
681
|
-
]),
|
|
682
|
-
],
|
|
683
|
-
policy: serializedPolicy,
|
|
684
|
-
};
|
|
685
|
-
}
|
|
686
|
-
function formatUnknownError(error) {
|
|
687
|
-
if (error instanceof Error && error.message.trim().length > 0) {
|
|
688
|
-
return error.message;
|
|
689
|
-
}
|
|
690
|
-
return String(error);
|
|
691
|
-
}
|
|
692
|
-
async function readCurrentPmCliVersion() {
|
|
693
|
-
try {
|
|
694
|
-
const packageRoot = resolvePmPackageRootFromModule(import.meta.url, [
|
|
695
|
-
"../../..",
|
|
696
|
-
]);
|
|
697
|
-
const raw = await fs.readFile(path.join(packageRoot, "package.json"), "utf8");
|
|
698
|
-
const parsed = JSON.parse(raw);
|
|
699
|
-
return typeof parsed.version === "string" &&
|
|
700
|
-
parsed.version.trim().length > 0
|
|
701
|
-
? parsed.version.trim()
|
|
702
|
-
: null;
|
|
703
|
-
}
|
|
704
|
-
catch {
|
|
705
|
-
return null;
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
function resolveCurrentPmCliVersion() {
|
|
709
|
-
currentPmCliVersionPromise ??= readCurrentPmCliVersion();
|
|
710
|
-
return currentPmCliVersionPromise;
|
|
711
|
-
}
|
|
712
|
-
function formatPmVersionCompatibilityWarning(layer, manifest, evaluation) {
|
|
713
|
-
const current = evaluation.current ?? "unknown";
|
|
714
|
-
if (evaluation.kind === "pm_min_version") {
|
|
715
|
-
switch (evaluation.status) {
|
|
716
|
-
case "invalid":
|
|
717
|
-
return `extension_pm_min_version_invalid:${layer}:${manifest.name}:required=${evaluation.required}`;
|
|
718
|
-
case "unchecked":
|
|
719
|
-
return `extension_pm_min_version_unchecked:${layer}:${manifest.name}:required=${evaluation.required}:current=${current}`;
|
|
720
|
-
case "unmet":
|
|
721
|
-
return `extension_pm_min_version_unmet:${layer}:${manifest.name}:required=${evaluation.required}:current=${current}`;
|
|
722
|
-
default:
|
|
723
|
-
return undefined;
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
switch (evaluation.status) {
|
|
727
|
-
case "invalid":
|
|
728
|
-
return `extension_pm_max_version_invalid:${layer}:${manifest.name}:allowed=${evaluation.required}`;
|
|
729
|
-
case "unchecked":
|
|
730
|
-
return `extension_pm_max_version_unchecked:${layer}:${manifest.name}:allowed=${evaluation.required}:current=${current}`;
|
|
731
|
-
case "exceeded_warn":
|
|
732
|
-
return `extension_pm_max_version_exceeded_warn:${layer}:${manifest.name}:allowed=${evaluation.required}:current=${current}`;
|
|
733
|
-
case "exceeded":
|
|
734
|
-
return `extension_pm_max_version_exceeded:${layer}:${manifest.name}:allowed=${evaluation.required}:current=${current}`;
|
|
735
|
-
default:
|
|
736
|
-
return undefined;
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
async function evaluatePmMinVersionCompatibility(layer, manifest) {
|
|
740
|
-
// Resolve the current CLI version only when a bound is declared, so the common
|
|
741
|
-
// no-bound case never reads package.json.
|
|
742
|
-
if (manifest.pm_min_version === undefined) {
|
|
743
|
-
return { allowed: true };
|
|
744
|
-
}
|
|
745
|
-
const evaluation = evaluatePmMinVersionBound(manifest.pm_min_version, await resolveCurrentPmCliVersion());
|
|
746
|
-
const warning = formatPmVersionCompatibilityWarning(layer, manifest, evaluation);
|
|
747
|
-
return warning
|
|
748
|
-
? { allowed: evaluation.allowed, warning }
|
|
749
|
-
: { allowed: evaluation.allowed };
|
|
750
|
-
}
|
|
751
|
-
async function evaluatePmMaxVersionCompatibility(layer, manifest, exceededMode) {
|
|
752
|
-
if (manifest.pm_max_version === undefined) {
|
|
753
|
-
return { allowed: true };
|
|
754
|
-
}
|
|
755
|
-
const evaluation = evaluatePmMaxVersionBound(manifest.pm_max_version, await resolveCurrentPmCliVersion(), exceededMode);
|
|
756
|
-
const warning = formatPmVersionCompatibilityWarning(layer, manifest, evaluation);
|
|
757
|
-
return warning
|
|
758
|
-
? { allowed: evaluation.allowed, warning }
|
|
759
|
-
: { allowed: evaluation.allowed };
|
|
760
|
-
}
|
|
761
|
-
async function fingerprintPath(pathToInspect) {
|
|
762
|
-
try {
|
|
763
|
-
const stats = await fs.stat(pathToInspect);
|
|
764
|
-
return `${Math.trunc(stats.mtimeMs)}-${stats.size}`;
|
|
765
|
-
}
|
|
766
|
-
catch {
|
|
767
|
-
return "missing";
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
async function resolveExtensionImportHref(extension, options) {
|
|
771
|
-
let importEntryPath = extension.entry_path;
|
|
772
|
-
if (options.module_graph_snapshot_root) {
|
|
773
|
-
importEntryPath = await snapshotExtensionModuleGraph(options.module_graph_snapshot_root, extension);
|
|
774
|
-
}
|
|
775
|
-
const baseUrl = new URL(pathToFileURL(importEntryPath).href);
|
|
776
|
-
const shouldCacheBust = options.cache_bust === true || typeof options.reload_token === "string";
|
|
777
|
-
if (!shouldCacheBust) {
|
|
778
|
-
return baseUrl.href;
|
|
779
|
-
}
|
|
780
|
-
const [entryFingerprint, manifestFingerprint] = await Promise.all([
|
|
781
|
-
fingerprintPath(extension.entry_path),
|
|
782
|
-
fingerprintPath(extension.manifest_path),
|
|
783
|
-
]);
|
|
784
|
-
const reloadToken = options.reload_token ?? nextExtensionReloadToken();
|
|
785
|
-
baseUrl.searchParams.set("pm_ext_reload", reloadToken);
|
|
786
|
-
baseUrl.searchParams.set("pm_ext_entry", entryFingerprint);
|
|
787
|
-
baseUrl.searchParams.set("pm_ext_manifest", manifestFingerprint);
|
|
788
|
-
return baseUrl.href;
|
|
789
|
-
}
|
|
790
|
-
/** Implements load extensions for the public runtime surface of this module. */
|
|
791
|
-
export async function loadExtensions(options) {
|
|
792
|
-
const discovery = await discoverExtensions(options);
|
|
793
|
-
const loaded = [];
|
|
794
|
-
const failed = [];
|
|
795
|
-
const warnings = [...discovery.warnings];
|
|
796
|
-
if (discovery.disabled_by_flag) {
|
|
797
|
-
return {
|
|
798
|
-
...discovery,
|
|
799
|
-
warnings,
|
|
800
|
-
loaded,
|
|
801
|
-
failed,
|
|
802
|
-
};
|
|
803
|
-
}
|
|
804
|
-
const extensionsToLoad = typeof options.extensionFilter === "function"
|
|
805
|
-
? discovery.effective.filter(options.extensionFilter)
|
|
806
|
-
: discovery.effective;
|
|
807
|
-
for (const extension of extensionsToLoad) {
|
|
808
|
-
try {
|
|
809
|
-
const importHref = await resolveExtensionImportHref(extension, options);
|
|
810
|
-
const module = await import(importHref);
|
|
811
|
-
loaded.push({
|
|
812
|
-
...extension,
|
|
813
|
-
module,
|
|
814
|
-
});
|
|
815
|
-
}
|
|
816
|
-
catch (error) {
|
|
817
|
-
warnings.push(`extension_load_failed:${extension.layer}:${extension.name}`);
|
|
818
|
-
failed.push({
|
|
819
|
-
layer: extension.layer,
|
|
820
|
-
name: extension.name,
|
|
821
|
-
entry_path: extension.entry_path,
|
|
822
|
-
error: formatUnknownError(error),
|
|
823
|
-
});
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
return {
|
|
827
|
-
...discovery,
|
|
828
|
-
warnings,
|
|
829
|
-
loaded,
|
|
830
|
-
failed,
|
|
831
|
-
};
|
|
832
|
-
}
|
|
833
|
-
const DEFAULT_EXTENSION_DEACTIVATE_TIMEOUT_MS = 5_000;
|
|
834
|
-
const MAX_EXTENSION_DEACTIVATE_TIMEOUT_MS = 2_147_483_647;
|
|
835
|
-
function toActivatableExtension(source) {
|
|
836
|
-
// Bind to `source` so a module/default-export authored with methods (or a class
|
|
837
|
-
// instance) keeps its `this` across both lifecycle calls — `activate` is a
|
|
838
|
-
// method call on a fresh object and `deactivate` is invoked bare, so without
|
|
839
|
-
// binding the two would see different (or undefined) `this`.
|
|
840
|
-
const activate = source.activate;
|
|
841
|
-
const activatable = {
|
|
842
|
-
activate: activate.bind(source),
|
|
843
|
-
};
|
|
844
|
-
if (typeof source.deactivate === "function") {
|
|
845
|
-
const deactivate = source.deactivate;
|
|
846
|
-
activatable.deactivate = deactivate.bind(source);
|
|
847
|
-
}
|
|
848
|
-
return activatable;
|
|
849
|
-
}
|
|
850
|
-
function resolveActivatableExtension(module) {
|
|
851
|
-
const activatableRecord = resolveActivatablePropertyRecord(module);
|
|
852
|
-
return activatableRecord ? toActivatableExtension(activatableRecord) : null;
|
|
853
|
-
}
|
|
854
|
-
/**
|
|
855
|
-
* Run the optional `deactivate` teardown hook for every loaded extension that
|
|
856
|
-
* exports one. Best-effort: a throwing teardown is captured as a warning and a
|
|
857
|
-
* failure entry rather than propagated, so one extension cannot block another's
|
|
858
|
-
* cleanup. Hosts call this on shutdown/reload (e.g. the MCP server between
|
|
859
|
-
* native-action requests) to release resources opened during `activate`.
|
|
860
|
-
*
|
|
861
|
-
* Pass the `activationResult` to skip extensions whose `activate` failed — they
|
|
862
|
-
* never fully initialized, so (VS Code-style) their `deactivate` must not run.
|
|
863
|
-
* Teardowns run concurrently and each hook has a bounded timeout by default, so
|
|
864
|
-
* one slow or hanging hook cannot serialize the rest or block the host
|
|
865
|
-
* indefinitely unless the host explicitly disables the timeout; the returned
|
|
866
|
-
* warnings/failures preserve loaded order.
|
|
867
|
-
*/
|
|
868
|
-
export async function deactivateExtensions(loadResult, activationResult, options = {}) {
|
|
869
|
-
const timeoutMs = normalizeExtensionDeactivateTimeout(options?.deactivate_timeout_ms);
|
|
870
|
-
const failedActivationKeys = new Set((activationResult?.failed ?? []).map((entry) => `${entry.layer}:${entry.name}`));
|
|
871
|
-
const targets = [];
|
|
872
|
-
for (const extension of loadResult.loaded) {
|
|
873
|
-
if (failedActivationKeys.has(`${extension.layer}:${extension.name}`)) {
|
|
874
|
-
continue;
|
|
875
|
-
}
|
|
876
|
-
const activatable = resolveActivatableExtension(extension.module);
|
|
877
|
-
if (!activatable || typeof activatable.deactivate !== "function") {
|
|
878
|
-
continue;
|
|
879
|
-
}
|
|
880
|
-
targets.push({ extension, deactivate: activatable.deactivate });
|
|
881
|
-
}
|
|
882
|
-
const outcomes = await Promise.all(targets.map(async ({ extension, deactivate }) => {
|
|
883
|
-
try {
|
|
884
|
-
await runExtensionDeactivateWithTimeout(deactivate, timeoutMs);
|
|
885
|
-
return { ok: true };
|
|
886
|
-
}
|
|
887
|
-
catch (error) {
|
|
888
|
-
return {
|
|
889
|
-
ok: false,
|
|
890
|
-
layer: extension.layer,
|
|
891
|
-
name: extension.name,
|
|
892
|
-
error: formatUnknownError(error),
|
|
893
|
-
};
|
|
894
|
-
}
|
|
895
|
-
}));
|
|
896
|
-
const warnings = [];
|
|
897
|
-
const failed = [];
|
|
898
|
-
let deactivated = 0;
|
|
899
|
-
for (const outcome of outcomes) {
|
|
900
|
-
if (outcome.ok) {
|
|
901
|
-
deactivated += 1;
|
|
902
|
-
continue;
|
|
903
|
-
}
|
|
904
|
-
warnings.push(`extension_deactivate_failed:${outcome.layer}:${outcome.name}`);
|
|
905
|
-
failed.push({
|
|
906
|
-
layer: outcome.layer,
|
|
907
|
-
name: outcome.name,
|
|
908
|
-
error: outcome.error,
|
|
909
|
-
});
|
|
910
|
-
}
|
|
911
|
-
return { deactivated, warnings, failed };
|
|
912
|
-
}
|
|
913
|
-
function normalizeExtensionDeactivateTimeout(rawTimeout) {
|
|
914
|
-
if (typeof rawTimeout !== "number" || rawTimeout < 0) {
|
|
915
|
-
return DEFAULT_EXTENSION_DEACTIVATE_TIMEOUT_MS;
|
|
916
|
-
}
|
|
917
|
-
if (rawTimeout === 0 || rawTimeout === Infinity) {
|
|
918
|
-
return 0;
|
|
919
|
-
}
|
|
920
|
-
if (!Number.isFinite(rawTimeout)) {
|
|
921
|
-
return DEFAULT_EXTENSION_DEACTIVATE_TIMEOUT_MS;
|
|
922
|
-
}
|
|
923
|
-
return Math.min(MAX_EXTENSION_DEACTIVATE_TIMEOUT_MS, Math.max(1, Math.floor(rawTimeout)));
|
|
924
|
-
}
|
|
925
|
-
async function runExtensionDeactivateWithTimeout(deactivate, timeoutMs) {
|
|
926
|
-
if (timeoutMs === 0) {
|
|
927
|
-
await deactivate();
|
|
928
|
-
return;
|
|
929
|
-
}
|
|
930
|
-
let timeoutHandle;
|
|
931
|
-
try {
|
|
932
|
-
// A timed-out deactivate promise may still finish later; JavaScript promises
|
|
933
|
-
// are not cancellable, so the host only stops waiting and consumes any late
|
|
934
|
-
// rejection from the hook.
|
|
935
|
-
const deactivatePromise = Promise.resolve().then(() => deactivate());
|
|
936
|
-
deactivatePromise.catch(() => { });
|
|
937
|
-
await Promise.race([
|
|
938
|
-
deactivatePromise,
|
|
939
|
-
new Promise((_, reject) => {
|
|
940
|
-
timeoutHandle = setTimeout(() => {
|
|
941
|
-
reject(new Error(`extension deactivate timed out after ${timeoutMs}ms`));
|
|
942
|
-
}, timeoutMs);
|
|
943
|
-
timeoutHandle.unref?.();
|
|
944
|
-
}),
|
|
945
|
-
]);
|
|
946
|
-
}
|
|
947
|
-
finally {
|
|
948
|
-
clearTimeout(timeoutHandle);
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
const FLAG_DEFINITION_KEYS = new Set([
|
|
952
|
-
"default",
|
|
953
|
-
"description",
|
|
954
|
-
"enabled",
|
|
955
|
-
"list",
|
|
956
|
-
"long",
|
|
957
|
-
"repeatable",
|
|
958
|
-
"required",
|
|
959
|
-
"short",
|
|
960
|
-
"type",
|
|
961
|
-
"value_name",
|
|
962
|
-
"value_type",
|
|
963
|
-
"visible",
|
|
964
|
-
]);
|
|
965
|
-
function normalizeFlagDefinitions(name, value) {
|
|
966
|
-
return normalizeRegistrationRecordList(name, value).map((record) => {
|
|
967
|
-
if (record.repeatable === true) {
|
|
968
|
-
record.list = true;
|
|
969
|
-
}
|
|
970
|
-
return record;
|
|
971
|
-
});
|
|
972
|
-
}
|
|
973
|
-
function normalizeCommandActionName(value) {
|
|
974
|
-
return value
|
|
975
|
-
.trim()
|
|
976
|
-
.toLowerCase()
|
|
977
|
-
.replace(/[\s_]+/g, "-")
|
|
978
|
-
.replace(/[^a-z0-9-]/g, "-")
|
|
979
|
-
.replace(/-+/g, "-")
|
|
980
|
-
.replace(/^-+|-+$/g, "");
|
|
981
|
-
}
|
|
982
|
-
function resolveCommandDefinitionAction(commandPath, action) {
|
|
983
|
-
if (action === undefined) {
|
|
984
|
-
return commandPath.replace(/\s+/g, "-");
|
|
985
|
-
}
|
|
986
|
-
if (typeof action !== "string" || action.trim().length === 0) {
|
|
987
|
-
throw new TypeError("registerCommand definition.action must be a non-empty string when provided");
|
|
988
|
-
}
|
|
989
|
-
const normalized = normalizeCommandActionName(action);
|
|
990
|
-
if (normalized.length === 0) {
|
|
991
|
-
throw new TypeError("registerCommand definition.action must contain alphanumeric characters");
|
|
992
|
-
}
|
|
993
|
-
return normalized;
|
|
994
|
-
}
|
|
995
|
-
function normalizeCommandDefinitionArguments(value) {
|
|
996
|
-
if (value === undefined) {
|
|
997
|
-
return [];
|
|
998
|
-
}
|
|
999
|
-
if (!Array.isArray(value)) {
|
|
1000
|
-
throw new TypeError("registerCommand definition.arguments must be an array when provided");
|
|
1001
|
-
}
|
|
1002
|
-
const normalized = [];
|
|
1003
|
-
for (const [index, entry] of value.entries()) {
|
|
1004
|
-
const record = asRegistrationRecord(`registerCommand definition.arguments[${index}]`, entry);
|
|
1005
|
-
const name = assertNonEmptyRegistrationString(`registerCommand definition.arguments[${index}].name`, record.name);
|
|
1006
|
-
assertOptionalBooleanField(`registerCommand definition.arguments[${index}].required`, record.required);
|
|
1007
|
-
assertOptionalBooleanField(`registerCommand definition.arguments[${index}].variadic`, record.variadic);
|
|
1008
|
-
assertOptionalStringField(`registerCommand definition.arguments[${index}].description`, record.description);
|
|
1009
|
-
if (name.includes(" ")) {
|
|
1010
|
-
throw new TypeError(`registerCommand definition.arguments[${index}].name must not contain spaces`);
|
|
1011
|
-
}
|
|
1012
|
-
const definition = {
|
|
1013
|
-
name,
|
|
1014
|
-
};
|
|
1015
|
-
if (record.required === true) {
|
|
1016
|
-
definition.required = true;
|
|
1017
|
-
}
|
|
1018
|
-
if (record.variadic === true) {
|
|
1019
|
-
definition.variadic = true;
|
|
1020
|
-
}
|
|
1021
|
-
if (typeof record.description === "string") {
|
|
1022
|
-
definition.description = record.description.trim();
|
|
1023
|
-
}
|
|
1024
|
-
normalized.push(definition);
|
|
1025
|
-
}
|
|
1026
|
-
const variadicIndexes = normalized
|
|
1027
|
-
.map((argument, index) => (argument.variadic ? index : -1))
|
|
1028
|
-
.filter((index) => index >= 0);
|
|
1029
|
-
if (variadicIndexes.length > 1) {
|
|
1030
|
-
throw new TypeError("registerCommand definition.arguments supports at most one variadic argument");
|
|
1031
|
-
}
|
|
1032
|
-
if (variadicIndexes.length === 1 &&
|
|
1033
|
-
variadicIndexes[0] !== normalized.length - 1) {
|
|
1034
|
-
throw new TypeError("registerCommand definition.arguments variadic argument must be the final argument");
|
|
1035
|
-
}
|
|
1036
|
-
return normalized;
|
|
1037
|
-
}
|
|
1038
|
-
function validateFlagDefinitions(flags) {
|
|
1039
|
-
if (!Array.isArray(flags)) {
|
|
1040
|
-
throw new TypeError("registerFlags flags requires an array of object definitions");
|
|
1041
|
-
}
|
|
1042
|
-
for (const [index, raw] of flags.entries()) {
|
|
1043
|
-
const record = asRegistrationRecord(`registerFlags flags[${index}]`, raw);
|
|
1044
|
-
const unknownKeys = Object.keys(record)
|
|
1045
|
-
.filter((key) => !FLAG_DEFINITION_KEYS.has(key))
|
|
1046
|
-
.sort((left, right) => left.localeCompare(right));
|
|
1047
|
-
if (unknownKeys.length > 0) {
|
|
1048
|
-
throw new TypeError(`registerFlags flags[${index}] contains unknown field(s): ${unknownKeys.join(", ")}`);
|
|
1049
|
-
}
|
|
1050
|
-
const long = record.long;
|
|
1051
|
-
const short = record.short;
|
|
1052
|
-
if (long === undefined && short === undefined) {
|
|
1053
|
-
throw new TypeError(`registerFlags flags[${index}] requires at least one of long or short`);
|
|
1054
|
-
}
|
|
1055
|
-
assertOptionalStringField(`registerFlags flags[${index}].long`, long);
|
|
1056
|
-
assertOptionalStringField(`registerFlags flags[${index}].short`, short);
|
|
1057
|
-
const tokenFinding = findExtensionFlagTokenFailure(long, short);
|
|
1058
|
-
if (tokenFinding !== null) {
|
|
1059
|
-
throw new TypeError(`registerFlags flags[${index}] ${describeExtensionLongFlagFailure(tokenFinding.token, tokenFinding.failure)}`);
|
|
1060
|
-
}
|
|
1061
|
-
assertOptionalStringField(`registerFlags flags[${index}].value_name`, record.value_name);
|
|
1062
|
-
assertOptionalStringField(`registerFlags flags[${index}].description`, record.description);
|
|
1063
|
-
assertOptionalBooleanField(`registerFlags flags[${index}].required`, record.required);
|
|
1064
|
-
assertOptionalBooleanField(`registerFlags flags[${index}].enabled`, record.enabled);
|
|
1065
|
-
assertOptionalBooleanField(`registerFlags flags[${index}].visible`, record.visible);
|
|
1066
|
-
assertOptionalBooleanField(`registerFlags flags[${index}].list`, record.list);
|
|
1067
|
-
assertOptionalBooleanField(`registerFlags flags[${index}].repeatable`, record.repeatable);
|
|
1068
|
-
if (record.list !== undefined &&
|
|
1069
|
-
record.repeatable !== undefined &&
|
|
1070
|
-
record.list !== record.repeatable) {
|
|
1071
|
-
throw new TypeError(`registerFlags flags[${index}].list and repeatable must match when both are provided`);
|
|
1072
|
-
}
|
|
1073
|
-
assertOptionalFlagDefaultField(`registerFlags flags[${index}].default`, record.default);
|
|
1074
|
-
if (Array.isArray(record.default) &&
|
|
1075
|
-
record.list !== true &&
|
|
1076
|
-
record.repeatable !== true) {
|
|
1077
|
-
throw new TypeError(`registerFlags flags[${index}].default cannot be an array unless list is true.`);
|
|
1078
|
-
}
|
|
1079
|
-
assertFlagValueTypeAndDefault(`registerFlags flags[${index}]`, record);
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
/** Reject a declared `value_type`/`type` that is not a known flag value kind, and a `default` whose value(s) would not cleanly coerce under that kind — so the typed-flag contract is enforced at registration instead of silently leaving an untyped value to surface at use time. */
|
|
1083
|
-
function assertFlagValueTypeAndDefault(label, record) {
|
|
1084
|
-
const declaredType = (typeof record.value_type === "string" ? record.value_type : undefined) ??
|
|
1085
|
-
(typeof record.type === "string" ? record.type : undefined);
|
|
1086
|
-
if (declaredType === undefined) {
|
|
1087
|
-
return;
|
|
1088
|
-
}
|
|
1089
|
-
const kind = resolveFlagValueKind(declaredType);
|
|
1090
|
-
if (kind === null) {
|
|
1091
|
-
throw new TypeError(`${label} value_type "${declaredType}" is not a known flag value type (expected one of: string, number, boolean).`);
|
|
1092
|
-
}
|
|
1093
|
-
if (record.default === undefined) {
|
|
1094
|
-
return;
|
|
1095
|
-
}
|
|
1096
|
-
// For list flags, validate the default exactly as the runtime will see it —
|
|
1097
|
-
// comma-joined strings and nested arrays are flattened first — so a valid
|
|
1098
|
-
// default like `value_type: "number", default: "10,20"` is not wrongly rejected.
|
|
1099
|
-
const defaults = record.list === true || record.repeatable === true
|
|
1100
|
-
? flattenFlagListValue(record.default)
|
|
1101
|
-
: [record.default];
|
|
1102
|
-
for (const [defaultIndex, defaultValue] of defaults.entries()) {
|
|
1103
|
-
if (!isFlagDefaultValueCoercible(defaultValue, kind)) {
|
|
1104
|
-
const suffix = defaults.length > 1 ? `default[${defaultIndex}]` : "default";
|
|
1105
|
-
throw new TypeError(`${label}.${suffix} (${JSON.stringify(defaultValue)}) is not coercible to ${kind}.`);
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
function validateItemFieldDefinitions(fields) {
|
|
1110
|
-
if (!Array.isArray(fields)) {
|
|
1111
|
-
throw new TypeError("registerItemFields fields requires an array of object definitions");
|
|
1112
|
-
}
|
|
1113
|
-
for (const [index, raw] of fields.entries()) {
|
|
1114
|
-
const record = asRegistrationRecord(`registerItemFields fields[${index}]`, raw);
|
|
1115
|
-
assertNonEmptyRegistrationString(`registerItemFields fields[${index}].name`, record.name);
|
|
1116
|
-
const fieldType = assertNonEmptyRegistrationString(`registerItemFields fields[${index}].type`, record.type);
|
|
1117
|
-
if (normalizeItemFieldType(fieldType) === null) {
|
|
1118
|
-
const suggestion = suggestKnownItemFieldType(fieldType);
|
|
1119
|
-
const hint = suggestion ? ` Did you mean "${suggestion}"?` : "";
|
|
1120
|
-
throw new TypeError(`registerItemFields fields[${index}].type "${fieldType}" is not a known field type ` +
|
|
1121
|
-
`(expected one of: ${KNOWN_ITEM_FIELD_TYPES.join(", ")}).${hint}`);
|
|
1122
|
-
}
|
|
1123
|
-
assertOptionalBooleanField(`registerItemFields fields[${index}].optional`, record.optional);
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
/** Validate the optional command-specific visibility and requirement policies of one extension item type. */
|
|
1127
|
-
function validateItemTypeCommandOptionPolicies(typeIndex, value) {
|
|
1128
|
-
if (value === undefined) {
|
|
1129
|
-
return;
|
|
1130
|
-
}
|
|
1131
|
-
const label = `registerItemTypes types[${typeIndex}].command_option_policies`;
|
|
1132
|
-
if (!Array.isArray(value)) {
|
|
1133
|
-
throw new TypeError(`${label} must be an array when provided`);
|
|
1134
|
-
}
|
|
1135
|
-
for (const [policyIndex, rawPolicy] of value.entries()) {
|
|
1136
|
-
const at = `${label}[${policyIndex}]`;
|
|
1137
|
-
const policy = asRegistrationRecord(at, rawPolicy);
|
|
1138
|
-
assertNonEmptyRegistrationString(`${at}.command`, policy.command);
|
|
1139
|
-
assertNonEmptyRegistrationString(`${at}.option`, policy.option);
|
|
1140
|
-
assertOptionalBooleanField(`${at}.enabled`, policy.enabled);
|
|
1141
|
-
assertOptionalBooleanField(`${at}.required`, policy.required);
|
|
1142
|
-
assertOptionalBooleanField(`${at}.visible`, policy.visible);
|
|
1143
|
-
}
|
|
1144
|
-
}
|
|
1145
|
-
/** Validate the optional custom option vocabulary of one extension item type. */
|
|
1146
|
-
function validateItemTypeOptions(typeIndex, value) {
|
|
1147
|
-
if (value === undefined) {
|
|
1148
|
-
return;
|
|
1149
|
-
}
|
|
1150
|
-
const label = `registerItemTypes types[${typeIndex}].options`;
|
|
1151
|
-
if (!Array.isArray(value)) {
|
|
1152
|
-
throw new TypeError(`${label} must be an array when provided`);
|
|
1153
|
-
}
|
|
1154
|
-
for (const [optionIndex, rawOption] of value.entries()) {
|
|
1155
|
-
const at = `${label}[${optionIndex}]`;
|
|
1156
|
-
const option = asRegistrationRecord(at, rawOption);
|
|
1157
|
-
assertNonEmptyRegistrationString(`${at}.key`, option.key);
|
|
1158
|
-
assertOptionalStringArrayField(`${at}.values`, option.values);
|
|
1159
|
-
assertOptionalBooleanField(`${at}.required`, option.required);
|
|
1160
|
-
assertOptionalStringArrayField(`${at}.aliases`, option.aliases);
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
function validateItemTypeDefinitions(types) {
|
|
1164
|
-
if (!Array.isArray(types)) {
|
|
1165
|
-
throw new TypeError("registerItemTypes types requires an array of object definitions");
|
|
1166
|
-
}
|
|
1167
|
-
for (const [typeIndex, raw] of types.entries()) {
|
|
1168
|
-
const at = `registerItemTypes types[${typeIndex}]`;
|
|
1169
|
-
const record = asRegistrationRecord(at, raw);
|
|
1170
|
-
assertNonEmptyRegistrationString(`${at}.name`, record.name);
|
|
1171
|
-
assertOptionalStringField(`${at}.folder`, record.folder);
|
|
1172
|
-
assertOptionalStringArrayField(`${at}.aliases`, record.aliases);
|
|
1173
|
-
assertOptionalStringArrayField(`${at}.required_create_fields`, record.required_create_fields);
|
|
1174
|
-
assertOptionalStringArrayField(`${at}.required_create_repeatables`, record.required_create_repeatables);
|
|
1175
|
-
validateItemTypeCommandOptionPolicies(typeIndex, record.command_option_policies);
|
|
1176
|
-
validateItemTypeOptions(typeIndex, record.options);
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
function validateMigrationDefinition(definition) {
|
|
1180
|
-
const record = asRegistrationRecord("registerMigration definition", definition);
|
|
1181
|
-
if (record.id !== undefined && typeof record.id !== "string") {
|
|
1182
|
-
throw new TypeError("registerMigration definition.id must be a string when provided");
|
|
1183
|
-
}
|
|
1184
|
-
if (record.description !== undefined &&
|
|
1185
|
-
typeof record.description !== "string") {
|
|
1186
|
-
throw new TypeError("registerMigration definition.description must be a string when provided");
|
|
1187
|
-
}
|
|
1188
|
-
if (record.status !== undefined && typeof record.status !== "string") {
|
|
1189
|
-
throw new TypeError("registerMigration definition.status must be a string when provided");
|
|
1190
|
-
}
|
|
1191
|
-
assertOptionalBooleanField("registerMigration definition.mandatory", record.mandatory);
|
|
1192
|
-
if (record.run !== undefined && typeof record.run !== "function") {
|
|
1193
|
-
throw new TypeError("registerMigration definition.run must be a function when provided");
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
/**
|
|
1197
|
-
* The seven array-valued dimensions a {@link ProjectProfileDefinition} stages.
|
|
1198
|
-
* Each is "optional-by-emptiness": an omitted dimension normalizes to an empty
|
|
1199
|
-
* array so the profile planner can iterate every dimension unconditionally.
|
|
1200
|
-
*/
|
|
1201
|
-
const PROJECT_PROFILE_DIMENSIONS = [
|
|
1202
|
-
"types",
|
|
1203
|
-
"statuses",
|
|
1204
|
-
"fields",
|
|
1205
|
-
"workflows",
|
|
1206
|
-
"config",
|
|
1207
|
-
"templates",
|
|
1208
|
-
"packages",
|
|
1209
|
-
];
|
|
1210
|
-
/** Dimension-specific profile entry validators used after the common object-shape boundary. */
|
|
1211
|
-
const PROJECT_PROFILE_ENTRY_VALIDATORS = {
|
|
1212
|
-
types: (at, entry) => {
|
|
1213
|
-
if (entry.name !== undefined && typeof entry.name !== "string") {
|
|
1214
|
-
throw new TypeError(`${at}.name must be a string when provided`);
|
|
1215
|
-
}
|
|
1216
|
-
},
|
|
1217
|
-
workflows: (at, entry) => {
|
|
1218
|
-
if (typeof entry.type !== "string") {
|
|
1219
|
-
throw new TypeError(`${at}.type must be a string`);
|
|
1220
|
-
}
|
|
1221
|
-
if (!Array.isArray(entry.allowed_transitions)) {
|
|
1222
|
-
throw new TypeError(`${at}.allowed_transitions must be an array`);
|
|
1223
|
-
}
|
|
1224
|
-
for (const [pairIndex, pair] of entry.allowed_transitions.entries()) {
|
|
1225
|
-
if (!Array.isArray(pair)) {
|
|
1226
|
-
throw new TypeError(`${at}.allowed_transitions[${pairIndex}] must be a [from, to] array`);
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
},
|
|
1230
|
-
templates: (at, entry) => {
|
|
1231
|
-
if (typeof entry.name !== "string") {
|
|
1232
|
-
throw new TypeError(`${at}.name must be a string`);
|
|
1233
|
-
}
|
|
1234
|
-
if (typeof entry.options !== "object" ||
|
|
1235
|
-
entry.options === null ||
|
|
1236
|
-
Array.isArray(entry.options)) {
|
|
1237
|
-
throw new TypeError(`${at}.options must be an object`);
|
|
1238
|
-
}
|
|
1239
|
-
},
|
|
1240
|
-
packages: (at, entry) => {
|
|
1241
|
-
if (typeof entry.spec !== "string") {
|
|
1242
|
-
throw new TypeError(`${at}.spec must be a string`);
|
|
1243
|
-
}
|
|
1244
|
-
},
|
|
1245
|
-
};
|
|
1246
|
-
function validateProjectProfileDefinition(profile) {
|
|
1247
|
-
const record = asRegistrationRecord("registerProfile profile", profile);
|
|
1248
|
-
assertNonEmptyRegistrationString("registerProfile profile.name", record.name);
|
|
1249
|
-
assertNonEmptyRegistrationString("registerProfile profile.title", record.title);
|
|
1250
|
-
if (record.summary !== undefined && typeof record.summary !== "string") {
|
|
1251
|
-
throw new TypeError("registerProfile profile.summary must be a string when provided");
|
|
1252
|
-
}
|
|
1253
|
-
for (const dimension of PROJECT_PROFILE_DIMENSIONS) {
|
|
1254
|
-
const value = record[dimension];
|
|
1255
|
-
if (value === undefined) {
|
|
1256
|
-
continue;
|
|
1257
|
-
}
|
|
1258
|
-
if (!Array.isArray(value)) {
|
|
1259
|
-
throw new TypeError(`registerProfile profile.${dimension} must be an array when provided`);
|
|
1260
|
-
}
|
|
1261
|
-
// Each dimension entry must be a non-null object: a primitive or null entry
|
|
1262
|
-
// (e.g. `statuses: [null]`, `types: [42]`) survives an array-only check but
|
|
1263
|
-
// crashes the profile planner and `pm profile show` when they read `entry.id`
|
|
1264
|
-
// / `entry.key` / `entry.type` later. Reject it at the registration boundary.
|
|
1265
|
-
for (const [index, entry] of value.entries()) {
|
|
1266
|
-
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
1267
|
-
throw new TypeError(`registerProfile profile.${dimension}[${index}] must be an object`);
|
|
1268
|
-
}
|
|
1269
|
-
// Beyond "is an object", validate the specific field shapes consumers
|
|
1270
|
-
// dereference so a type-violating entry can never crash the planner, the
|
|
1271
|
-
// `pm profile` surfaces, or describeProjectProfile downstream.
|
|
1272
|
-
PROJECT_PROFILE_ENTRY_VALIDATORS[dimension]?.(`registerProfile profile.${dimension}[${index}]`, entry);
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
/**
|
|
1277
|
-
* Fills an already-validated profile snapshot's optional surfaces — an absent
|
|
1278
|
-
* `summary` becomes an empty string and every omitted dimension an empty array —
|
|
1279
|
-
* so the stored definition always has the full {@link ProjectProfileDefinition}
|
|
1280
|
-
* shape the profile planner and `pm profile` resolution rely on. It runs after
|
|
1281
|
-
* validation on the cloned snapshot, so it only ever supplies missing defaults
|
|
1282
|
-
* and never has to coerce an invalid type (those are already rejected).
|
|
1283
|
-
*/
|
|
1284
|
-
function applyProjectProfileDefaults(profile) {
|
|
1285
|
-
if (profile.summary === undefined) {
|
|
1286
|
-
profile.summary = "";
|
|
1287
|
-
}
|
|
1288
|
-
for (const dimension of PROJECT_PROFILE_DIMENSIONS) {
|
|
1289
|
-
if (profile[dimension] === undefined) {
|
|
1290
|
-
profile[dimension] = [];
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
return profile;
|
|
1294
|
-
}
|
|
1295
|
-
function getDeclaredExtensionCapabilities(extension) {
|
|
1296
|
-
if (!Array.isArray(extension.capabilities)) {
|
|
1297
|
-
return null;
|
|
1298
|
-
}
|
|
1299
|
-
const declared = new Set();
|
|
1300
|
-
for (const capability of extension.capabilities) {
|
|
1301
|
-
const normalized = capability.trim().toLowerCase();
|
|
1302
|
-
if (isKnownExtensionCapability(normalized)) {
|
|
1303
|
-
declared.add(normalized);
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1306
|
-
return declared;
|
|
1307
|
-
}
|
|
1308
|
-
function assertExtensionCapability(extension, capability, method) {
|
|
1309
|
-
const declared = getDeclaredExtensionCapabilities(extension);
|
|
1310
|
-
// Keep direct unit tests that construct LoadedExtension fixtures without
|
|
1311
|
-
// capability metadata backwards-compatible while enforcing manifest-declared
|
|
1312
|
-
// capabilities for runtime-loaded extensions.
|
|
1313
|
-
if (declared === null) {
|
|
1314
|
-
return;
|
|
1315
|
-
}
|
|
1316
|
-
if (!declared.has(capability)) {
|
|
1317
|
-
throw createRegistrationValidationError(`${method} requires capability '${capability}' in extension manifest capabilities`, {
|
|
1318
|
-
method,
|
|
1319
|
-
registration_index: -1,
|
|
1320
|
-
capability,
|
|
1321
|
-
missing_capability: capability,
|
|
1322
|
-
expected_schema: `"capabilities": [..., "${capability}"]`,
|
|
1323
|
-
received: extension.capabilities,
|
|
1324
|
-
hint: `Add "${capability}" to ${extension.name} manifest capabilities, or remove the ${method} registration call.`,
|
|
1325
|
-
});
|
|
1326
|
-
}
|
|
1327
|
-
}
|
|
1328
|
-
function buildExtensionSelfIdentity(extension) {
|
|
1329
|
-
return Object.freeze({
|
|
1330
|
-
name: extension.name,
|
|
1331
|
-
layer: extension.layer,
|
|
1332
|
-
version: extension.version,
|
|
1333
|
-
capabilities: Object.freeze((extension.capabilities ?? []).filter((capability) => KNOWN_EXTENSION_CAPABILITIES.includes(capability))),
|
|
1334
|
-
pm_min_version: extension.pm_min_version,
|
|
1335
|
-
pm_max_version: extension.pm_max_version,
|
|
1336
|
-
source_package: extension.source_package,
|
|
1337
|
-
});
|
|
1338
|
-
}
|
|
1339
|
-
function buildPolicyExtensionRef(extension) {
|
|
1340
|
-
return {
|
|
1341
|
-
layer: extension.layer,
|
|
1342
|
-
name: extension.name,
|
|
1343
|
-
trusted: extension.trusted === true,
|
|
1344
|
-
provenanceVerified: extension.provenance?.verified === true,
|
|
1345
|
-
sandboxProfile: extension.sandbox_profile,
|
|
1346
|
-
permissions: extension.permissions && typeof extension.permissions === "object"
|
|
1347
|
-
? {
|
|
1348
|
-
fs_read: extension.permissions.fs_read,
|
|
1349
|
-
fs_write: extension.permissions.fs_write,
|
|
1350
|
-
network: extension.permissions.network,
|
|
1351
|
-
env_read: extension.permissions.env_read,
|
|
1352
|
-
env_write: extension.permissions.env_write,
|
|
1353
|
-
process_spawn: extension.permissions.process_spawn,
|
|
1354
|
-
}
|
|
1355
|
-
: undefined,
|
|
1356
|
-
};
|
|
1357
|
-
}
|
|
1358
|
-
class ExtensionApiRegistrar {
|
|
1359
|
-
extension;
|
|
1360
|
-
hooks;
|
|
1361
|
-
#loadedExtension;
|
|
1362
|
-
#extensionRef;
|
|
1363
|
-
#hookRegistry;
|
|
1364
|
-
#commandRegistry;
|
|
1365
|
-
#parserRegistry;
|
|
1366
|
-
#preflightRegistry;
|
|
1367
|
-
#serviceRegistry;
|
|
1368
|
-
#rendererRegistry;
|
|
1369
|
-
#registrationRegistry;
|
|
1370
|
-
#activationWarnings;
|
|
1371
|
-
#activationFailures;
|
|
1372
|
-
#policy;
|
|
1373
|
-
constructor(extension, hooks, commands, parsers, preflight, services, renderers, registrations, activationWarnings, activationFailures, policy) {
|
|
1374
|
-
this.#loadedExtension = extension;
|
|
1375
|
-
this.extension = buildExtensionSelfIdentity(extension);
|
|
1376
|
-
this.#extensionRef = buildPolicyExtensionRef(extension);
|
|
1377
|
-
this.#hookRegistry = hooks;
|
|
1378
|
-
this.#commandRegistry = commands;
|
|
1379
|
-
this.#parserRegistry = parsers;
|
|
1380
|
-
this.#preflightRegistry = preflight;
|
|
1381
|
-
this.#serviceRegistry = services;
|
|
1382
|
-
this.#rendererRegistry = renderers;
|
|
1383
|
-
this.#registrationRegistry = registrations;
|
|
1384
|
-
this.#activationWarnings = activationWarnings;
|
|
1385
|
-
this.#activationFailures = activationFailures;
|
|
1386
|
-
this.#policy = policy;
|
|
1387
|
-
this.registerCommand = this.registerCommand.bind(this);
|
|
1388
|
-
this.registerParser = this.registerParser.bind(this);
|
|
1389
|
-
this.registerPreflight = this.registerPreflight.bind(this);
|
|
1390
|
-
this.registerService = this.registerService.bind(this);
|
|
1391
|
-
this.registerFlags = this.registerFlags.bind(this);
|
|
1392
|
-
this.registerItemFields = this.registerItemFields.bind(this);
|
|
1393
|
-
this.registerItemTypes = this.registerItemTypes.bind(this);
|
|
1394
|
-
this.registerRelationshipKinds = this.registerRelationshipKinds.bind(this);
|
|
1395
|
-
this.registerMigration = this.registerMigration.bind(this);
|
|
1396
|
-
this.registerProfile = this.registerProfile.bind(this);
|
|
1397
|
-
this.registerRenderer = this.registerRenderer.bind(this);
|
|
1398
|
-
this.registerImporter = this.registerImporter.bind(this);
|
|
1399
|
-
this.registerExporter = this.registerExporter.bind(this);
|
|
1400
|
-
this.registerSearchProvider = this.registerSearchProvider.bind(this);
|
|
1401
|
-
this.registerVectorStoreAdapter =
|
|
1402
|
-
this.registerVectorStoreAdapter.bind(this);
|
|
1403
|
-
this.registerAssuranceMeasurementProvider =
|
|
1404
|
-
this.registerAssuranceMeasurementProvider.bind(this);
|
|
1405
|
-
this.hooks = {
|
|
1406
|
-
beforeCommand: (hook) => this.registerBeforeCommand(hook),
|
|
1407
|
-
beforeMutation: (hook) => this.registerBeforeMutation(hook),
|
|
1408
|
-
afterCommand: (hook) => this.registerAfterCommand(hook),
|
|
1409
|
-
onWrite: (hook) => this.registerOnWrite(hook),
|
|
1410
|
-
onRead: (hook) => this.registerOnRead(hook),
|
|
1411
|
-
onIndex: (hook) => this.registerOnIndex(hook),
|
|
1412
|
-
};
|
|
1413
|
-
}
|
|
1414
|
-
allowRegistration(surface, method, capability, details) {
|
|
1415
|
-
const decision = evaluateExtensionPolicyForRegistration(this.#policy, this.#extensionRef, surface, method, capability, details);
|
|
1416
|
-
if (decision.warning) {
|
|
1417
|
-
this.#activationWarnings.push(decision.warning);
|
|
1418
|
-
}
|
|
1419
|
-
return decision.allowed;
|
|
1420
|
-
}
|
|
1421
|
-
registerCommandTrace(mode, command, expectedSchema, received, hint) {
|
|
1422
|
-
return {
|
|
1423
|
-
method: "registerCommand",
|
|
1424
|
-
registration_index: mode === "override"
|
|
1425
|
-
? this.#commandRegistry.overrides.length
|
|
1426
|
-
: this.#commandRegistry.handlers.length,
|
|
1427
|
-
command,
|
|
1428
|
-
expected_schema: expectedSchema,
|
|
1429
|
-
received: sanitizeRegistrationValue(received),
|
|
1430
|
-
hint,
|
|
1431
|
-
};
|
|
1432
|
-
}
|
|
1433
|
-
registerCommandOverride(command, override) {
|
|
1434
|
-
const normalizedCommand = normalizeCommandName(command);
|
|
1435
|
-
if (normalizedCommand.length === 0) {
|
|
1436
|
-
throw createRegistrationValidationError("registerCommand requires a non-empty command name", this.registerCommandTrace("override", command, 'registerCommand("<command>", (context) => unknown)', command, "Provide a non-empty command path as the first argument."));
|
|
1437
|
-
}
|
|
1438
|
-
if (typeof override !== "function") {
|
|
1439
|
-
const trace = this.registerCommandTrace("override", normalizedCommand, 'registerCommand("<command>", (context) => unknown)', override, "Provide a function as the second registerCommand argument.");
|
|
1440
|
-
throw createRegistrationValidationError(`registerCommand requires an override function when command name is provided (command="${normalizedCommand}", registration_index=${trace.registration_index})`, trace);
|
|
1441
|
-
}
|
|
1442
|
-
if (!this.allowRegistration("commands.override", "registerCommand", "commands", { command: normalizedCommand })) {
|
|
1443
|
-
return;
|
|
1444
|
-
}
|
|
1445
|
-
this.#commandRegistry.overrides.push({
|
|
1446
|
-
layer: this.#loadedExtension.layer,
|
|
1447
|
-
name: this.#loadedExtension.name,
|
|
1448
|
-
command: normalizedCommand,
|
|
1449
|
-
run: override,
|
|
1450
|
-
});
|
|
1451
|
-
}
|
|
1452
|
-
resolveCommandDefinitionRunHandler(definition, normalizedCommand) {
|
|
1453
|
-
const runHandler = typeof definition.run === "function" ? definition.run : undefined;
|
|
1454
|
-
const legacyHandler = typeof definition.handler === "function" ? definition.handler : undefined;
|
|
1455
|
-
if (!runHandler && legacyHandler) {
|
|
1456
|
-
this.#activationWarnings.push(`extension_command_definition_legacy_handler_alias:${this.#loadedExtension.layer}:${this.#loadedExtension.name}:${normalizedCommand}`);
|
|
1457
|
-
}
|
|
1458
|
-
return runHandler ?? legacyHandler;
|
|
1459
|
-
}
|
|
1460
|
-
registerCommandDefinition(definition) {
|
|
1461
|
-
if (typeof definition !== "object" || definition === null) {
|
|
1462
|
-
throw createRegistrationValidationError("registerCommand requires a command definition object", this.registerCommandTrace("definition", undefined, "{ name: string; run: (context) => unknown; }", definition, 'Use registerCommand({ name: "command path", run: (context) => ... }).'));
|
|
1463
|
-
}
|
|
1464
|
-
if (typeof definition.name !== "string") {
|
|
1465
|
-
throw createRegistrationValidationError("registerCommand requires a command definition name", this.registerCommandTrace("definition", undefined, "{ name: string; run: (context) => unknown; }", definition, "Set command definition.name to a non-empty string command path."));
|
|
1466
|
-
}
|
|
1467
|
-
const normalizedCommand = normalizeCommandName(definition.name);
|
|
1468
|
-
if (normalizedCommand.length === 0) {
|
|
1469
|
-
throw createRegistrationValidationError("registerCommand requires a non-empty command definition name", this.registerCommandTrace("definition", definition.name, "{ name: string; run: (context) => unknown; }", definition, "Ensure command definition.name contains a non-empty command path."));
|
|
1470
|
-
}
|
|
1471
|
-
const resolvedHandler = this.resolveCommandDefinitionRunHandler(definition, normalizedCommand);
|
|
1472
|
-
if (typeof resolvedHandler !== "function") {
|
|
1473
|
-
const trace = this.registerCommandTrace("definition", normalizedCommand, "{ name: string; run: (context) => unknown; }", resolvedHandler, "Define command definition.run as a function.");
|
|
1474
|
-
throw createRegistrationValidationError(`registerCommand requires a command definition run handler (command="${normalizedCommand}", registration_index=${trace.registration_index})`, trace);
|
|
1475
|
-
}
|
|
1476
|
-
try {
|
|
1477
|
-
assertCommandDefinitionMetadataStrings(definition);
|
|
1478
|
-
const action = resolveCommandDefinitionAction(normalizedCommand, definition.action);
|
|
1479
|
-
if (!this.allowRegistration("commands.handler", "registerCommand", "commands", { command: normalizedCommand, action })) {
|
|
1480
|
-
return;
|
|
1481
|
-
}
|
|
1482
|
-
const description = definition.description?.trim();
|
|
1483
|
-
const intent = definition.intent?.trim();
|
|
1484
|
-
const examples = normalizeOptionalStringArrayField("registerCommand definition.examples", definition.examples);
|
|
1485
|
-
const failureHints = normalizeOptionalStringArrayField("registerCommand definition.failure_hints", definition.failure_hints);
|
|
1486
|
-
const argumentsDefinition = normalizeCommandDefinitionArguments(definition.arguments);
|
|
1487
|
-
if (definition.flags !== undefined) {
|
|
1488
|
-
assertExtensionCapability(this.#loadedExtension, "schema", "registerCommand flags");
|
|
1489
|
-
if (this.allowRegistration("schema.flags", "registerCommand flags", "schema")) {
|
|
1490
|
-
validateFlagDefinitions(definition.flags);
|
|
1491
|
-
this.#registrationRegistry.flags.push({
|
|
1492
|
-
layer: this.#loadedExtension.layer,
|
|
1493
|
-
name: this.#loadedExtension.name,
|
|
1494
|
-
target_command: normalizedCommand,
|
|
1495
|
-
flags: normalizeFlagDefinitions("registerCommand definition.flags", definition.flags),
|
|
1496
|
-
});
|
|
1497
|
-
}
|
|
1498
|
-
}
|
|
1499
|
-
const registration = {
|
|
1500
|
-
layer: this.#loadedExtension.layer,
|
|
1501
|
-
name: this.#loadedExtension.name,
|
|
1502
|
-
source_package: this.#loadedExtension.source_package,
|
|
1503
|
-
command: normalizedCommand,
|
|
1504
|
-
action,
|
|
1505
|
-
examples,
|
|
1506
|
-
failure_hints: failureHints,
|
|
1507
|
-
arguments: argumentsDefinition,
|
|
1508
|
-
tier: definition.tier ?? "standard",
|
|
1509
|
-
family: definition.family ?? "extensions",
|
|
1510
|
-
};
|
|
1511
|
-
if (description) {
|
|
1512
|
-
registration.description = description;
|
|
1513
|
-
}
|
|
1514
|
-
if (intent) {
|
|
1515
|
-
registration.intent = intent;
|
|
1516
|
-
}
|
|
1517
|
-
this.#registrationRegistry.commands.push(registration);
|
|
1518
|
-
}
|
|
1519
|
-
catch (error) {
|
|
1520
|
-
const reason = formatUnknownError(error);
|
|
1521
|
-
const trace = this.registerCommandTrace("definition", normalizedCommand, "{ name: string; run: (context) => unknown; action?: string; arguments?: object[]; flags?: object[]; }", definition, reason);
|
|
1522
|
-
const validationError = createRegistrationValidationError(`registerCommand definition metadata invalid (command="${normalizedCommand}", registration_index=${trace.registration_index}): ${reason}`, trace);
|
|
1523
|
-
this.#activationWarnings.push(`extension_command_quarantined:${this.#loadedExtension.layer}:${this.#loadedExtension.name}:${normalizedCommand}`);
|
|
1524
|
-
this.#activationFailures.push({
|
|
1525
|
-
layer: this.#loadedExtension.layer,
|
|
1526
|
-
name: this.#loadedExtension.name,
|
|
1527
|
-
entry_path: this.#loadedExtension.entry_path,
|
|
1528
|
-
error: validationError.message,
|
|
1529
|
-
trace,
|
|
1530
|
-
});
|
|
1531
|
-
return;
|
|
1532
|
-
}
|
|
1533
|
-
this.#commandRegistry.handlers.push({
|
|
1534
|
-
layer: this.#loadedExtension.layer,
|
|
1535
|
-
name: this.#loadedExtension.name,
|
|
1536
|
-
command: normalizedCommand,
|
|
1537
|
-
run: resolvedHandler,
|
|
1538
|
-
});
|
|
1539
|
-
}
|
|
1540
|
-
registerCommand(commandOrDefinition, override) {
|
|
1541
|
-
assertExtensionCapability(this.#loadedExtension, "commands", "registerCommand");
|
|
1542
|
-
if (typeof commandOrDefinition === "string") {
|
|
1543
|
-
this.registerCommandOverride(commandOrDefinition, override);
|
|
1544
|
-
return;
|
|
1545
|
-
}
|
|
1546
|
-
this.registerCommandDefinition(commandOrDefinition);
|
|
1547
|
-
}
|
|
1548
|
-
registerParser(command, override) {
|
|
1549
|
-
assertExtensionCapability(this.#loadedExtension, "parser", "registerParser");
|
|
1550
|
-
if (!this.allowRegistration("parser.override", "registerParser", "parser")) {
|
|
1551
|
-
return;
|
|
1552
|
-
}
|
|
1553
|
-
const normalizedCommand = normalizeCommandName(assertNonEmptyRegistrationString("registerParser command", command));
|
|
1554
|
-
assertRegistrationFunction("registerParser override", override);
|
|
1555
|
-
this.#parserRegistry.overrides.push({
|
|
1556
|
-
layer: this.#loadedExtension.layer,
|
|
1557
|
-
name: this.#loadedExtension.name,
|
|
1558
|
-
command: normalizedCommand,
|
|
1559
|
-
run: override,
|
|
1560
|
-
});
|
|
1561
|
-
}
|
|
1562
|
-
registerPreflight(override) {
|
|
1563
|
-
assertExtensionCapability(this.#loadedExtension, "preflight", "registerPreflight");
|
|
1564
|
-
if (!this.allowRegistration("preflight.override", "registerPreflight", "preflight")) {
|
|
1565
|
-
return;
|
|
1566
|
-
}
|
|
1567
|
-
const normalized = normalizePreflightOverride(override);
|
|
1568
|
-
this.#preflightRegistry.overrides.push({
|
|
1569
|
-
layer: this.#loadedExtension.layer,
|
|
1570
|
-
name: this.#loadedExtension.name,
|
|
1571
|
-
...normalized,
|
|
1572
|
-
});
|
|
1573
|
-
}
|
|
1574
|
-
registerService(service, override, ownership = {}) {
|
|
1575
|
-
assertExtensionCapability(this.#loadedExtension, "services", "registerService");
|
|
1576
|
-
const normalizedService = String(service).trim().toLowerCase();
|
|
1577
|
-
if (!isExtensionServiceName(normalizedService)) {
|
|
1578
|
-
throw new TypeError(`registerService service must be one of: ${KNOWN_EXTENSION_SERVICE_NAMES.join(", ")}`);
|
|
1579
|
-
}
|
|
1580
|
-
if (!this.allowRegistration("services.override", "registerService", "services", { service: normalizedService })) {
|
|
1581
|
-
return;
|
|
1582
|
-
}
|
|
1583
|
-
assertRegistrationFunction("registerService override", override);
|
|
1584
|
-
this.#serviceRegistry.overrides.push({
|
|
1585
|
-
layer: this.#loadedExtension.layer,
|
|
1586
|
-
name: this.#loadedExtension.name,
|
|
1587
|
-
service: normalizedService,
|
|
1588
|
-
run: override,
|
|
1589
|
-
...(normalizeServiceOverrideOwnership(ownership)
|
|
1590
|
-
? { passThrough: true }
|
|
1591
|
-
: {}),
|
|
1592
|
-
});
|
|
1593
|
-
}
|
|
1594
|
-
registerRenderer(format, renderer, ownership = {}) {
|
|
1595
|
-
assertExtensionCapability(this.#loadedExtension, "renderers", "registerRenderer");
|
|
1596
|
-
if (!this.allowRegistration("renderers.override", "registerRenderer", "renderers")) {
|
|
1597
|
-
return;
|
|
1598
|
-
}
|
|
1599
|
-
if (typeof renderer !== "function") {
|
|
1600
|
-
throw new TypeError("registerRenderer requires a renderer function");
|
|
1601
|
-
}
|
|
1602
|
-
const normalizedFormat = String(format).trim().toLowerCase();
|
|
1603
|
-
if (!isOutputRendererFormat(normalizedFormat)) {
|
|
1604
|
-
throw new Error(`registerRenderer format must be toon|json, received: ${String(format)}`);
|
|
1605
|
-
}
|
|
1606
|
-
if (ownership.resultDiscriminator !== undefined &&
|
|
1607
|
-
typeof ownership.resultDiscriminator !== "function") {
|
|
1608
|
-
throw new TypeError("registerRenderer ownership.resultDiscriminator must be a function when provided");
|
|
1609
|
-
}
|
|
1610
|
-
const commands = [
|
|
1611
|
-
...new Set((ownership.commands ?? []).map((command) => {
|
|
1612
|
-
if (typeof command !== "string" || command.trim().length === 0) {
|
|
1613
|
-
throw new TypeError("registerRenderer ownership.commands must contain non-empty command paths");
|
|
1614
|
-
}
|
|
1615
|
-
return normalizeCommandName(command);
|
|
1616
|
-
})),
|
|
1617
|
-
];
|
|
1618
|
-
this.#rendererRegistry.overrides.push({
|
|
1619
|
-
layer: this.#loadedExtension.layer,
|
|
1620
|
-
name: this.#loadedExtension.name,
|
|
1621
|
-
format: normalizedFormat,
|
|
1622
|
-
run: renderer,
|
|
1623
|
-
commands,
|
|
1624
|
-
...(ownership.resultDiscriminator
|
|
1625
|
-
? { resultDiscriminator: ownership.resultDiscriminator }
|
|
1626
|
-
: {}),
|
|
1627
|
-
});
|
|
1628
|
-
}
|
|
1629
|
-
registerFlags(targetCommand, flags) {
|
|
1630
|
-
assertExtensionCapability(this.#loadedExtension, "schema", "registerFlags");
|
|
1631
|
-
if (!this.allowRegistration("schema.flags", "registerFlags", "schema")) {
|
|
1632
|
-
return;
|
|
1633
|
-
}
|
|
1634
|
-
const normalizedTargetCommand = normalizeCommandName(assertNonEmptyRegistrationString("registerFlags targetCommand", targetCommand));
|
|
1635
|
-
validateFlagDefinitions(flags);
|
|
1636
|
-
const normalizedFlags = normalizeFlagDefinitions("registerFlags flags", flags);
|
|
1637
|
-
if (normalizedFlags.length === 0) {
|
|
1638
|
-
throw new TypeError("registerFlags requires at least one flag definition");
|
|
1639
|
-
}
|
|
1640
|
-
this.#registrationRegistry.flags.push({
|
|
1641
|
-
layer: this.#loadedExtension.layer,
|
|
1642
|
-
name: this.#loadedExtension.name,
|
|
1643
|
-
target_command: normalizedTargetCommand,
|
|
1644
|
-
flags: normalizedFlags,
|
|
1645
|
-
});
|
|
1646
|
-
}
|
|
1647
|
-
registerItemFields(fields) {
|
|
1648
|
-
assertExtensionCapability(this.#loadedExtension, "schema", "registerItemFields");
|
|
1649
|
-
if (!this.allowRegistration("schema.itemfields", "registerItemFields", "schema")) {
|
|
1650
|
-
return;
|
|
1651
|
-
}
|
|
1652
|
-
validateItemFieldDefinitions(fields);
|
|
1653
|
-
const normalizedFields = normalizeRegistrationRecordList("registerItemFields fields", fields);
|
|
1654
|
-
if (normalizedFields.length === 0) {
|
|
1655
|
-
throw new TypeError("registerItemFields requires at least one field definition");
|
|
1656
|
-
}
|
|
1657
|
-
this.#registrationRegistry.item_fields.push({
|
|
1658
|
-
layer: this.#loadedExtension.layer,
|
|
1659
|
-
name: this.#loadedExtension.name,
|
|
1660
|
-
fields: normalizedFields,
|
|
1661
|
-
});
|
|
1662
|
-
}
|
|
1663
|
-
registerItemTypes(types) {
|
|
1664
|
-
assertExtensionCapability(this.#loadedExtension, "schema", "registerItemTypes");
|
|
1665
|
-
if (!this.allowRegistration("schema.itemtypes", "registerItemTypes", "schema")) {
|
|
1666
|
-
return;
|
|
1667
|
-
}
|
|
1668
|
-
validateItemTypeDefinitions(types);
|
|
1669
|
-
const normalizedTypes = normalizeRegistrationRecordList("registerItemTypes types", types);
|
|
1670
|
-
if (normalizedTypes.length === 0) {
|
|
1671
|
-
throw new TypeError("registerItemTypes requires at least one type definition");
|
|
1672
|
-
}
|
|
1673
|
-
this.#registrationRegistry.item_types.push({
|
|
1674
|
-
layer: this.#loadedExtension.layer,
|
|
1675
|
-
name: this.#loadedExtension.name,
|
|
1676
|
-
types: normalizedTypes,
|
|
1677
|
-
});
|
|
1678
|
-
}
|
|
1679
|
-
registerRelationshipKinds(definitions) {
|
|
1680
|
-
assertExtensionCapability(this.#loadedExtension, "schema", "registerRelationshipKinds");
|
|
1681
|
-
if (!this.allowRegistration("schema.relationshipkinds", "registerRelationshipKinds", "schema")) {
|
|
1682
|
-
return;
|
|
1683
|
-
}
|
|
1684
|
-
if (!Array.isArray(definitions)) {
|
|
1685
|
-
throw new TypeError("registerRelationshipKinds definitions requires an array of object definitions");
|
|
1686
|
-
}
|
|
1687
|
-
if (definitions.length === 0) {
|
|
1688
|
-
throw new TypeError("registerRelationshipKinds requires at least one definition");
|
|
1689
|
-
}
|
|
1690
|
-
const registry = createRelationshipKindRegistry();
|
|
1691
|
-
for (const registration of this.#registrationRegistry.relationship_kinds) {
|
|
1692
|
-
for (const definition of registration.definitions) {
|
|
1693
|
-
registry.register(definition);
|
|
1694
|
-
}
|
|
1695
|
-
}
|
|
1696
|
-
const validated = definitions.map((definition) => {
|
|
1697
|
-
registry.register(definition);
|
|
1698
|
-
return registry.require(definition.kind);
|
|
1699
|
-
});
|
|
1700
|
-
this.#registrationRegistry.relationship_kinds.push({
|
|
1701
|
-
layer: this.#loadedExtension.layer,
|
|
1702
|
-
name: this.#loadedExtension.name,
|
|
1703
|
-
definitions: validated,
|
|
1704
|
-
});
|
|
1705
|
-
}
|
|
1706
|
-
registerMigration(definition) {
|
|
1707
|
-
assertExtensionCapability(this.#loadedExtension, "schema", "registerMigration");
|
|
1708
|
-
if (!this.allowRegistration("schema.migrations", "registerMigration", "schema")) {
|
|
1709
|
-
return;
|
|
1710
|
-
}
|
|
1711
|
-
validateMigrationDefinition(definition);
|
|
1712
|
-
const runtimeDefinition = normalizeRuntimeRegistrationRecord("registerMigration definition", definition);
|
|
1713
|
-
this.#registrationRegistry.migrations.push(attachRuntimeDefinition({
|
|
1714
|
-
layer: this.#loadedExtension.layer,
|
|
1715
|
-
name: this.#loadedExtension.name,
|
|
1716
|
-
definition: normalizeRegistrationRecord("registerMigration definition", definition),
|
|
1717
|
-
}, runtimeDefinition));
|
|
1718
|
-
}
|
|
1719
|
-
registerProfile(profile) {
|
|
1720
|
-
assertExtensionCapability(this.#loadedExtension, "schema", "registerProfile");
|
|
1721
|
-
if (!this.allowRegistration("schema.profiles", "registerProfile", "schema")) {
|
|
1722
|
-
return;
|
|
1723
|
-
}
|
|
1724
|
-
// Snapshot first, then validate and default the snapshot: cloning resolves
|
|
1725
|
-
// any getters once into plain data decoupled from the caller's object, so
|
|
1726
|
-
// validation and storage operate on the same value — a getter cannot present
|
|
1727
|
-
// one value to validation and another to the registry. Defaults are applied
|
|
1728
|
-
// only after validation, so an invalid type is rejected, not silently coerced.
|
|
1729
|
-
const snapshot = cloneRuntimeRegistrationValue(profile);
|
|
1730
|
-
validateProjectProfileDefinition(snapshot);
|
|
1731
|
-
this.#registrationRegistry.profiles.push({
|
|
1732
|
-
layer: this.#loadedExtension.layer,
|
|
1733
|
-
name: this.#loadedExtension.name,
|
|
1734
|
-
profile: applyProjectProfileDefaults(snapshot),
|
|
1735
|
-
});
|
|
1736
|
-
}
|
|
1737
|
-
/** Validates and records optional importer/exporter flag metadata through the schema policy gate. */
|
|
1738
|
-
registerImportExportCommandFlags(method, commandPath, resolvedOptions) {
|
|
1739
|
-
if (resolvedOptions.flags === undefined) {
|
|
1740
|
-
return;
|
|
1741
|
-
}
|
|
1742
|
-
assertExtensionCapability(this.#loadedExtension, "schema", `${method} options.flags`);
|
|
1743
|
-
if (!this.allowRegistration("schema.flags", `${method} options.flags`, "schema")) {
|
|
1744
|
-
return;
|
|
1745
|
-
}
|
|
1746
|
-
validateFlagDefinitions(resolvedOptions.flags);
|
|
1747
|
-
this.#registrationRegistry.flags.push({
|
|
1748
|
-
layer: this.#loadedExtension.layer,
|
|
1749
|
-
name: this.#loadedExtension.name,
|
|
1750
|
-
target_command: commandPath,
|
|
1751
|
-
flags: normalizeFlagDefinitions(`${method} options.flags`, resolvedOptions.flags),
|
|
1752
|
-
});
|
|
1753
|
-
}
|
|
1754
|
-
applyImportExportCommandMetadata(method, commandPath, options) {
|
|
1755
|
-
if (options !== undefined &&
|
|
1756
|
-
(typeof options !== "object" ||
|
|
1757
|
-
options === null ||
|
|
1758
|
-
Array.isArray(options))) {
|
|
1759
|
-
throw new TypeError(`${method} options must be an object when provided`);
|
|
1760
|
-
}
|
|
1761
|
-
const defaultDescription = `${method === "registerImporter" ? "Import" : "Export"} items with the registered extension adapter.`;
|
|
1762
|
-
const defaultArguments = [
|
|
1763
|
-
{
|
|
1764
|
-
name: "file",
|
|
1765
|
-
required: false,
|
|
1766
|
-
description: "Optional input or output file path.",
|
|
1767
|
-
},
|
|
1768
|
-
];
|
|
1769
|
-
const resolvedOptions = {
|
|
1770
|
-
...options,
|
|
1771
|
-
description: options?.description ?? defaultDescription,
|
|
1772
|
-
arguments: options?.arguments ?? defaultArguments,
|
|
1773
|
-
};
|
|
1774
|
-
const output = resolveImportExportArtifactOutput(method, resolvedOptions, options?.description !== undefined);
|
|
1775
|
-
assertOptionalStringField(`${method} options.action`, resolvedOptions.action);
|
|
1776
|
-
assertOptionalStringField(`${method} options.description`, resolvedOptions.description);
|
|
1777
|
-
assertOptionalStringField(`${method} options.intent`, resolvedOptions.intent);
|
|
1778
|
-
const action = resolveCommandDefinitionAction(commandPath, resolvedOptions.action);
|
|
1779
|
-
const examples = normalizeOptionalStringArrayField(`${method} options.examples`, resolvedOptions.examples);
|
|
1780
|
-
const failureHints = normalizeOptionalStringArrayField(`${method} options.failure_hints`, resolvedOptions.failure_hints);
|
|
1781
|
-
const argumentsDefinition = normalizeCommandDefinitionArguments(resolvedOptions.arguments);
|
|
1782
|
-
this.registerImportExportCommandFlags(method, commandPath, resolvedOptions);
|
|
1783
|
-
const registration = {
|
|
1784
|
-
layer: this.#loadedExtension.layer,
|
|
1785
|
-
name: this.#loadedExtension.name,
|
|
1786
|
-
source_package: this.#loadedExtension.source_package,
|
|
1787
|
-
command: commandPath,
|
|
1788
|
-
action,
|
|
1789
|
-
examples,
|
|
1790
|
-
failure_hints: failureHints,
|
|
1791
|
-
arguments: argumentsDefinition,
|
|
1792
|
-
};
|
|
1793
|
-
const description = resolvedOptions.description?.trim();
|
|
1794
|
-
if (description) {
|
|
1795
|
-
registration.description = description;
|
|
1796
|
-
}
|
|
1797
|
-
const intent = resolvedOptions.intent?.trim();
|
|
1798
|
-
if (intent) {
|
|
1799
|
-
registration.intent = intent;
|
|
1800
|
-
}
|
|
1801
|
-
this.#registrationRegistry.commands.push(registration);
|
|
1802
|
-
return output;
|
|
1803
|
-
}
|
|
1804
|
-
registerImporter(name, importer, options) {
|
|
1805
|
-
assertExtensionCapability(this.#loadedExtension, "importers", "registerImporter");
|
|
1806
|
-
if (!this.allowRegistration("importers.importer", "registerImporter", "importers")) {
|
|
1807
|
-
return;
|
|
1808
|
-
}
|
|
1809
|
-
const normalizedName = normalizeRegistrationName(assertNonEmptyRegistrationString("registerImporter name", name));
|
|
1810
|
-
assertRegistrationFunction("registerImporter importer", importer);
|
|
1811
|
-
const commandPath = toRegistrationCommandPath(normalizedName, "import");
|
|
1812
|
-
// Validate and register optional command metadata before mutating the registry
|
|
1813
|
-
// so an invalid options object leaves no partial importer registration.
|
|
1814
|
-
this.applyImportExportCommandMetadata("registerImporter", commandPath, options);
|
|
1815
|
-
this.#registrationRegistry.importers.push({
|
|
1816
|
-
layer: this.#loadedExtension.layer,
|
|
1817
|
-
name: this.#loadedExtension.name,
|
|
1818
|
-
importer: normalizedName,
|
|
1819
|
-
});
|
|
1820
|
-
this.#commandRegistry.handlers.push({
|
|
1821
|
-
layer: this.#loadedExtension.layer,
|
|
1822
|
-
name: this.#loadedExtension.name,
|
|
1823
|
-
command: commandPath,
|
|
1824
|
-
run: async (context) => importer(buildImportExportContext(context, normalizedName, "import")),
|
|
1825
|
-
});
|
|
1826
|
-
}
|
|
1827
|
-
registerExporter(name, exporter, options) {
|
|
1828
|
-
assertExtensionCapability(this.#loadedExtension, "importers", "registerExporter");
|
|
1829
|
-
if (!this.allowRegistration("importers.exporter", "registerExporter", "importers")) {
|
|
1830
|
-
return;
|
|
1831
|
-
}
|
|
1832
|
-
const normalizedName = normalizeRegistrationName(assertNonEmptyRegistrationString("registerExporter name", name));
|
|
1833
|
-
assertRegistrationFunction("registerExporter exporter", exporter);
|
|
1834
|
-
const commandPath = toRegistrationCommandPath(normalizedName, "export");
|
|
1835
|
-
// Validate and register optional command metadata before mutating the registry
|
|
1836
|
-
// so an invalid options object leaves no partial exporter registration.
|
|
1837
|
-
const output = this.applyImportExportCommandMetadata("registerExporter", commandPath, options);
|
|
1838
|
-
this.#registrationRegistry.exporters.push({
|
|
1839
|
-
layer: this.#loadedExtension.layer,
|
|
1840
|
-
name: this.#loadedExtension.name,
|
|
1841
|
-
exporter: normalizedName,
|
|
1842
|
-
...(output === undefined ? {} : { output }),
|
|
1843
|
-
});
|
|
1844
|
-
this.#commandRegistry.handlers.push({
|
|
1845
|
-
layer: this.#loadedExtension.layer,
|
|
1846
|
-
name: this.#loadedExtension.name,
|
|
1847
|
-
command: commandPath,
|
|
1848
|
-
run: async (context) => {
|
|
1849
|
-
const result = await exporter(buildImportExportContext(context, normalizedName, "export"));
|
|
1850
|
-
return output?.receipt === "suppress" &&
|
|
1851
|
-
!isHostOutputSuppressed(result)
|
|
1852
|
-
? suppressHostOutput(result)
|
|
1853
|
-
: result;
|
|
1854
|
-
},
|
|
1855
|
-
});
|
|
1856
|
-
}
|
|
1857
|
-
registerSearchProvider(provider) {
|
|
1858
|
-
assertExtensionCapability(this.#loadedExtension, "search", "registerSearchProvider");
|
|
1859
|
-
if (!this.allowRegistration("search.provider", "registerSearchProvider", "search")) {
|
|
1860
|
-
return;
|
|
1861
|
-
}
|
|
1862
|
-
const runtimeDefinition = normalizeRuntimeRegistrationRecord("registerSearchProvider provider", provider);
|
|
1863
|
-
this.#registrationRegistry.search_providers.push(attachRuntimeDefinition({
|
|
1864
|
-
layer: this.#loadedExtension.layer,
|
|
1865
|
-
name: this.#loadedExtension.name,
|
|
1866
|
-
definition: normalizeRegistrationRecord("registerSearchProvider provider", provider),
|
|
1867
|
-
}, runtimeDefinition));
|
|
1868
|
-
}
|
|
1869
|
-
registerVectorStoreAdapter(adapter) {
|
|
1870
|
-
assertExtensionCapability(this.#loadedExtension, "search", "registerVectorStoreAdapter");
|
|
1871
|
-
if (!this.allowRegistration("search.vectorstore", "registerVectorStoreAdapter", "search")) {
|
|
1872
|
-
return;
|
|
1873
|
-
}
|
|
1874
|
-
const runtimeDefinition = normalizeRuntimeRegistrationRecord("registerVectorStoreAdapter adapter", adapter);
|
|
1875
|
-
this.#registrationRegistry.vector_store_adapters.push(attachRuntimeDefinition({
|
|
1876
|
-
layer: this.#loadedExtension.layer,
|
|
1877
|
-
name: this.#loadedExtension.name,
|
|
1878
|
-
definition: normalizeRegistrationRecord("registerVectorStoreAdapter adapter", adapter),
|
|
1879
|
-
}, runtimeDefinition));
|
|
1880
|
-
}
|
|
1881
|
-
registerAssuranceMeasurementProvider(provider) {
|
|
1882
|
-
assertExtensionCapability(this.#loadedExtension, "services", "registerAssuranceMeasurementProvider");
|
|
1883
|
-
if (!this.allowRegistration("services.assuranceprovider", "registerAssuranceMeasurementProvider", "services")) {
|
|
1884
|
-
return;
|
|
1885
|
-
}
|
|
1886
|
-
validateAssuranceMeasurementProviderDefinition(provider);
|
|
1887
|
-
if (provider.network &&
|
|
1888
|
-
this.#loadedExtension.permissions?.network !== true) {
|
|
1889
|
-
throw new TypeError("registerAssuranceMeasurementProvider network provider requires permissions.network=true");
|
|
1890
|
-
}
|
|
1891
|
-
const runtimeDefinition = normalizeRuntimeRegistrationRecord("registerAssuranceMeasurementProvider provider", provider);
|
|
1892
|
-
this.#registrationRegistry.assurance_providers.push(attachRuntimeDefinition({
|
|
1893
|
-
layer: this.#loadedExtension.layer,
|
|
1894
|
-
name: this.#loadedExtension.name,
|
|
1895
|
-
network_permission: this.#loadedExtension.permissions?.network === true,
|
|
1896
|
-
definition: normalizeRegistrationRecord("registerAssuranceMeasurementProvider provider", provider),
|
|
1897
|
-
}, runtimeDefinition));
|
|
1898
|
-
}
|
|
1899
|
-
registerBeforeCommand(hook) {
|
|
1900
|
-
assertExtensionCapability(this.#loadedExtension, "hooks", "api.hooks.beforeCommand");
|
|
1901
|
-
if (!this.allowRegistration("hooks.beforecommand", "api.hooks.beforeCommand", "hooks"))
|
|
1902
|
-
return;
|
|
1903
|
-
assertHookHandler("beforeCommand", hook);
|
|
1904
|
-
this.#hookRegistry.beforeCommand.push({
|
|
1905
|
-
layer: this.#loadedExtension.layer,
|
|
1906
|
-
name: this.#loadedExtension.name,
|
|
1907
|
-
run: hook,
|
|
1908
|
-
});
|
|
1909
|
-
}
|
|
1910
|
-
registerBeforeMutation(hook) {
|
|
1911
|
-
assertExtensionCapability(this.#loadedExtension, "hooks", "api.hooks.beforeMutation");
|
|
1912
|
-
if (!this.allowRegistration("hooks.beforemutation", "api.hooks.beforeMutation", "hooks"))
|
|
1913
|
-
return;
|
|
1914
|
-
assertHookHandler("beforeMutation", hook);
|
|
1915
|
-
this.#hookRegistry.beforeMutation.push({
|
|
1916
|
-
layer: this.#loadedExtension.layer,
|
|
1917
|
-
name: this.#loadedExtension.name,
|
|
1918
|
-
run: hook,
|
|
1919
|
-
});
|
|
1920
|
-
}
|
|
1921
|
-
registerAfterCommand(hook) {
|
|
1922
|
-
assertExtensionCapability(this.#loadedExtension, "hooks", "api.hooks.afterCommand");
|
|
1923
|
-
if (!this.allowRegistration("hooks.aftercommand", "api.hooks.afterCommand", "hooks"))
|
|
1924
|
-
return;
|
|
1925
|
-
assertHookHandler("afterCommand", hook);
|
|
1926
|
-
this.#hookRegistry.afterCommand.push({
|
|
1927
|
-
layer: this.#loadedExtension.layer,
|
|
1928
|
-
name: this.#loadedExtension.name,
|
|
1929
|
-
run: hook,
|
|
1930
|
-
});
|
|
1931
|
-
}
|
|
1932
|
-
registerOnWrite(hook) {
|
|
1933
|
-
assertExtensionCapability(this.#loadedExtension, "hooks", "api.hooks.onWrite");
|
|
1934
|
-
if (!this.allowRegistration("hooks.onwrite", "api.hooks.onWrite", "hooks"))
|
|
1935
|
-
return;
|
|
1936
|
-
assertHookHandler("onWrite", hook);
|
|
1937
|
-
this.#hookRegistry.onWrite.push({
|
|
1938
|
-
layer: this.#loadedExtension.layer,
|
|
1939
|
-
name: this.#loadedExtension.name,
|
|
1940
|
-
run: hook,
|
|
1941
|
-
});
|
|
1942
|
-
}
|
|
1943
|
-
registerOnRead(hook) {
|
|
1944
|
-
assertExtensionCapability(this.#loadedExtension, "hooks", "api.hooks.onRead");
|
|
1945
|
-
if (!this.allowRegistration("hooks.onread", "api.hooks.onRead", "hooks"))
|
|
1946
|
-
return;
|
|
1947
|
-
assertHookHandler("onRead", hook);
|
|
1948
|
-
this.#hookRegistry.onRead.push({
|
|
1949
|
-
layer: this.#loadedExtension.layer,
|
|
1950
|
-
name: this.#loadedExtension.name,
|
|
1951
|
-
run: hook,
|
|
1952
|
-
});
|
|
1953
|
-
}
|
|
1954
|
-
registerOnIndex(hook) {
|
|
1955
|
-
assertExtensionCapability(this.#loadedExtension, "hooks", "api.hooks.onIndex");
|
|
1956
|
-
if (!this.allowRegistration("hooks.onindex", "api.hooks.onIndex", "hooks"))
|
|
1957
|
-
return;
|
|
1958
|
-
assertHookHandler("onIndex", hook);
|
|
1959
|
-
this.#hookRegistry.onIndex.push({
|
|
1960
|
-
layer: this.#loadedExtension.layer,
|
|
1961
|
-
name: this.#loadedExtension.name,
|
|
1962
|
-
run: hook,
|
|
1963
|
-
});
|
|
1964
|
-
}
|
|
1965
|
-
}
|
|
1966
|
-
function createExtensionApi(extension, hooks, commands, parsers, preflight, services, renderers, registrations, activationWarnings, activationFailures, policy) {
|
|
1967
|
-
return new ExtensionApiRegistrar(extension, hooks, commands, parsers, preflight, services, renderers, registrations, activationWarnings, activationFailures, policy);
|
|
1968
|
-
}
|
|
1969
|
-
function getRegistrationCounts(registrations) {
|
|
1970
|
-
const commandCount = registrations.commands.length;
|
|
1971
|
-
const flagCount = registrations.flags.reduce((total, entry) => total + entry.flags.length, 0);
|
|
1972
|
-
const itemFieldCount = registrations.item_fields.reduce((total, entry) => total + entry.fields.length, 0);
|
|
1973
|
-
const itemTypeCount = registrations.item_types.reduce((total, entry) => total + entry.types.length, 0);
|
|
1974
|
-
// Preserve compatibility with activation payloads produced before this registry existed.
|
|
1975
|
-
const relationshipKindCount = (registrations.relationship_kinds ?? []).reduce((total, entry) => total + entry.definitions.length, 0);
|
|
1976
|
-
return {
|
|
1977
|
-
commands: commandCount,
|
|
1978
|
-
flags: flagCount,
|
|
1979
|
-
item_fields: itemFieldCount,
|
|
1980
|
-
item_types: itemTypeCount,
|
|
1981
|
-
...(relationshipKindCount > 0
|
|
1982
|
-
? { relationship_kinds: relationshipKindCount }
|
|
1983
|
-
: {}),
|
|
1984
|
-
migrations: registrations.migrations.length,
|
|
1985
|
-
profiles: registrations.profiles.length,
|
|
1986
|
-
importers: registrations.importers.length,
|
|
1987
|
-
exporters: registrations.exporters.length,
|
|
1988
|
-
search_providers: registrations.search_providers.length,
|
|
1989
|
-
vector_store_adapters: registrations.vector_store_adapters.length,
|
|
1990
|
-
...((registrations.assurance_providers?.length ?? 0) > 0
|
|
1991
|
-
? { assurance_providers: registrations.assurance_providers.length }
|
|
1992
|
-
: {}),
|
|
1993
|
-
};
|
|
1994
|
-
}
|
|
1995
|
-
function collectCommandCollisionWarnings(commands) {
|
|
1996
|
-
const warnings = [];
|
|
1997
|
-
const collectByCommand = (entries, codePrefix) => {
|
|
1998
|
-
const grouped = new Map();
|
|
1999
|
-
for (const entry of entries) {
|
|
2000
|
-
const bucket = grouped.get(entry.command) ?? [];
|
|
2001
|
-
bucket.push(entry);
|
|
2002
|
-
grouped.set(entry.command, bucket);
|
|
2003
|
-
}
|
|
2004
|
-
for (const command of [...grouped.keys()].sort((left, right) => left.localeCompare(right))) {
|
|
2005
|
-
const bucket = grouped.get(command);
|
|
2006
|
-
if (bucket.length <= 1) {
|
|
2007
|
-
continue;
|
|
2008
|
-
}
|
|
2009
|
-
const winner = bucket[bucket.length - 1];
|
|
2010
|
-
for (const displaced of bucket.slice(0, -1)) {
|
|
2011
|
-
warnings.push(`${codePrefix}:${command}:${winner.layer}:${winner.name}:${displaced.layer}:${displaced.name}`);
|
|
2012
|
-
}
|
|
2013
|
-
}
|
|
2014
|
-
};
|
|
2015
|
-
collectByCommand(commands.handlers, "extension_command_handler_collision");
|
|
2016
|
-
collectByCommand(commands.overrides, "extension_command_override_collision");
|
|
2017
|
-
const handlerCommands = new Set(commands.handlers.map((entry) => entry.command));
|
|
2018
|
-
const overlapCommands = [
|
|
2019
|
-
...new Set(commands.overrides.map((entry) => entry.command)),
|
|
2020
|
-
].filter((command) => handlerCommands.has(command));
|
|
2021
|
-
overlapCommands.sort((left, right) => left.localeCompare(right));
|
|
2022
|
-
for (const command of overlapCommands) {
|
|
2023
|
-
const handlers = commands.handlers.filter((entry) => entry.command === command);
|
|
2024
|
-
const overrides = commands.overrides.filter((entry) => entry.command === command);
|
|
2025
|
-
for (const override of overrides) {
|
|
2026
|
-
for (const handler of handlers) {
|
|
2027
|
-
warnings.push(`extension_command_override_handler_overlap:${command}:${override.layer}:${override.name}:${handler.layer}:${handler.name}`);
|
|
2028
|
-
}
|
|
2029
|
-
}
|
|
2030
|
-
}
|
|
2031
|
-
return warnings;
|
|
2032
|
-
}
|
|
2033
|
-
function collectRendererCollisionWarnings(renderers) {
|
|
2034
|
-
const grouped = new Map();
|
|
2035
|
-
for (const entry of renderers.overrides) {
|
|
2036
|
-
const bucket = grouped.get(entry.format) ?? [];
|
|
2037
|
-
bucket.push(entry);
|
|
2038
|
-
grouped.set(entry.format, bucket);
|
|
2039
|
-
}
|
|
2040
|
-
const warnings = [];
|
|
2041
|
-
for (const format of [...grouped.keys()].sort((left, right) => left.localeCompare(right))) {
|
|
2042
|
-
const bucket = grouped.get(format);
|
|
2043
|
-
if (bucket.length <= 1) {
|
|
2044
|
-
continue;
|
|
2045
|
-
}
|
|
2046
|
-
const winner = bucket[bucket.length - 1];
|
|
2047
|
-
for (const displaced of bucket.slice(0, -1)) {
|
|
2048
|
-
if (winner.commands?.length &&
|
|
2049
|
-
displaced.commands?.length &&
|
|
2050
|
-
!displaced.commands.some((command) => winner.commands?.includes(command))) {
|
|
2051
|
-
continue;
|
|
2052
|
-
}
|
|
2053
|
-
warnings.push(`extension_renderer_collision:${format}:${winner.layer}:${winner.name}:${displaced.layer}:${displaced.name}`);
|
|
2054
|
-
}
|
|
2055
|
-
}
|
|
2056
|
-
return warnings;
|
|
2057
|
-
}
|
|
2058
|
-
function collectParserCollisionWarnings(parsers) {
|
|
2059
|
-
const warnings = [];
|
|
2060
|
-
const grouped = new Map();
|
|
2061
|
-
for (const entry of parsers.overrides) {
|
|
2062
|
-
const bucket = grouped.get(entry.command) ?? [];
|
|
2063
|
-
bucket.push(entry);
|
|
2064
|
-
grouped.set(entry.command, bucket);
|
|
2065
|
-
}
|
|
2066
|
-
for (const command of [...grouped.keys()].sort((left, right) => left.localeCompare(right))) {
|
|
2067
|
-
const bucket = grouped.get(command);
|
|
2068
|
-
if (bucket.length <= 1) {
|
|
2069
|
-
continue;
|
|
2070
|
-
}
|
|
2071
|
-
const winner = bucket[bucket.length - 1];
|
|
2072
|
-
for (const displaced of bucket.slice(0, -1)) {
|
|
2073
|
-
warnings.push(`extension_parser_override_collision:${command}:${winner.layer}:${winner.name}:${displaced.layer}:${displaced.name}`);
|
|
2074
|
-
}
|
|
2075
|
-
}
|
|
2076
|
-
return warnings;
|
|
2077
|
-
}
|
|
2078
|
-
// Services whose runtime semantics are chain/fall-through (each override gets a chance);
|
|
2079
|
-
// for those, registering multiple overrides is by design, not a collision.
|
|
2080
|
-
const CHAINED_SERVICE_NAMES = new Set(["output_format"]);
|
|
2081
|
-
function collectServiceCollisionWarnings(services) {
|
|
2082
|
-
const warnings = [];
|
|
2083
|
-
const grouped = new Map();
|
|
2084
|
-
for (const entry of services.overrides) {
|
|
2085
|
-
const bucket = grouped.get(entry.service) ?? [];
|
|
2086
|
-
bucket.push(entry);
|
|
2087
|
-
grouped.set(entry.service, bucket);
|
|
2088
|
-
}
|
|
2089
|
-
for (const service of [...grouped.keys()].sort((left, right) => left.localeCompare(right))) {
|
|
2090
|
-
const bucket = grouped.get(service);
|
|
2091
|
-
if (bucket.length <= 1) {
|
|
2092
|
-
continue;
|
|
2093
|
-
}
|
|
2094
|
-
if (CHAINED_SERVICE_NAMES.has(service)) {
|
|
2095
|
-
continue;
|
|
2096
|
-
}
|
|
2097
|
-
const winner = bucket[bucket.length - 1];
|
|
2098
|
-
for (const displaced of bucket.slice(0, -1)) {
|
|
2099
|
-
warnings.push(`extension_service_override_collision:${service}:${winner.layer}:${winner.name}:${displaced.layer}:${displaced.name}`);
|
|
2100
|
-
}
|
|
2101
|
-
}
|
|
2102
|
-
return warnings;
|
|
2103
|
-
}
|
|
2104
|
-
/** Implements activate extensions for the public runtime surface of this module. */
|
|
2105
|
-
export async function activateExtensions(loadResult) {
|
|
2106
|
-
const policy = hydrateExtensionPolicy(loadResult.policy ?? DEFAULT_EXTENSION_POLICY);
|
|
2107
|
-
const hooks = createEmptyExtensionHookRegistry();
|
|
2108
|
-
const commands = createEmptyExtensionCommandRegistry();
|
|
2109
|
-
const parsers = createEmptyExtensionParserRegistry();
|
|
2110
|
-
const preflight = createEmptyExtensionPreflightRegistry();
|
|
2111
|
-
const services = createEmptyExtensionServiceRegistry();
|
|
2112
|
-
const renderers = createEmptyExtensionRendererRegistry();
|
|
2113
|
-
const registrations = createEmptyExtensionRegistrationRegistry();
|
|
2114
|
-
const failed = [];
|
|
2115
|
-
const warnings = [];
|
|
2116
|
-
for (const extension of loadResult.loaded) {
|
|
2117
|
-
const activatable = resolveActivatableExtension(extension.module);
|
|
2118
|
-
if (!activatable) {
|
|
2119
|
-
continue;
|
|
2120
|
-
}
|
|
2121
|
-
const failedBeforeActivation = failed.length;
|
|
2122
|
-
const rollbackPartialActivation = captureExtensionActivationRollback({
|
|
2123
|
-
hooks,
|
|
2124
|
-
commands,
|
|
2125
|
-
parsers,
|
|
2126
|
-
preflight,
|
|
2127
|
-
services,
|
|
2128
|
-
renderers,
|
|
2129
|
-
registrations,
|
|
2130
|
-
});
|
|
2131
|
-
try {
|
|
2132
|
-
await activatable.activate(createExtensionApi(extension, hooks, commands, parsers, preflight, services, renderers, registrations, warnings, failed, policy));
|
|
2133
|
-
if (failed.length > failedBeforeActivation) {
|
|
2134
|
-
rollbackPartialActivation();
|
|
2135
|
-
warnings.push(`extension_activation_rolled_back:${extension.layer}:${extension.name}`);
|
|
2136
|
-
}
|
|
2137
|
-
}
|
|
2138
|
-
catch (error) {
|
|
2139
|
-
rollbackPartialActivation();
|
|
2140
|
-
warnings.push(`extension_activate_failed:${extension.layer}:${extension.name}`);
|
|
2141
|
-
const trace = extractRegistrationValidationTrace(error);
|
|
2142
|
-
failed.push({
|
|
2143
|
-
layer: extension.layer,
|
|
2144
|
-
name: extension.name,
|
|
2145
|
-
entry_path: extension.entry_path,
|
|
2146
|
-
error: formatUnknownError(error),
|
|
2147
|
-
trace,
|
|
2148
|
-
});
|
|
2149
|
-
}
|
|
2150
|
-
}
|
|
2151
|
-
const collisionWarnings = [
|
|
2152
|
-
...collectCommandCollisionWarnings(commands),
|
|
2153
|
-
...collectParserCollisionWarnings(parsers),
|
|
2154
|
-
...collectPreflightCollisionWarnings(preflight),
|
|
2155
|
-
...collectServiceCollisionWarnings(services),
|
|
2156
|
-
...collectRendererCollisionWarnings(renderers),
|
|
2157
|
-
];
|
|
2158
|
-
const mergedWarnings = [...new Set([...warnings, ...collisionWarnings])];
|
|
2159
|
-
return {
|
|
2160
|
-
hooks,
|
|
2161
|
-
commands,
|
|
2162
|
-
parsers,
|
|
2163
|
-
preflight,
|
|
2164
|
-
services,
|
|
2165
|
-
renderers,
|
|
2166
|
-
registrations,
|
|
2167
|
-
failed,
|
|
2168
|
-
warnings: mergedWarnings,
|
|
2169
|
-
hook_counts: {
|
|
2170
|
-
before_command: hooks.beforeCommand.length,
|
|
2171
|
-
before_mutation: hooks.beforeMutation.length,
|
|
2172
|
-
after_command: hooks.afterCommand.length,
|
|
2173
|
-
on_write: hooks.onWrite.length,
|
|
2174
|
-
on_read: hooks.onRead.length,
|
|
2175
|
-
on_index: hooks.onIndex.length,
|
|
2176
|
-
},
|
|
2177
|
-
command_override_count: commands.overrides.length,
|
|
2178
|
-
command_handler_count: commands.handlers.length,
|
|
2179
|
-
parser_override_count: parsers.overrides.length,
|
|
2180
|
-
preflight_override_count: preflight.overrides.length,
|
|
2181
|
-
service_override_count: services.overrides.length,
|
|
2182
|
-
renderer_override_count: renderers.overrides.length,
|
|
2183
|
-
registration_counts: getRegistrationCounts(registrations),
|
|
2184
|
-
};
|
|
2185
|
-
}
|
|
2186
|
-
/** Public contract for test only loader, shared by SDK and presentation-layer consumers. */
|
|
2187
|
-
export const _testOnlyLoader = {
|
|
2188
|
-
assertFlagValueTypeAndDefault,
|
|
2189
|
-
assertOptionalStringField,
|
|
2190
|
-
compareComparableVersions,
|
|
2191
|
-
collectCommandCollisionWarnings,
|
|
2192
|
-
collectParserCollisionWarnings,
|
|
2193
|
-
collectRendererCollisionWarnings,
|
|
2194
|
-
collectServiceCollisionWarnings,
|
|
2195
|
-
createExtensionApi,
|
|
2196
|
-
createRegistrationValidationError,
|
|
2197
|
-
evaluatePmMaxVersionCompatibility,
|
|
2198
|
-
evaluatePmMinVersionCompatibility,
|
|
2199
|
-
extractRegistrationValidationTrace,
|
|
2200
|
-
fingerprintPath,
|
|
2201
|
-
getRegistrationCounts,
|
|
2202
|
-
normalizeCommandDefinitionArguments,
|
|
2203
|
-
normalizeExtensionDeactivateTimeout,
|
|
2204
|
-
normalizeOptionalStringArrayField,
|
|
2205
|
-
normalizeRegistrationRecord,
|
|
2206
|
-
normalizeRegistrationRecordList,
|
|
2207
|
-
normalizeRuntimeRegistrationRecord,
|
|
2208
|
-
parseComparableVersion,
|
|
2209
|
-
parseManifest: parseExtensionManifestDocument,
|
|
2210
|
-
readCurrentPmCliVersion,
|
|
2211
|
-
readManagedExtensionSourcePackages: async (extensionsRoot) => new Map([...(await readManagedExtensionSourcePackages(extensionsRoot))]
|
|
2212
|
-
.filter((entry) => typeof entry[1].package_name === "string")
|
|
2213
|
-
.map(([key, identity]) => [key, identity.package_name])),
|
|
2214
|
-
resolveExtensionImportHref,
|
|
2215
|
-
resolveCurrentPmCliVersion,
|
|
2216
|
-
resolveCommandDefinitionAction,
|
|
2217
|
-
sanitizeRegistrationValue,
|
|
2218
|
-
validateItemFieldDefinitions,
|
|
2219
|
-
resetCurrentPmCliVersionCacheForTest: () => {
|
|
2220
|
-
currentPmCliVersionPromise = null;
|
|
2221
|
-
},
|
|
2222
|
-
};
|
|
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]="2f54ac29-9bf8-51f4-9352-8f57d1b5a798")}catch(e2){}})();import fs from"node:fs/promises";import path from"node:path";import{pathToFileURL}from"node:url";import{pathExists}from"../fs/fs-utils.js";import{isPathWithinDirectory}from"../fs/path-utils.js";import{isHostOutputSuppressed,suppressHostOutput}from"../output/output-control.js";import{resolvePmPackageRootFromModule}from"../packages/root.js";import{resolveGlobalPmRoot}from"../store/paths.js";import{asRecordLoose,resolveActivatablePropertyRecord}from"../shared/primitives.js";import{flattenFlagListValue,isFlagDefaultValueCoercible,resolveFlagValueKind}from"./flag-value-types.js";import{KNOWN_ITEM_FIELD_TYPES,normalizeItemFieldType,suggestKnownItemFieldType}from"./item-field-types.js";import{snapshotExtensionModuleGraph}from"./module-graph-snapshot.js";import{captureExtensionActivationRollback}from"./activation-transaction.js";import{collectPreflightCollisionWarnings,normalizePreflightOverride}from"./preflight-ownership.js";import{normalizeServiceOverrideOwnership}from"./service-ownership.js";import{assertCommandDefinitionMetadataStrings}from"./command-visibility-tier.js";import{buildImportExportContext,resolveImportExportArtifactOutput}from"./exporter-output-contract.js";import{asRegistrationRecord,assertOptionalBooleanField,assertOptionalFlagDefaultField,assertOptionalStringArrayField,assertOptionalStringField,normalizeOptionalStringArrayField}from"./registration-validation.js";import{describeExtensionLongFlagFailure,findExtensionFlagTokenFailure}from"./flag-definition-validation.js";import{compareComparableVersions,evaluatePmMaxVersionBound,evaluatePmMinVersionBound,parseComparableVersion}from"./version-compat.js";import{createRelationshipKindRegistry}from"../../sdk/relationships.js";import{normalizeNames,isKnownExtensionCapability,collectUnknownExtensionCapabilities,normalizeManifestCapabilities,formatUnknownExtensionCapabilityWarning,formatLegacyExtensionCapabilityAliasWarning}from"./extension-capability-aliases.js";import{normalizeExtensionPolicy,serializeExtensionPolicy,hydrateExtensionPolicy,normalizePolicySandboxProfile,evaluateExtensionPolicyForExtension,evaluateExtensionPolicyForCapability,evaluateExtensionPolicyForRegistration}from"./extension-policy.js";import{createEmptyExtensionHookRegistry,createEmptyExtensionCommandRegistry,createEmptyExtensionParserRegistry,createEmptyExtensionPreflightRegistry,createEmptyExtensionServiceRegistry,createEmptyExtensionRendererRegistry,createEmptyExtensionRegistrationRegistry}from"./extension-registries.js";import{normalizeCommandName}from"./extension-runtime-helpers.js";import{normalizeExtensionContributionInventory}from"./contribution-inventory.js";import{formatExtensionManifestSchemaWarnings}from"./manifest-schema.js";import{attachRuntimeDefinition,assertHookHandler,assertNonEmptyRegistrationString,assertRegistrationFunction,cloneRuntimeRegistrationValue,createRegistrationValidationError,extractRegistrationValidationTrace,isExtensionServiceName,isOutputRendererFormat,normalizeRegistrationRecord,normalizeRegistrationRecordList,normalizeRuntimeRegistrationRecord,normalizeRegistrationName,sanitizeRegistrationValue,toRegistrationCommandPath,validateAssuranceMeasurementProviderDefinition}from"./registration-values.js";import{buildReadyExtensionCandidate}from"./extension-candidate.js";import{parseUnknownExtensionCapabilityWarning,parseLegacyExtensionCapabilityAliasWarning}from"./extension-capability-aliases.js";import{createEmptyExtensionHookRegistry as createEmptyExtensionHookRegistry2,createEmptyExtensionCommandRegistry as createEmptyExtensionCommandRegistry2,createEmptyExtensionParserRegistry as createEmptyExtensionParserRegistry2,createEmptyExtensionPreflightRegistry as createEmptyExtensionPreflightRegistry2,createEmptyExtensionServiceRegistry as createEmptyExtensionServiceRegistry2,createEmptyExtensionRendererRegistry as createEmptyExtensionRendererRegistry2,createEmptyExtensionRegistrationRegistry as createEmptyExtensionRegistrationRegistry2}from"./extension-registries.js";import{runBeforeCommandHooks,runBeforeMutationHooks,runAfterCommandHooks,runOnWriteHooks,runOnReadHooks,runOnIndexHooks,runCommandHandler,runParserOverride,runPreflightOverride,runServiceOverrideSync,runServiceOverride,runCommandOverride,runRendererOverride}from"./extension-hook-runtime.js";import{KNOWN_EXTENSION_CAPABILITIES,KNOWN_EXTENSION_SERVICE_NAMES,createDefaultExtensionGovernancePolicy}from"./extension-types.js";export*from"./extension-types.js";const DEFAULT_EXTENSION_PRIORITY=100;let currentPmCliVersionPromise=null;const DEFAULT_EXTENSION_POLICY=Object.freeze(createDefaultExtensionGovernancePolicy());let extensionReloadEpoch=0;function nextExtensionReloadToken(seed=Date.now()){extensionReloadEpoch+=1;return`${extensionReloadEpoch}-${seed}`}function parseOptionalManifestString(candidate,field){const value=candidate[field];if(value===void 0||value===null){return void 0}if(typeof value!=="string"||value.trim().length===0){return null}return value.trim()}function parseManifestEngines(value){if(value===void 0||value===null){return void 0}const enginesRecord=asRecordLoose(value);if(!enginesRecord){return null}const engines={};for(const key of Object.keys(enginesRecord).sort((left,right)=>left.localeCompare(right))){if(key.trim().length===0){return null}const engineValue=enginesRecord[key];if(typeof engineValue!=="string"||engineValue.trim().length===0){return null}engines[key.trim()]=engineValue.trim()}return Object.keys(engines).length>0?engines:void 0}function parseRequiredManifestString(candidate,field){const value=candidate[field];if(typeof value!=="string"||value.trim().length===0){return null}return value.trim()}function parseOptionalIntegerValue(value){if(value===void 0||value===null){return void 0}if(typeof value!=="number"||!Number.isInteger(value)){return null}return value}function parseOptionalBooleanValue(value){if(value===void 0||value===null){return void 0}if(typeof value!=="boolean"){return null}return value}function parseManifestPriority(candidate){const value=parseOptionalIntegerValue(candidate.priority);return value===void 0?DEFAULT_EXTENSION_PRIORITY:value}function parseManifestSandboxProfile(candidate){const value=candidate.sandbox_profile;if(value===void 0||value===null){return void 0}if(typeof value!=="string"){return null}const normalizedProfile=normalizePolicySandboxProfile(value);if(normalizedProfile!==value.trim().toLowerCase()){return null}return normalizedProfile}function optionalTrimmedString(value){return typeof value==="string"&&value.trim().length>0?value.trim():void 0}function parseManifestProvenance(value){if(value===void 0||value===null){return void 0}const provenanceRecord=asRecordLoose(value);if(!provenanceRecord){return null}const source=optionalTrimmedString(provenanceRecord.source);const signature=optionalTrimmedString(provenanceRecord.signature);const attestation=optionalTrimmedString(provenanceRecord.attestation);const verified=provenanceRecord.verified===void 0||provenanceRecord.verified===null?void 0:typeof provenanceRecord.verified==="boolean"?provenanceRecord.verified:null;if(verified===null){return null}return{...source?{source}:{},...signature?{signature}:{},...attestation?{attestation}:{},...typeof verified==="boolean"?{verified}:{}}}function parseManifestPermissions(value){if(value===void 0||value===null){return void 0}const permissionsRecord=asRecordLoose(value);if(!permissionsRecord){return null}const fsRead=parseOptionalBooleanValue(permissionsRecord.fs_read);const fsWrite=parseOptionalBooleanValue(permissionsRecord.fs_write);const network=parseOptionalBooleanValue(permissionsRecord.network);const envRead=parseOptionalBooleanValue(permissionsRecord.env_read);const envWrite=parseOptionalBooleanValue(permissionsRecord.env_write);const processSpawn=parseOptionalBooleanValue(permissionsRecord.process_spawn);if([fsRead,fsWrite,network,envRead,envWrite,processSpawn].includes(null)){return null}return{...typeof fsRead==="boolean"?{fs_read:fsRead}:{},...typeof fsWrite==="boolean"?{fs_write:fsWrite}:{},...typeof network==="boolean"?{network}:{},...typeof envRead==="boolean"?{env_read:envRead}:{},...typeof envWrite==="boolean"?{env_write:envWrite}:{},...typeof processSpawn==="boolean"?{process_spawn:processSpawn}:{}}}function parseManifestCapabilities(value){if(value===void 0||value===null){return{capabilities:[],legacy_aliases:[]}}if(!Array.isArray(value)||value.some(entry=>typeof entry!=="string")){return null}const normalizedCapabilities=normalizeManifestCapabilities(value);return{capabilities:normalizedCapabilities.capabilities,legacy_aliases:normalizedCapabilities.legacy_aliases}}function parseManifestActivation(value){if(value===void 0||value===null){return void 0}const activationRecord=asRecordLoose(value);if(!activationRecord){return null}const rawCommands=activationRecord.commands;if(rawCommands===void 0||rawCommands===null){return void 0}if(!Array.isArray(rawCommands)||rawCommands.some(entry=>typeof entry!=="string")){return null}const commands=[...new Set(rawCommands.map(entry=>normalizeCommandName(entry)).filter(entry=>entry.length>0))].sort((left,right)=>left.localeCompare(right));return commands.length>0?{commands}:void 0}function parseManifestMetadata(candidate){const manifestVersion=parseOptionalIntegerValue(candidate.manifest_version);if(manifestVersion===null){return null}const pmMinVersion=parseOptionalManifestString(candidate,"pm_min_version");if(pmMinVersion===null){return null}const pmMaxVersion=parseOptionalManifestString(candidate,"pm_max_version");if(pmMaxVersion===null){return null}const engines=parseManifestEngines(candidate.engines);if(engines===null){return null}const trusted=parseOptionalBooleanValue(candidate.trusted);if(trusted===null){return null}const sandboxProfile=parseManifestSandboxProfile(candidate);if(sandboxProfile===null){return null}const provenance=parseManifestProvenance(candidate.provenance);if(provenance===null){return null}const permissions=parseManifestPermissions(candidate.permissions);if(permissions===null){return null}const capabilities=parseManifestCapabilities(candidate.capabilities);if(capabilities===null){return null}const activation=parseManifestActivation(candidate.activation);if(activation===null){return null}const contributions=normalizeExtensionContributionInventory(candidate.contributions);if(contributions===null){return null}return{manifest_version:manifestVersion,pm_min_version:pmMinVersion,pm_max_version:pmMaxVersion,engines,trusted,sandbox_profile:sandboxProfile,provenance,permissions,capabilities:capabilities.capabilities,legacy_capability_aliases:capabilities.legacy_aliases,activation,contributions}}function parseExtensionManifestDocument(raw){if(typeof raw!=="object"||raw===null){return null}const candidate=raw;const name=parseRequiredManifestString(candidate,"name");if(name===null){return null}const version=parseRequiredManifestString(candidate,"version");if(version===null){return null}const entry=parseRequiredManifestString(candidate,"entry");if(entry===null){return null}const priority=parseManifestPriority(candidate);if(priority===null){return null}const metadata=parseManifestMetadata(candidate);if(metadata===null){return null}return{name,version,entry,priority,manifest_version:metadata.manifest_version,pm_min_version:metadata.pm_min_version,pm_max_version:metadata.pm_max_version,engines:metadata.engines,trusted:metadata.trusted,provenance:metadata.provenance,sandbox_profile:metadata.sandbox_profile,permissions:metadata.permissions,activation:metadata.activation,contributions:metadata.contributions,capabilities:metadata.capabilities,legacy_capability_aliases:metadata.legacy_capability_aliases.length>0?metadata.legacy_capability_aliases:void 0}}function shouldEnable(name,enabled,disabled){if(disabled.has(name)){return false}if(enabled.size===0){return true}return enabled.has(name)}async function isCanonicalPathWithinDirectory(directory,targetPath){const[resolvedDirectory,resolvedTargetPath]=await Promise.all([fs.realpath(directory),fs.realpath(targetPath)]);return isPathWithinDirectory(resolvedDirectory,resolvedTargetPath)}function resolveExtensionRoots(pmRoot,cwd=process.cwd()){return{global:path.join(resolveGlobalPmRoot(cwd),"extensions"),project:path.join(pmRoot,"extensions")}}async function listExtensionDirectories(extensionsRoot){try{const entries=await fs.readdir(extensionsRoot,{withFileTypes:true});return entries.filter(entry=>entry.isDirectory()).map(entry=>entry.name).sort((a,b)=>a.localeCompare(b))}catch{return[]}}function summarizeCandidate(candidate){const summary={layer:candidate.layer,directory:candidate.directory,manifest_path:candidate.manifest_path,name:candidate.manifest.name,version:candidate.manifest.version,entry:candidate.manifest.entry,priority:candidate.manifest.priority,entry_path:candidate.entry_path,manifest_version:candidate.manifest.manifest_version,pm_min_version:candidate.manifest.pm_min_version,pm_max_version:candidate.manifest.pm_max_version,engines:candidate.manifest.engines,trusted:candidate.manifest.trusted,provenance:candidate.manifest.provenance,sandbox_profile:candidate.manifest.sandbox_profile,permissions:candidate.manifest.permissions,capabilities:[...candidate.manifest.capabilities],activation:candidate.manifest.activation?{commands:[...candidate.manifest.activation.commands]}:void 0,contributions:candidate.manifest.contributions??candidate.contributions};if(candidate.source_package){summary.source_package=candidate.source_package}if(candidate.source_aliases){summary.source_aliases=[...candidate.source_aliases]}return summary}function normalizeManagedSourcePackage(value){return typeof value==="string"&&value.trim().length>0?value.trim():void 0}async function readManagedExtensionSourcePackages(extensionsRoot){const packages=new Map;try{const parsed=JSON.parse(await fs.readFile(path.join(extensionsRoot,".managed-extensions.json"),"utf8"));const managedExtensions=asRecordLoose(parsed);const entries=managedExtensions?.entries;if(!Array.isArray(entries)){return packages}for(const entry of entries){if(typeof entry!=="object"||entry===null){continue}const record=entry;const sourcePackage=normalizeManagedSourcePackage(record.source?.package);const aliases=[record.source?.input,record.source?.name,sourcePackage].map(value=>normalizeManagedSourcePackage(value)).filter(value=>value!==void 0);const contributions=normalizeExtensionContributionInventory(record.contributions);const identity={aliases:[...new Set(aliases)],...sourcePackage?{package_name:sourcePackage}:{},...contributions?{contributions}:{}};if(typeof record.directory==="string"&&record.directory.trim().length>0){packages.set(`directory:${record.directory.trim()}`,identity)}if(typeof record.name==="string"&&record.name.trim().length>0){packages.set(`name:${record.name.trim()}`,identity)}}}catch{return packages}return packages}function sortCandidates(candidates){return[...candidates].sort((left,right)=>{if(left.manifest.priority!==right.manifest.priority){return left.manifest.priority-right.manifest.priority}const byName=left.manifest.name.localeCompare(right.manifest.name);if(byName!==0){return byName}return left.directory.localeCompare(right.directory)})}function buildEffectiveExtensions(globalCandidates,projectCandidates){const ordered=[...sortCandidates(globalCandidates),...sortCandidates(projectCandidates)];const effective=[];for(const candidate of ordered){const existingIndex=effective.findIndex(entry=>entry.manifest.name===candidate.manifest.name);if(existingIndex>=0){effective.splice(existingIndex,1)}effective.push(candidate)}return effective}async function scanExtensionLayer(layer,extensionsRoot,enabled,disabled,pmMaxVersionExceededMode){const diagnostics=[];const warnings=[];const candidates=[];const directories=await listExtensionDirectories(extensionsRoot);const managedSourcePackages=await readManagedExtensionSourcePackages(extensionsRoot);for(const directory of directories){const scanned=await scanExtensionDirectory(layer,extensionsRoot,directory,enabled,disabled,managedSourcePackages,pmMaxVersionExceededMode);diagnostics.push(scanned.diagnostic);warnings.push(...scanned.warnings);if(scanned.candidate){candidates.push(scanned.candidate)}}return{diagnostics,warnings,candidates}}function emptyExtensionLayerScan(){return{diagnostics:[],warnings:[],candidates:[]}}function buildUnavailableExtensionScan(layer,directory,manifestPath,warning){return{diagnostic:{layer,directory,manifest_path:manifestPath,name:null,version:null,entry:null,priority:null,entry_path:null,enabled:null,status:"warn"},warnings:[warning],candidate:null}}function collectScannedExtensionWarnings(layer,manifest,rawManifest,entryWithinDirectory,entryExists,pmVersionCompatibility,pmMaxVersionCompatibility){const extensionWarnings=formatExtensionManifestSchemaWarnings(layer,manifest,rawManifest);if(Array.isArray(manifest.legacy_capability_aliases)&&manifest.legacy_capability_aliases.length>0){extensionWarnings.push(formatLegacyExtensionCapabilityAliasWarning(layer,manifest.name,manifest.legacy_capability_aliases))}for(const capability of collectUnknownExtensionCapabilities(manifest.capabilities)){extensionWarnings.push(formatUnknownExtensionCapabilityWarning(layer,manifest.name,capability))}if(!entryWithinDirectory){extensionWarnings.push(`extension_entry_outside_extension:${layer}:${manifest.name}`)}else if(!entryExists){extensionWarnings.push(`extension_entry_missing:${layer}:${manifest.name}`)}if(pmVersionCompatibility.warning){extensionWarnings.push(pmVersionCompatibility.warning)}if(pmMaxVersionCompatibility.warning){extensionWarnings.push(pmMaxVersionCompatibility.warning)}return extensionWarnings}async function scanExtensionDirectory(layer,extensionsRoot,directory,enabled,disabled,managedSourcePackages,pmMaxVersionExceededMode){const extensionDir=path.join(extensionsRoot,directory);const manifestPath=path.join(extensionDir,"manifest.json");if(!await pathExists(manifestPath)){return buildUnavailableExtensionScan(layer,directory,manifestPath,`extension_manifest_missing:${layer}:${directory}`)}let manifest;let rawManifest;try{const parsed=JSON.parse(await fs.readFile(manifestPath,"utf8"));rawManifest=asRecordLoose(parsed);manifest=parseExtensionManifestDocument(parsed)}catch{rawManifest=null;manifest=null}if(!manifest||!rawManifest){return buildUnavailableExtensionScan(layer,directory,manifestPath,`extension_manifest_invalid:${layer}:${directory}`)}const entryPath=path.resolve(extensionDir,manifest.entry);const entryWithinDirectoryByPath=isPathWithinDirectory(extensionDir,entryPath);const entryExists=entryWithinDirectoryByPath?await pathExists(entryPath):false;const entryWithinDirectory=entryWithinDirectoryByPath&&entryExists?await isCanonicalPathWithinDirectory(extensionDir,entryPath):entryWithinDirectoryByPath;const enabledForLoad=shouldEnable(manifest.name,enabled,disabled);const pmVersionCompatibility=await evaluatePmMinVersionCompatibility(layer,manifest);const pmMaxVersionCompatibility=await evaluatePmMaxVersionCompatibility(layer,manifest,pmMaxVersionExceededMode);const extensionWarnings=collectScannedExtensionWarnings(layer,manifest,rawManifest,entryWithinDirectory,entryExists,pmVersionCompatibility,pmMaxVersionCompatibility);const extensionReady=entryWithinDirectory&&entryExists&&pmVersionCompatibility.allowed&&pmMaxVersionCompatibility.allowed;const sourceIdentity=managedSourcePackages.get(`directory:${directory}`)??managedSourcePackages.get(`name:${manifest.name}`);return{diagnostic:{layer,directory,manifest_path:manifestPath,name:manifest.name,version:manifest.version,entry:manifest.entry,priority:manifest.priority,entry_path:entryPath,enabled:enabledForLoad,status:extensionReady?"ok":"warn"},warnings:extensionWarnings,candidate:buildReadyExtensionCandidate({layer,directory,manifestPath,entryPath,manifest,sourceIdentity,extensionReady,enabledForLoad})}}async function discoverExtensions(options){const roots=resolveExtensionRoots(options.pmRoot,options.cwd??process.cwd());const configured_enabled=normalizeNames(options.settings.extensions.enabled);const configured_disabled=normalizeNames(options.settings.extensions.disabled);const policy=normalizeExtensionPolicy(options.settings);const serializedPolicy=serializeExtensionPolicy(policy);if(options.noExtensions){return{disabled_by_flag:true,roots,configured_enabled,configured_disabled,discovered:[],effective:[],warnings:[...policy.warnings],policy:serializedPolicy}}const enabled=new Set(configured_enabled);const disabled=new Set(configured_disabled);const globalScan=options.ignoreGlobalExtensions===true?emptyExtensionLayerScan():await scanExtensionLayer("global",roots.global,enabled,disabled,policy.pmMaxVersionExceededMode.global);const projectScan=await scanExtensionLayer("project",roots.project,enabled,disabled,policy.pmMaxVersionExceededMode.project);const policyWarnings=[...policy.warnings];const effectiveCandidates=buildEffectiveExtensions(globalScan.candidates,projectScan.candidates);const effective=[];for(const candidate of effectiveCandidates){const extensionRef={layer:candidate.layer,name:candidate.manifest.name,trusted:candidate.manifest.trusted===true,provenanceVerified:candidate.manifest.provenance?.verified===true,sandboxProfile:candidate.manifest.sandbox_profile,permissions:candidate.manifest.permissions&&typeof candidate.manifest.permissions==="object"?{fs_read:candidate.manifest.permissions.fs_read,fs_write:candidate.manifest.permissions.fs_write,network:candidate.manifest.permissions.network,env_read:candidate.manifest.permissions.env_read,env_write:candidate.manifest.permissions.env_write,process_spawn:candidate.manifest.permissions.process_spawn}:void 0};const extensionDecision=evaluateExtensionPolicyForExtension(policy,extensionRef);if(extensionDecision.warning){policyWarnings.push(extensionDecision.warning)}if(!extensionDecision.allowed){continue}for(const capability of candidate.manifest.capabilities){const capabilityDecision=evaluateExtensionPolicyForCapability(policy,extensionRef,capability);if(capabilityDecision.warning){policyWarnings.push(capabilityDecision.warning)}}effective.push(summarizeCandidate(candidate))}return{disabled_by_flag:false,roots,configured_enabled,configured_disabled,discovered:[...globalScan.diagnostics,...projectScan.diagnostics],effective,warnings:[...new Set([...globalScan.warnings,...projectScan.warnings,...policyWarnings])],policy:serializedPolicy}}function formatUnknownError(error){if(error instanceof Error&&error.message.trim().length>0){return error.message}return String(error)}async function readCurrentPmCliVersion(){try{const packageRoot=resolvePmPackageRootFromModule(import.meta.url,["../../.."]);const raw=await fs.readFile(path.join(packageRoot,"package.json"),"utf8");const parsed=JSON.parse(raw);return typeof parsed.version==="string"&&parsed.version.trim().length>0?parsed.version.trim():null}catch{return null}}function resolveCurrentPmCliVersion(){currentPmCliVersionPromise??=readCurrentPmCliVersion();return currentPmCliVersionPromise}function formatPmVersionCompatibilityWarning(layer,manifest,evaluation){const current=evaluation.current??"unknown";if(evaluation.kind==="pm_min_version"){switch(evaluation.status){case"invalid":return`extension_pm_min_version_invalid:${layer}:${manifest.name}:required=${evaluation.required}`;case"unchecked":return`extension_pm_min_version_unchecked:${layer}:${manifest.name}:required=${evaluation.required}:current=${current}`;case"unmet":return`extension_pm_min_version_unmet:${layer}:${manifest.name}:required=${evaluation.required}:current=${current}`;default:return void 0}}switch(evaluation.status){case"invalid":return`extension_pm_max_version_invalid:${layer}:${manifest.name}:allowed=${evaluation.required}`;case"unchecked":return`extension_pm_max_version_unchecked:${layer}:${manifest.name}:allowed=${evaluation.required}:current=${current}`;case"exceeded_warn":return`extension_pm_max_version_exceeded_warn:${layer}:${manifest.name}:allowed=${evaluation.required}:current=${current}`;case"exceeded":return`extension_pm_max_version_exceeded:${layer}:${manifest.name}:allowed=${evaluation.required}:current=${current}`;default:return void 0}}async function evaluatePmMinVersionCompatibility(layer,manifest){if(manifest.pm_min_version===void 0){return{allowed:true}}const evaluation=evaluatePmMinVersionBound(manifest.pm_min_version,await resolveCurrentPmCliVersion());const warning=formatPmVersionCompatibilityWarning(layer,manifest,evaluation);return warning?{allowed:evaluation.allowed,warning}:{allowed:evaluation.allowed}}async function evaluatePmMaxVersionCompatibility(layer,manifest,exceededMode){if(manifest.pm_max_version===void 0){return{allowed:true}}const evaluation=evaluatePmMaxVersionBound(manifest.pm_max_version,await resolveCurrentPmCliVersion(),exceededMode);const warning=formatPmVersionCompatibilityWarning(layer,manifest,evaluation);return warning?{allowed:evaluation.allowed,warning}:{allowed:evaluation.allowed}}async function fingerprintPath(pathToInspect){try{const stats=await fs.stat(pathToInspect);return`${Math.trunc(stats.mtimeMs)}-${stats.size}`}catch{return"missing"}}async function resolveExtensionImportHref(extension,options){let importEntryPath=extension.entry_path;if(options.module_graph_snapshot_root){importEntryPath=await snapshotExtensionModuleGraph(options.module_graph_snapshot_root,extension)}const baseUrl=new URL(pathToFileURL(importEntryPath).href);const shouldCacheBust=options.cache_bust===true||typeof options.reload_token==="string";if(!shouldCacheBust){return baseUrl.href}const[entryFingerprint,manifestFingerprint]=await Promise.all([fingerprintPath(extension.entry_path),fingerprintPath(extension.manifest_path)]);const reloadToken=options.reload_token??nextExtensionReloadToken();baseUrl.searchParams.set("pm_ext_reload",reloadToken);baseUrl.searchParams.set("pm_ext_entry",entryFingerprint);baseUrl.searchParams.set("pm_ext_manifest",manifestFingerprint);return baseUrl.href}async function loadExtensions(options){const discovery=await discoverExtensions(options);const loaded=[];const failed=[];const warnings=[...discovery.warnings];if(discovery.disabled_by_flag){return{...discovery,warnings,loaded,failed}}const extensionsToLoad=typeof options.extensionFilter==="function"?discovery.effective.filter(options.extensionFilter):discovery.effective;for(const extension of extensionsToLoad){try{const importHref=await resolveExtensionImportHref(extension,options);const module=await import(importHref);loaded.push({...extension,module})}catch(error){warnings.push(`extension_load_failed:${extension.layer}:${extension.name}`);failed.push({layer:extension.layer,name:extension.name,entry_path:extension.entry_path,error:formatUnknownError(error)})}}return{...discovery,warnings,loaded,failed}}const DEFAULT_EXTENSION_DEACTIVATE_TIMEOUT_MS=5e3;const MAX_EXTENSION_DEACTIVATE_TIMEOUT_MS=2147483647;function toActivatableExtension(source){const activate=source.activate;const activatable={activate:activate.bind(source)};if(typeof source.deactivate==="function"){const deactivate=source.deactivate;activatable.deactivate=deactivate.bind(source)}return activatable}function resolveActivatableExtension(module){const activatableRecord=resolveActivatablePropertyRecord(module);return activatableRecord?toActivatableExtension(activatableRecord):null}async function deactivateExtensions(loadResult,activationResult,options={}){const timeoutMs=normalizeExtensionDeactivateTimeout(options?.deactivate_timeout_ms);const failedActivationKeys=new Set((activationResult?.failed??[]).map(entry=>`${entry.layer}:${entry.name}`));const targets=[];for(const extension of loadResult.loaded){if(failedActivationKeys.has(`${extension.layer}:${extension.name}`)){continue}const activatable=resolveActivatableExtension(extension.module);if(!activatable||typeof activatable.deactivate!=="function"){continue}targets.push({extension,deactivate:activatable.deactivate})}const outcomes=await Promise.all(targets.map(async({extension,deactivate})=>{try{await runExtensionDeactivateWithTimeout(deactivate,timeoutMs);return{ok:true}}catch(error){return{ok:false,layer:extension.layer,name:extension.name,error:formatUnknownError(error)}}}));const warnings=[];const failed=[];let deactivated=0;for(const outcome of outcomes){if(outcome.ok){deactivated+=1;continue}warnings.push(`extension_deactivate_failed:${outcome.layer}:${outcome.name}`);failed.push({layer:outcome.layer,name:outcome.name,error:outcome.error})}return{deactivated,warnings,failed}}function normalizeExtensionDeactivateTimeout(rawTimeout){if(typeof rawTimeout!=="number"||rawTimeout<0){return DEFAULT_EXTENSION_DEACTIVATE_TIMEOUT_MS}if(rawTimeout===0||rawTimeout===Infinity){return 0}if(!Number.isFinite(rawTimeout)){return DEFAULT_EXTENSION_DEACTIVATE_TIMEOUT_MS}return Math.min(MAX_EXTENSION_DEACTIVATE_TIMEOUT_MS,Math.max(1,Math.floor(rawTimeout)))}async function runExtensionDeactivateWithTimeout(deactivate,timeoutMs){if(timeoutMs===0){await deactivate();return}let timeoutHandle;try{const deactivatePromise=Promise.resolve().then(()=>deactivate());deactivatePromise.catch(()=>{});await Promise.race([deactivatePromise,new Promise((_,reject)=>{timeoutHandle=setTimeout(()=>{reject(new Error(`extension deactivate timed out after ${timeoutMs}ms`))},timeoutMs);timeoutHandle.unref?.()})])}finally{clearTimeout(timeoutHandle)}}const FLAG_DEFINITION_KEYS=new Set(["default","description","enabled","list","long","repeatable","required","short","type","value_name","value_type","visible"]);function normalizeFlagDefinitions(name,value){return normalizeRegistrationRecordList(name,value).map(record=>{if(record.repeatable===true){record.list=true}return record})}function normalizeCommandActionName(value){return value.trim().toLowerCase().replace(/[\s_]+/g,"-").replace(/[^a-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function resolveCommandDefinitionAction(commandPath,action){if(action===void 0){return commandPath.replace(/\s+/g,"-")}if(typeof action!=="string"||action.trim().length===0){throw new TypeError("registerCommand definition.action must be a non-empty string when provided")}const normalized=normalizeCommandActionName(action);if(normalized.length===0){throw new TypeError("registerCommand definition.action must contain alphanumeric characters")}return normalized}function normalizeCommandDefinitionArguments(value){if(value===void 0){return[]}if(!Array.isArray(value)){throw new TypeError("registerCommand definition.arguments must be an array when provided")}const normalized=[];for(const[index,entry]of value.entries()){const record=asRegistrationRecord(`registerCommand definition.arguments[${index}]`,entry);const name=assertNonEmptyRegistrationString(`registerCommand definition.arguments[${index}].name`,record.name);assertOptionalBooleanField(`registerCommand definition.arguments[${index}].required`,record.required);assertOptionalBooleanField(`registerCommand definition.arguments[${index}].variadic`,record.variadic);assertOptionalStringField(`registerCommand definition.arguments[${index}].description`,record.description);if(name.includes(" ")){throw new TypeError(`registerCommand definition.arguments[${index}].name must not contain spaces`)}const definition={name};if(record.required===true){definition.required=true}if(record.variadic===true){definition.variadic=true}if(typeof record.description==="string"){definition.description=record.description.trim()}normalized.push(definition)}const variadicIndexes=normalized.map((argument,index)=>argument.variadic?index:-1).filter(index=>index>=0);if(variadicIndexes.length>1){throw new TypeError("registerCommand definition.arguments supports at most one variadic argument")}if(variadicIndexes.length===1&&variadicIndexes[0]!==normalized.length-1){throw new TypeError("registerCommand definition.arguments variadic argument must be the final argument")}return normalized}function validateFlagDefinitions(flags){if(!Array.isArray(flags)){throw new TypeError("registerFlags flags requires an array of object definitions")}for(const[index,raw]of flags.entries()){const record=asRegistrationRecord(`registerFlags flags[${index}]`,raw);const unknownKeys=Object.keys(record).filter(key=>!FLAG_DEFINITION_KEYS.has(key)).sort((left,right)=>left.localeCompare(right));if(unknownKeys.length>0){throw new TypeError(`registerFlags flags[${index}] contains unknown field(s): ${unknownKeys.join(", ")}`)}const long=record.long;const short=record.short;if(long===void 0&&short===void 0){throw new TypeError(`registerFlags flags[${index}] requires at least one of long or short`)}assertOptionalStringField(`registerFlags flags[${index}].long`,long);assertOptionalStringField(`registerFlags flags[${index}].short`,short);const tokenFinding=findExtensionFlagTokenFailure(long,short);if(tokenFinding!==null){throw new TypeError(`registerFlags flags[${index}] ${describeExtensionLongFlagFailure(tokenFinding.token,tokenFinding.failure)}`)}assertOptionalStringField(`registerFlags flags[${index}].value_name`,record.value_name);assertOptionalStringField(`registerFlags flags[${index}].description`,record.description);assertOptionalBooleanField(`registerFlags flags[${index}].required`,record.required);assertOptionalBooleanField(`registerFlags flags[${index}].enabled`,record.enabled);assertOptionalBooleanField(`registerFlags flags[${index}].visible`,record.visible);assertOptionalBooleanField(`registerFlags flags[${index}].list`,record.list);assertOptionalBooleanField(`registerFlags flags[${index}].repeatable`,record.repeatable);if(record.list!==void 0&&record.repeatable!==void 0&&record.list!==record.repeatable){throw new TypeError(`registerFlags flags[${index}].list and repeatable must match when both are provided`)}assertOptionalFlagDefaultField(`registerFlags flags[${index}].default`,record.default);if(Array.isArray(record.default)&&record.list!==true&&record.repeatable!==true){throw new TypeError(`registerFlags flags[${index}].default cannot be an array unless list is true.`)}assertFlagValueTypeAndDefault(`registerFlags flags[${index}]`,record)}}function assertFlagValueTypeAndDefault(label,record){const declaredType=(typeof record.value_type==="string"?record.value_type:void 0)??(typeof record.type==="string"?record.type:void 0);if(declaredType===void 0){return}const kind=resolveFlagValueKind(declaredType);if(kind===null){throw new TypeError(`${label} value_type "${declaredType}" is not a known flag value type (expected one of: string, number, boolean).`)}if(record.default===void 0){return}const defaults=record.list===true||record.repeatable===true?flattenFlagListValue(record.default):[record.default];for(const[defaultIndex,defaultValue]of defaults.entries()){if(!isFlagDefaultValueCoercible(defaultValue,kind)){const suffix=defaults.length>1?`default[${defaultIndex}]`:"default";throw new TypeError(`${label}.${suffix} (${JSON.stringify(defaultValue)}) is not coercible to ${kind}.`)}}}function validateItemFieldDefinitions(fields){if(!Array.isArray(fields)){throw new TypeError("registerItemFields fields requires an array of object definitions")}for(const[index,raw]of fields.entries()){const record=asRegistrationRecord(`registerItemFields fields[${index}]`,raw);assertNonEmptyRegistrationString(`registerItemFields fields[${index}].name`,record.name);const fieldType=assertNonEmptyRegistrationString(`registerItemFields fields[${index}].type`,record.type);if(normalizeItemFieldType(fieldType)===null){const suggestion=suggestKnownItemFieldType(fieldType);const hint=suggestion?` Did you mean "${suggestion}"?`:"";throw new TypeError(`registerItemFields fields[${index}].type "${fieldType}" is not a known field type (expected one of: ${KNOWN_ITEM_FIELD_TYPES.join(", ")}).${hint}`)}assertOptionalBooleanField(`registerItemFields fields[${index}].optional`,record.optional)}}function validateItemTypeCommandOptionPolicies(typeIndex,value){if(value===void 0){return}const label=`registerItemTypes types[${typeIndex}].command_option_policies`;if(!Array.isArray(value)){throw new TypeError(`${label} must be an array when provided`)}for(const[policyIndex,rawPolicy]of value.entries()){const at=`${label}[${policyIndex}]`;const policy=asRegistrationRecord(at,rawPolicy);assertNonEmptyRegistrationString(`${at}.command`,policy.command);assertNonEmptyRegistrationString(`${at}.option`,policy.option);assertOptionalBooleanField(`${at}.enabled`,policy.enabled);assertOptionalBooleanField(`${at}.required`,policy.required);assertOptionalBooleanField(`${at}.visible`,policy.visible)}}function validateItemTypeOptions(typeIndex,value){if(value===void 0){return}const label=`registerItemTypes types[${typeIndex}].options`;if(!Array.isArray(value)){throw new TypeError(`${label} must be an array when provided`)}for(const[optionIndex,rawOption]of value.entries()){const at=`${label}[${optionIndex}]`;const option=asRegistrationRecord(at,rawOption);assertNonEmptyRegistrationString(`${at}.key`,option.key);assertOptionalStringArrayField(`${at}.values`,option.values);assertOptionalBooleanField(`${at}.required`,option.required);assertOptionalStringArrayField(`${at}.aliases`,option.aliases)}}function validateItemTypeDefinitions(types){if(!Array.isArray(types)){throw new TypeError("registerItemTypes types requires an array of object definitions")}for(const[typeIndex,raw]of types.entries()){const at=`registerItemTypes types[${typeIndex}]`;const record=asRegistrationRecord(at,raw);assertNonEmptyRegistrationString(`${at}.name`,record.name);assertOptionalStringField(`${at}.folder`,record.folder);assertOptionalStringArrayField(`${at}.aliases`,record.aliases);assertOptionalStringArrayField(`${at}.required_create_fields`,record.required_create_fields);assertOptionalStringArrayField(`${at}.required_create_repeatables`,record.required_create_repeatables);validateItemTypeCommandOptionPolicies(typeIndex,record.command_option_policies);validateItemTypeOptions(typeIndex,record.options)}}function validateMigrationDefinition(definition){const record=asRegistrationRecord("registerMigration definition",definition);if(record.id!==void 0&&typeof record.id!=="string"){throw new TypeError("registerMigration definition.id must be a string when provided")}if(record.description!==void 0&&typeof record.description!=="string"){throw new TypeError("registerMigration definition.description must be a string when provided")}if(record.status!==void 0&&typeof record.status!=="string"){throw new TypeError("registerMigration definition.status must be a string when provided")}assertOptionalBooleanField("registerMigration definition.mandatory",record.mandatory);if(record.run!==void 0&&typeof record.run!=="function"){throw new TypeError("registerMigration definition.run must be a function when provided")}}const PROJECT_PROFILE_DIMENSIONS=["types","statuses","fields","workflows","config","templates","packages"];const PROJECT_PROFILE_ENTRY_VALIDATORS={types:(at,entry)=>{if(entry.name!==void 0&&typeof entry.name!=="string"){throw new TypeError(`${at}.name must be a string when provided`)}},workflows:(at,entry)=>{if(typeof entry.type!=="string"){throw new TypeError(`${at}.type must be a string`)}if(!Array.isArray(entry.allowed_transitions)){throw new TypeError(`${at}.allowed_transitions must be an array`)}for(const[pairIndex,pair]of entry.allowed_transitions.entries()){if(!Array.isArray(pair)){throw new TypeError(`${at}.allowed_transitions[${pairIndex}] must be a [from, to] array`)}}},templates:(at,entry)=>{if(typeof entry.name!=="string"){throw new TypeError(`${at}.name must be a string`)}if(typeof entry.options!=="object"||entry.options===null||Array.isArray(entry.options)){throw new TypeError(`${at}.options must be an object`)}},packages:(at,entry)=>{if(typeof entry.spec!=="string"){throw new TypeError(`${at}.spec must be a string`)}}};function validateProjectProfileDefinition(profile){const record=asRegistrationRecord("registerProfile profile",profile);assertNonEmptyRegistrationString("registerProfile profile.name",record.name);assertNonEmptyRegistrationString("registerProfile profile.title",record.title);if(record.summary!==void 0&&typeof record.summary!=="string"){throw new TypeError("registerProfile profile.summary must be a string when provided")}for(const dimension of PROJECT_PROFILE_DIMENSIONS){const value=record[dimension];if(value===void 0){continue}if(!Array.isArray(value)){throw new TypeError(`registerProfile profile.${dimension} must be an array when provided`)}for(const[index,entry]of value.entries()){if(typeof entry!=="object"||entry===null||Array.isArray(entry)){throw new TypeError(`registerProfile profile.${dimension}[${index}] must be an object`)}PROJECT_PROFILE_ENTRY_VALIDATORS[dimension]?.(`registerProfile profile.${dimension}[${index}]`,entry)}}}function applyProjectProfileDefaults(profile){if(profile.summary===void 0){profile.summary=""}for(const dimension of PROJECT_PROFILE_DIMENSIONS){if(profile[dimension]===void 0){profile[dimension]=[]}}return profile}function getDeclaredExtensionCapabilities(extension){if(!Array.isArray(extension.capabilities)){return null}const declared=new Set;for(const capability of extension.capabilities){const normalized=capability.trim().toLowerCase();if(isKnownExtensionCapability(normalized)){declared.add(normalized)}}return declared}function assertExtensionCapability(extension,capability,method){const declared=getDeclaredExtensionCapabilities(extension);if(declared===null){return}if(!declared.has(capability)){throw createRegistrationValidationError(`${method} requires capability '${capability}' in extension manifest capabilities`,{method,registration_index:-1,capability,missing_capability:capability,expected_schema:`"capabilities": [..., "${capability}"]`,received:extension.capabilities,hint:`Add "${capability}" to ${extension.name} manifest capabilities, or remove the ${method} registration call.`})}}function buildExtensionSelfIdentity(extension){return Object.freeze({name:extension.name,layer:extension.layer,version:extension.version,capabilities:Object.freeze((extension.capabilities??[]).filter(capability=>KNOWN_EXTENSION_CAPABILITIES.includes(capability))),pm_min_version:extension.pm_min_version,pm_max_version:extension.pm_max_version,source_package:extension.source_package})}function buildPolicyExtensionRef(extension){return{layer:extension.layer,name:extension.name,trusted:extension.trusted===true,provenanceVerified:extension.provenance?.verified===true,sandboxProfile:extension.sandbox_profile,permissions:extension.permissions&&typeof extension.permissions==="object"?{fs_read:extension.permissions.fs_read,fs_write:extension.permissions.fs_write,network:extension.permissions.network,env_read:extension.permissions.env_read,env_write:extension.permissions.env_write,process_spawn:extension.permissions.process_spawn}:void 0}}class ExtensionApiRegistrar{extension;hooks;#loadedExtension;#extensionRef;#hookRegistry;#commandRegistry;#parserRegistry;#preflightRegistry;#serviceRegistry;#rendererRegistry;#registrationRegistry;#activationWarnings;#activationFailures;#policy;constructor(extension,hooks,commands,parsers,preflight,services,renderers,registrations,activationWarnings,activationFailures,policy){this.#loadedExtension=extension;this.extension=buildExtensionSelfIdentity(extension);this.#extensionRef=buildPolicyExtensionRef(extension);this.#hookRegistry=hooks;this.#commandRegistry=commands;this.#parserRegistry=parsers;this.#preflightRegistry=preflight;this.#serviceRegistry=services;this.#rendererRegistry=renderers;this.#registrationRegistry=registrations;this.#activationWarnings=activationWarnings;this.#activationFailures=activationFailures;this.#policy=policy;this.registerCommand=this.registerCommand.bind(this);this.registerParser=this.registerParser.bind(this);this.registerPreflight=this.registerPreflight.bind(this);this.registerService=this.registerService.bind(this);this.registerFlags=this.registerFlags.bind(this);this.registerItemFields=this.registerItemFields.bind(this);this.registerItemTypes=this.registerItemTypes.bind(this);this.registerRelationshipKinds=this.registerRelationshipKinds.bind(this);this.registerMigration=this.registerMigration.bind(this);this.registerProfile=this.registerProfile.bind(this);this.registerRenderer=this.registerRenderer.bind(this);this.registerImporter=this.registerImporter.bind(this);this.registerExporter=this.registerExporter.bind(this);this.registerSearchProvider=this.registerSearchProvider.bind(this);this.registerVectorStoreAdapter=this.registerVectorStoreAdapter.bind(this);this.registerAssuranceMeasurementProvider=this.registerAssuranceMeasurementProvider.bind(this);this.hooks={beforeCommand:hook=>this.registerBeforeCommand(hook),beforeMutation:hook=>this.registerBeforeMutation(hook),afterCommand:hook=>this.registerAfterCommand(hook),onWrite:hook=>this.registerOnWrite(hook),onRead:hook=>this.registerOnRead(hook),onIndex:hook=>this.registerOnIndex(hook)}}allowRegistration(surface,method,capability,details){const decision=evaluateExtensionPolicyForRegistration(this.#policy,this.#extensionRef,surface,method,capability,details);if(decision.warning){this.#activationWarnings.push(decision.warning)}return decision.allowed}registerCommandTrace(mode,command,expectedSchema,received,hint){return{method:"registerCommand",registration_index:mode==="override"?this.#commandRegistry.overrides.length:this.#commandRegistry.handlers.length,command,expected_schema:expectedSchema,received:sanitizeRegistrationValue(received),hint}}registerCommandOverride(command,override){const normalizedCommand=normalizeCommandName(command);if(normalizedCommand.length===0){throw createRegistrationValidationError("registerCommand requires a non-empty command name",this.registerCommandTrace("override",command,'registerCommand("<command>", (context) => unknown)',command,"Provide a non-empty command path as the first argument."))}if(typeof override!=="function"){const trace=this.registerCommandTrace("override",normalizedCommand,'registerCommand("<command>", (context) => unknown)',override,"Provide a function as the second registerCommand argument.");throw createRegistrationValidationError(`registerCommand requires an override function when command name is provided (command="${normalizedCommand}", registration_index=${trace.registration_index})`,trace)}if(!this.allowRegistration("commands.override","registerCommand","commands",{command:normalizedCommand})){return}this.#commandRegistry.overrides.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,command:normalizedCommand,run:override})}resolveCommandDefinitionRunHandler(definition,normalizedCommand){const runHandler=typeof definition.run==="function"?definition.run:void 0;const legacyHandler=typeof definition.handler==="function"?definition.handler:void 0;if(!runHandler&&legacyHandler){this.#activationWarnings.push(`extension_command_definition_legacy_handler_alias:${this.#loadedExtension.layer}:${this.#loadedExtension.name}:${normalizedCommand}`)}return runHandler??legacyHandler}registerCommandDefinition(definition){if(typeof definition!=="object"||definition===null){throw createRegistrationValidationError("registerCommand requires a command definition object",this.registerCommandTrace("definition",void 0,"{ name: string; run: (context) => unknown; }",definition,'Use registerCommand({ name: "command path", run: (context) => ... }).'))}if(typeof definition.name!=="string"){throw createRegistrationValidationError("registerCommand requires a command definition name",this.registerCommandTrace("definition",void 0,"{ name: string; run: (context) => unknown; }",definition,"Set command definition.name to a non-empty string command path."))}const normalizedCommand=normalizeCommandName(definition.name);if(normalizedCommand.length===0){throw createRegistrationValidationError("registerCommand requires a non-empty command definition name",this.registerCommandTrace("definition",definition.name,"{ name: string; run: (context) => unknown; }",definition,"Ensure command definition.name contains a non-empty command path."))}const resolvedHandler=this.resolveCommandDefinitionRunHandler(definition,normalizedCommand);if(typeof resolvedHandler!=="function"){const trace=this.registerCommandTrace("definition",normalizedCommand,"{ name: string; run: (context) => unknown; }",resolvedHandler,"Define command definition.run as a function.");throw createRegistrationValidationError(`registerCommand requires a command definition run handler (command="${normalizedCommand}", registration_index=${trace.registration_index})`,trace)}try{assertCommandDefinitionMetadataStrings(definition);const action=resolveCommandDefinitionAction(normalizedCommand,definition.action);if(!this.allowRegistration("commands.handler","registerCommand","commands",{command:normalizedCommand,action})){return}const description=definition.description?.trim();const intent=definition.intent?.trim();const examples=normalizeOptionalStringArrayField("registerCommand definition.examples",definition.examples);const failureHints=normalizeOptionalStringArrayField("registerCommand definition.failure_hints",definition.failure_hints);const argumentsDefinition=normalizeCommandDefinitionArguments(definition.arguments);if(definition.flags!==void 0){assertExtensionCapability(this.#loadedExtension,"schema","registerCommand flags");if(this.allowRegistration("schema.flags","registerCommand flags","schema")){validateFlagDefinitions(definition.flags);this.#registrationRegistry.flags.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,target_command:normalizedCommand,flags:normalizeFlagDefinitions("registerCommand definition.flags",definition.flags)})}}const registration={layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,source_package:this.#loadedExtension.source_package,command:normalizedCommand,action,examples,failure_hints:failureHints,arguments:argumentsDefinition,tier:definition.tier??"standard",family:definition.family??"extensions"};if(description){registration.description=description}if(intent){registration.intent=intent}this.#registrationRegistry.commands.push(registration)}catch(error){const reason=formatUnknownError(error);const trace=this.registerCommandTrace("definition",normalizedCommand,"{ name: string; run: (context) => unknown; action?: string; arguments?: object[]; flags?: object[]; }",definition,reason);const validationError=createRegistrationValidationError(`registerCommand definition metadata invalid (command="${normalizedCommand}", registration_index=${trace.registration_index}): ${reason}`,trace);this.#activationWarnings.push(`extension_command_quarantined:${this.#loadedExtension.layer}:${this.#loadedExtension.name}:${normalizedCommand}`);this.#activationFailures.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,entry_path:this.#loadedExtension.entry_path,error:validationError.message,trace});return}this.#commandRegistry.handlers.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,command:normalizedCommand,run:resolvedHandler})}registerCommand(commandOrDefinition,override){assertExtensionCapability(this.#loadedExtension,"commands","registerCommand");if(typeof commandOrDefinition==="string"){this.registerCommandOverride(commandOrDefinition,override);return}this.registerCommandDefinition(commandOrDefinition)}registerParser(command,override){assertExtensionCapability(this.#loadedExtension,"parser","registerParser");if(!this.allowRegistration("parser.override","registerParser","parser")){return}const normalizedCommand=normalizeCommandName(assertNonEmptyRegistrationString("registerParser command",command));assertRegistrationFunction("registerParser override",override);this.#parserRegistry.overrides.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,command:normalizedCommand,run:override})}registerPreflight(override){assertExtensionCapability(this.#loadedExtension,"preflight","registerPreflight");if(!this.allowRegistration("preflight.override","registerPreflight","preflight")){return}const normalized=normalizePreflightOverride(override);this.#preflightRegistry.overrides.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,...normalized})}registerService(service,override,ownership={}){assertExtensionCapability(this.#loadedExtension,"services","registerService");const normalizedService=String(service).trim().toLowerCase();if(!isExtensionServiceName(normalizedService)){throw new TypeError(`registerService service must be one of: ${KNOWN_EXTENSION_SERVICE_NAMES.join(", ")}`)}if(!this.allowRegistration("services.override","registerService","services",{service:normalizedService})){return}assertRegistrationFunction("registerService override",override);this.#serviceRegistry.overrides.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,service:normalizedService,run:override,...normalizeServiceOverrideOwnership(ownership)?{passThrough:true}:{}})}registerRenderer(format,renderer,ownership={}){assertExtensionCapability(this.#loadedExtension,"renderers","registerRenderer");if(!this.allowRegistration("renderers.override","registerRenderer","renderers")){return}if(typeof renderer!=="function"){throw new TypeError("registerRenderer requires a renderer function")}const normalizedFormat=String(format).trim().toLowerCase();if(!isOutputRendererFormat(normalizedFormat)){throw new Error(`registerRenderer format must be toon|json, received: ${String(format)}`)}if(ownership.resultDiscriminator!==void 0&&typeof ownership.resultDiscriminator!=="function"){throw new TypeError("registerRenderer ownership.resultDiscriminator must be a function when provided")}const commands=[...new Set((ownership.commands??[]).map(command=>{if(typeof command!=="string"||command.trim().length===0){throw new TypeError("registerRenderer ownership.commands must contain non-empty command paths")}return normalizeCommandName(command)}))];this.#rendererRegistry.overrides.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,format:normalizedFormat,run:renderer,commands,...ownership.resultDiscriminator?{resultDiscriminator:ownership.resultDiscriminator}:{}})}registerFlags(targetCommand,flags){assertExtensionCapability(this.#loadedExtension,"schema","registerFlags");if(!this.allowRegistration("schema.flags","registerFlags","schema")){return}const normalizedTargetCommand=normalizeCommandName(assertNonEmptyRegistrationString("registerFlags targetCommand",targetCommand));validateFlagDefinitions(flags);const normalizedFlags=normalizeFlagDefinitions("registerFlags flags",flags);if(normalizedFlags.length===0){throw new TypeError("registerFlags requires at least one flag definition")}this.#registrationRegistry.flags.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,target_command:normalizedTargetCommand,flags:normalizedFlags})}registerItemFields(fields){assertExtensionCapability(this.#loadedExtension,"schema","registerItemFields");if(!this.allowRegistration("schema.itemfields","registerItemFields","schema")){return}validateItemFieldDefinitions(fields);const normalizedFields=normalizeRegistrationRecordList("registerItemFields fields",fields);if(normalizedFields.length===0){throw new TypeError("registerItemFields requires at least one field definition")}this.#registrationRegistry.item_fields.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,fields:normalizedFields})}registerItemTypes(types){assertExtensionCapability(this.#loadedExtension,"schema","registerItemTypes");if(!this.allowRegistration("schema.itemtypes","registerItemTypes","schema")){return}validateItemTypeDefinitions(types);const normalizedTypes=normalizeRegistrationRecordList("registerItemTypes types",types);if(normalizedTypes.length===0){throw new TypeError("registerItemTypes requires at least one type definition")}this.#registrationRegistry.item_types.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,types:normalizedTypes})}registerRelationshipKinds(definitions){assertExtensionCapability(this.#loadedExtension,"schema","registerRelationshipKinds");if(!this.allowRegistration("schema.relationshipkinds","registerRelationshipKinds","schema")){return}if(!Array.isArray(definitions)){throw new TypeError("registerRelationshipKinds definitions requires an array of object definitions")}if(definitions.length===0){throw new TypeError("registerRelationshipKinds requires at least one definition")}const registry=createRelationshipKindRegistry();for(const registration of this.#registrationRegistry.relationship_kinds){for(const definition of registration.definitions){registry.register(definition)}}const validated=definitions.map(definition=>{registry.register(definition);return registry.require(definition.kind)});this.#registrationRegistry.relationship_kinds.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,definitions:validated})}registerMigration(definition){assertExtensionCapability(this.#loadedExtension,"schema","registerMigration");if(!this.allowRegistration("schema.migrations","registerMigration","schema")){return}validateMigrationDefinition(definition);const runtimeDefinition=normalizeRuntimeRegistrationRecord("registerMigration definition",definition);this.#registrationRegistry.migrations.push(attachRuntimeDefinition({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,definition:normalizeRegistrationRecord("registerMigration definition",definition)},runtimeDefinition))}registerProfile(profile){assertExtensionCapability(this.#loadedExtension,"schema","registerProfile");if(!this.allowRegistration("schema.profiles","registerProfile","schema")){return}const snapshot=cloneRuntimeRegistrationValue(profile);validateProjectProfileDefinition(snapshot);this.#registrationRegistry.profiles.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,profile:applyProjectProfileDefaults(snapshot)})}registerImportExportCommandFlags(method,commandPath,resolvedOptions){if(resolvedOptions.flags===void 0){return}assertExtensionCapability(this.#loadedExtension,"schema",`${method} options.flags`);if(!this.allowRegistration("schema.flags",`${method} options.flags`,"schema")){return}validateFlagDefinitions(resolvedOptions.flags);this.#registrationRegistry.flags.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,target_command:commandPath,flags:normalizeFlagDefinitions(`${method} options.flags`,resolvedOptions.flags)})}applyImportExportCommandMetadata(method,commandPath,options){if(options!==void 0&&(typeof options!=="object"||options===null||Array.isArray(options))){throw new TypeError(`${method} options must be an object when provided`)}const defaultDescription=`${method==="registerImporter"?"Import":"Export"} items with the registered extension adapter.`;const defaultArguments=[{name:"file",required:false,description:"Optional input or output file path."}];const resolvedOptions={...options,description:options?.description??defaultDescription,arguments:options?.arguments??defaultArguments};const output=resolveImportExportArtifactOutput(method,resolvedOptions,options?.description!==void 0);assertOptionalStringField(`${method} options.action`,resolvedOptions.action);assertOptionalStringField(`${method} options.description`,resolvedOptions.description);assertOptionalStringField(`${method} options.intent`,resolvedOptions.intent);const action=resolveCommandDefinitionAction(commandPath,resolvedOptions.action);const examples=normalizeOptionalStringArrayField(`${method} options.examples`,resolvedOptions.examples);const failureHints=normalizeOptionalStringArrayField(`${method} options.failure_hints`,resolvedOptions.failure_hints);const argumentsDefinition=normalizeCommandDefinitionArguments(resolvedOptions.arguments);this.registerImportExportCommandFlags(method,commandPath,resolvedOptions);const registration={layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,source_package:this.#loadedExtension.source_package,command:commandPath,action,examples,failure_hints:failureHints,arguments:argumentsDefinition};const description=resolvedOptions.description?.trim();if(description){registration.description=description}const intent=resolvedOptions.intent?.trim();if(intent){registration.intent=intent}this.#registrationRegistry.commands.push(registration);return output}registerImporter(name,importer,options){assertExtensionCapability(this.#loadedExtension,"importers","registerImporter");if(!this.allowRegistration("importers.importer","registerImporter","importers")){return}const normalizedName=normalizeRegistrationName(assertNonEmptyRegistrationString("registerImporter name",name));assertRegistrationFunction("registerImporter importer",importer);const commandPath=toRegistrationCommandPath(normalizedName,"import");this.applyImportExportCommandMetadata("registerImporter",commandPath,options);this.#registrationRegistry.importers.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,importer:normalizedName});this.#commandRegistry.handlers.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,command:commandPath,run:async context=>importer(buildImportExportContext(context,normalizedName,"import"))})}registerExporter(name,exporter,options){assertExtensionCapability(this.#loadedExtension,"importers","registerExporter");if(!this.allowRegistration("importers.exporter","registerExporter","importers")){return}const normalizedName=normalizeRegistrationName(assertNonEmptyRegistrationString("registerExporter name",name));assertRegistrationFunction("registerExporter exporter",exporter);const commandPath=toRegistrationCommandPath(normalizedName,"export");const output=this.applyImportExportCommandMetadata("registerExporter",commandPath,options);this.#registrationRegistry.exporters.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,exporter:normalizedName,...output===void 0?{}:{output}});this.#commandRegistry.handlers.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,command:commandPath,run:async context=>{const result=await exporter(buildImportExportContext(context,normalizedName,"export"));return output?.receipt==="suppress"&&!isHostOutputSuppressed(result)?suppressHostOutput(result):result}})}registerSearchProvider(provider){assertExtensionCapability(this.#loadedExtension,"search","registerSearchProvider");if(!this.allowRegistration("search.provider","registerSearchProvider","search")){return}const runtimeDefinition=normalizeRuntimeRegistrationRecord("registerSearchProvider provider",provider);this.#registrationRegistry.search_providers.push(attachRuntimeDefinition({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,definition:normalizeRegistrationRecord("registerSearchProvider provider",provider)},runtimeDefinition))}registerVectorStoreAdapter(adapter){assertExtensionCapability(this.#loadedExtension,"search","registerVectorStoreAdapter");if(!this.allowRegistration("search.vectorstore","registerVectorStoreAdapter","search")){return}const runtimeDefinition=normalizeRuntimeRegistrationRecord("registerVectorStoreAdapter adapter",adapter);this.#registrationRegistry.vector_store_adapters.push(attachRuntimeDefinition({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,definition:normalizeRegistrationRecord("registerVectorStoreAdapter adapter",adapter)},runtimeDefinition))}registerAssuranceMeasurementProvider(provider){assertExtensionCapability(this.#loadedExtension,"services","registerAssuranceMeasurementProvider");if(!this.allowRegistration("services.assuranceprovider","registerAssuranceMeasurementProvider","services")){return}validateAssuranceMeasurementProviderDefinition(provider);if(provider.network&&this.#loadedExtension.permissions?.network!==true){throw new TypeError("registerAssuranceMeasurementProvider network provider requires permissions.network=true")}const runtimeDefinition=normalizeRuntimeRegistrationRecord("registerAssuranceMeasurementProvider provider",provider);this.#registrationRegistry.assurance_providers.push(attachRuntimeDefinition({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,network_permission:this.#loadedExtension.permissions?.network===true,definition:normalizeRegistrationRecord("registerAssuranceMeasurementProvider provider",provider)},runtimeDefinition))}registerBeforeCommand(hook){assertExtensionCapability(this.#loadedExtension,"hooks","api.hooks.beforeCommand");if(!this.allowRegistration("hooks.beforecommand","api.hooks.beforeCommand","hooks"))return;assertHookHandler("beforeCommand",hook);this.#hookRegistry.beforeCommand.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,run:hook})}registerBeforeMutation(hook){assertExtensionCapability(this.#loadedExtension,"hooks","api.hooks.beforeMutation");if(!this.allowRegistration("hooks.beforemutation","api.hooks.beforeMutation","hooks"))return;assertHookHandler("beforeMutation",hook);this.#hookRegistry.beforeMutation.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,run:hook})}registerAfterCommand(hook){assertExtensionCapability(this.#loadedExtension,"hooks","api.hooks.afterCommand");if(!this.allowRegistration("hooks.aftercommand","api.hooks.afterCommand","hooks"))return;assertHookHandler("afterCommand",hook);this.#hookRegistry.afterCommand.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,run:hook})}registerOnWrite(hook){assertExtensionCapability(this.#loadedExtension,"hooks","api.hooks.onWrite");if(!this.allowRegistration("hooks.onwrite","api.hooks.onWrite","hooks"))return;assertHookHandler("onWrite",hook);this.#hookRegistry.onWrite.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,run:hook})}registerOnRead(hook){assertExtensionCapability(this.#loadedExtension,"hooks","api.hooks.onRead");if(!this.allowRegistration("hooks.onread","api.hooks.onRead","hooks"))return;assertHookHandler("onRead",hook);this.#hookRegistry.onRead.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,run:hook})}registerOnIndex(hook){assertExtensionCapability(this.#loadedExtension,"hooks","api.hooks.onIndex");if(!this.allowRegistration("hooks.onindex","api.hooks.onIndex","hooks"))return;assertHookHandler("onIndex",hook);this.#hookRegistry.onIndex.push({layer:this.#loadedExtension.layer,name:this.#loadedExtension.name,run:hook})}}function createExtensionApi(extension,hooks,commands,parsers,preflight,services,renderers,registrations,activationWarnings,activationFailures,policy){return new ExtensionApiRegistrar(extension,hooks,commands,parsers,preflight,services,renderers,registrations,activationWarnings,activationFailures,policy)}function getRegistrationCounts(registrations){const commandCount=registrations.commands.length;const flagCount=registrations.flags.reduce((total,entry)=>total+entry.flags.length,0);const itemFieldCount=registrations.item_fields.reduce((total,entry)=>total+entry.fields.length,0);const itemTypeCount=registrations.item_types.reduce((total,entry)=>total+entry.types.length,0);const relationshipKindCount=(registrations.relationship_kinds??[]).reduce((total,entry)=>total+entry.definitions.length,0);return{commands:commandCount,flags:flagCount,item_fields:itemFieldCount,item_types:itemTypeCount,...relationshipKindCount>0?{relationship_kinds:relationshipKindCount}:{},migrations:registrations.migrations.length,profiles:registrations.profiles.length,importers:registrations.importers.length,exporters:registrations.exporters.length,search_providers:registrations.search_providers.length,vector_store_adapters:registrations.vector_store_adapters.length,...(registrations.assurance_providers?.length??0)>0?{assurance_providers:registrations.assurance_providers.length}:{}}}function collectCommandCollisionWarnings(commands){const warnings=[];const collectByCommand=(entries,codePrefix)=>{const grouped=new Map;for(const entry of entries){const bucket=grouped.get(entry.command)??[];bucket.push(entry);grouped.set(entry.command,bucket)}for(const command of[...grouped.keys()].sort((left,right)=>left.localeCompare(right))){const bucket=grouped.get(command);if(bucket.length<=1){continue}const winner=bucket[bucket.length-1];for(const displaced of bucket.slice(0,-1)){warnings.push(`${codePrefix}:${command}:${winner.layer}:${winner.name}:${displaced.layer}:${displaced.name}`)}}};collectByCommand(commands.handlers,"extension_command_handler_collision");collectByCommand(commands.overrides,"extension_command_override_collision");const handlerCommands=new Set(commands.handlers.map(entry=>entry.command));const overlapCommands=[...new Set(commands.overrides.map(entry=>entry.command))].filter(command=>handlerCommands.has(command));overlapCommands.sort((left,right)=>left.localeCompare(right));for(const command of overlapCommands){const handlers=commands.handlers.filter(entry=>entry.command===command);const overrides=commands.overrides.filter(entry=>entry.command===command);for(const override of overrides){for(const handler of handlers){warnings.push(`extension_command_override_handler_overlap:${command}:${override.layer}:${override.name}:${handler.layer}:${handler.name}`)}}}return warnings}function collectRendererCollisionWarnings(renderers){const grouped=new Map;for(const entry of renderers.overrides){const bucket=grouped.get(entry.format)??[];bucket.push(entry);grouped.set(entry.format,bucket)}const warnings=[];for(const format of[...grouped.keys()].sort((left,right)=>left.localeCompare(right))){const bucket=grouped.get(format);if(bucket.length<=1){continue}const winner=bucket[bucket.length-1];for(const displaced of bucket.slice(0,-1)){if(winner.commands?.length&&displaced.commands?.length&&!displaced.commands.some(command=>winner.commands?.includes(command))){continue}warnings.push(`extension_renderer_collision:${format}:${winner.layer}:${winner.name}:${displaced.layer}:${displaced.name}`)}}return warnings}function collectParserCollisionWarnings(parsers){const warnings=[];const grouped=new Map;for(const entry of parsers.overrides){const bucket=grouped.get(entry.command)??[];bucket.push(entry);grouped.set(entry.command,bucket)}for(const command of[...grouped.keys()].sort((left,right)=>left.localeCompare(right))){const bucket=grouped.get(command);if(bucket.length<=1){continue}const winner=bucket[bucket.length-1];for(const displaced of bucket.slice(0,-1)){warnings.push(`extension_parser_override_collision:${command}:${winner.layer}:${winner.name}:${displaced.layer}:${displaced.name}`)}}return warnings}const CHAINED_SERVICE_NAMES=new Set(["output_format"]);function collectServiceCollisionWarnings(services){const warnings=[];const grouped=new Map;for(const entry of services.overrides){const bucket=grouped.get(entry.service)??[];bucket.push(entry);grouped.set(entry.service,bucket)}for(const service of[...grouped.keys()].sort((left,right)=>left.localeCompare(right))){const bucket=grouped.get(service);if(bucket.length<=1){continue}if(CHAINED_SERVICE_NAMES.has(service)){continue}const winner=bucket[bucket.length-1];for(const displaced of bucket.slice(0,-1)){warnings.push(`extension_service_override_collision:${service}:${winner.layer}:${winner.name}:${displaced.layer}:${displaced.name}`)}}return warnings}async function activateExtensions(loadResult){const policy=hydrateExtensionPolicy(loadResult.policy??DEFAULT_EXTENSION_POLICY);const hooks=createEmptyExtensionHookRegistry();const commands=createEmptyExtensionCommandRegistry();const parsers=createEmptyExtensionParserRegistry();const preflight=createEmptyExtensionPreflightRegistry();const services=createEmptyExtensionServiceRegistry();const renderers=createEmptyExtensionRendererRegistry();const registrations=createEmptyExtensionRegistrationRegistry();const failed=[];const warnings=[];for(const extension of loadResult.loaded){const activatable=resolveActivatableExtension(extension.module);if(!activatable){continue}const failedBeforeActivation=failed.length;const rollbackPartialActivation=captureExtensionActivationRollback({hooks,commands,parsers,preflight,services,renderers,registrations});try{await activatable.activate(createExtensionApi(extension,hooks,commands,parsers,preflight,services,renderers,registrations,warnings,failed,policy));if(failed.length>failedBeforeActivation){rollbackPartialActivation();warnings.push(`extension_activation_rolled_back:${extension.layer}:${extension.name}`)}}catch(error){rollbackPartialActivation();warnings.push(`extension_activate_failed:${extension.layer}:${extension.name}`);const trace=extractRegistrationValidationTrace(error);failed.push({layer:extension.layer,name:extension.name,entry_path:extension.entry_path,error:formatUnknownError(error),trace})}}const collisionWarnings=[...collectCommandCollisionWarnings(commands),...collectParserCollisionWarnings(parsers),...collectPreflightCollisionWarnings(preflight),...collectServiceCollisionWarnings(services),...collectRendererCollisionWarnings(renderers)];const mergedWarnings=[...new Set([...warnings,...collisionWarnings])];return{hooks,commands,parsers,preflight,services,renderers,registrations,failed,warnings:mergedWarnings,hook_counts:{before_command:hooks.beforeCommand.length,before_mutation:hooks.beforeMutation.length,after_command:hooks.afterCommand.length,on_write:hooks.onWrite.length,on_read:hooks.onRead.length,on_index:hooks.onIndex.length},command_override_count:commands.overrides.length,command_handler_count:commands.handlers.length,parser_override_count:parsers.overrides.length,preflight_override_count:preflight.overrides.length,service_override_count:services.overrides.length,renderer_override_count:renderers.overrides.length,registration_counts:getRegistrationCounts(registrations)}}const _testOnlyLoader={assertFlagValueTypeAndDefault,assertOptionalStringField,compareComparableVersions,collectCommandCollisionWarnings,collectParserCollisionWarnings,collectRendererCollisionWarnings,collectServiceCollisionWarnings,createExtensionApi,createRegistrationValidationError,evaluatePmMaxVersionCompatibility,evaluatePmMinVersionCompatibility,extractRegistrationValidationTrace,fingerprintPath,getRegistrationCounts,normalizeCommandDefinitionArguments,normalizeExtensionDeactivateTimeout,normalizeOptionalStringArrayField,normalizeRegistrationRecord,normalizeRegistrationRecordList,normalizeRuntimeRegistrationRecord,parseComparableVersion,parseManifest:parseExtensionManifestDocument,readCurrentPmCliVersion,readManagedExtensionSourcePackages:async extensionsRoot=>new Map([...await readManagedExtensionSourcePackages(extensionsRoot)].filter(entry=>typeof entry[1].package_name==="string").map(([key,identity])=>[key,identity.package_name])),resolveExtensionImportHref,resolveCurrentPmCliVersion,resolveCommandDefinitionAction,sanitizeRegistrationValue,validateItemFieldDefinitions,resetCurrentPmCliVersionCacheForTest:()=>{currentPmCliVersionPromise=null}};export{DEFAULT_EXTENSION_PRIORITY,_testOnlyLoader,activateExtensions,createEmptyExtensionCommandRegistry2 as createEmptyExtensionCommandRegistry,createEmptyExtensionHookRegistry2 as createEmptyExtensionHookRegistry,createEmptyExtensionParserRegistry2 as createEmptyExtensionParserRegistry,createEmptyExtensionPreflightRegistry2 as createEmptyExtensionPreflightRegistry,createEmptyExtensionRegistrationRegistry2 as createEmptyExtensionRegistrationRegistry,createEmptyExtensionRendererRegistry2 as createEmptyExtensionRendererRegistry,createEmptyExtensionServiceRegistry2 as createEmptyExtensionServiceRegistry,deactivateExtensions,discoverExtensions,isCanonicalPathWithinDirectory,loadExtensions,nextExtensionReloadToken,parseExtensionManifestDocument,parseLegacyExtensionCapabilityAliasWarning,parseUnknownExtensionCapabilityWarning,resolveExtensionRoots,runAfterCommandHooks,runBeforeCommandHooks,runBeforeMutationHooks,runCommandHandler,runCommandOverride,runOnIndexHooks,runOnReadHooks,runOnWriteHooks,runParserOverride,runPreflightOverride,runRendererOverride,runServiceOverride,runServiceOverrideSync};
|
|
2223
2
|
//# sourceMappingURL=loader.js.map
|
|
2224
|
-
//# debugId=e4e1b7c2-6551-5e56-b26a-30062aed5b97
|