@unbrained/pm-cli 2026.10.4 → 2026.10.6
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/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +37 -1
- package/dist/cli/after-command-context-usage.js +1 -1
- package/dist/cli/argv-utils.js +1 -1
- package/dist/cli/bootstrap-args.js +1 -1
- package/dist/cli/bundle-integrity.js +2 -2
- package/dist/cli/command-namespaces.js +1 -1
- package/dist/cli/commander-usage.d.ts +1 -1
- package/dist/cli/commander-usage.js +7 -4
- package/dist/cli/commands/annotations/comments.js +1 -1
- package/dist/cli/commands/annotations/docs.js +1 -1
- package/dist/cli/commands/annotations/files.js +1 -1
- package/dist/cli/commands/annotations/learnings.js +1 -1
- package/dist/cli/commands/annotations/notes.js +1 -1
- package/dist/cli/commands/extension/describe.js +1 -1
- package/dist/cli/commands/extension/extension.js +1 -1
- package/dist/cli/commands/extension/scaffold.js +1 -1
- package/dist/cli/commands/extension/shared.js +1 -1
- package/dist/cli/commands/governance/gc.js +1 -1
- package/dist/cli/commands/governance/health.js +1 -1
- package/dist/cli/commands/governance/telemetry.js +1 -1
- package/dist/cli/commands/governance/validate.js +1 -1
- package/dist/cli/commands/history/activity.js +1 -1
- package/dist/cli/commands/history/history-compact.js +1 -1
- package/dist/cli/commands/history/history-redact.js +1 -1
- package/dist/cli/commands/history/history-repair.js +1 -1
- package/dist/cli/commands/history/history.js +1 -1
- package/dist/cli/commands/history/restore.js +1 -1
- package/dist/cli/commands/lifecycle/append.js +1 -1
- package/dist/cli/commands/lifecycle/claim.js +1 -1
- package/dist/cli/commands/lifecycle/close-many.js +1 -1
- package/dist/cli/commands/lifecycle/close.js +1 -1
- package/dist/cli/commands/lifecycle/copy.js +1 -1
- package/dist/cli/commands/lifecycle/create.js +1 -1
- package/dist/cli/commands/lifecycle/delete.js +1 -1
- package/dist/cli/commands/lifecycle/focus.js +1 -1
- package/dist/cli/commands/lifecycle/plan.js +1 -1
- package/dist/cli/commands/lifecycle/update-many.js +1 -1
- package/dist/cli/commands/lifecycle/update.js +1 -1
- package/dist/cli/commands/query/aggregate.js +1 -1
- package/dist/cli/commands/query/context.js +1 -1
- package/dist/cli/commands/query/deps.js +1 -1
- package/dist/cli/commands/query/duplicates.js +1 -1
- package/dist/cli/commands/query/eval.js +1 -1
- package/dist/cli/commands/query/get.js +1 -1
- package/dist/cli/commands/query/graph.js +1 -1
- package/dist/cli/commands/query/list.js +1 -1
- package/dist/cli/commands/query/next.js +1 -1
- package/dist/cli/commands/query/search.js +1 -1
- package/dist/cli/commands/query/stats.js +1 -1
- package/dist/cli/commands/test/test-all.js +1 -1
- package/dist/cli/commands/test/test-runs.js +1 -1
- package/dist/cli/commands/test/test.js +1 -1
- package/dist/cli/commands/workspace/config.js +1 -1
- package/dist/cli/commands/workspace/contracts.js +1 -1
- package/dist/cli/commands/workspace/init.js +1 -1
- package/dist/cli/commands/workspace/merge.js +1 -1
- package/dist/cli/commands/workspace/profile.js +1 -1
- package/dist/cli/commands/workspace/schema.js +1 -1
- package/dist/cli/commands/workspace/upgrade.js +1 -1
- package/dist/cli/context-intent-invocation.js +1 -1
- package/dist/cli/description-stdin.js +1 -1
- package/dist/cli/error-guidance.js +3 -1
- package/dist/cli/extension-command-help.js +5 -3
- package/dist/cli/extension-command-options.js +1 -1
- package/dist/cli/extension-recovery.js +1 -1
- package/dist/cli/help-content.js +5 -2
- package/dist/cli/help-json-payload.js +6 -3
- package/dist/cli/invocation-profile.js +2 -2
- package/dist/cli/main.js +5 -5
- package/dist/cli/migration-gates.js +1 -1
- package/dist/cli/option-values.js +1 -1
- package/dist/cli/public.js +1 -1
- package/dist/cli/register-annotations.js +1 -1
- package/dist/cli/register-assurance.js +1 -1
- package/dist/cli/register-files-lookup.js +1 -1
- package/dist/cli/register-history-activity.js +1 -1
- package/dist/cli/register-history-author.js +1 -1
- package/dist/cli/register-history-maintenance.js +2 -2
- package/dist/cli/register-list-query.js +10 -10
- package/dist/cli/register-mutation-options.js +1 -1
- package/dist/cli/register-mutation.js +2 -2
- package/dist/cli/register-operations.js +1 -1
- package/dist/cli/register-setup.js +1 -1
- package/dist/cli/register-structured-mutation.js +1 -1
- package/dist/cli/registration-helpers.js +1 -1
- package/dist/cli/runtime/activation.js +1 -1
- package/dist/cli/runtime/invocation-options.js +1 -1
- package/dist/cli/runtime/projection-retry.js +1 -1
- package/dist/cli/runtime/selection.js +1 -1
- package/dist/cli/runtime/telemetry-outcome.js +1 -1
- package/dist/cli/runtime-compatibility-boundary.js +4 -4
- package/dist/cli/schema/registration.js +2 -2
- package/dist/cli/schema-registration-helpers.js +1 -1
- package/dist/cli/search-refresh.js +1 -1
- package/dist/cli/stats-analytics-json.js +1 -1
- package/dist/cli/telemetry-flush.js +1 -1
- package/dist/cli-bundle/bundle-manifest.json +163 -163
- package/dist/cli-bundle/chunks/{chunk-SMKHR6BM.js → chunk-25EW53VO.js} +89 -88
- package/dist/cli-bundle/chunks/chunk-3CCVTV6Q.js +8 -0
- package/dist/cli-bundle/chunks/chunk-3REXBTST.js +3 -0
- package/dist/cli-bundle/chunks/chunk-4WB55TBC.js +80 -0
- package/dist/cli-bundle/chunks/{chunk-7CE2DJMA.js → chunk-6STTPXOC.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-ATB4ZZBQ.js +20 -0
- package/dist/cli-bundle/chunks/chunk-D4G43LBV.js +238 -0
- package/dist/cli-bundle/chunks/chunk-K6D6DMRT.js +31 -0
- package/dist/cli-bundle/chunks/chunk-KIRHWPZB.js +2 -0
- package/dist/cli-bundle/chunks/chunk-O67BH435.js +6 -0
- package/dist/cli-bundle/chunks/chunk-R7CG2DB7.js +2 -0
- package/dist/cli-bundle/chunks/chunk-RJHLD64E.js +3 -0
- package/dist/cli-bundle/chunks/chunk-TUKO5NF7.js +2 -0
- package/dist/cli-bundle/chunks/chunk-UZ7BIUCI.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-GZMWISWW.js → chunk-XJD47LUH.js} +3 -3
- package/dist/cli-bundle/chunks/{register-list-query-QBGXO5JJ.js → register-list-query-53WYLNZT.js} +11 -11
- package/dist/cli-bundle/chunks/register-mutation-34XXUBVI.js +20 -0
- package/dist/cli-bundle/chunks/register-operations-WANO6EIM.js +2 -0
- package/dist/cli-bundle/chunks/register-setup-WT37UPBQ.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-6KFKQD2D.js +165 -0
- package/dist/cli-bundle/focused-chunks/chunk-FOHRPFIT.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-GRQXL5G5.js +8 -0
- package/dist/cli-bundle/focused-chunks/{chunk-467EW5RL.js → chunk-JZ4WGUVH.js} +3 -3
- package/dist/cli-bundle/focused-chunks/chunk-NM3PM6O6.js +3 -0
- package/dist/cli-bundle/focused-chunks/chunk-OT7HK7SG.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-Q6DJ5DFQ.js → chunk-PCLU34KB.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-HFAW3FJQ.js → chunk-PSXFFQFT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-QQIE4L42.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-RPUNVKXK.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-RXSVJPZ7.js +3 -0
- package/dist/cli-bundle/focused-chunks/chunk-SPN5QTZ3.js +30 -0
- package/dist/cli-bundle/focused-chunks/chunk-SUZJNPGB.js +6 -0
- package/dist/cli-bundle/focused-chunks/chunk-W4BG5HHS.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-Y5HXFDTZ.js +20 -0
- package/dist/cli-bundle/focused-chunks/chunk-ZK5SOOPC.js +75 -0
- package/dist/cli-bundle/focused-chunks/chunk-ZQK2XUSS.js +12 -0
- package/dist/cli-bundle/main.js +25 -25
- 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 +25 -24
- 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 +55 -55
- 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 +10 -10
- package/dist/cli.js +1 -1
- package/dist/core/checkpoint/checkpoint-gc.js +1 -1
- package/dist/core/checkpoint/mutation-checkpoint.js +2 -2
- package/dist/core/config/nested-settings.js +1 -1
- package/dist/core/config/positional-value.js +1 -1
- package/dist/core/diagnostics/remediation.js +1 -1
- package/dist/core/extensions/activation-summary-markdown.js +2 -1
- package/dist/core/extensions/activation-summary.js +1 -1
- package/dist/core/extensions/activation-transaction.js +1 -1
- package/dist/core/extensions/capability-usage.js +1 -1
- package/dist/core/extensions/command-hook-context.js +1 -1
- package/dist/core/extensions/command-metadata-contract.js +1 -1
- package/dist/core/extensions/command-visibility-tier.js +1 -1
- package/dist/core/extensions/contribution-inventory.js +1 -1
- package/dist/core/extensions/exporter-output-contract.js +1 -1
- package/dist/core/extensions/extension-candidate.js +1 -1
- package/dist/core/extensions/extension-capability-aliases.js +1 -1
- package/dist/core/extensions/extension-hook-runtime.js +1 -1
- package/dist/core/extensions/extension-policy.js +1 -1
- package/dist/core/extensions/extension-registries.js +1 -1
- package/dist/core/extensions/extension-runtime-helpers.js +1 -1
- package/dist/core/extensions/extension-types.d.ts +2 -0
- package/dist/core/extensions/extension-types.js +1 -1
- package/dist/core/extensions/flag-definition-validation.js +1 -1
- package/dist/core/extensions/flag-value-types.js +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/item-field-types.js +1 -1
- package/dist/core/extensions/item-fields.js +1 -1
- package/dist/core/extensions/loader.js +1 -1
- package/dist/core/extensions/manifest-parser.js +1 -1
- package/dist/core/extensions/manifest-schema.js +1 -1
- package/dist/core/extensions/module-graph-snapshot.js +1 -1
- package/dist/core/extensions/preflight-ownership.js +1 -1
- package/dist/core/extensions/registration-contracts.js +1 -1
- package/dist/core/extensions/registration-validation.js +1 -1
- package/dist/core/extensions/registration-values.js +1 -1
- package/dist/core/extensions/reserved-host-flags.js +1 -1
- package/dist/core/extensions/runtime-registrations.js +1 -1
- package/dist/core/extensions/service-ownership.js +1 -1
- package/dist/core/extensions/version-compat.js +1 -1
- package/dist/core/fs/atomic-create.js +1 -1
- package/dist/core/fs/fs-utils.js +2 -2
- package/dist/core/fs/host-environment-errors.js +1 -1
- package/dist/core/fs/index.js +1 -1
- package/dist/core/fs/path-utils.js +1 -1
- package/dist/core/governance/content-fields.js +1 -1
- package/dist/core/governance/issue-codes.js +1 -1
- package/dist/core/governance/metadata-coverage.js +1 -1
- package/dist/core/history/digest.js +1 -1
- package/dist/core/history/drift-cache.js +3 -3
- package/dist/core/history/drift-scan.d.ts +4 -0
- package/dist/core/history/drift-scan.js +1 -1
- package/dist/core/history/event-classification.js +1 -1
- package/dist/core/history/event-index.js +8 -7
- package/dist/core/history/history-compact-bulk.js +1 -1
- package/dist/core/history/history-diff.js +1 -1
- package/dist/core/history/history-rewrite.js +1 -1
- package/dist/core/history/history-storage-stats.js +1 -1
- package/dist/core/history/history-stream-policy.js +1 -1
- package/dist/core/history/history.js +2 -2
- package/dist/core/history/identity.js +1 -1
- package/dist/core/history/index.js +1 -1
- package/dist/core/history/operation-contract.js +1 -1
- package/dist/core/history/projection.js +1 -1
- package/dist/core/history/read.js +1 -1
- package/dist/core/history/replay.js +2 -1
- package/dist/core/history/tombstone.js +1 -1
- package/dist/core/history/version-address.js +1 -1
- package/dist/core/history/workspace-history.js +2 -2
- package/dist/core/io/body-file.js +1 -1
- package/dist/core/io/bulk-ids-input.js +2 -1
- package/dist/core/item/actionability.js +1 -1
- package/dist/core/item/dependency-reference.js +1 -1
- package/dist/core/item/id.js +1 -1
- package/dist/core/item/index.js +1 -1
- package/dist/core/item/item-format-version.js +1 -1
- package/dist/core/item/item-format.js +6 -4
- package/dist/core/item/item-record.js +1 -1
- package/dist/core/item/item-type-definition.js +1 -1
- package/dist/core/item/parent-reference-policy.js +1 -1
- package/dist/core/item/parse.js +8 -2
- package/dist/core/item/plan-lifecycle.js +1 -1
- package/dist/core/item/priority.js +1 -1
- package/dist/core/item/sprint-release-format.js +1 -1
- package/dist/core/item/status-filter.js +1 -1
- package/dist/core/item/status.js +1 -1
- package/dist/core/item/toon-decode.js +1 -1
- package/dist/core/item/type-registry.js +1 -1
- package/dist/core/item/type-synonyms.js +1 -1
- package/dist/core/lock/index.js +1 -1
- package/dist/core/lock/lock-gc.js +1 -1
- package/dist/core/lock/lock.js +3 -3
- package/dist/core/output/mutation-projection.js +1 -1
- package/dist/core/output/output-control.js +1 -1
- package/dist/core/output/output.js +22 -10
- package/dist/core/output/query-summary.js +1 -1
- package/dist/core/output/tabular.js +3 -1
- package/dist/core/packages/manifest.js +1 -1
- package/dist/core/packages/root.js +1 -1
- package/dist/core/policy/workflow-policy-schema.js +1 -1
- package/dist/core/policy/workflow-policy-store.js +1 -1
- package/dist/core/policy/workflow-policy.js +1 -1
- package/dist/core/profile/profile-describe.js +1 -1
- package/dist/core/profile/profile-lint.js +1 -1
- package/dist/core/profile/profile-plan.js +1 -1
- package/dist/core/profile/profile-presets.js +25 -1
- package/dist/core/reproducibility/context.js +1 -1
- package/dist/core/schema/fields-file.js +2 -2
- package/dist/core/schema/item-types-file.js +2 -2
- package/dist/core/schema/runtime-field-filters.js +1 -1
- package/dist/core/schema/runtime-field-values.js +1 -1
- package/dist/core/schema/runtime-schema.js +2 -2
- package/dist/core/schema/status-defs-file.js +2 -2
- package/dist/core/schema/status-token.js +1 -1
- package/dist/core/schema/type-inference.js +1 -1
- package/dist/core/schema/type-presets.js +1 -1
- package/dist/core/schema/type-workflows.js +1 -1
- package/dist/core/search/background-refresh.js +2 -2
- package/dist/core/search/bm25.js +1 -1
- package/dist/core/search/cache.js +2 -2
- package/dist/core/search/corpus.js +1 -1
- package/dist/core/search/embedding-batches.js +1 -1
- package/dist/core/search/eval-thresholds.js +1 -1
- package/dist/core/search/eval.js +1 -1
- package/dist/core/search/http-client.js +1 -1
- package/dist/core/search/providers.js +1 -1
- package/dist/core/search/relevance.js +1 -1
- package/dist/core/search/semantic-defaults.js +1 -1
- package/dist/core/search/staleness.js +1 -1
- package/dist/core/search/vector-stores.js +2 -2
- package/dist/core/search/vectorization-metadata.js +1 -1
- package/dist/core/sentry/helpers.js +1 -1
- package/dist/core/sentry/instrument.js +1 -1
- package/dist/core/session/session-state.js +1 -1
- package/dist/core/shared/agent-session-context.js +1 -1
- package/dist/core/shared/author.js +5 -1
- package/dist/core/shared/command-line.js +1 -1
- package/dist/core/shared/command-types.js +1 -1
- package/dist/core/shared/conflict-markers.js +1 -1
- package/dist/core/shared/constants.js +1 -1
- package/dist/core/shared/errors.js +1 -1
- package/dist/core/shared/html-entity-decode.js +1 -1
- package/dist/core/shared/index.js +1 -1
- package/dist/core/shared/item-metadata-contract.js +1 -1
- package/dist/core/shared/lazy-module.js +1 -1
- package/dist/core/shared/levenshtein.js +1 -1
- package/dist/core/shared/memo.js +1 -1
- package/dist/core/shared/numeric-parsers.js +1 -1
- package/dist/core/shared/option-alias-visibility.js +1 -1
- package/dist/core/shared/primitives.js +1 -1
- package/dist/core/shared/secret-rules.js +1 -1
- package/dist/core/shared/serial-queue.js +1 -1
- package/dist/core/shared/serialization.js +1 -1
- package/dist/core/shared/split-comma-list.js +1 -1
- package/dist/core/shared/text-normalization.js +1 -1
- package/dist/core/shared/time.js +2 -1
- package/dist/core/store/index.js +1 -1
- package/dist/core/store/item-format-migration.js +1 -1
- package/dist/core/store/item-metadata-cache.js +1 -1
- package/dist/core/store/item-metadata-query-index.js +7 -7
- package/dist/core/store/item-metadata-read-work.js +1 -1
- package/dist/core/store/item-store.js +1 -1
- package/dist/core/store/paths.js +1 -1
- package/dist/core/store/settings-concurrency.js +1 -1
- package/dist/core/store/settings-read-cache.js +1 -1
- package/dist/core/store/settings-validator.js +1 -1
- package/dist/core/store/settings.js +3 -3
- package/dist/core/store/tracker-preflight.js +1 -1
- package/dist/core/telemetry/consent.js +2 -2
- package/dist/core/telemetry/observability.js +1 -1
- package/dist/core/telemetry/policy.js +1 -1
- package/dist/core/telemetry/read-sampling.js +2 -2
- package/dist/core/telemetry/runtime.js +9 -5
- package/dist/core/test/background-runs.js +3 -3
- package/dist/core/test/item-test-run-tracking.js +1 -1
- package/dist/core/test/run-selectors.js +1 -1
- package/dist/core/validate/estimate-defaults.js +1 -1
- package/dist/core/validate/fix-planning.js +1 -1
- package/dist/core/validate/linked-artifact-reference.js +1 -1
- package/dist/core/validate/missing-by-type.js +1 -1
- package/dist/core/validate/missing-link-owners.js +1 -1
- package/dist/core/validate/stale-file-classification.js +1 -1
- package/dist/mcp/http-server.js +6 -4
- package/dist/mcp/legacy-adapter.js +1 -1
- package/dist/mcp/runtime-capabilities.js +1 -1
- package/dist/mcp/server.js +4 -4
- package/dist/mcp/tool-definitions.js +1 -1
- package/dist/sdk/actionability.js +1 -1
- package/dist/sdk/agent/closed-domain-contracts.js +1 -1
- package/dist/sdk/agent/command-recovery.js +1 -1
- package/dist/sdk/agent/command-suggestions.js +1 -1
- package/dist/sdk/agent/create-option-policy.js +1 -1
- package/dist/sdk/agent/identity-config.js +1 -1
- package/dist/sdk/agent/item-addressing.js +1 -1
- package/dist/sdk/agent/refusal-closure-census.js +2 -1
- package/dist/sdk/agent/refusal-closure.js +1 -1
- package/dist/sdk/agent/refusal-corpus-contracts.js +1 -1
- package/dist/sdk/agent/refusal-reachability.js +3 -1
- package/dist/sdk/agent/subcommand-recovery.js +1 -1
- package/dist/sdk/agent/task-transcript-contracts.js +1 -1
- package/dist/sdk/agent/tracker-preflight-contracts.js +1 -1
- package/dist/sdk/agent-capability-contracts.js +3 -1
- package/dist/sdk/agent-session-context.js +1 -1
- package/dist/sdk/annotations.js +1 -1
- package/dist/sdk/author-attribution.js +1 -1
- package/dist/sdk/authoring.js +1 -1
- package/dist/sdk/cli-bootstrap.d.ts +5 -1
- package/dist/sdk/cli-bootstrap.js +1 -1
- package/dist/sdk/cli-contracts/agent-output-contracts.js +5 -3
- package/dist/sdk/cli-contracts/bootstrap-command-scanner.js +1 -1
- package/dist/sdk/cli-contracts/command-aliases.js +1 -1
- package/dist/sdk/cli-contracts/command-exit-contracts.js +1 -1
- package/dist/sdk/cli-contracts/commander-mutation-options.js +1 -1
- package/dist/sdk/cli-contracts/commander-types.js +1 -1
- package/dist/sdk/cli-contracts/completeness.js +1 -1
- package/dist/sdk/cli-contracts/enum-contracts.js +1 -1
- package/dist/sdk/cli-contracts/flag-contracts.js +1 -1
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +2 -1
- package/dist/sdk/cli-contracts/grammar-contracts.js +1 -1
- package/dist/sdk/cli-contracts/registration-helpers.js +7 -7
- package/dist/sdk/cli-contracts/runtime-contracts.js +1 -1
- package/dist/sdk/cli-contracts/schemas/assurance-definition.js +1 -1
- package/dist/sdk/cli-contracts/string-lists.js +1 -1
- package/dist/sdk/cli-contracts/tool-option-contracts.js +1 -1
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +1 -1
- package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
- package/dist/sdk/cli-contracts/tool-schema.js +1 -1
- package/dist/sdk/cli-contracts/typed-action-inputs.js +1 -1
- package/dist/sdk/cli-contracts.js +1 -1
- package/dist/sdk/cli-program.js +1 -1
- package/dist/sdk/command-line.js +1 -1
- package/dist/sdk/comments.js +1 -1
- package/dist/sdk/compile-cache.js +1 -1
- package/dist/sdk/completion/bash.js +2 -1
- package/dist/sdk/completion/fish.js +13 -7
- package/dist/sdk/completion/shared.js +1 -1
- package/dist/sdk/completion/zsh.js +14 -8
- package/dist/sdk/completion.js +1 -1
- package/dist/sdk/compose.js +1 -1
- package/dist/sdk/config.js +1 -1
- package/dist/sdk/context/recency.js +1 -1
- package/dist/sdk/context/semantic-session-attribution.js +1 -1
- package/dist/sdk/context/usage-egress.js +1 -1
- package/dist/sdk/context/usage-ledger.js +6 -3
- package/dist/sdk/context-intent-contracts.js +1 -1
- package/dist/sdk/context-intent-runtime.js +1 -1
- package/dist/sdk/context-packing.js +1 -1
- package/dist/sdk/context-relevance.js +1 -1
- package/dist/sdk/context-signal-store.js +2 -2
- package/dist/sdk/context-usage.js +1 -1
- package/dist/sdk/contracts.js +1 -1
- package/dist/sdk/core-governance.js +1 -1
- package/dist/sdk/core.js +1 -1
- package/dist/sdk/corpus-shape.js +1 -1
- package/dist/sdk/define.js +1 -1
- package/dist/sdk/dependencies.js +1 -1
- package/dist/sdk/dependency-flag-validation.js +1 -1
- package/dist/sdk/dependency-provenance.js +1 -1
- package/dist/sdk/docs.js +1 -1
- package/dist/sdk/duplicates.js +1 -1
- package/dist/sdk/environment/agent-environment.js +1 -1
- package/dist/sdk/environment/host-environment-errors.js +1 -1
- package/dist/sdk/environment/project-runtime-compatibility.js +2 -1
- package/dist/sdk/environment/source-context.js +1 -1
- package/dist/sdk/environment/tracker-preflight.js +1 -1
- package/dist/sdk/error-code-catalog.js +1 -1
- package/dist/sdk/error-runtime.js +1 -1
- package/dist/sdk/errors.js +1 -1
- package/dist/sdk/eval.js +1 -1
- package/dist/sdk/extension/author-manifest.js +1 -1
- package/dist/sdk/extension/bundled-catalog.js +1 -1
- package/dist/sdk/extension/concurrency.js +1 -1
- package/dist/sdk/extension/copy-scope.js +1 -1
- package/dist/sdk/extension/custom-field-collisions.js +1 -1
- package/dist/sdk/extension/describe.js +4 -2
- package/dist/sdk/extension/doctor.js +1 -1
- package/dist/sdk/extension/install-plan.js +1 -1
- package/dist/sdk/extension/install-receipts.js +1 -1
- package/dist/sdk/extension/install-runtime.js +3 -3
- package/dist/sdk/extension/install-snapshot.js +1 -1
- package/dist/sdk/extension/install-sources.js +5 -5
- package/dist/sdk/extension/managed-state.d.ts +2 -0
- package/dist/sdk/extension/managed-state.js +2 -2
- package/dist/sdk/extension/managed-update-status.d.ts +3 -0
- package/dist/sdk/extension/managed-update-status.js +2 -0
- package/dist/sdk/extension/migrations.js +2 -2
- package/dist/sdk/extension/output-ownership.js +1 -1
- package/dist/sdk/extension/runtime-summary.js +1 -1
- package/dist/sdk/extension/scaffold.js +11 -4
- package/dist/sdk/extension/shared.js +1 -1
- package/dist/sdk/extension/source-resolution.d.ts +2 -6
- package/dist/sdk/extension/source-resolution.js +1 -1
- package/dist/sdk/extension/static-inventory.js +1 -1
- package/dist/sdk/extension/update-check.d.ts +10 -0
- package/dist/sdk/extension/update-check.js +1 -1
- package/dist/sdk/extension-command-context.js +2 -1
- package/dist/sdk/extension-contracts.js +1 -1
- package/dist/sdk/extension.d.ts +4 -0
- package/dist/sdk/extension.js +1 -1
- package/dist/sdk/files.js +1 -1
- package/dist/sdk/flag-invocation-contracts.js +1 -1
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1 -1
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -1
- package/dist/sdk/generated-error-code-catalog.js +1 -1
- package/dist/sdk/governance/assurance-action-contracts.js +1 -1
- package/dist/sdk/governance/assurance-action.js +1 -1
- package/dist/sdk/governance/assurance-limits.js +1 -1
- package/dist/sdk/governance/assurance-mutation-error.js +1 -1
- package/dist/sdk/governance/assurance-presets.js +1 -1
- package/dist/sdk/governance/assurance-runtime.js +1 -1
- package/dist/sdk/governance/assurance.js +4 -4
- package/dist/sdk/governance/boundary-fixtures.js +1 -1
- package/dist/sdk/governance/closure-timestamps.js +1 -1
- package/dist/sdk/governance/coverage-assurance.js +1 -1
- package/dist/sdk/governance/defect-recurrence-coverage.js +1 -1
- package/dist/sdk/governance/defect-recurrence-graph.js +1 -1
- package/dist/sdk/governance/defect-recurrence-signals.js +1 -1
- package/dist/sdk/governance/defect-recurrence.js +1 -1
- package/dist/sdk/governance/extension-host-version.js +1 -1
- package/dist/sdk/governance/gc.js +1 -1
- package/dist/sdk/governance/health-merge-evidence.js +1 -1
- package/dist/sdk/governance/health.js +2 -1
- package/dist/sdk/governance/hierarchy-validation.js +1 -1
- package/dist/sdk/governance/linked-file-report.js +1 -1
- package/dist/sdk/governance/merge-receipt-history.js +1 -1
- package/dist/sdk/governance/provenance-health.js +4 -1
- package/dist/sdk/governance/reindex.js +5 -4
- package/dist/sdk/governance/stale-work.js +1 -1
- package/dist/sdk/governance/status-role-diagnostics.js +1 -1
- package/dist/sdk/governance/storage-integrity.js +1 -1
- package/dist/sdk/governance/tracked-runtime-cache.js +1 -1
- package/dist/sdk/governance/upgrade.js +2 -2
- package/dist/sdk/governance/validate-history-drift.js +1 -1
- package/dist/sdk/governance/validate-item-reader.js +1 -1
- package/dist/sdk/governance/validate-normalization.js +1 -1
- package/dist/sdk/governance/validate.js +1 -1
- package/dist/sdk/governance/workflow-completeness.js +1 -1
- package/dist/sdk/governance/workflow-policy.js +3 -3
- package/dist/sdk/governance/workspace-position.js +2 -1
- package/dist/sdk/governance.js +1 -1
- package/dist/sdk/graph/adapter.js +1 -1
- package/dist/sdk/graph/analytics.js +1 -1
- package/dist/sdk/graph/assembly.js +1 -1
- package/dist/sdk/graph/cache.js +1 -1
- package/dist/sdk/graph/centrality.js +1 -1
- package/dist/sdk/graph/conformance.js +1 -1
- package/dist/sdk/graph/deadline-scheduling.js +1 -1
- package/dist/sdk/graph/durable-cache.js +1 -1
- package/dist/sdk/graph/governance-contracts.js +1 -1
- package/dist/sdk/graph/governance.js +1 -1
- package/dist/sdk/graph/hierarchy-integrity.js +1 -1
- package/dist/sdk/graph/index.js +1 -1
- package/dist/sdk/graph/lifecycle-coverage.js +1 -1
- package/dist/sdk/graph/mutation-advisory.js +1 -1
- package/dist/sdk/graph/query-contracts.js +1 -1
- package/dist/sdk/graph/remediation.js +1 -1
- package/dist/sdk/graph/run.js +1 -1
- package/dist/sdk/graph/scheduling.js +1 -1
- package/dist/sdk/graph/traversal.js +1 -1
- package/dist/sdk/graph/workspace-relationship-kind-registry.js +1 -1
- package/dist/sdk/graph.js +1 -1
- package/dist/sdk/guide-topics.js +1 -1
- package/dist/sdk/guide.js +8 -1
- package/dist/sdk/history/attestation-command.js +1 -1
- package/dist/sdk/history/attestation-contract.js +1 -1
- package/dist/sdk/history/attestation-scan.js +1 -1
- package/dist/sdk/history/attestation.js +1 -1
- package/dist/sdk/history/maintenance.js +1 -1
- package/dist/sdk/history/salvage.js +3 -2
- package/dist/sdk/history/subject.js +1 -1
- package/dist/sdk/history-analytics.js +1 -1
- package/dist/sdk/history-compact.js +1 -1
- package/dist/sdk/history-mcp.js +1 -1
- package/dist/sdk/history-provenance.js +1 -1
- package/dist/sdk/history-read.js +1 -1
- package/dist/sdk/history-redact.js +1 -1
- package/dist/sdk/history-repair.js +1 -1
- package/dist/sdk/improvement-ledger-validation.js +1 -1
- package/dist/sdk/improvement-ledger.js +2 -2
- package/dist/sdk/index.js +1 -1
- package/dist/sdk/init-agent-guidance.js +16 -2
- package/dist/sdk/init.js +16 -2
- package/dist/sdk/invocation-author.js +1 -1
- package/dist/sdk/item-children.js +1 -1
- package/dist/sdk/item-metadata-index.js +1 -1
- package/dist/sdk/item-schedule.js +1 -1
- package/dist/sdk/item-transaction.js +1 -1
- package/dist/sdk/learnings.js +1 -1
- package/dist/sdk/lifecycle/append.js +4 -2
- package/dist/sdk/lifecycle/claim.js +1 -1
- package/dist/sdk/lifecycle/close-many.js +1 -1
- package/dist/sdk/lifecycle/close.js +1 -1
- package/dist/sdk/lifecycle/copy.js +1 -1
- package/dist/sdk/lifecycle/create.js +1 -1
- package/dist/sdk/lifecycle/delete.js +1 -1
- package/dist/sdk/lifecycle/event-validation-messages.js +1 -1
- package/dist/sdk/lifecycle/focus.js +1 -1
- package/dist/sdk/lifecycle/hierarchy-mutation-lock.js +1 -1
- package/dist/sdk/lifecycle/legacy-none-tokens.js +1 -1
- package/dist/sdk/lifecycle/lifecycle-transitions.js +1 -1
- package/dist/sdk/lifecycle/mcp-actions.js +1 -1
- package/dist/sdk/lifecycle/metadata-normalizers.js +1 -1
- package/dist/sdk/lifecycle/mutation-command-options.js +1 -1
- package/dist/sdk/lifecycle/plan-mutation-receipt.js +1 -1
- package/dist/sdk/lifecycle/plan.js +1 -1
- package/dist/sdk/lifecycle/recurrence-parsers.js +1 -1
- package/dist/sdk/lifecycle/reopen.js +1 -1
- package/dist/sdk/lifecycle/repeatable-metadata-parsers.js +2 -1
- package/dist/sdk/lifecycle/restore.js +1 -1
- package/dist/sdk/lifecycle/shared-unset-fields.js +1 -1
- package/dist/sdk/lifecycle/task-composition.js +1 -1
- package/dist/sdk/lifecycle/update-many.js +1 -1
- package/dist/sdk/lifecycle/update.js +2 -1
- package/dist/sdk/lifecycle-completion.js +1 -1
- package/dist/sdk/lifecycle-policy.js +1 -1
- package/dist/sdk/linked-artifacts.js +2 -1
- package/dist/sdk/mcp/apps.js +1 -1
- package/dist/sdk/mcp/authorization.js +1 -1
- package/dist/sdk/mcp/discovery.js +1 -1
- package/dist/sdk/mcp/interactions.js +1 -1
- package/dist/sdk/mcp/protocol.js +1 -1
- package/dist/sdk/mcp/skills.js +3 -1
- package/dist/sdk/mcp/subscriptions.js +1 -1
- package/dist/sdk/mcp/tasks.js +2 -2
- package/dist/sdk/mcp/transport.js +1 -1
- package/dist/sdk/merge/abandoned-receipts.js +1 -1
- package/dist/sdk/merge/driver.js +1 -1
- package/dist/sdk/merge/index.js +1 -1
- package/dist/sdk/merge/install.js +4 -2
- package/dist/sdk/merge/receipt-file-boundary.js +1 -1
- package/dist/sdk/merge/receipt-operation.js +1 -1
- package/dist/sdk/merge/receipt-schema.js +1 -1
- package/dist/sdk/merge/receipts.js +4 -4
- package/dist/sdk/merge/reconcile.js +1 -1
- package/dist/sdk/merge/three-way.js +3 -2
- package/dist/sdk/merge/worktree-config.js +1 -1
- package/dist/sdk/merge.js +1 -1
- package/dist/sdk/mutation-events.js +1 -1
- package/dist/sdk/mutation-guard.js +1 -1
- package/dist/sdk/notes.js +1 -1
- package/dist/sdk/output-contracts.js +1 -1
- package/dist/sdk/output-projection.js +1 -1
- package/dist/sdk/output-token-accounting.js +1 -1
- package/dist/sdk/output.js +2 -1
- package/dist/sdk/ownership-source.js +1 -1
- package/dist/sdk/package-import-adapters.js +1 -1
- package/dist/sdk/package-migrations.js +1 -1
- package/dist/sdk/package-runtime-options.js +1 -1
- package/dist/sdk/pagination.js +1 -1
- package/dist/sdk/profile.js +5 -1
- package/dist/sdk/provenance.js +1 -1
- package/dist/sdk/public-surface.json +1 -1
- package/dist/sdk/query/activity.js +1 -1
- package/dist/sdk/query/aggregate.js +1 -1
- package/dist/sdk/query/calendar.js +4 -1
- package/dist/sdk/query/complete-list.js +1 -1
- package/dist/sdk/query/context.js +2 -1
- package/dist/sdk/query/duplicate-candidates.js +1 -1
- package/dist/sdk/query/get.d.ts +14 -2
- package/dist/sdk/query/get.js +1 -1
- package/dist/sdk/query/history.js +1 -1
- package/dist/sdk/query/item-filter-options.js +1 -1
- package/dist/sdk/query/light-metadata.js +1 -1
- package/dist/sdk/query/list-filter-shared.js +1 -1
- package/dist/sdk/query/list.js +1 -1
- package/dist/sdk/query/multi-value-filters.js +1 -1
- package/dist/sdk/query/next-ready-budget.js +1 -1
- package/dist/sdk/query/next.js +2 -1
- package/dist/sdk/query/parsers.js +1 -1
- package/dist/sdk/query/projection-contracts.js +1 -1
- package/dist/sdk/query/search/corpus.js +2 -1
- package/dist/sdk/query/search/filters.js +1 -1
- package/dist/sdk/query/search/input.js +1 -1
- package/dist/sdk/query/search/lexical.js +1 -1
- package/dist/sdk/query/search/response.js +1 -1
- package/dist/sdk/query/search/semantic.js +3 -2
- package/dist/sdk/query/search/types.js +1 -1
- package/dist/sdk/query/search-contracts.js +1 -1
- package/dist/sdk/query/search-pagination.js +1 -1
- package/dist/sdk/query/search-rendering.js +1 -1
- package/dist/sdk/query/search.js +1 -1
- package/dist/sdk/query/workspace-contracts.js +1 -1
- package/dist/sdk/query.js +1 -1
- package/dist/sdk/read-output/continuation.js +1 -1
- package/dist/sdk/read-output/options.js +1 -1
- package/dist/sdk/read-output/provenance.js +1 -1
- package/dist/sdk/read-output-budget.js +1 -1
- package/dist/sdk/read-output-contracts.js +1 -1
- package/dist/sdk/read-output-rows.js +1 -1
- package/dist/sdk/read-output-session.js +1 -1
- package/dist/sdk/relationship-analytics.js +1 -1
- package/dist/sdk/relationship-context.js +1 -1
- package/dist/sdk/relationship-history.js +7 -4
- package/dist/sdk/relationship-kinds/contract.js +1 -1
- package/dist/sdk/relationship-migration.js +1 -1
- package/dist/sdk/relationships.js +1 -1
- package/dist/sdk/reproducibility/process.js +1 -1
- package/dist/sdk/runtime/actions.js +1 -1
- package/dist/sdk/runtime/context.js +1 -1
- package/dist/sdk/runtime/schema-preview.js +1 -1
- package/dist/sdk/runtime/schema.js +1 -1
- package/dist/sdk/runtime-action-aliases.js +1 -1
- package/dist/sdk/runtime-extended-actions.js +1 -1
- package/dist/sdk/runtime-input.js +1 -1
- package/dist/sdk/runtime-primitives.js +1 -1
- package/dist/sdk/runtime-public-contracts.js +1 -1
- package/dist/sdk/runtime-stats-options.js +1 -1
- package/dist/sdk/runtime.js +1 -1
- package/dist/sdk/scheduling-shortcuts.js +1 -1
- package/dist/sdk/schema-migration.js +4 -3
- package/dist/sdk/schema.js +7 -1
- package/dist/sdk/search-refresh-worker.js +1 -1
- package/dist/sdk/similarity-scoring.js +1 -1
- package/dist/sdk/similarity.js +1 -1
- package/dist/sdk/start-task-status.js +1 -1
- package/dist/sdk/stats.js +1 -1
- package/dist/sdk/structured-mutations.js +1 -1
- package/dist/sdk/telemetry-flush.js +1 -1
- package/dist/sdk/telemetry.js +4 -3
- package/dist/sdk/templates.js +26 -2
- package/dist/sdk/test/batch.js +2 -2
- package/dist/sdk/test/entry.js +1 -1
- package/dist/sdk/test/execution.d.ts +2 -1
- package/dist/sdk/test/execution.js +6 -5
- package/dist/sdk/test/json-path.js +1 -1
- package/dist/sdk/test/linked-command-detection.js +1 -1
- package/dist/sdk/test/measurements.js +1 -1
- package/dist/sdk/test/parsers.js +1 -1
- package/dist/sdk/test/runs.js +1 -1
- package/dist/sdk/test/trust.js +2 -2
- package/dist/sdk/test/workspace-snapshot.js +1 -1
- package/dist/sdk/testing.js +7 -4
- package/dist/sdk/traceability/runtime-files-lookup.js +1 -1
- package/dist/sdk/traceability/source-traceability.js +2 -1
- package/dist/sdk/tracker-root-discovery.js +1 -1
- package/dist/sdk/workspace-contracts-cache.js +1 -1
- package/dist/sdk/workspace-contracts.js +1 -1
- package/dist/sdk/workspace-memory.js +2 -2
- package/dist/sdk/workspace-recipe.js +1 -1
- package/dist/sdk/workspace-snapshot.js +5 -4
- package/dist/sdk/workspace-transaction-gc.js +1 -1
- package/dist/sdk/workspace-transaction.js +2 -2
- package/dist/sdk/workspace.js +3 -2
- package/dist/types/index.js +1 -1
- package/dist/types.js +1 -1
- package/docs/AGENT_EVIDENCE_CONSISTENCY.md +88 -0
- package/docs/DEVELOPMENT_DEPENDENCY_SECURITY.md +36 -0
- package/docs/GET_READ_EVIDENCE.md +84 -0
- package/docs/OUTPUT_PROJECTION_CONTRACTS.md +23 -0
- package/docs/PR_REVIEW_LOOP.md +21 -4
- package/docs/README.md +3 -0
- package/docs/RELEASING.md +18 -0
- package/docs/SDK_CONFIGURATION_SAFETY.md +123 -0
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +3 -3
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +4 -3
- package/marketplace.json +2 -2
- package/package.json +3 -3
- 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/extensions/vcs/index.ts +4 -2
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-claude/package.json +2 -2
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/pm-codex/package.json +2 -2
- package/plugins/pm-codex/plugin.json +1 -1
- package/scripts/finalize-build.mjs +3 -2
- package/dist/cli-bundle/chunks/chunk-7UVXKI7K.js +0 -2
- package/dist/cli-bundle/chunks/chunk-D7Z2ZMJL.js +0 -3
- package/dist/cli-bundle/chunks/chunk-DEZPZOQ7.js +0 -2
- package/dist/cli-bundle/chunks/chunk-J52QIRRZ.js +0 -80
- package/dist/cli-bundle/chunks/chunk-JDKD3WGG.js +0 -6
- package/dist/cli-bundle/chunks/chunk-JQ7DW663.js +0 -2
- package/dist/cli-bundle/chunks/chunk-QXIDOOWT.js +0 -20
- package/dist/cli-bundle/chunks/chunk-SGFQQXFD.js +0 -2
- package/dist/cli-bundle/chunks/chunk-V3U77H3V.js +0 -31
- package/dist/cli-bundle/chunks/chunk-XZDWAYJC.js +0 -3
- package/dist/cli-bundle/chunks/chunk-Y6VRBTP3.js +0 -238
- package/dist/cli-bundle/chunks/chunk-YAAFYFS4.js +0 -8
- package/dist/cli-bundle/chunks/register-mutation-53ZLT4RX.js +0 -20
- package/dist/cli-bundle/chunks/register-operations-OBK2FXUU.js +0 -2
- package/dist/cli-bundle/chunks/register-setup-HM3OCBH2.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-2JFYR56O.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-32EVUSS4.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-5GUSO2P4.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-6XBRADQQ.js +0 -3
- package/dist/cli-bundle/focused-chunks/chunk-7O4NUJVO.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-CURTIIQT.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-IJUWEEEB.js +0 -6
- package/dist/cli-bundle/focused-chunks/chunk-JCVMOSWQ.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-JMJK2L4Z.js +0 -3
- package/dist/cli-bundle/focused-chunks/chunk-KG3H4UZZ.js +0 -30
- package/dist/cli-bundle/focused-chunks/chunk-MHQ2XICU.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-RJV6QVJE.js +0 -75
- package/dist/cli-bundle/focused-chunks/chunk-ZE2JZ7R6.js +0 -12
- package/dist/cli-bundle/focused-chunks/chunk-ZLEN4HZD.js +0 -165
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
`)},globalPmRoot)}catch{}}function isSensitiveKey(key){const normalized=key.trim().toLowerCase().replaceAll("-","_").replaceAll(/[^a-z0-9_]+/g,"_")
|
|
3
|
-
`)}return{source_context:inferTelemetrySourceContext(globalOptions),source_context_source:source}}function inferTelemetrySourceContext(globalOptions){const nodeEnv=(process.env.NODE_ENV??"").trim().toLowerCase();if(typeof process.env.VITEST==="string"||typeof process.env.VITEST_WORKER_ID==="string"||nodeEnv==="test"){return"test"}const nonTty=process.stdin.isTTY!==true||process.stdout.isTTY!==true;const ci=parseBooleanTrueLike(process.env.CI);const scriptLikeMode=globalOptions.json===true||globalOptions.quiet===true;if(nonTty||ci||scriptLikeMode){return"automation"}return"user"}function hashWithInstallationId(installationId,value){return crypto.createHash("sha256").update(`${installationId}:${value}`).digest("hex")}function buildAuthorContextPayloadFields(captureLevel,installationId){const author=(readAuthorEnvironment()??"").trim();const agent=detectAgentIdentity({env:process.env,argv:process.argv});const hasAgentContext=agent.harness!==void 0||agent.model!==void 0;if(captureLevel==="minimal"){return{has_author_context:author.length>0,has_agent_context:hasAgentContext}}return{agent_harness:agent.harness?TELEMETRY_HARNESSES.has(agent.harness)?agent.harness:"other":"none",ci:parseBooleanTrueLike(process.env.CI),...author.length>0?{author_context_hash:hashWithInstallationId(installationId,author)}:{},...agent.harness?{agent_harness_hash:hashWithInstallationId(installationId,agent.harness)}:{},...agent.model?{agent_model_hash:hashWithInstallationId(installationId,agent.model)}:{},...agent.model_source?{agent_model_source:agent.model_source}:{}}}function normalizeForHash(value,depth=0){if(value===null||value===void 0){return value}if(typeof value==="string"||typeof value==="number"||typeof value==="boolean"){return value}if(depth>=TELEMETRY_SANITIZE_MAX_DEPTH){return"[depth_truncated]"}if(Array.isArray(value)){return value.slice(0,TELEMETRY_SANITIZE_MAX_ARRAY_ITEMS).map(entry=>normalizeForHash(entry,depth+1))}if(typeof value==="object"){const record=value;const normalized={};const sortedKeys=Object.keys(record).sort((left,right)=>left.localeCompare(right));for(const key of sortedKeys){normalized[key]=normalizeForHash(record[key],depth+1)}return normalized}return String(value)}function hashTelemetryValue(installationId,value){return hashWithInstallationId(installationId,JSON.stringify(normalizeForHash(value)))}function hashCommandArgs(installationId,args){return{hashes:args.map(arg=>hashWithInstallationId(installationId,arg)),digest:hashWithInstallationId(installationId,args.join("\0"))}}function hashTelemetryErrorFingerprint(installationId,command,errorCode2,errorMessage){const normalizedMessage=sanitizeString(typeof errorMessage==="string"?errorMessage:"","redacted");const normalizedCode=typeof errorCode2==="string"&&errorCode2.length>0?errorCode2:"unknown_error";const fingerprintSource=`${command}\0${normalizedCode}\0${normalizedMessage}`;return hashWithInstallationId(installationId,fingerprintSource)}function resolveOtelTracesEndpoint(){if(PM_TELEMETRY_OTEL_DISABLED_VALUES.has((process.env[PM_TELEMETRY_OTEL_DISABLED_ENV]??"").trim().toLowerCase())){return null}const directEndpoint=(process.env[OTEL_TRACES_ENDPOINT_ENV]??"").trim();if(directEndpoint.length>0){try{return new URL(directEndpoint).toString()}catch{return null}}const baseEndpoint=(process.env[OTEL_BASE_ENDPOINT_ENV]??"").trim();if(baseEndpoint.length===0){return null}try{const url=new URL(baseEndpoint);const normalizedPath=url.pathname.replace(/\/+$/,"");if(!normalizedPath.endsWith("/v1/traces")){url.pathname=`${normalizedPath.length===0?"":normalizedPath}/v1/traces`}return url.toString()}catch{return null}}function isoToUnixNano(iso){const parsedMs=Date.parse(iso);const epochMs=Number.isNaN(parsedMs)?Date.now():parsedMs;return`${BigInt(epochMs)*1000000n}`}function otlpStringAttribute(key,value){return{key,value:{stringValue:value}}}function otlpBoolAttribute(key,value){return{key,value:{boolValue:value}}}function otlpIntAttribute(key,value){return{key,value:{intValue:String(Math.max(0,Math.trunc(value)))}}}function buildOtelSpanRequest(activeCommand,outcome,finishedAtIso,durationMs,sampleRate=1){const endpoint=activeCommand.otel_traces_endpoint;if(typeof endpoint!=="string"||endpoint.trim().length===0||[activeCommand.otel_trace_id,activeCommand.otel_span_id].some(id=>typeof id!=="string"||id.length===0)){return null}const serviceNameCandidate=sanitizeString((process.env[OTEL_SERVICE_NAME_ENV]??"").trim());const serviceName=serviceNameCandidate.length>0?serviceNameCandidate:"pm-cli";const normalizedExitCode=normalizeTelemetryExitCode(outcome.exit_code,outcome.ok);const normalizedErrorCode=normalizeTelemetryErrorCode(outcome.error_code);const normalizedErrorCategory=normalizeTelemetryErrorCategory({ok:outcome.ok,errorCode:normalizedErrorCode,errorCategory:outcome.error_category});const attributes=[otlpStringAttribute("pm.command",sanitizeString(activeCommand.command)),otlpStringAttribute("pm.version",activeCommand.pm_version),otlpStringAttribute("pm.source_context",activeCommand.source_context),otlpStringAttribute("pm.source_context_source",activeCommand.source_context_source),otlpStringAttribute("pm.installation_id",activeCommand.installation_id),otlpStringAttribute("pm.session_id",PROCESS_SESSION_ID),otlpStringAttribute("pm.pm_root_hash",activeCommand.pm_root_hash),otlpStringAttribute("pm.cwd_hash",activeCommand.cwd_hash),otlpBoolAttribute("pm.ok",outcome.ok),otlpIntAttribute("pm.exit_code",normalizedExitCode),otlpIntAttribute("pm.duration_ms",durationMs),otlpStringAttribute("pm.sample_rate",String(sampleRate))];if(typeof normalizedErrorCode==="string"){attributes.push(otlpStringAttribute("pm.error_code",normalizedErrorCode))}if(typeof normalizedErrorCategory==="string"){attributes.push(otlpStringAttribute("pm.error_category",normalizedErrorCategory))}if(typeof outcome.error==="string"&&outcome.error.trim().length>0){attributes.push(otlpStringAttribute("pm.error",sanitizeString(outcome.error)))}const payload={resourceSpans:[{resource:{attributes:[otlpStringAttribute("service.name",serviceName)]},scopeSpans:[{scope:{name:"pm-cli.telemetry",version:"1"},spans:[{traceId:activeCommand.otel_trace_id,spanId:activeCommand.otel_span_id,name:`pm.command.${sanitizeString(activeCommand.command)}`,kind:1,startTimeUnixNano:isoToUnixNano(activeCommand.started_at),endTimeUnixNano:isoToUnixNano(finishedAtIso),attributes,status:{code:outcome.ok?1:2,message:outcome.ok?"":sanitizeString(typeof outcome.error==="string"?outcome.error:"command_failed")}}]}]}]};return{endpoint,payload}}function summarizeResult(result,captureLevel="redacted"){if(result===null||result===void 0){return{type:"nullish"}}if(typeof result==="string"){return{type:"string",value:sanitizeString(result,captureLevel)}}if(typeof result==="number"||typeof result==="boolean"){return{type:typeof result,value:result}}if(Array.isArray(result)){return{type:"array",length:result.length,sample:result.slice(0,5).map(entry=>sanitizeValue(entry,void 0,captureLevel))}}if(typeof result==="object"){const record=result;const keys=Object.keys(record).sort((left,right)=>left.localeCompare(right));const sanitized={};let previewBytes=0;for(const key of keys.slice(0,25)){const sanitizedValue=sanitizeValue(record[key],key,captureLevel);if(sanitizedValue===void 0)continue;const entrySize=JSON.stringify(sanitizedValue).length;if(previewBytes+entrySize>TELEMETRY_RESULT_PREVIEW_MAX_BYTES){sanitized[key]="[preview_truncated]";break}previewBytes+=entrySize;sanitized[key]=sanitizedValue}return{type:"object",key_count:keys.length,keys_preview:keys.slice(0,50),preview:sanitized}}return{type:typeof result,value:String(result)}}function buildCommandStartPayload(params){const{captureLevel,context,pmVersion,sourceContext,pmRootHash,cwdHash,installationId}=params;const commandTaxonomy=deriveTelemetryCommandTaxonomy(context.command);const hashedArgs=hashCommandArgs(installationId,context.args);const commandInvocationDigest=hashWithInstallationId(installationId,`${context.command}\0${context.args.join("\0")}`);const commandOptionsDigest=hashTelemetryValue(installationId,context.options);const globalOptionsDigest=hashTelemetryValue(installationId,context.global);const authorContextFields=buildAuthorContextPayloadFields(captureLevel,installationId);if(captureLevel==="minimal"){return{capture_level:captureLevel,pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,command_taxonomy:commandTaxonomy,command_args_digest:hashedArgs.digest,command_invocation_digest:commandInvocationDigest,command_options_digest:commandOptionsDigest,global_options_digest:globalOptionsDigest,...authorContextFields}}return{pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,command_taxonomy:commandTaxonomy,...authorContextFields,command_args:sanitizeCommandArgs(context.args,captureLevel),command_args_hashes:hashedArgs.hashes,command_args_digest:hashedArgs.digest,command_invocation_digest:commandInvocationDigest,command_options:sanitizeValue(context.options,void 0,captureLevel),command_options_digest:commandOptionsDigest,global_options:sanitizeValue(context.global,void 0,captureLevel),global_options_digest:globalOptionsDigest,pm_root_hash:pmRootHash,cwd_hash:cwdHash,capture_level:captureLevel,runtime:{node:process.version,platform:process.platform,arch:process.arch,hostname_hash:hashWithInstallationId(installationId,os.hostname()),stdin_tty:process.stdin.isTTY===true,stdout_tty:process.stdout.isTTY===true}}}function buildCommandFinishPayload(params){const{captureLevel,pmVersion,sourceContext,outcome,durationMs,startedAt,command,installationId,commandTaxonomy,exitCode,errorCode:errorCode2,errorCategory,commandResolution,resolutionStage}=params;const errorFingerprint=outcome.ok===false?hashTelemetryErrorFingerprint(installationId,command,errorCode2,outcome.error):void 0;const authorContextFields=buildAuthorContextPayloadFields(captureLevel,installationId);if(captureLevel==="minimal"){return{capture_level:captureLevel,pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,command_taxonomy:commandTaxonomy,command_resolution:commandResolution,resolution_stage:resolutionStage,ok:outcome.ok,exit_code:exitCode,error_code:errorCode2,error_category:errorCategory,error:outcome.error?sanitizeString(outcome.error,"redacted"):void 0,error_fingerprint:errorFingerprint,duration_ms:durationMs,...authorContextFields}}return{capture_level:captureLevel,pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,command_taxonomy:commandTaxonomy,command_resolution:commandResolution,resolution_stage:resolutionStage,...authorContextFields,ok:outcome.ok,exit_code:exitCode,error_code:errorCode2,error_category:errorCategory,error:outcome.error?sanitizeString(outcome.error,captureLevel):void 0,error_fingerprint:errorFingerprint,duration_ms:durationMs,started_at:startedAt,result_summary:summarizeResult(outcome.result,captureLevel)}}function buildCommandErrorPayload(params){const{captureLevel,pmVersion,sourceContext,command,commandTaxonomy,commandResolution,resolutionStage,args,options,pmRootHash,cwdHash,installationId,errorCode:errorCode2,errorMessage,errorCategory,exitCode}=params;const attemptedArgHashes=hashCommandArgs(installationId,args);const attemptedCommandDigest=hashWithInstallationId(installationId,command);const attemptedOptionsDigest=hashTelemetryValue(installationId,options);const errorFingerprint=hashTelemetryErrorFingerprint(installationId,command,errorCode2,errorMessage);const authorContextFields=buildAuthorContextPayloadFields(captureLevel,installationId);if(captureLevel==="minimal"){return{capture_level:captureLevel,pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,command_taxonomy:commandTaxonomy,command_resolution:commandResolution,resolution_stage:resolutionStage,attempted_command_digest:attemptedCommandDigest,attempted_args_digest:attemptedArgHashes.digest,attempted_options_digest:attemptedOptionsDigest,error_code:errorCode2,error_category:errorCategory,exit_code:exitCode,error:sanitizeString(errorMessage,"redacted"),error_fingerprint:errorFingerprint,...authorContextFields}}return{capture_level:captureLevel,pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,command_taxonomy:commandTaxonomy,command_resolution:commandResolution,resolution_stage:resolutionStage,...authorContextFields,attempted_command:sanitizeString(command,captureLevel),attempted_command_digest:attemptedCommandDigest,attempted_args:sanitizeCommandArgs(args,captureLevel),attempted_args_hashes:attemptedArgHashes.hashes,attempted_args_digest:attemptedArgHashes.digest,attempted_options:sanitizeValue(options,void 0,captureLevel),attempted_options_digest:attemptedOptionsDigest,error_code:errorCode2,error_category:errorCategory,exit_code:exitCode,error:sanitizeString(errorMessage,captureLevel),error_fingerprint:errorFingerprint,pm_root_hash:pmRootHash,cwd_hash:cwdHash,runtime:{node:process.version,platform:process.platform,arch:process.arch,hostname_hash:hashWithInstallationId(installationId,os.hostname()),stdin_tty:process.stdin.isTTY===true,stdout_tty:process.stdout.isTTY===true}}}async function ensureInstallationId(globalPmRoot){const settings=await readSettings(globalPmRoot);if(!settings.telemetry.enabled||resolveTelemetryEnvironmentPolicy().telemetry_disabled)return null;if(settings.telemetry.installation_id.trim().length===0){if(isConfigurationOnlySettingsRead(globalPmRoot))return null;settings.telemetry.installation_id=crypto.randomUUID();await writeSettings(globalPmRoot,settings,"telemetry:install_id")}return{installationId:settings.telemetry.installation_id,endpoint:settings.telemetry.endpoint,retentionDays:Math.max(1,Math.trunc(settings.telemetry.retention_days)),captureLevel:normalizeCaptureLevel(settings.telemetry.capture_level)}}async function appendTelemetryEvent(globalPmRoot,event){const queued={client_schema_version:TELEMETRY_CLIENT_SCHEMA_VERSION,event,attempts:0};let serialized=JSON.stringify(queued);if(serialized.length>TELEMETRY_MAX_EVENT_BYTES){const trimmed={...event,payload:{...event.payload,result_summary:{truncated:true,reason:"payload_size_exceeded",original_bytes:serialized.length}}};const trimmedQueued={client_schema_version:TELEMETRY_CLIENT_SCHEMA_VERSION,event:trimmed,attempts:0};serialized=JSON.stringify(trimmedQueued)}await appendLineAtomic(queuePath(globalPmRoot),serialized)}async function enqueueTelemetryEvent(globalPmRoot,event){await withQueueMutation(()=>appendTelemetryEvent(globalPmRoot,event),globalPmRoot)}function parseQueueLines(raw){const entries=[];for(const line of raw.split("\n")){const trimmed=line.trim();if(trimmed.length===0){continue}try{const parsed=JSON.parse(trimmed);if(parsed&&typeof parsed==="object"&&parsed.event&&typeof parsed.event==="object"&&typeof parsed.attempts==="number"&&(parsed.client_schema_version===void 0||typeof parsed.client_schema_version==="number"&&Number.isFinite(parsed.client_schema_version))){entries.push(parsed)}}catch{}}return entries}function nextRetryIso(attempts){const delay=Math.min(TELEMETRY_RETRY_BASE_DELAY_MS*2**Math.max(attempts-1,0),TELEMETRY_MAX_RETRY_DELAY_MS);return new Date(Date.now()+delay).toISOString()}function isDueForRetryAt(nextAttemptAfter){if(typeof nextAttemptAfter!=="string"||nextAttemptAfter.trim().length===0){return true}const dueAtMs=Date.parse(nextAttemptAfter);if(Number.isNaN(dueAtMs)){return true}return dueAtMs<=Date.now()}function isDueForRetry(entry){return isDueForRetryAt(entry.next_attempt_after)}function retentionCutoffMs(retentionDays){const normalizedDays=Number.isFinite(retentionDays)?Math.max(1,Math.trunc(retentionDays)):1;return Date.now()-normalizedDays*MILLISECONDS_PER_DAY}function isExpiredQueueEntry(entry,cutoffMs){const occurredAt=entry.event?.occurred_at;if(typeof occurredAt!=="string"||occurredAt.trim().length===0){return false}const occurredAtMs=Date.parse(occurredAt);if(Number.isNaN(occurredAtMs)){return false}return occurredAtMs<cutoffMs}function pruneExpiredQueueEntries(entries,retentionDays){const cutoffMs=retentionCutoffMs(retentionDays);const retained=[];let prunedCount=0;for(const entry of entries){const serializedSize=JSON.stringify(entry).length;const oversized=serializedSize>TELEMETRY_MAX_EVENT_BYTES;if(oversized||isExpiredQueueEntry(entry,cutoffMs)||entry.attempts>=TELEMETRY_MAX_QUEUE_ENTRY_ATTEMPTS){prunedCount+=1;continue}retained.push(entry)}return{entries:retained,prunedCount}}async function rewriteQueue(globalPmRoot,entries){const serialized=entries.map(entry=>JSON.stringify(entry)).join("\n");const contents=serialized.length>0?`${serialized}
|
|
4
|
-
|
|
5
|
-
`:"";for(let attempt=0;;attempt+=1){try{await writeFileAtomic(otelSpansQueuePath(globalPmRoot),contents);return}catch(error){const retryDelay=TELEMETRY_QUEUE_REWRITE_RETRY_DELAYS_MS[attempt];if(retryDelay===void 0||!isRetryableQueueRewriteError(error)){throw error}await sleep(retryDelay)}}}async function reconcilePendingOtelSpansAfterFlush(globalPmRoot,retentionDays,succeededIds,failedUpdates){return withQueueMutation(async()=>{const raw=await readFileIfExists(otelSpansQueuePath(globalPmRoot));const current=raw===null?[]:parsePendingOtelSpanLines(raw);const reconciled=[];for(const entry of current){if(succeededIds.has(entry.id)){continue}const failure=failedUpdates.get(entry.id);reconciled.push(failure?{...entry,attempts:failure.attempts,next_attempt_after:failure.next_attempt_after}:entry)}const{entries:retained}=prunePendingOtelSpans(reconciled,retentionDays);await rewritePendingOtelSpans(globalPmRoot,retained);return retained.length},globalPmRoot)}async function flushPendingOtelSpans(globalPmRoot,retentionDays){const raw=await readFileIfExists(otelSpansQueuePath(globalPmRoot));if(raw===null||raw.trim().length===0){await writeRuntimeState(globalPmRoot,{pending_otel_spans:0});return}const entries=parsePendingOtelSpanLines(raw);const{entries:retained,prunedCount}=prunePendingOtelSpans(entries,retentionDays);const due=retained.filter(entry=>isDueForRetryAt(entry.next_attempt_after)).slice(0,TELEMETRY_OTEL_SPANS_FLUSH_BATCH_SIZE);if(due.length===0){const remaining2=prunedCount>0?await reconcilePendingOtelSpansAfterFlush(globalPmRoot,retentionDays,new Set,new Map):retained.length;await writeRuntimeState(globalPmRoot,{pending_otel_spans:remaining2});return}const attemptTime=nowIso();const succeededIds=new Set;const failedUpdates=new Map;let succeededCount=0;let lastError;await Promise.all(due.map(async span=>{try{const status=await postTelemetryJson(span.endpoint,{"content-type":"application/json"},JSON.stringify(span.payload));if(status<200||status>=300){throw new Error(`local_otel_export_http_${status}`)}succeededIds.add(span.id);succeededCount+=1}catch(error){lastError=error instanceof Error?sanitizeString(error.message,"redacted"):"local_otel_export_failed";const nextAttempts=span.attempts+1;failedUpdates.set(span.id,{attempts:nextAttempts,next_attempt_after:nextRetryIso(nextAttempts)})}}));const remaining=await reconcilePendingOtelSpansAfterFlush(globalPmRoot,retentionDays,succeededIds,failedUpdates);const statePatch={pending_otel_spans:remaining,last_otel_attempt_at:attemptTime};if(succeededCount>0){statePatch.last_otel_success_at=attemptTime}if(lastError!==void 0){statePatch.last_otel_failure_at=attemptTime;statePatch.last_otel_failure_error=lastError}else if(remaining===0){statePatch.last_otel_failure_at=void 0;statePatch.last_otel_failure_error=void 0}await writeRuntimeState(globalPmRoot,statePatch)}async function flushTelemetryArtifacts(globalPmRoot,endpoint,retentionDays){try{await flushQueue(globalPmRoot,endpoint,retentionDays)}catch{}try{await flushPendingOtelSpans(globalPmRoot,retentionDays)}catch{}}async function cleanupTelemetryQueueTempOrphans(globalPmRoot,maxAgeMs=TELEMETRY_QUEUE_TMP_ORPHAN_MAX_AGE_MS){try{const dirPath=telemetryRuntimeDirectory(globalPmRoot);const entries=await readdir(dirPath,{withFileTypes:true});const cutoffMs=Date.now()-Math.max(0,maxAgeMs);await Promise.all(entries.filter(entry=>entry.isFile()&&/^\.events\.jsonl\.\d+\.\d+\.[a-f0-9]+\.tmp$/.test(entry.name)).map(async entry=>{const candidate=path.join(dirPath,entry.name);const candidateStats=await stat(candidate);if(candidateStats.mtimeMs<cutoffMs){await rm(candidate,{force:true})}}))}catch{}}async function withQueueMutation(operation,globalPmRoot=resolveGlobalPmRoot(process.cwd()),waitMs=5e3){const run=_queueMutationPromise.catch(()=>{}).then(()=>runWithIsolatedExtensionRuntime(async()=>{const release=await acquireLock(globalPmRoot,"telemetry-queue",60,"telemetry",false,false,waitMs);try{clearSettingsReadCache(globalPmRoot);return await operation()}finally{await release()}}));_queueMutationPromise=run.catch(()=>{});return run}async function readCurrentQueueEntries(globalPmRoot){const raw=await readFileIfExists(queuePath(globalPmRoot));if(raw===null||raw.trim().length===0){return[]}return parseQueueLines(raw)}async function removeFlushedEntriesFromCurrentQueue(globalPmRoot,flushedIds,retentionDays){return withQueueMutation(async()=>{const currentEntries=await readCurrentQueueEntries(globalPmRoot);const{entries:retainedEntries}=pruneExpiredQueueEntries(currentEntries,retentionDays);const remaining=retainedEntries.filter(entry=>!flushedIds.has(entry.event.event_id));await rewriteQueue(globalPmRoot,remaining);return remaining},globalPmRoot)}async function markFailedEntriesInCurrentQueue(globalPmRoot,failedIds,attemptTime,retentionDays){return withQueueMutation(async()=>{const currentEntries=await readCurrentQueueEntries(globalPmRoot);const{entries:retainedEntries}=pruneExpiredQueueEntries(currentEntries,retentionDays);const retried=retainedEntries.map(entry=>{if(!failedIds.has(entry.event.event_id)){return entry}const attempts=entry.attempts+1;return{...entry,attempts,last_attempt_at:attemptTime,next_attempt_after:nextRetryIso(attempts)}});await rewriteQueue(globalPmRoot,retried);return retried},globalPmRoot)}async function flushQueue(globalPmRoot,endpoint,retentionDays){await cleanupTelemetryQueueTempOrphans(globalPmRoot);const normalizedEndpoint=endpoint.trim();if(normalizedEndpoint.length===0){return}const raw=await readFileIfExists(queuePath(globalPmRoot));if(raw===null||raw.trim().length===0){await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:0});return}const queueEntries=parseQueueLines(raw);if(queueEntries.length===0){await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:0});return}const{entries:retainedEntries,prunedCount}=pruneExpiredQueueEntries(queueEntries,retentionDays);if(retainedEntries.length===0){const remaining=await removeFlushedEntriesFromCurrentQueue(globalPmRoot,new Set,retentionDays);await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:remaining.length});return}const dueEntries=retainedEntries.filter(entry=>isDueForRetry(entry)).slice(0,TELEMETRY_FLUSH_BATCH_SIZE);if(dueEntries.length===0){const remaining=prunedCount>0?await removeFlushedEntriesFromCurrentQueue(globalPmRoot,new Set,retentionDays):retainedEntries;await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:remaining.length});return}const dueIds=new Set(dueEntries.map(entry=>entry.event.event_id));const attemptTime=nowIso();const requestHeaders={"content-type":"application/json"};const ingestKey=process.env.PM_TELEMETRY_INGEST_KEY?.trim();if(ingestKey){requestHeaders["x-pm-telemetry-key"]=ingestKey}try{const status=await postTelemetryJson(normalizedEndpoint,requestHeaders,JSON.stringify({schema_version:TELEMETRY_SCHEMA_VERSION,events:dueEntries.map(entry=>entry.event)}));if(status<200||status>=300){throw new Error(`telemetry_flush_http_${status}`)}}catch(error){const retried=await markFailedEntriesInCurrentQueue(globalPmRoot,dueIds,attemptTime,retentionDays);const errorMessage=(()=>{if(error instanceof Error){return sanitizeString(error.message,"redacted")}return"telemetry_flush_failed"})();await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:retried.length,last_attempted_flush_at:attemptTime,last_failed_flush_at:attemptTime,last_failed_flush_error:errorMessage});return}try{const remaining=await removeFlushedEntriesFromCurrentQueue(globalPmRoot,dueIds,retentionDays);await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:remaining.length,last_attempted_flush_at:attemptTime,last_successful_flush_at:attemptTime,last_failed_flush_at:void 0,last_failed_flush_error:void 0})}catch(error){const errorMessage=(()=>{if(error instanceof Error){return sanitizeString(error.message,"redacted")}return"telemetry_flush_failed"})();const currentEntries=await readCurrentQueueEntries(globalPmRoot).catch(()=>retainedEntries);await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:currentEntries.length,last_attempted_flush_at:attemptTime,last_failed_flush_at:attemptTime,last_failed_flush_error:errorMessage})}}async function acquireTelemetryFlushLock(globalPmRoot){const lockPath=flushLockPath(globalPmRoot);await mkdir(path.dirname(lockPath),{recursive:true});try{await mkdir(lockPath);return true}catch(error){if(typeof error!=="object"||error===null||!("code"in error)||error.code!=="EEXIST"){throw error}}try{const lockStats=await stat(lockPath);if(Date.now()-lockStats.mtimeMs<TELEMETRY_FLUSH_LOCK_STALE_MS){return false}await rm(lockPath,{recursive:true,force:true});await mkdir(lockPath);return true}catch{return false}}function isFreshDirectoryLock(lockPath,staleMs){try{return Date.now()-statSync(lockPath).mtimeMs<staleMs}catch{return false}}function removeDirectoryLockBestEffort(lockPath){try{rmSync(lockPath,{recursive:true,force:true})}catch{}}function errorCode(error){if(typeof error!=="object"||error===null||!("code"in error)){return void 0}const code=error.code;return typeof code==="string"?code:void 0}function createDirectoryLock(lockPath){try{mkdirSync(lockPath);return true}catch(error){const code=errorCode(error);if(code==="EEXIST"){return false}if(!isFileMissingError(error)){return false}}try{mkdirSync(path.dirname(lockPath),{recursive:true});mkdirSync(lockPath);return true}catch{return false}}function acquireTelemetryFlushSpawnGate(globalPmRoot){if(isFreshDirectoryLock(flushLockPath(globalPmRoot),TELEMETRY_FLUSH_LOCK_STALE_MS)){return false}const lockPath=flushSpawnLockPath(globalPmRoot);try{if(Date.now()-statSync(lockPath).mtimeMs<TELEMETRY_FLUSH_SPAWN_LOCK_STALE_MS){return false}removeDirectoryLockBestEffort(lockPath)}catch(error){if(!isFileMissingError(error)){return false}}return createDirectoryLock(lockPath)}function releaseTelemetryFlushSpawnGate(globalPmRoot){removeDirectoryLockBestEffort(flushSpawnLockPath(globalPmRoot))}const _testOnly={acquireTelemetryFlushSpawnGate,acquireTelemetryFlushLock,buildAuthorContextPayloadFields,buildCommandErrorPayload,buildCommandFinishPayload,buildCommandStartPayload,buildOtelSpanRequest,createDirectoryLock,enqueuePendingOtelSpan,enqueueTelemetryEvent,errorCode,flushPendingOtelSpans,flushQueue,flushQueueWithProcessLock,flushTelemetryArtifacts,hashTelemetryErrorFingerprint,hashTelemetryValue,isEmailDomainCharacter,isEmailLocalCharacter,isExpiredPendingOtelSpan,isExpiredQueueEntry,isFreshDirectoryLock,isDueForRetry,isDueForRetryAt,isRetryableQueueRewriteError,looksLikeEmailToken,otelSpansQueuePath,parseBooleanTrueLike,postTelemetryJson,parsePendingOtelSpanLines,prunePendingOtelSpans,reconcilePendingOtelSpansAfterFlush,retentionCutoffMs,resolveOtelTracesEndpoint,resolveTelemetryHttpTimeoutMs,rewritePendingOtelSpans,normalizeForHash,normalizeCaptureLevel,normalizePmVersion,normalizeTelemetryErrorCategory,normalizeTelemetryErrorCode,normalizeTelemetryExitCode,parseQueueLines,pruneExpiredQueueEntries,readRuntimeState,readCurrentQueueEntries,releaseTelemetryFlushSpawnGate,removeFlushedEntriesFromCurrentQueue,removeDirectoryLockBestEffort,resolveTelemetrySourceContext,rewriteQueue,sanitizeCommandArgs,sanitizeStringMax,sanitizeStringRedacted,sanitizeValue,scheduleTelemetryFlush,shouldFlushInline,sleep,summarizeResult,telemetryFlushRunnerPath,withQueueMutation,flushLockPath,flushSpawnLockPath,runtimeStatePath,writeRuntimeState};async function flushQueueWithProcessLock(globalPmRoot,endpoint,retentionDays){const acquired=await acquireTelemetryFlushLock(globalPmRoot);releaseTelemetryFlushSpawnGate(globalPmRoot);if(!acquired){return}try{await flushTelemetryArtifacts(globalPmRoot,endpoint,retentionDays)}finally{try{await rm(flushLockPath(globalPmRoot),{recursive:true,force:true})}catch{}}}function scheduleTelemetryFlush(globalPmRoot,endpoint,retentionDays){if(isConfigurationOnlySettingsRead(globalPmRoot))return;if(shouldFlushInline()){const previousFlush=_lastFlushPromise;const nextFlush=flushTelemetryArtifacts(globalPmRoot,endpoint,retentionDays);_lastFlushPromise=Promise.allSettled([previousFlush,nextFlush]).then(()=>{});return}try{const acquiredSpawnGate=acquireTelemetryFlushSpawnGate(globalPmRoot);if(!acquiredSpawnGate){return}const child=spawn(process.execPath,[telemetryFlushRunnerPath()],{detached:true,stdio:"ignore",cwd:os.tmpdir(),env:{...process.env,PM_GLOBAL_PATH:globalPmRoot,[PM_TELEMETRY_FLUSH_CHILD_ENV]:"1"}});child.on("error",()=>{releaseTelemetryFlushSpawnGate(globalPmRoot)});child.unref()}catch{releaseTelemetryFlushSpawnGate(globalPmRoot)}}async function flushTelemetryQueueNow(globalPmRoot=resolveGlobalPmRoot(process.cwd())){if(resolveTelemetryEnvironmentPolicy().telemetry_disabled){return}try{const settings=await readSettings(globalPmRoot);if(!settings.telemetry.enabled){return}const installation=await withQueueMutation(()=>ensureInstallationId(globalPmRoot),globalPmRoot);if(!installation)return;await flushQueueWithProcessLock(globalPmRoot,installation.endpoint,installation.retentionDays)}catch{}}async function startTelemetryCommand(context){if(resolveTelemetryEnvironmentPolicy().telemetry_disabled){return null}if(context.command==="telemetry"&&context.args.some(token=>token.trim().toLowerCase()==="clear")){return null}try{const globalPmRoot=resolveGlobalPmRoot(process.cwd());const settings=await readSettings(globalPmRoot);if(!settings.telemetry.enabled){return null}const coreReadOwned=context.global.noExtensions===true||isActiveCommandUnextended(context.command);const activeCommand=await withQueueMutation(async()=>{const installation=await ensureInstallationId(globalPmRoot);if(!installation)return null;const{installationId,endpoint,retentionDays,captureLevel}=installation;const pmVersion=normalizePmVersion(context.pm_version);const sourceContext=resolveTelemetrySourceContext(context.global);const pmRootHash=hashWithInstallationId(installationId,context.pm_root);const cwdHash=hashWithInstallationId(installationId,process.cwd());const otelTracesEndpoint=resolveOtelTracesEndpoint();const occurredAt=nowIso();const event={schema_version:TELEMETRY_SCHEMA_VERSION,event_id:crypto.randomUUID(),event_type:"command_start",occurred_at:occurredAt,installation_id:installationId,session_id:PROCESS_SESSION_ID,command:context.command,payload:buildCommandStartPayload({captureLevel,context,pmVersion,sourceContext,pmRootHash,cwdHash,installationId})};const sampleRate=await resolveAutomaticReadSampleRate(globalPmRoot,context.command,coreReadOwned);if(sampleRate===1){await appendTelemetryEvent(globalPmRoot,event)}const commandTaxonomy=deriveTelemetryCommandTaxonomy(context.command);const active={...sampleRate<1?{sample_rate:sampleRate}:{},started_at:occurredAt,started_at_ms:Date.now(),command:context.command,command_taxonomy:commandTaxonomy,pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,installation_id:installationId,pm_root_hash:pmRootHash,cwd_hash:cwdHash,endpoint,retention_days:retentionDays,global_pm_root:globalPmRoot,capture_level:captureLevel,otel_traces_endpoint:otelTracesEndpoint??void 0,otel_trace_id:otelTracesEndpoint?crypto.randomBytes(16).toString("hex"):void 0,otel_span_id:otelTracesEndpoint?crypto.randomBytes(8).toString("hex"):void 0};if(sampleRate<1)deferredReadStarts.set(active,event);return active},globalPmRoot,TELEMETRY_FOREGROUND_LOCK_WAIT_MS);if(activeCommand&&activeCommand.sample_rate===void 0){scheduleTelemetryFlush(globalPmRoot,activeCommand.endpoint,activeCommand.retention_days)}return activeCommand}catch{return null}}async function finishTelemetryCommand(activeCommand,outcome){if(!activeCommand||resolveTelemetryEnvironmentPolicy().telemetry_disabled){return}try{const captured=await withQueueMutation(async()=>{const settings=await readSettings(activeCommand.global_pm_root);if(resolveTelemetryEnvironmentPolicy().telemetry_disabled||!settings.telemetry.enabled||settings.telemetry.installation_id!==activeCommand.installation_id){deferredReadStarts.delete(activeCommand);return false}const deferredStart=deferredReadStarts.get(activeCommand);const sampleRate=outcome.ok?activeCommand.sample_rate??1:1;if(deferredStart){deferredReadStarts.delete(activeCommand);if(crypto.randomBytes(6).readUIntBE(0,6)/2**48>=sampleRate)return false;deferredStart.payload.sample_rate=sampleRate;await appendTelemetryEvent(activeCommand.global_pm_root,deferredStart)}const finishedAt=nowIso();const durationMs=Math.max(0,Date.now()-activeCommand.started_at_ms);const normalizedErrorCode=normalizeTelemetryErrorCode(inferTelemetryErrorCode({ok:outcome.ok,errorCode:outcome.error_code,errorMessage:outcome.error,exitCode:outcome.exit_code}));const normalizedErrorCategory=normalizeTelemetryErrorCategory({ok:outcome.ok,errorCode:normalizedErrorCode,errorCategory:outcome.error_category});const normalizedExitCode=normalizeTelemetryExitCode(outcome.exit_code,outcome.ok);const commandResolution=outcome.command_resolution??deriveTelemetryCommandResolution({ok:outcome.ok,errorCode:normalizedErrorCode,errorCategory:normalizedErrorCategory});const resolutionStage=outcome.resolution_stage??"execute";const event={schema_version:TELEMETRY_SCHEMA_VERSION,event_id:crypto.randomUUID(),event_type:"command_finish",occurred_at:finishedAt,installation_id:activeCommand.installation_id,session_id:PROCESS_SESSION_ID,command:activeCommand.command,payload:{...deferredStart?{sample_rate:sampleRate}:{},...buildCommandFinishPayload({captureLevel:activeCommand.capture_level,pmVersion:activeCommand.pm_version,sourceContext:{source_context:activeCommand.source_context,source_context_source:activeCommand.source_context_source},outcome,durationMs,startedAt:activeCommand.started_at,command:activeCommand.command,installationId:activeCommand.installation_id,commandTaxonomy:activeCommand.command_taxonomy,exitCode:normalizedExitCode,errorCode:normalizedErrorCode,errorCategory:normalizedErrorCategory,commandResolution,resolutionStage})}};await appendTelemetryEvent(activeCommand.global_pm_root,event);const otelRequest=buildOtelSpanRequest(activeCommand,{...outcome,exit_code:normalizedExitCode,error_code:normalizedErrorCode,error_category:normalizedErrorCategory},finishedAt,durationMs,sampleRate);if(otelRequest){await appendPendingOtelSpan(activeCommand.global_pm_root,otelRequest)}return true},activeCommand.global_pm_root,TELEMETRY_FOREGROUND_LOCK_WAIT_MS);if(!captured)return;scheduleTelemetryFlush(activeCommand.global_pm_root,activeCommand.endpoint,activeCommand.retention_days)}catch{}}async function emitTelemetryErrorEvent(context){if(resolveTelemetryEnvironmentPolicy().telemetry_disabled){return}try{const globalPmRoot=resolveGlobalPmRoot(process.cwd());const settings=await readSettings(globalPmRoot);if(!settings.telemetry.enabled){return}const captured=await withQueueMutation(async()=>{const installation=await ensureInstallationId(globalPmRoot);if(!installation)return null;const{installationId,captureLevel}=installation;const pmVersion=normalizePmVersion(context.pm_version);const sourceContext=resolveTelemetrySourceContext(context.global);const pmRootHash=hashWithInstallationId(installationId,context.pm_root);const cwdHash=hashWithInstallationId(installationId,process.cwd());const occurredAt=nowIso();const normalizedErrorCode=normalizeTelemetryErrorCode(inferTelemetryErrorCode({ok:false,errorCode:context.error_code,errorMessage:context.error_message,exitCode:context.exit_code}));const normalizedErrorCategory=context.error_category??resolveTelemetryErrorCategory(normalizedErrorCode);const normalizedExitCode=normalizeTelemetryExitCode(context.exit_code,false);const normalizedCommand=context.command.trim().length>0?context.command:"<unknown>";const commandTaxonomy=deriveTelemetryCommandTaxonomy(normalizedCommand);const commandResolution=context.command_resolution??deriveTelemetryCommandResolution({ok:false,errorCode:normalizedErrorCode,errorCategory:normalizedErrorCategory});const resolutionStage=context.resolution_stage??"unknown";const event={schema_version:TELEMETRY_SCHEMA_VERSION,event_id:crypto.randomUUID(),event_type:"command_error",occurred_at:occurredAt,installation_id:installationId,session_id:PROCESS_SESSION_ID,command:sanitizeString(normalizedCommand,"redacted"),payload:buildCommandErrorPayload({captureLevel,pmVersion,sourceContext,command:normalizedCommand,commandTaxonomy,commandResolution,resolutionStage,args:context.args,options:context.options,pmRootHash,cwdHash,installationId,errorCode:normalizedErrorCode,errorCategory:normalizedErrorCategory,exitCode:normalizedExitCode,errorMessage:context.error_message})};await appendTelemetryEvent(globalPmRoot,event);return installation},globalPmRoot,TELEMETRY_FOREGROUND_LOCK_WAIT_MS);if(captured)scheduleTelemetryFlush(globalPmRoot,captured.endpoint,captured.retentionDays)}catch{}}export{PM_TELEMETRY_SOURCE_CONTEXT_VALUES2 as PM_TELEMETRY_SOURCE_CONTEXT_VALUES,TELEMETRY_MAX_QUEUE_ENTRY_ATTEMPTS,TELEMETRY_SCHEMA_VERSION,_testOnly,emitTelemetryErrorEvent,finishTelemetryCommand,flushTelemetryQueueNow,startTelemetryCommand,waitForPendingFlush,withQueueMutation as withTelemetryQueueMutation};
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="caedc995-da65-59a5-8230-1ac643f0966e")}catch{}})();import crypto from"node:crypto";import{spawn}from"node:child_process";import{mkdirSync,rmSync,statSync}from"node:fs";import{mkdir,readdir,rm,stat}from"node:fs/promises";import{request as httpRequest}from"node:http";import{request as httpsRequest}from"node:https";import os from"node:os";import path from"node:path";import{acquireLock}from"../lock/lock.js";import{isActiveCommandUnextended,runWithIsolatedExtensionRuntime}from"../extensions/index.js";import{resolveAutomaticReadSampleRate}from"./read-sampling.js";import{PM_TELEMETRY_SOURCE_CONTEXT_VALUES,resolveTelemetryEnvironmentPolicy}from"./policy.js";import{resolvePmPackageRootFromModule}from"../packages/root.js";import{isFileMissingError,appendLineAtomic,readFileIfExists,writeFileAtomic}from"../fs/fs-utils.js";import{resolveTelemetryErrorCategory}from"../shared/constants.js";import{nowIso}from"../shared/time.js";import{detectAgentIdentity,readAuthorEnvironment}from"../shared/author.js";import{resolveGlobalPmRoot}from"../store/paths.js";import{isConfigurationOnlySettingsRead,readSettings,writeSettings}from"../store/settings.js";import{clearSettingsReadCache}from"../store/settings-read-cache.js";import{deriveTelemetryCommandResolution,deriveTelemetryCommandTaxonomy,inferTelemetryErrorCode}from"./observability.js";const TELEMETRY_QUEUE_RELATIVE_PATH=path.join("runtime","telemetry","events.jsonl"),TELEMETRY_STATE_RELATIVE_PATH=path.join("runtime","telemetry","state.json"),TELEMETRY_OTEL_SPANS_RELATIVE_PATH=path.join("runtime","telemetry","otel-spans.jsonl"),TELEMETRY_OTEL_SPANS_FLUSH_BATCH_SIZE=8,TELEMETRY_OTEL_SPANS_MAX_PENDING=500,TELEMETRY_SCHEMA_VERSION=1,TELEMETRY_CLIENT_SCHEMA_VERSION=1,TELEMETRY_FLUSH_BATCH_SIZE=100,TELEMETRY_MAX_RETRY_DELAY_MS=36e5,TELEMETRY_RETRY_BASE_DELAY_MS=3e4,TELEMETRY_HTTP_TIMEOUT_DEFAULT_MS=2e4,TELEMETRY_HTTP_TIMEOUT_MIN_MS=1e3,TELEMETRY_HTTP_TIMEOUT_MAX_MS=25e3,TELEMETRY_FOREGROUND_LOCK_WAIT_MS=250,MILLISECONDS_PER_DAY=864e5,TELEMETRY_MAX_EVENT_BYTES=65536,TELEMETRY_SANITIZE_MAX_DEPTH=6,TELEMETRY_SANITIZE_MAX_ARRAY_ITEMS=20,TELEMETRY_MAX_QUEUE_ENTRY_ATTEMPTS=15,TELEMETRY_RESULT_PREVIEW_MAX_BYTES=8192,TELEMETRY_QUEUE_REWRITE_RETRY_DELAYS_MS=[25,50,100,200],TELEMETRY_QUEUE_TMP_ORPHAN_MAX_AGE_MS=3600*1e3,TELEMETRY_FLUSH_LOCK_STALE_MS=6e4,TELEMETRY_FLUSH_SPAWN_LOCK_STALE_MS=6e4,OTEL_TRACES_ENDPOINT_ENV="OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",OTEL_BASE_ENDPOINT_ENV="OTEL_EXPORTER_OTLP_ENDPOINT",OTEL_SERVICE_NAME_ENV="OTEL_SERVICE_NAME",PM_TELEMETRY_OTEL_DISABLED_ENV="PM_TELEMETRY_OTEL_DISABLED",PM_TELEMETRY_OTEL_DISABLED_VALUES=new Set(["1","true","yes","on"]),PM_TELEMETRY_INLINE_FLUSH_ENV="PM_TELEMETRY_INLINE_FLUSH",PM_TELEMETRY_FLUSH_CHILD_ENV="PM_TELEMETRY_FLUSH_CHILD",PM_TELEMETRY_SOURCE_CONTEXT_ENV="PM_TELEMETRY_SOURCE_CONTEXT",PM_TELEMETRY_HTTP_TIMEOUT_MS_ENV="PM_TELEMETRY_HTTP_TIMEOUT_MS",NATIVE_FETCH=globalThis.fetch;import{PM_TELEMETRY_SOURCE_CONTEXT_VALUES as PM_TELEMETRY_SOURCE_CONTEXT_VALUES2}from"./policy.js";let sourceContextWarningEmitted=!1,_lastFlushPromise=Promise.resolve(),_queueMutationPromise=Promise.resolve();const deferredReadStarts=new WeakMap;async function waitForPendingFlush(){await _lastFlushPromise,await _queueMutationPromise}const PM_TELEMETRY_SOURCE_CONTEXT_SET=new Set(PM_TELEMETRY_SOURCE_CONTEXT_VALUES),BOOLEAN_TRUE_VALUES=new Set(["1","true","yes","on"]),TELEMETRY_HARNESSES=new Set(["claude-code","codex","pi","opencode","cursor","aider","gemini-cli","ci"]),PROCESS_SESSION_ID=crypto.randomUUID(),SENSITIVE_KEYWORDS=["token","secret","password","passwd","api_key","apikey","authorization","cookie","session","credentials","bearer"],REDACTION_INPUT_KEYS=new Set(["literal","literals","regex","regexes","replacement","replacements"]),SENSITIVE_INLINE_KEY_PATTERN="(?:token|secret|password|passwd|api[_-]?key|apikey|authorization|cookie|session|credentials|bearer|literals?|regex(?:es)?|replacements?)",INLINE_SENSITIVE_ASSIGNMENT_PATTERN=new RegExp(`\\b(${SENSITIVE_INLINE_KEY_PATTERN})\\s*([:=])\\s*([^\\s,;]+)`,"giu"),INLINE_SENSITIVE_FLAG_PATTERN=new RegExp(`(--${SENSITIVE_INLINE_KEY_PATTERN})(=|\\s+)([^\\s,;]+)`,"giu"),ABSOLUTE_PATH_TOKEN_PATTERN=/(^|[\s"'`(=])\/(?:[^\s"'`),;]+)/g,BEARER_TOKEN_PATTERN=/bearer\s+[a-z0-9._=-]+/giu,PRIVATE_IP_PATTERN=/\b(?:10\.(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.(?:25[0-5]|2[0-4]\d|[01]?\d?\d)|172\.(?:1[6-9]|2\d|3[01])\.(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.(?:25[0-5]|2[0-4]\d|[01]?\d?\d)|192\.168\.(?:25[0-5]|2[0-4]\d|[01]?\d?\d)\.(?:25[0-5]|2[0-4]\d|[01]?\d?\d))\b/g;function queuePath(globalPmRoot){return path.join(globalPmRoot,TELEMETRY_QUEUE_RELATIVE_PATH)}function otelSpansQueuePath(globalPmRoot){return path.join(globalPmRoot,TELEMETRY_OTEL_SPANS_RELATIVE_PATH)}function telemetryRuntimeDirectory(globalPmRoot){return path.dirname(queuePath(globalPmRoot))}function runtimeStatePath(globalPmRoot){return path.join(globalPmRoot,TELEMETRY_STATE_RELATIVE_PATH)}function flushLockPath(globalPmRoot){return path.join(globalPmRoot,"runtime","telemetry","flush.lock")}function flushSpawnLockPath(globalPmRoot){return path.join(globalPmRoot,"runtime","telemetry","flush.spawn.lock")}function telemetryFlushRunnerPath(){return path.join(resolvePmPackageRootFromModule(import.meta.url,["../../.."]),"dist","cli","telemetry-flush.js")}function shouldFlushInline(){if(parseBooleanTrueLike(process.env[PM_TELEMETRY_INLINE_FLUSH_ENV])||parseBooleanTrueLike(process.env[PM_TELEMETRY_FLUSH_CHILD_ENV]))return!0;const nodeEnv=(process.env.NODE_ENV??"").trim().toLowerCase();return typeof process.env.VITEST=="string"||typeof process.env.VITEST_WORKER_ID=="string"||nodeEnv==="test"}async function readRuntimeState(globalPmRoot){const raw=await readFileIfExists(runtimeStatePath(globalPmRoot));if(!raw||raw.trim().length===0)return{};try{const parsed=JSON.parse(raw);return typeof parsed!="object"||parsed===null||Array.isArray(parsed)?{}:parsed}catch{return{}}}async function writeRuntimeState(globalPmRoot,patch){try{await withQueueMutation(async()=>{const next={...await readRuntimeState(globalPmRoot),...patch},normalized=Object.fromEntries(Object.entries(next).filter(([,value])=>value!==void 0).sort((left,right)=>left[0].localeCompare(right[0])));await writeFileAtomic(runtimeStatePath(globalPmRoot),`${JSON.stringify(normalized,null,2)}
|
|
2
|
+
`)},globalPmRoot)}catch{}}function isSensitiveKey(key){const normalized=key.trim().toLowerCase().replaceAll("-","_").replaceAll(/[^a-z0-9_]+/g,"_"),tokens=normalized.split("_").filter(token=>token.length>0);return REDACTION_INPUT_KEYS.has(normalized)||SENSITIVE_KEYWORDS.some(keyword=>normalized===keyword||normalized.endsWith(`_${keyword}`)||tokens.includes(keyword))}function redactInlineSensitiveAssignments(input){return input.replaceAll(INLINE_SENSITIVE_ASSIGNMENT_PATTERN,(_match,key,delimiter)=>`${key}${delimiter}[redacted]`).replaceAll(INLINE_SENSITIVE_FLAG_PATTERN,(_match,flag,delimiter)=>`${flag}${delimiter}[redacted]`)}function redactAbsolutePathTokens(input){return input.replaceAll(ABSOLUTE_PATH_TOKEN_PATTERN,(_match,prefix)=>`${prefix}[redacted_path]`)}function isAsciiLetterOrDigitCode(code){const isUpper=code>=65&&code<=90,isLower=code>=97&&code<=122,isDigit=code>=48&&code<=57;return isUpper||isLower||isDigit}function isEmailLocalCharacter(character){if(!character)return!1;const code=character.charCodeAt(0);return isAsciiLetterOrDigitCode(code)?!0:character==="."||character==="_"||character==="%"||character==="+"||character==="-"}function isEmailDomainCharacter(character){if(!character)return!1;const code=character.charCodeAt(0);return isAsciiLetterOrDigitCode(code)?!0:character==="."||character==="-"}function looksLikeEmailToken(token){const atIndex=token.indexOf("@");if(atIndex<=0||atIndex!==token.lastIndexOf("@")||atIndex===token.length-1)return!1;const localPart=token.slice(0,atIndex),domainPart=token.slice(atIndex+1),lastDot=domainPart.lastIndexOf(".");if(lastDot<=0||lastDot===domainPart.length-1||domainPart.length-(lastDot+1)<2)return!1;for(const character of localPart)if(!isEmailLocalCharacter(character))return!1;for(const character of domainPart)if(!isEmailDomainCharacter(character))return!1;return!0}function redactEmailTokens(input){let redacted="",cursor=0;for(;cursor<input.length;){const atIndex=input.indexOf("@",cursor);if(atIndex<0){redacted+=input.slice(cursor);break}let start=atIndex-1;for(;start>=cursor&&isEmailLocalCharacter(input[start]);)start-=1;start+=1;let end=atIndex+1;for(;end<input.length&&isEmailDomainCharacter(input[end]);)end+=1;const candidate=input.slice(start,end);if(looksLikeEmailToken(candidate)){redacted+=input.slice(cursor,start),redacted+="[redacted_email]",cursor=end;continue}redacted+=input.slice(cursor,atIndex+1),cursor=atIndex+1}return redacted}function sanitizeCommonSensitiveTokens(input){return redactEmailTokens(input).replaceAll(BEARER_TOKEN_PATTERN,"bearer [redacted_token]").replaceAll(PRIVATE_IP_PATTERN,"[redacted_ip]")}function sanitizeStringRedacted(input){const withoutCommonSensitiveTokens=sanitizeCommonSensitiveTokens(input),withoutInlineSecrets=redactInlineSensitiveAssignments(withoutCommonSensitiveTokens),withoutAbsolutePaths=redactAbsolutePathTokens(withoutInlineSecrets),trimmed=withoutAbsolutePaths.trim();return trimmed.startsWith("/")&&trimmed.length>1?"[redacted_path]":withoutAbsolutePaths.length>512?`${withoutAbsolutePaths.slice(0,509)}...`:withoutAbsolutePaths}function sanitizeStringMax(input){const withoutCommonSensitiveTokens=sanitizeCommonSensitiveTokens(input),withoutInlineSecrets=redactInlineSensitiveAssignments(withoutCommonSensitiveTokens),withoutAbsolutePaths=redactAbsolutePathTokens(withoutInlineSecrets),trimmed=withoutAbsolutePaths.trim();return trimmed.startsWith("/")&&trimmed.length>1?"[redacted_path]":withoutAbsolutePaths.length>2048?`${withoutAbsolutePaths.slice(0,2045)}...`:withoutAbsolutePaths}function sanitizeString(input,captureLevel="redacted"){return captureLevel==="max"?sanitizeStringMax(input):sanitizeStringRedacted(input)}function sanitizeValue(value,keyHint,captureLevel="redacted",depth=0){if(keyHint&&isSensitiveKey(keyHint))return"[redacted]";if(value==null)return value;if(typeof value=="string")return sanitizeString(value,captureLevel);if(typeof value=="number"||typeof value=="boolean")return value;if(depth>=TELEMETRY_SANITIZE_MAX_DEPTH)return"[depth_truncated]";if(Array.isArray(value))return value.slice(0,TELEMETRY_SANITIZE_MAX_ARRAY_ITEMS).map(entry=>sanitizeValue(entry,void 0,captureLevel,depth+1));if(typeof value=="object"){const record=value,sanitized={};for(const[key,nested]of Object.entries(record))sanitized[key]=sanitizeValue(nested,key,captureLevel,depth+1);return sanitized}return String(value)}function sanitizeCommandArgs(args,captureLevel="redacted"){const sanitized=[];let nextIsSensitiveValue=!1;for(const rawArg of args){const arg=sanitizeString(rawArg,captureLevel);if(nextIsSensitiveValue){sanitized.push("[redacted]"),nextIsSensitiveValue=!1;continue}if(arg.startsWith("--")){const withoutPrefix=arg.slice(2),delimiterIndex=withoutPrefix.indexOf("=");if(delimiterIndex>=0){const key=withoutPrefix.slice(0,delimiterIndex),value=withoutPrefix.slice(delimiterIndex+1);isSensitiveKey(key)?sanitized.push(`--${key}=[redacted]`):sanitized.push(`--${key}=${sanitizeString(value,captureLevel)}`);continue}if(isSensitiveKey(withoutPrefix)){sanitized.push(`--${withoutPrefix}`),nextIsSensitiveValue=!0;continue}}sanitized.push(arg)}return sanitized}function normalizeCaptureLevel(value){const normalized=value?.trim().toLowerCase();return normalized==="minimal"||normalized==="redacted"||normalized==="max"?normalized:"redacted"}function parseBooleanTrueLike(value){return BOOLEAN_TRUE_VALUES.has((value??"").trim().toLowerCase())}function resolveTelemetryHttpTimeoutMs(){const rawConfigured=process.env[PM_TELEMETRY_HTTP_TIMEOUT_MS_ENV]?.trim();if(!rawConfigured)return TELEMETRY_HTTP_TIMEOUT_DEFAULT_MS;const configured=Number(rawConfigured);return Number.isFinite(configured)?Math.min(TELEMETRY_HTTP_TIMEOUT_MAX_MS,Math.max(TELEMETRY_HTTP_TIMEOUT_MIN_MS,Math.trunc(configured))):TELEMETRY_HTTP_TIMEOUT_DEFAULT_MS}async function postTelemetryJson(endpoint,headers,body){const url=new URL(endpoint);if(globalThis.fetch!==NATIVE_FETCH){const controller=new AbortController;let timeout;const deadline=new Promise((_resolve,reject)=>{timeout=setTimeout(()=>{controller.abort(),reject(new Error("telemetry_http_timeout"))},resolveTelemetryHttpTimeoutMs())});try{return(await Promise.race([globalThis.fetch(endpoint,{method:"POST",headers,body,signal:controller.signal}),deadline])).status}finally{clearTimeout(timeout)}}const request=url.protocol==="https:"?httpsRequest:url.protocol==="http:"?httpRequest:void 0;if(!request)throw new Error(`telemetry_http_protocol_unsupported_${url.protocol}`);return new Promise((resolve,reject)=>{const timeoutMs=resolveTelemetryHttpTimeoutMs(),requestOptions={method:"POST",headers:{...headers,"content-length":Buffer.byteLength(body)},signal:AbortSignal.timeout(timeoutMs),autoSelectFamilyAttemptTimeout:Math.min(5e3,timeoutMs)},clientRequest=request(url,requestOptions,response=>{response.once("error",reject),response.once("end",()=>resolve(response.statusCode)),response.resume()});clientRequest.once("error",reject),clientRequest.end(body)})}function normalizePmVersion(value){const trimmed=typeof value=="string"?value.trim():"";return trimmed.length>0?trimmed:"0.0.0"}function normalizeTelemetryErrorCode(value){const normalized=value?.trim();return normalized&&normalized.length>0?normalized:void 0}function normalizeTelemetryExitCode(exitCode,ok){return Number.isFinite(exitCode)?Math.max(0,Math.trunc(exitCode)):ok?0:1}function normalizeTelemetryErrorCategory(params){if(!params.ok)return typeof params.errorCategory=="string"&¶ms.errorCategory.trim().length>0?params.errorCategory:typeof params.errorCode=="string"&¶ms.errorCode.trim().length>0?resolveTelemetryErrorCategory(params.errorCode):"unknown"}function resolveTelemetrySourceContext(globalOptions){const override=(process.env[PM_TELEMETRY_SOURCE_CONTEXT_ENV]??"").trim().toLowerCase();if(PM_TELEMETRY_SOURCE_CONTEXT_SET.has(override))return{source_context:override,source_context_source:"env_override"};const source=override.length>0?"env_override_rejected":"inferred";return source==="env_override_rejected"&&!sourceContextWarningEmitted&&!globalOptions.quiet&&(sourceContextWarningEmitted=!0,process.stderr.write(`[pm] warning: PM_TELEMETRY_SOURCE_CONTEXT is not one of ${PM_TELEMETRY_SOURCE_CONTEXT_VALUES.join("|")}; ignoring override.
|
|
3
|
+
`)),{source_context:inferTelemetrySourceContext(globalOptions),source_context_source:source}}function inferTelemetrySourceContext(globalOptions){const nodeEnv=(process.env.NODE_ENV??"").trim().toLowerCase();if(typeof process.env.VITEST=="string"||typeof process.env.VITEST_WORKER_ID=="string"||nodeEnv==="test")return"test";const nonTty=process.stdin.isTTY!==!0||process.stdout.isTTY!==!0,ci=parseBooleanTrueLike(process.env.CI),scriptLikeMode=globalOptions.json===!0||globalOptions.quiet===!0;return nonTty||ci||scriptLikeMode?"automation":"user"}function hashWithInstallationId(installationId,value){return crypto.createHash("sha256").update(`${installationId}:${value}`).digest("hex")}function buildAuthorContextPayloadFields(captureLevel,installationId){const author=(readAuthorEnvironment()??"").trim(),agent=detectAgentIdentity({env:process.env,argv:process.argv}),hasAgentContext=agent.harness!==void 0||agent.model!==void 0;return captureLevel==="minimal"?{has_author_context:author.length>0,has_agent_context:hasAgentContext}:{agent_harness:agent.harness?TELEMETRY_HARNESSES.has(agent.harness)?agent.harness:"other":"none",ci:parseBooleanTrueLike(process.env.CI),...author.length>0?{author_context_hash:hashWithInstallationId(installationId,author)}:{},...agent.harness?{agent_harness_hash:hashWithInstallationId(installationId,agent.harness)}:{},...agent.model?{agent_model_hash:hashWithInstallationId(installationId,agent.model)}:{},...agent.model_source?{agent_model_source:agent.model_source}:{}}}function normalizeForHash(value,depth=0){if(value==null||typeof value=="string"||typeof value=="number"||typeof value=="boolean")return value;if(depth>=TELEMETRY_SANITIZE_MAX_DEPTH)return"[depth_truncated]";if(Array.isArray(value))return value.slice(0,TELEMETRY_SANITIZE_MAX_ARRAY_ITEMS).map(entry=>normalizeForHash(entry,depth+1));if(typeof value=="object"){const record=value,normalized={},sortedKeys=Object.keys(record).sort((left,right)=>left.localeCompare(right));for(const key of sortedKeys)normalized[key]=normalizeForHash(record[key],depth+1);return normalized}return String(value)}function hashTelemetryValue(installationId,value){return hashWithInstallationId(installationId,JSON.stringify(normalizeForHash(value)))}function hashCommandArgs(installationId,args){return{hashes:args.map(arg=>hashWithInstallationId(installationId,arg)),digest:hashWithInstallationId(installationId,args.join("\0"))}}function hashTelemetryErrorFingerprint(installationId,command,errorCode2,errorMessage){const normalizedMessage=sanitizeString(typeof errorMessage=="string"?errorMessage:"","redacted"),normalizedCode=typeof errorCode2=="string"&&errorCode2.length>0?errorCode2:"unknown_error",fingerprintSource=`${command}\0${normalizedCode}\0${normalizedMessage}`;return hashWithInstallationId(installationId,fingerprintSource)}function resolveOtelTracesEndpoint(){if(PM_TELEMETRY_OTEL_DISABLED_VALUES.has((process.env[PM_TELEMETRY_OTEL_DISABLED_ENV]??"").trim().toLowerCase()))return null;const directEndpoint=(process.env[OTEL_TRACES_ENDPOINT_ENV]??"").trim();if(directEndpoint.length>0)try{return new URL(directEndpoint).toString()}catch{return null}const baseEndpoint=(process.env[OTEL_BASE_ENDPOINT_ENV]??"").trim();if(baseEndpoint.length===0)return null;try{const url=new URL(baseEndpoint),normalizedPath=url.pathname.replace(/\/+$/,"");return normalizedPath.endsWith("/v1/traces")||(url.pathname=`${normalizedPath.length===0?"":normalizedPath}/v1/traces`),url.toString()}catch{return null}}function isoToUnixNano(iso){const parsedMs=Date.parse(iso),epochMs=Number.isNaN(parsedMs)?Date.now():parsedMs;return`${BigInt(epochMs)*1000000n}`}function otlpStringAttribute(key,value){return{key,value:{stringValue:value}}}function otlpBoolAttribute(key,value){return{key,value:{boolValue:value}}}function otlpIntAttribute(key,value){return{key,value:{intValue:String(Math.max(0,Math.trunc(value)))}}}function buildOtelSpanRequest(activeCommand,outcome,finishedAtIso,durationMs,sampleRate=1){const endpoint=activeCommand.otel_traces_endpoint;if(typeof endpoint!="string"||endpoint.trim().length===0||[activeCommand.otel_trace_id,activeCommand.otel_span_id].some(id=>typeof id!="string"||id.length===0))return null;const serviceNameCandidate=sanitizeString((process.env[OTEL_SERVICE_NAME_ENV]??"").trim()),serviceName=serviceNameCandidate.length>0?serviceNameCandidate:"pm-cli",normalizedExitCode=normalizeTelemetryExitCode(outcome.exit_code,outcome.ok),normalizedErrorCode=normalizeTelemetryErrorCode(outcome.error_code),normalizedErrorCategory=normalizeTelemetryErrorCategory({ok:outcome.ok,errorCode:normalizedErrorCode,errorCategory:outcome.error_category}),attributes=[otlpStringAttribute("pm.command",sanitizeString(activeCommand.command)),otlpStringAttribute("pm.version",activeCommand.pm_version),otlpStringAttribute("pm.source_context",activeCommand.source_context),otlpStringAttribute("pm.source_context_source",activeCommand.source_context_source),otlpStringAttribute("pm.installation_id",activeCommand.installation_id),otlpStringAttribute("pm.session_id",PROCESS_SESSION_ID),otlpStringAttribute("pm.pm_root_hash",activeCommand.pm_root_hash),otlpStringAttribute("pm.cwd_hash",activeCommand.cwd_hash),otlpBoolAttribute("pm.ok",outcome.ok),otlpIntAttribute("pm.exit_code",normalizedExitCode),otlpIntAttribute("pm.duration_ms",durationMs),otlpStringAttribute("pm.sample_rate",String(sampleRate))];typeof normalizedErrorCode=="string"&&attributes.push(otlpStringAttribute("pm.error_code",normalizedErrorCode)),typeof normalizedErrorCategory=="string"&&attributes.push(otlpStringAttribute("pm.error_category",normalizedErrorCategory)),typeof outcome.error=="string"&&outcome.error.trim().length>0&&attributes.push(otlpStringAttribute("pm.error",sanitizeString(outcome.error)));const payload={resourceSpans:[{resource:{attributes:[otlpStringAttribute("service.name",serviceName)]},scopeSpans:[{scope:{name:"pm-cli.telemetry",version:"1"},spans:[{traceId:activeCommand.otel_trace_id,spanId:activeCommand.otel_span_id,name:`pm.command.${sanitizeString(activeCommand.command)}`,kind:1,startTimeUnixNano:isoToUnixNano(activeCommand.started_at),endTimeUnixNano:isoToUnixNano(finishedAtIso),attributes,status:{code:outcome.ok?1:2,message:outcome.ok?"":sanitizeString(typeof outcome.error=="string"?outcome.error:"command_failed")}}]}]}]};return{endpoint,payload}}function summarizeResult(result,captureLevel="redacted"){if(result==null)return{type:"nullish"};if(typeof result=="string")return{type:"string",value:sanitizeString(result,captureLevel)};if(typeof result=="number"||typeof result=="boolean")return{type:typeof result,value:result};if(Array.isArray(result))return{type:"array",length:result.length,sample:result.slice(0,5).map(entry=>sanitizeValue(entry,void 0,captureLevel))};if(typeof result=="object"){const record=result,keys=Object.keys(record).sort((left,right)=>left.localeCompare(right)),sanitized={};let previewBytes=0;for(const key of keys.slice(0,25)){const sanitizedValue=sanitizeValue(record[key],key,captureLevel);if(sanitizedValue===void 0)continue;const entrySize=JSON.stringify(sanitizedValue).length;if(previewBytes+entrySize>TELEMETRY_RESULT_PREVIEW_MAX_BYTES){sanitized[key]="[preview_truncated]";break}previewBytes+=entrySize,sanitized[key]=sanitizedValue}return{type:"object",key_count:keys.length,keys_preview:keys.slice(0,50),preview:sanitized}}return{type:typeof result,value:String(result)}}function buildCommandStartPayload(params){const{captureLevel,context,pmVersion,sourceContext,pmRootHash,cwdHash,installationId}=params,commandTaxonomy=deriveTelemetryCommandTaxonomy(context.command),hashedArgs=hashCommandArgs(installationId,context.args),commandInvocationDigest=hashWithInstallationId(installationId,`${context.command}\0${context.args.join("\0")}`),commandOptionsDigest=hashTelemetryValue(installationId,context.options),globalOptionsDigest=hashTelemetryValue(installationId,context.global),authorContextFields=buildAuthorContextPayloadFields(captureLevel,installationId);return captureLevel==="minimal"?{capture_level:captureLevel,pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,command_taxonomy:commandTaxonomy,command_args_digest:hashedArgs.digest,command_invocation_digest:commandInvocationDigest,command_options_digest:commandOptionsDigest,global_options_digest:globalOptionsDigest,...authorContextFields}:{pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,command_taxonomy:commandTaxonomy,...authorContextFields,command_args:sanitizeCommandArgs(context.args,captureLevel),command_args_hashes:hashedArgs.hashes,command_args_digest:hashedArgs.digest,command_invocation_digest:commandInvocationDigest,command_options:sanitizeValue(context.options,void 0,captureLevel),command_options_digest:commandOptionsDigest,global_options:sanitizeValue(context.global,void 0,captureLevel),global_options_digest:globalOptionsDigest,pm_root_hash:pmRootHash,cwd_hash:cwdHash,capture_level:captureLevel,runtime:{node:process.version,platform:process.platform,arch:process.arch,hostname_hash:hashWithInstallationId(installationId,os.hostname()),stdin_tty:process.stdin.isTTY===!0,stdout_tty:process.stdout.isTTY===!0}}}function buildCommandFinishPayload(params){const{captureLevel,pmVersion,sourceContext,outcome,durationMs,startedAt,command,installationId,commandTaxonomy,exitCode,errorCode:errorCode2,errorCategory,commandResolution,resolutionStage}=params,errorFingerprint=outcome.ok===!1?hashTelemetryErrorFingerprint(installationId,command,errorCode2,outcome.error):void 0,authorContextFields=buildAuthorContextPayloadFields(captureLevel,installationId);return captureLevel==="minimal"?{capture_level:captureLevel,pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,command_taxonomy:commandTaxonomy,command_resolution:commandResolution,resolution_stage:resolutionStage,ok:outcome.ok,exit_code:exitCode,error_code:errorCode2,error_category:errorCategory,error:outcome.error?sanitizeString(outcome.error,"redacted"):void 0,error_fingerprint:errorFingerprint,duration_ms:durationMs,...authorContextFields}:{capture_level:captureLevel,pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,command_taxonomy:commandTaxonomy,command_resolution:commandResolution,resolution_stage:resolutionStage,...authorContextFields,ok:outcome.ok,exit_code:exitCode,error_code:errorCode2,error_category:errorCategory,error:outcome.error?sanitizeString(outcome.error,captureLevel):void 0,error_fingerprint:errorFingerprint,duration_ms:durationMs,started_at:startedAt,result_summary:summarizeResult(outcome.result,captureLevel)}}function buildCommandErrorPayload(params){const{captureLevel,pmVersion,sourceContext,command,commandTaxonomy,commandResolution,resolutionStage,args,options,pmRootHash,cwdHash,installationId,errorCode:errorCode2,errorMessage,errorCategory,exitCode}=params,attemptedArgHashes=hashCommandArgs(installationId,args),attemptedCommandDigest=hashWithInstallationId(installationId,command),attemptedOptionsDigest=hashTelemetryValue(installationId,options),errorFingerprint=hashTelemetryErrorFingerprint(installationId,command,errorCode2,errorMessage),authorContextFields=buildAuthorContextPayloadFields(captureLevel,installationId);return captureLevel==="minimal"?{capture_level:captureLevel,pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,command_taxonomy:commandTaxonomy,command_resolution:commandResolution,resolution_stage:resolutionStage,attempted_command_digest:attemptedCommandDigest,attempted_args_digest:attemptedArgHashes.digest,attempted_options_digest:attemptedOptionsDigest,error_code:errorCode2,error_category:errorCategory,exit_code:exitCode,error:sanitizeString(errorMessage,"redacted"),error_fingerprint:errorFingerprint,...authorContextFields}:{capture_level:captureLevel,pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,command_taxonomy:commandTaxonomy,command_resolution:commandResolution,resolution_stage:resolutionStage,...authorContextFields,attempted_command:sanitizeString(command,captureLevel),attempted_command_digest:attemptedCommandDigest,attempted_args:sanitizeCommandArgs(args,captureLevel),attempted_args_hashes:attemptedArgHashes.hashes,attempted_args_digest:attemptedArgHashes.digest,attempted_options:sanitizeValue(options,void 0,captureLevel),attempted_options_digest:attemptedOptionsDigest,error_code:errorCode2,error_category:errorCategory,exit_code:exitCode,error:sanitizeString(errorMessage,captureLevel),error_fingerprint:errorFingerprint,pm_root_hash:pmRootHash,cwd_hash:cwdHash,runtime:{node:process.version,platform:process.platform,arch:process.arch,hostname_hash:hashWithInstallationId(installationId,os.hostname()),stdin_tty:process.stdin.isTTY===!0,stdout_tty:process.stdout.isTTY===!0}}}async function ensureInstallationId(globalPmRoot){const settings=await readSettings(globalPmRoot);if(!settings.telemetry.enabled||resolveTelemetryEnvironmentPolicy().telemetry_disabled)return null;if(settings.telemetry.installation_id.trim().length===0){if(isConfigurationOnlySettingsRead(globalPmRoot))return null;settings.telemetry.installation_id=crypto.randomUUID(),await writeSettings(globalPmRoot,settings,"telemetry:install_id")}return{installationId:settings.telemetry.installation_id,endpoint:settings.telemetry.endpoint,retentionDays:Math.max(1,Math.trunc(settings.telemetry.retention_days)),captureLevel:normalizeCaptureLevel(settings.telemetry.capture_level)}}async function appendTelemetryEvent(globalPmRoot,event){let serialized=JSON.stringify({client_schema_version:TELEMETRY_CLIENT_SCHEMA_VERSION,event,attempts:0});if(serialized.length>TELEMETRY_MAX_EVENT_BYTES){const trimmed={...event,payload:{...event.payload,result_summary:{truncated:!0,reason:"payload_size_exceeded",original_bytes:serialized.length}}};serialized=JSON.stringify({client_schema_version:TELEMETRY_CLIENT_SCHEMA_VERSION,event:trimmed,attempts:0})}await appendLineAtomic(queuePath(globalPmRoot),serialized)}async function enqueueTelemetryEvent(globalPmRoot,event){await withQueueMutation(()=>appendTelemetryEvent(globalPmRoot,event),globalPmRoot)}function parseQueueLines(raw){const entries=[];for(const line of raw.split(`
|
|
4
|
+
`)){const trimmed=line.trim();if(trimmed.length!==0)try{const parsed=JSON.parse(trimmed);parsed&&typeof parsed=="object"&&parsed.event&&typeof parsed.event=="object"&&typeof parsed.attempts=="number"&&(parsed.client_schema_version===void 0||typeof parsed.client_schema_version=="number"&&Number.isFinite(parsed.client_schema_version))&&entries.push(parsed)}catch{}}return entries}function nextRetryIso(attempts){const delay=Math.min(TELEMETRY_RETRY_BASE_DELAY_MS*2**Math.max(attempts-1,0),TELEMETRY_MAX_RETRY_DELAY_MS);return new Date(Date.now()+delay).toISOString()}function isDueForRetryAt(nextAttemptAfter){if(typeof nextAttemptAfter!="string"||nextAttemptAfter.trim().length===0)return!0;const dueAtMs=Date.parse(nextAttemptAfter);return Number.isNaN(dueAtMs)?!0:dueAtMs<=Date.now()}function isDueForRetry(entry){return isDueForRetryAt(entry.next_attempt_after)}function retentionCutoffMs(retentionDays){const normalizedDays=Number.isFinite(retentionDays)?Math.max(1,Math.trunc(retentionDays)):1;return Date.now()-normalizedDays*MILLISECONDS_PER_DAY}function isExpiredQueueEntry(entry,cutoffMs){const occurredAt=entry.event?.occurred_at;if(typeof occurredAt!="string"||occurredAt.trim().length===0)return!1;const occurredAtMs=Date.parse(occurredAt);return Number.isNaN(occurredAtMs)?!1:occurredAtMs<cutoffMs}function pruneExpiredQueueEntries(entries,retentionDays){const cutoffMs=retentionCutoffMs(retentionDays),retained=[];let prunedCount=0;for(const entry of entries){if(JSON.stringify(entry).length>TELEMETRY_MAX_EVENT_BYTES||isExpiredQueueEntry(entry,cutoffMs)||entry.attempts>=TELEMETRY_MAX_QUEUE_ENTRY_ATTEMPTS){prunedCount+=1;continue}retained.push(entry)}return{entries:retained,prunedCount}}async function rewriteQueue(globalPmRoot,entries){const serialized=entries.map(entry=>JSON.stringify(entry)).join(`
|
|
5
|
+
`),contents=serialized.length>0?`${serialized}
|
|
6
|
+
`:"";for(let attempt=0;;attempt+=1)try{await writeFileAtomic(queuePath(globalPmRoot),contents);return}catch(error){const retryDelay=TELEMETRY_QUEUE_REWRITE_RETRY_DELAYS_MS[attempt];if(retryDelay===void 0||!isRetryableQueueRewriteError(error))throw error;await sleep(retryDelay)}}function isRetryableQueueRewriteError(error){if(typeof error!="object"||error===null||!("code"in error))return!1;const code=error.code;return code==="EACCES"||code==="EBUSY"||code==="EPERM"}function sleep(milliseconds){return new Promise(resolve=>{setTimeout(resolve,milliseconds)})}async function appendPendingOtelSpan(globalPmRoot,request){const pending={id:crypto.randomUUID(),endpoint:request.endpoint,payload:request.payload,enqueued_at:nowIso(),attempts:0},serialized=JSON.stringify(pending);serialized.length>TELEMETRY_MAX_EVENT_BYTES||await appendLineAtomic(otelSpansQueuePath(globalPmRoot),serialized)}async function enqueuePendingOtelSpan(globalPmRoot,request){await withQueueMutation(()=>appendPendingOtelSpan(globalPmRoot,request),globalPmRoot)}function backfillPendingOtelSpanId(entry){const material=JSON.stringify([entry.endpoint,entry.enqueued_at,entry.payload]);return crypto.createHash("sha256").update(material).digest("hex").slice(0,32)}function parsePendingOtelSpanLines(raw){const entries=[];for(const line of raw.split(`
|
|
7
|
+
`)){const trimmed=line.trim();if(trimmed.length!==0)try{const parsed=JSON.parse(trimmed);parsed&&typeof parsed=="object"&&typeof parsed.endpoint=="string"&&parsed.endpoint.trim().length>0&&"payload"in parsed&&typeof parsed.attempts=="number"&&Number.isFinite(parsed.attempts)&&((typeof parsed.id!="string"||parsed.id.length===0)&&(parsed.id=backfillPendingOtelSpanId(parsed)),entries.push(parsed))}catch{}}return entries}function isExpiredPendingOtelSpan(entry,cutoffMs){if(typeof entry.enqueued_at!="string"||entry.enqueued_at.trim().length===0)return!1;const enqueuedAtMs=Date.parse(entry.enqueued_at);return Number.isNaN(enqueuedAtMs)?!1:enqueuedAtMs<cutoffMs}function prunePendingOtelSpans(entries,retentionDays){const cutoffMs=retentionCutoffMs(retentionDays),retained=[];let prunedCount=0;for(const entry of entries){if(JSON.stringify(entry).length>TELEMETRY_MAX_EVENT_BYTES||isExpiredPendingOtelSpan(entry,cutoffMs)||entry.attempts>=TELEMETRY_MAX_QUEUE_ENTRY_ATTEMPTS){prunedCount+=1;continue}retained.push(entry)}if(retained.length>TELEMETRY_OTEL_SPANS_MAX_PENDING){const overflow=retained.length-TELEMETRY_OTEL_SPANS_MAX_PENDING;return prunedCount+=overflow,{entries:retained.slice(overflow),prunedCount}}return{entries:retained,prunedCount}}async function rewritePendingOtelSpans(globalPmRoot,entries){const serialized=entries.map(entry=>JSON.stringify(entry)).join(`
|
|
8
|
+
`),contents=serialized.length>0?`${serialized}
|
|
9
|
+
`:"";for(let attempt=0;;attempt+=1)try{await writeFileAtomic(otelSpansQueuePath(globalPmRoot),contents);return}catch(error){const retryDelay=TELEMETRY_QUEUE_REWRITE_RETRY_DELAYS_MS[attempt];if(retryDelay===void 0||!isRetryableQueueRewriteError(error))throw error;await sleep(retryDelay)}}async function reconcilePendingOtelSpansAfterFlush(globalPmRoot,retentionDays,succeededIds,failedUpdates){return withQueueMutation(async()=>{const raw=await readFileIfExists(otelSpansQueuePath(globalPmRoot)),current=raw===null?[]:parsePendingOtelSpanLines(raw),reconciled=[];for(const entry of current){if(succeededIds.has(entry.id))continue;const failure=failedUpdates.get(entry.id);reconciled.push(failure?{...entry,attempts:failure.attempts,next_attempt_after:failure.next_attempt_after}:entry)}const{entries:retained}=prunePendingOtelSpans(reconciled,retentionDays);return await rewritePendingOtelSpans(globalPmRoot,retained),retained.length},globalPmRoot)}async function flushPendingOtelSpans(globalPmRoot,retentionDays){const raw=await readFileIfExists(otelSpansQueuePath(globalPmRoot));if(raw===null||raw.trim().length===0){await writeRuntimeState(globalPmRoot,{pending_otel_spans:0});return}const entries=parsePendingOtelSpanLines(raw),{entries:retained,prunedCount}=prunePendingOtelSpans(entries,retentionDays),due=retained.filter(entry=>isDueForRetryAt(entry.next_attempt_after)).slice(0,TELEMETRY_OTEL_SPANS_FLUSH_BATCH_SIZE);if(due.length===0){const remaining2=prunedCount>0?await reconcilePendingOtelSpansAfterFlush(globalPmRoot,retentionDays,new Set,new Map):retained.length;await writeRuntimeState(globalPmRoot,{pending_otel_spans:remaining2});return}const attemptTime=nowIso(),succeededIds=new Set,failedUpdates=new Map;let succeededCount=0,lastError;await Promise.all(due.map(async span=>{try{const status=await postTelemetryJson(span.endpoint,{"content-type":"application/json"},JSON.stringify(span.payload));if(status<200||status>=300)throw new Error(`local_otel_export_http_${status}`);succeededIds.add(span.id),succeededCount+=1}catch(error){lastError=error instanceof Error?sanitizeString(error.message,"redacted"):"local_otel_export_failed";const nextAttempts=span.attempts+1;failedUpdates.set(span.id,{attempts:nextAttempts,next_attempt_after:nextRetryIso(nextAttempts)})}}));const remaining=await reconcilePendingOtelSpansAfterFlush(globalPmRoot,retentionDays,succeededIds,failedUpdates),statePatch={pending_otel_spans:remaining,last_otel_attempt_at:attemptTime};succeededCount>0&&(statePatch.last_otel_success_at=attemptTime),lastError!==void 0?(statePatch.last_otel_failure_at=attemptTime,statePatch.last_otel_failure_error=lastError):remaining===0&&(statePatch.last_otel_failure_at=void 0,statePatch.last_otel_failure_error=void 0),await writeRuntimeState(globalPmRoot,statePatch)}async function flushTelemetryArtifacts(globalPmRoot,endpoint,retentionDays){try{await flushQueue(globalPmRoot,endpoint,retentionDays)}catch{}try{await flushPendingOtelSpans(globalPmRoot,retentionDays)}catch{}}async function cleanupTelemetryQueueTempOrphans(globalPmRoot,maxAgeMs=TELEMETRY_QUEUE_TMP_ORPHAN_MAX_AGE_MS){try{const dirPath=telemetryRuntimeDirectory(globalPmRoot),entries=await readdir(dirPath,{withFileTypes:!0}),cutoffMs=Date.now()-Math.max(0,maxAgeMs);await Promise.all(entries.filter(entry=>entry.isFile()&&/^\.events\.jsonl\.\d+\.\d+\.[a-f0-9]+\.tmp$/.test(entry.name)).map(async entry=>{const candidate=path.join(dirPath,entry.name);(await stat(candidate)).mtimeMs<cutoffMs&&await rm(candidate,{force:!0})}))}catch{}}async function withQueueMutation(operation,globalPmRoot=resolveGlobalPmRoot(process.cwd()),waitMs=5e3){const run=_queueMutationPromise.catch(()=>{}).then(()=>runWithIsolatedExtensionRuntime(async()=>{const release=await acquireLock(globalPmRoot,"telemetry-queue",60,"telemetry",!1,!1,waitMs);try{return clearSettingsReadCache(globalPmRoot),await operation()}finally{await release()}}));return _queueMutationPromise=run.catch(()=>{}),run}async function readCurrentQueueEntries(globalPmRoot){const raw=await readFileIfExists(queuePath(globalPmRoot));return raw===null||raw.trim().length===0?[]:parseQueueLines(raw)}async function removeFlushedEntriesFromCurrentQueue(globalPmRoot,flushedIds,retentionDays){return withQueueMutation(async()=>{const currentEntries=await readCurrentQueueEntries(globalPmRoot),{entries:retainedEntries}=pruneExpiredQueueEntries(currentEntries,retentionDays),remaining=retainedEntries.filter(entry=>!flushedIds.has(entry.event.event_id));return await rewriteQueue(globalPmRoot,remaining),remaining},globalPmRoot)}async function markFailedEntriesInCurrentQueue(globalPmRoot,failedIds,attemptTime,retentionDays){return withQueueMutation(async()=>{const currentEntries=await readCurrentQueueEntries(globalPmRoot),{entries:retainedEntries}=pruneExpiredQueueEntries(currentEntries,retentionDays),retried=retainedEntries.map(entry=>{if(!failedIds.has(entry.event.event_id))return entry;const attempts=entry.attempts+1;return{...entry,attempts,last_attempt_at:attemptTime,next_attempt_after:nextRetryIso(attempts)}});return await rewriteQueue(globalPmRoot,retried),retried},globalPmRoot)}async function flushQueue(globalPmRoot,endpoint,retentionDays){await cleanupTelemetryQueueTempOrphans(globalPmRoot);const normalizedEndpoint=endpoint.trim();if(normalizedEndpoint.length===0)return;const raw=await readFileIfExists(queuePath(globalPmRoot));if(raw===null||raw.trim().length===0){await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:0});return}const queueEntries=parseQueueLines(raw);if(queueEntries.length===0){await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:0});return}const{entries:retainedEntries,prunedCount}=pruneExpiredQueueEntries(queueEntries,retentionDays);if(retainedEntries.length===0){const remaining=await removeFlushedEntriesFromCurrentQueue(globalPmRoot,new Set,retentionDays);await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:remaining.length});return}const dueEntries=retainedEntries.filter(entry=>isDueForRetry(entry)).slice(0,TELEMETRY_FLUSH_BATCH_SIZE);if(dueEntries.length===0){const remaining=prunedCount>0?await removeFlushedEntriesFromCurrentQueue(globalPmRoot,new Set,retentionDays):retainedEntries;await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:remaining.length});return}const dueIds=new Set(dueEntries.map(entry=>entry.event.event_id)),attemptTime=nowIso(),requestHeaders={"content-type":"application/json"},ingestKey=process.env.PM_TELEMETRY_INGEST_KEY?.trim();ingestKey&&(requestHeaders["x-pm-telemetry-key"]=ingestKey);try{const status=await postTelemetryJson(normalizedEndpoint,requestHeaders,JSON.stringify({schema_version:TELEMETRY_SCHEMA_VERSION,events:dueEntries.map(entry=>entry.event)}));if(status<200||status>=300)throw new Error(`telemetry_flush_http_${status}`)}catch(error){const retried=await markFailedEntriesInCurrentQueue(globalPmRoot,dueIds,attemptTime,retentionDays),errorMessage=error instanceof Error?sanitizeString(error.message,"redacted"):"telemetry_flush_failed";await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:retried.length,last_attempted_flush_at:attemptTime,last_failed_flush_at:attemptTime,last_failed_flush_error:errorMessage});return}try{const remaining=await removeFlushedEntriesFromCurrentQueue(globalPmRoot,dueIds,retentionDays);await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:remaining.length,last_attempted_flush_at:attemptTime,last_successful_flush_at:attemptTime,last_failed_flush_at:void 0,last_failed_flush_error:void 0})}catch(error){const errorMessage=error instanceof Error?sanitizeString(error.message,"redacted"):"telemetry_flush_failed",currentEntries=await readCurrentQueueEntries(globalPmRoot).catch(()=>retainedEntries);await writeRuntimeState(globalPmRoot,{endpoint:normalizedEndpoint,queue_entries:currentEntries.length,last_attempted_flush_at:attemptTime,last_failed_flush_at:attemptTime,last_failed_flush_error:errorMessage})}}async function acquireTelemetryFlushLock(globalPmRoot){const lockPath=flushLockPath(globalPmRoot);await mkdir(path.dirname(lockPath),{recursive:!0});try{return await mkdir(lockPath),!0}catch(error){if(typeof error!="object"||error===null||!("code"in error)||error.code!=="EEXIST")throw error}try{const lockStats=await stat(lockPath);return Date.now()-lockStats.mtimeMs<TELEMETRY_FLUSH_LOCK_STALE_MS?!1:(await rm(lockPath,{recursive:!0,force:!0}),await mkdir(lockPath),!0)}catch{return!1}}function isFreshDirectoryLock(lockPath,staleMs){try{return Date.now()-statSync(lockPath).mtimeMs<staleMs}catch{return!1}}function removeDirectoryLockBestEffort(lockPath){try{rmSync(lockPath,{recursive:!0,force:!0})}catch{}}function errorCode(error){if(typeof error!="object"||error===null||!("code"in error))return;const code=error.code;return typeof code=="string"?code:void 0}function createDirectoryLock(lockPath){try{return mkdirSync(lockPath),!0}catch(error){if(errorCode(error)==="EEXIST"||!isFileMissingError(error))return!1}try{return mkdirSync(path.dirname(lockPath),{recursive:!0}),mkdirSync(lockPath),!0}catch{return!1}}function acquireTelemetryFlushSpawnGate(globalPmRoot){if(isFreshDirectoryLock(flushLockPath(globalPmRoot),TELEMETRY_FLUSH_LOCK_STALE_MS))return!1;const lockPath=flushSpawnLockPath(globalPmRoot);try{if(Date.now()-statSync(lockPath).mtimeMs<TELEMETRY_FLUSH_SPAWN_LOCK_STALE_MS)return!1;removeDirectoryLockBestEffort(lockPath)}catch(error){if(!isFileMissingError(error))return!1}return createDirectoryLock(lockPath)}function releaseTelemetryFlushSpawnGate(globalPmRoot){removeDirectoryLockBestEffort(flushSpawnLockPath(globalPmRoot))}const _testOnly={acquireTelemetryFlushSpawnGate,acquireTelemetryFlushLock,buildAuthorContextPayloadFields,buildCommandErrorPayload,buildCommandFinishPayload,buildCommandStartPayload,buildOtelSpanRequest,createDirectoryLock,enqueuePendingOtelSpan,enqueueTelemetryEvent,errorCode,flushPendingOtelSpans,flushQueue,flushQueueWithProcessLock,flushTelemetryArtifacts,hashTelemetryErrorFingerprint,hashTelemetryValue,isEmailDomainCharacter,isEmailLocalCharacter,isExpiredPendingOtelSpan,isExpiredQueueEntry,isFreshDirectoryLock,isDueForRetry,isDueForRetryAt,isRetryableQueueRewriteError,looksLikeEmailToken,otelSpansQueuePath,parseBooleanTrueLike,postTelemetryJson,parsePendingOtelSpanLines,prunePendingOtelSpans,reconcilePendingOtelSpansAfterFlush,retentionCutoffMs,resolveOtelTracesEndpoint,resolveTelemetryHttpTimeoutMs,rewritePendingOtelSpans,normalizeForHash,normalizeCaptureLevel,normalizePmVersion,normalizeTelemetryErrorCategory,normalizeTelemetryErrorCode,normalizeTelemetryExitCode,parseQueueLines,pruneExpiredQueueEntries,readRuntimeState,readCurrentQueueEntries,releaseTelemetryFlushSpawnGate,removeFlushedEntriesFromCurrentQueue,removeDirectoryLockBestEffort,resolveTelemetrySourceContext,rewriteQueue,sanitizeCommandArgs,sanitizeStringMax,sanitizeStringRedacted,sanitizeValue,scheduleTelemetryFlush,shouldFlushInline,sleep,summarizeResult,telemetryFlushRunnerPath,withQueueMutation,flushLockPath,flushSpawnLockPath,runtimeStatePath,writeRuntimeState};async function flushQueueWithProcessLock(globalPmRoot,endpoint,retentionDays){const acquired=await acquireTelemetryFlushLock(globalPmRoot);if(releaseTelemetryFlushSpawnGate(globalPmRoot),!!acquired)try{await flushTelemetryArtifacts(globalPmRoot,endpoint,retentionDays)}finally{try{await rm(flushLockPath(globalPmRoot),{recursive:!0,force:!0})}catch{}}}function scheduleTelemetryFlush(globalPmRoot,endpoint,retentionDays){if(!isConfigurationOnlySettingsRead(globalPmRoot)){if(shouldFlushInline()){const previousFlush=_lastFlushPromise,nextFlush=flushTelemetryArtifacts(globalPmRoot,endpoint,retentionDays);_lastFlushPromise=Promise.allSettled([previousFlush,nextFlush]).then(()=>{});return}try{if(!acquireTelemetryFlushSpawnGate(globalPmRoot))return;const child=spawn(process.execPath,[telemetryFlushRunnerPath()],{detached:!0,stdio:"ignore",cwd:os.tmpdir(),env:{...process.env,PM_GLOBAL_PATH:globalPmRoot,[PM_TELEMETRY_FLUSH_CHILD_ENV]:"1"}});child.on("error",()=>{releaseTelemetryFlushSpawnGate(globalPmRoot)}),child.unref()}catch{releaseTelemetryFlushSpawnGate(globalPmRoot)}}}async function flushTelemetryQueueNow(globalPmRoot=resolveGlobalPmRoot(process.cwd())){if(!resolveTelemetryEnvironmentPolicy().telemetry_disabled)try{if(!(await readSettings(globalPmRoot)).telemetry.enabled)return;const installation=await withQueueMutation(()=>ensureInstallationId(globalPmRoot),globalPmRoot);if(!installation)return;await flushQueueWithProcessLock(globalPmRoot,installation.endpoint,installation.retentionDays)}catch{}}async function startTelemetryCommand(context){if(resolveTelemetryEnvironmentPolicy().telemetry_disabled||context.command==="telemetry"&&context.args.some(token=>token.trim().toLowerCase()==="clear"))return null;try{const globalPmRoot=resolveGlobalPmRoot(process.cwd());if(!(await readSettings(globalPmRoot)).telemetry.enabled)return null;const coreReadOwned=context.global.noExtensions===!0||isActiveCommandUnextended(context.command),activeCommand=await withQueueMutation(async()=>{const installation=await ensureInstallationId(globalPmRoot);if(!installation)return null;const{installationId,endpoint,retentionDays,captureLevel}=installation,pmVersion=normalizePmVersion(context.pm_version),sourceContext=resolveTelemetrySourceContext(context.global),pmRootHash=hashWithInstallationId(installationId,context.pm_root),cwdHash=hashWithInstallationId(installationId,process.cwd()),otelTracesEndpoint=resolveOtelTracesEndpoint(),occurredAt=nowIso(),event={schema_version:TELEMETRY_SCHEMA_VERSION,event_id:crypto.randomUUID(),event_type:"command_start",occurred_at:occurredAt,installation_id:installationId,session_id:PROCESS_SESSION_ID,command:context.command,payload:buildCommandStartPayload({captureLevel,context,pmVersion,sourceContext,pmRootHash,cwdHash,installationId})},sampleRate=await resolveAutomaticReadSampleRate(globalPmRoot,context.command,coreReadOwned);sampleRate===1&&await appendTelemetryEvent(globalPmRoot,event);const commandTaxonomy=deriveTelemetryCommandTaxonomy(context.command),active={...sampleRate<1?{sample_rate:sampleRate}:{},started_at:occurredAt,started_at_ms:Date.now(),command:context.command,command_taxonomy:commandTaxonomy,pm_version:pmVersion,source_context:sourceContext.source_context,source_context_source:sourceContext.source_context_source,installation_id:installationId,pm_root_hash:pmRootHash,cwd_hash:cwdHash,endpoint,retention_days:retentionDays,global_pm_root:globalPmRoot,capture_level:captureLevel,otel_traces_endpoint:otelTracesEndpoint??void 0,otel_trace_id:otelTracesEndpoint?crypto.randomBytes(16).toString("hex"):void 0,otel_span_id:otelTracesEndpoint?crypto.randomBytes(8).toString("hex"):void 0};return sampleRate<1&&deferredReadStarts.set(active,event),active},globalPmRoot,TELEMETRY_FOREGROUND_LOCK_WAIT_MS);return activeCommand&&activeCommand.sample_rate===void 0&&scheduleTelemetryFlush(globalPmRoot,activeCommand.endpoint,activeCommand.retention_days),activeCommand}catch{return null}}async function finishTelemetryCommand(activeCommand,outcome){if(!(!activeCommand||resolveTelemetryEnvironmentPolicy().telemetry_disabled))try{if(!await withQueueMutation(async()=>{const settings=await readSettings(activeCommand.global_pm_root);if(resolveTelemetryEnvironmentPolicy().telemetry_disabled||!settings.telemetry.enabled||settings.telemetry.installation_id!==activeCommand.installation_id)return deferredReadStarts.delete(activeCommand),!1;const deferredStart=deferredReadStarts.get(activeCommand),sampleRate=outcome.ok?activeCommand.sample_rate??1:1;if(deferredStart){if(deferredReadStarts.delete(activeCommand),crypto.randomBytes(6).readUIntBE(0,6)/281474976710656>=sampleRate)return!1;deferredStart.payload.sample_rate=sampleRate,await appendTelemetryEvent(activeCommand.global_pm_root,deferredStart)}const finishedAt=nowIso(),durationMs=Math.max(0,Date.now()-activeCommand.started_at_ms),normalizedErrorCode=normalizeTelemetryErrorCode(inferTelemetryErrorCode({ok:outcome.ok,errorCode:outcome.error_code,errorMessage:outcome.error,exitCode:outcome.exit_code})),normalizedErrorCategory=normalizeTelemetryErrorCategory({ok:outcome.ok,errorCode:normalizedErrorCode,errorCategory:outcome.error_category}),normalizedExitCode=normalizeTelemetryExitCode(outcome.exit_code,outcome.ok),commandResolution=outcome.command_resolution??deriveTelemetryCommandResolution({ok:outcome.ok,errorCode:normalizedErrorCode,errorCategory:normalizedErrorCategory}),resolutionStage=outcome.resolution_stage??"execute",event={schema_version:TELEMETRY_SCHEMA_VERSION,event_id:crypto.randomUUID(),event_type:"command_finish",occurred_at:finishedAt,installation_id:activeCommand.installation_id,session_id:PROCESS_SESSION_ID,command:activeCommand.command,payload:{...deferredStart?{sample_rate:sampleRate}:{},...buildCommandFinishPayload({captureLevel:activeCommand.capture_level,pmVersion:activeCommand.pm_version,sourceContext:{source_context:activeCommand.source_context,source_context_source:activeCommand.source_context_source},outcome,durationMs,startedAt:activeCommand.started_at,command:activeCommand.command,installationId:activeCommand.installation_id,commandTaxonomy:activeCommand.command_taxonomy,exitCode:normalizedExitCode,errorCode:normalizedErrorCode,errorCategory:normalizedErrorCategory,commandResolution,resolutionStage})}};await appendTelemetryEvent(activeCommand.global_pm_root,event);const otelRequest=buildOtelSpanRequest(activeCommand,{...outcome,exit_code:normalizedExitCode,error_code:normalizedErrorCode,error_category:normalizedErrorCategory},finishedAt,durationMs,sampleRate);return otelRequest&&await appendPendingOtelSpan(activeCommand.global_pm_root,otelRequest),!0},activeCommand.global_pm_root,TELEMETRY_FOREGROUND_LOCK_WAIT_MS))return;scheduleTelemetryFlush(activeCommand.global_pm_root,activeCommand.endpoint,activeCommand.retention_days)}catch{}}async function emitTelemetryErrorEvent(context){if(!resolveTelemetryEnvironmentPolicy().telemetry_disabled)try{const globalPmRoot=resolveGlobalPmRoot(process.cwd());if(!(await readSettings(globalPmRoot)).telemetry.enabled)return;const captured=await withQueueMutation(async()=>{const installation=await ensureInstallationId(globalPmRoot);if(!installation)return null;const{installationId,captureLevel}=installation,pmVersion=normalizePmVersion(context.pm_version),sourceContext=resolveTelemetrySourceContext(context.global),pmRootHash=hashWithInstallationId(installationId,context.pm_root),cwdHash=hashWithInstallationId(installationId,process.cwd()),occurredAt=nowIso(),normalizedErrorCode=normalizeTelemetryErrorCode(inferTelemetryErrorCode({ok:!1,errorCode:context.error_code,errorMessage:context.error_message,exitCode:context.exit_code})),normalizedErrorCategory=context.error_category??resolveTelemetryErrorCategory(normalizedErrorCode),normalizedExitCode=normalizeTelemetryExitCode(context.exit_code,!1),normalizedCommand=context.command.trim().length>0?context.command:"<unknown>",commandTaxonomy=deriveTelemetryCommandTaxonomy(normalizedCommand),commandResolution=context.command_resolution??deriveTelemetryCommandResolution({ok:!1,errorCode:normalizedErrorCode,errorCategory:normalizedErrorCategory}),resolutionStage=context.resolution_stage??"unknown",event={schema_version:TELEMETRY_SCHEMA_VERSION,event_id:crypto.randomUUID(),event_type:"command_error",occurred_at:occurredAt,installation_id:installationId,session_id:PROCESS_SESSION_ID,command:sanitizeString(normalizedCommand,"redacted"),payload:buildCommandErrorPayload({captureLevel,pmVersion,sourceContext,command:normalizedCommand,commandTaxonomy,commandResolution,resolutionStage,args:context.args,options:context.options,pmRootHash,cwdHash,installationId,errorCode:normalizedErrorCode,errorCategory:normalizedErrorCategory,exitCode:normalizedExitCode,errorMessage:context.error_message})};return await appendTelemetryEvent(globalPmRoot,event),installation},globalPmRoot,TELEMETRY_FOREGROUND_LOCK_WAIT_MS);captured&&scheduleTelemetryFlush(globalPmRoot,captured.endpoint,captured.retentionDays)}catch{}}export{PM_TELEMETRY_SOURCE_CONTEXT_VALUES2 as PM_TELEMETRY_SOURCE_CONTEXT_VALUES,TELEMETRY_MAX_QUEUE_ENTRY_ATTEMPTS,TELEMETRY_SCHEMA_VERSION,_testOnly,emitTelemetryErrorEvent,finishTelemetryCommand,flushTelemetryQueueNow,startTelemetryCommand,waitForPendingFlush,withQueueMutation as withTelemetryQueueMutation};
|
|
6
10
|
//# sourceMappingURL=runtime.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
`)}async function readBackgroundTestRunRecord(pmRoot,runId){const recordPath=getTestRunRecordPath(pmRoot,runId);const raw=await readFileIfExists(recordPath);if(!raw){return null}return parseBackgroundRunRecord(raw,recordPath)}async function listBackgroundRunRecordPaths(pmRoot){const recordsRoot=getTestRunsRecordsPath(pmRoot);if(!await pathExists(recordsRoot)){return[]}const entries=await fs.readdir(recordsRoot,{withFileTypes:true});return entries.filter(entry=>entry.isFile()&&entry.name.endsWith(".json")).map(entry=>path.join(recordsRoot,entry.name)).sort((left,right)=>right.localeCompare(left))}function parseLinuxRssStatus(raw){const match=raw.match(/^VmRSS:\s+(\d+)\s+kB$/m);if(!match){return void 0}return Number.parseInt(match[1],10)*1024}async function readLinuxRssBytes(pid){if(process.platform!=="linux"){return void 0}try{const raw=await fs.readFile(`/proc/${pid}/status`,"utf8");return parseLinuxRssStatus(raw)}catch{return void 0}}function parseLinuxCpuStat(raw){const closeParenIndex=raw.lastIndexOf(")");if(closeParenIndex<0){return{}}const remainder=raw.slice(closeParenIndex+2).trim();const parts=remainder.split(/\s+/);const utimeTicks=Number.parseInt(parts[11],10);const stimeTicks=Number.parseInt(parts[12],10);if(!Number.isFinite(utimeTicks)||!Number.isFinite(stimeTicks)){return{}}return{cpu_user_seconds:utimeTicks/PROC_STAT_TICKS_PER_SECOND,cpu_system_seconds:stimeTicks/PROC_STAT_TICKS_PER_SECOND}}async function readLinuxCpuSeconds(pid){if(process.platform!=="linux"){return{}}try{const raw=await fs.readFile(`/proc/${pid}/stat`,"utf8");return parseLinuxCpuStat(raw)}catch{return{}}}async function buildResourceSnapshot(record){const pid=record.child_pid??record.worker_pid;if(!isPidRunning(pid)){return void 0}const rssBytes=await readLinuxRssBytes(pid);const cpu=await readLinuxCpuSeconds(pid);const startedAtMs=record.started_at?Date.parse(record.started_at):Number.NaN;const uptimeSeconds=Number.isFinite(startedAtMs)?Math.max(0,(nowMs()-startedAtMs)/1e3):void 0;return{recorded_at:nowIso(),rss_bytes:rssBytes,cpu_user_seconds:cpu.cpu_user_seconds,cpu_system_seconds:cpu.cpu_system_seconds,uptime_seconds:uptimeSeconds}}function readCount(value){return typeof value==="number"&&Number.isFinite(value)?value:0}function evaluateWorkerResult(kind,payload){if(!payload||typeof payload!=="object"){return{summary:{passed:0,failed:1,skipped:0},parsedResult:null}}const record=payload;if(kind==="test-all"){const totals=record.totals??{};return{summary:{items:typeof totals.items==="number"?totals.items:void 0,linked_tests:typeof totals.linked_tests==="number"?totals.linked_tests:void 0,passed:readCount(totals.passed),failed:readCount(totals.failed),skipped:readCount(totals.skipped),fail_on_skipped_triggered:record.fail_on_skipped_triggered===true?true:void 0},parsedResult:payload}}const runResults=Array.isArray(record.run_results)?record.run_results:[];let passed=0;let failed=0;let skipped=0;for(const entry of runResults){if(!entry||typeof entry!=="object"){continue}const status=entry.status;if(status==="passed"){passed+=1;continue}if(status==="failed"){failed+=1;continue}skipped+=1}return{summary:{passed,failed,skipped,fail_on_skipped_triggered:record.fail_on_skipped_triggered===true?true:void 0},parsedResult:payload}}function parseProgressLine(stderrLine){const line=stderrLine.trim();if(line.length===0){return null}const testAllMatch=line.match(/\[pm test-all\]\s+item\s+(\d+)\/(\d+)\s+(start|end)\s+id=([^\s]+)/i);if(testAllMatch){const itemIndex=Number.parseInt(testAllMatch[1],10);const itemTotal=Number.parseInt(testAllMatch[2],10);return{item_index:itemIndex,item_total:itemTotal,item_id:testAllMatch[4],linked_test_index:void 0,linked_test_total:void 0,current_command:void 0,elapsed_ms:void 0,heartbeat_at:nowIso(),phase:testAllMatch[3]?.toLowerCase()==="end"?"finished":"running"}}const linkedTestMatch=line.match(/\[pm test\]\s+linked-test\s+(\d+)\/(\d+)\s+(start|running|end)(?:.*elapsed_ms=(\d+))?/i);if(!linkedTestMatch){return null}const index=Number.parseInt(linkedTestMatch[1],10);const total=Number.parseInt(linkedTestMatch[2],10);const elapsed=linkedTestMatch[4]?Number.parseInt(linkedTestMatch[4],10):void 0;const commandMatch=line.match(/\scommand="((?:\\.|[^"\\])*)"/);const currentCommand=commandMatch?commandMatch[1].replaceAll('\\"','"').replaceAll("\\\\","\\"):void 0;return{linked_test_index:index,linked_test_total:total,current_command:currentCommand,elapsed_ms:Number.isFinite(elapsed)?elapsed:void 0,heartbeat_at:nowIso(),phase:linkedTestMatch[3]?.toLowerCase()==="end"?"finished":"running"}}function splitLines(value){return value.split(/\r?\n/).map(entry=>entry.trimEnd()).filter(entry=>entry.length>0)}function tailLines(value,limit){if(limit<=0){return[]}const lines=splitLines(value);if(lines.length<=limit){return lines}return lines.slice(lines.length-limit)}async function resolveBackgroundCliEntry(cwd){const configured=process.env.PM_BACKGROUND_CLI_ENTRY?.trim();if(configured&&configured.length>0){const resolvedConfigured=path.resolve(cwd,configured);if(await pathExists(resolvedConfigured)){return resolvedConfigured}}const distEntry=path.resolve(cwd,"dist","cli.js");if(await pathExists(distEntry)){return distEntry}const argvEntry=process.argv[1]?.trim();if(argvEntry&&argvEntry.length>0){const resolvedArgvEntry=path.resolve(cwd,argvEntry);if(await pathExists(resolvedArgvEntry)){return resolvedArgvEntry}}throw new PmCliError("Unable to resolve a CLI entrypoint for background test runs. Build the project or set PM_BACKGROUND_CLI_ENTRY.",EXIT_CODE.GENERIC_FAILURE)}async function refreshRunIfStale(pmRoot,record){if(!BACKGROUND_RUN_ACTIVE_STATUSES.has(record.status)){return record}const workerAlive=isPidRunning(record.worker_pid);if(workerAlive){return record}if(record.finished_at){return record}const next={...record,status:"failed",finished_at:nowIso(),error:record.error??"Background test run worker exited before writing terminal status."};await writeBackgroundRunRecord(pmRoot,next);return next}async function startBackgroundTestRun(options){await ensureBackgroundRunStorage(options.pmRoot);const normalizedArgs=normalizeCommandArgs(options.commandArgs);if(normalizedArgs.length===0){throw new PmCliError("Background test run requires command arguments.",EXIT_CODE.USAGE)}const fingerprint=buildBackgroundTestRunFingerprint(options.kind,normalizedArgs,options.pmRoot);const existingRuns=await listBackgroundTestRuns(options.pmRoot,{});for(const existing of existingRuns){const refreshed=await refreshRunIfStale(options.pmRoot,existing);if(refreshed.fingerprint!==fingerprint){continue}if(!BACKGROUND_RUN_ACTIVE_STATUSES.has(refreshed.status)||!isPidRunning(refreshed.worker_pid)){continue}return{started:false,run:{...refreshed,duplicate_of:refreshed.id},duplicate_of:refreshed.id}}const runId=buildRunId();const createdAt=nowIso();const stdoutPath=getTestRunStdoutPath(options.pmRoot,runId);const stderrPath=getTestRunStderrPath(options.pmRoot,runId);const resultPath=getTestRunResultPath(options.pmRoot,runId);await fs.writeFile(stdoutPath,"","utf8");await fs.writeFile(stderrPath,"","utf8");const record={id:runId,kind:options.kind,status:"queued",created_at:createdAt,updated_at:createdAt,requested_by:options.requestedBy,fingerprint,command_args:normalizedArgs,command_label:summarizeCommandLabel(normalizedArgs),pm_root:options.pmRoot,global_pm_root:options.globalPmRoot,target_id:options.targetId,status_filter:options.statusFilter,attempt:typeof options.attempt==="number"&&Number.isFinite(options.attempt)&&options.attempt>=1?Math.floor(options.attempt):1,resumed_from:options.resumedFrom,resumed_by:options.resumedBy,stdout_path:stdoutPath,stderr_path:stderrPath,result_path:resultPath,progress:{phase:"queued",message:"Queued for background execution.",heartbeat_at:createdAt}};await writeBackgroundRunRecord(options.pmRoot,record);return{started:true,run:record}}async function spawnBackgroundTestRunWorker(options){const record=await readBackgroundTestRunRecord(options.pmRoot,options.runId);if(!record){throw new PmCliError(`Background test run ${options.runId} not found`,EXIT_CODE.NOT_FOUND)}if(BACKGROUND_RUN_TERMINAL_STATUSES.has(record.status)){throw new PmCliError(`Background test run ${record.id} is already terminal (${record.status}).`,EXIT_CODE.CONFLICT)}const cliEntry=await resolveBackgroundCliEntry(process.cwd());const args=[];if(options.noExtensions===true){args.push("--no-extensions")}args.push("--path",record.pm_root,"test-runs-worker",record.id);const env={...process.env,PM_PATH:record.pm_root,PM_GLOBAL_PATH:record.global_pm_root,PM_BACKGROUND_TEST_RUN_ID:record.id,PM_BACKGROUND_TEST_RUN_ATTEMPT:String(record.attempt),PM_BACKGROUND_TEST_RUN_RESUMED_FROM:record.resumed_from??"",FORCE_COLOR:"0"};const child=spawn(process.execPath,[cliEntry,...args],{cwd:process.cwd(),env,detached:true,stdio:"ignore",windowsHide:true});child.unref();const next={...record,status:"queued",worker_pid:child.pid,progress:{phase:"queued",message:"Worker process started.",heartbeat_at:nowIso()}};await writeBackgroundRunRecord(options.pmRoot,next);return next}async function appendFileOrdered(queue,filePath,text){await queue;await fs.appendFile(filePath,text,"utf8")}function resolvePositiveEnvInteger(name,fallback){const parsed=Number.parseInt(process.env[name]??"",10);return Number.isFinite(parsed)&&parsed>0?parsed:fallback}function buildBackgroundWorkerEnv(record){return{...process.env,PM_PATH:record.pm_root,PM_GLOBAL_PATH:record.global_pm_root,FORCE_COLOR:"0"}}function buildBackgroundWorkerChildArgs(record,noExtensions){return noExtensions?["--no-extensions",...record.command_args]:[...record.command_args]}function createBackgroundRunRecordWriteScheduler(pmRoot,record){let writeQueue=Promise.resolve();return{schedule(){writeQueue=writeQueue.then(async()=>{try{await writeBackgroundRunRecord(pmRoot,record)}catch{}})},async flush(){await writeQueue}}}function requestChildSignal(child,signal){try{child.kill(signal)}catch{}}async function requestBackgroundWorkerStop(record,child,state,scheduleRecordWrite){if(state.stopRequested){return}state.stopRequested=true;record.stop_requested_at=nowIso();record.progress={...record.progress,phase:"stopping",message:"Stop requested for background run.",heartbeat_at:nowIso()};scheduleRecordWrite();requestChildSignal(child,"SIGTERM");const forceTimer=setTimeout(()=>requestChildSignal(child,"SIGKILL"),resolvePositiveEnvInteger("PM_BACKGROUND_RUN_FORCE_KILL_DELAY_MS",DEFAULT_BACKGROUND_RUN_FORCE_KILL_DELAY_MS));forceTimer.unref?.()}function buildItemBackgroundProgress(line,progressPatch,phase){return{phase,message:line,heartbeat_at:nowIso(),item_index:progressPatch.item_index,item_total:progressPatch.item_total,item_id:progressPatch.item_id,linked_test_index:void 0,linked_test_total:void 0,current_command:void 0,elapsed_ms:void 0}}function buildLinkedTestBackgroundProgress(line,record,progressPatch,phase){return{phase,message:line,heartbeat_at:nowIso(),item_index:progressPatch.item_index??record.progress?.item_index,item_total:progressPatch.item_total??record.progress?.item_total,item_id:progressPatch.item_id??record.progress?.item_id,linked_test_index:progressPatch.linked_test_index,linked_test_total:progressPatch.linked_test_total,current_command:progressPatch.current_command,elapsed_ms:progressPatch.elapsed_ms}}function applyBackgroundWorkerProgressLine(record,line,stopRequested){const progressPatch=parseProgressLine(line);if(!progressPatch){return false}const phase=record.progress?.phase==="stopping"?"stopping":"running";record.progress=progressPatch.item_id?buildItemBackgroundProgress(line,progressPatch,phase):buildLinkedTestBackgroundProgress(line,record,progressPatch,phase);if(progressPatch.phase==="finished"&&!stopRequested){record.progress.phase="running"}return true}function parseBackgroundWorkerStdout(stdoutBuffer){if(stdoutBuffer.trim().length===0){return null}try{return JSON.parse(stdoutBuffer)}catch{return null}}function resolveBackgroundWorkerFinalStatus(record,stopRequested){if(stopRequested){return"stopped"}const passed=record.exit_code===0&&(record.summary?.failed??0)===0&&record.summary?.fail_on_skipped_triggered!==true;return passed?"passed":"failed"}function buildFinishedBackgroundProgress(record,stopRequested){return{phase:"finished",message:stopRequested?"Background run stopped.":`Background run finished with status=${record.status}.`,heartbeat_at:nowIso(),item_index:record.progress?.item_index,item_total:record.progress?.item_total,item_id:record.progress?.item_id,linked_test_index:record.progress?.linked_test_index,linked_test_total:record.progress?.linked_test_total,current_command:record.progress?.current_command,elapsed_ms:record.progress?.elapsed_ms}}async function writeBackgroundWorkerResult(record,parsedResult,stdoutBuffer){if(parsedResult!==null){await writeFileAtomic(record.result_path,`${JSON.stringify(parsedResult,null,2)}
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="d5f2c177-4eed-5bc5-89b5-3c5d689f902a")}catch{}})();import fs from"node:fs/promises";import{spawn}from"node:child_process";import{createHash,randomBytes}from"node:crypto";import path from"node:path";import{ensureDir,pathExists,readFileIfExists,writeFileAtomic}from"../fs/fs-utils.js";import{PmCliError}from"../shared/errors.js";import{EXIT_CODE}from"../shared/constants.js";import{nowIso}from"../shared/time.js";import{getTestRunRecordPath,getTestRunResultPath,getTestRunStderrPath,getTestRunStdoutPath,getTestRunsPath,getTestRunsRecordsPath,getTestRunsResultsPath,getTestRunsStderrPath,getTestRunsStdoutPath}from"../store/paths.js";const BACKGROUND_RUN_ACTIVE_STATUSES=new Set(["queued","running"]),BACKGROUND_RUN_TERMINAL_STATUSES=new Set(["passed","failed","stopped","canceled"]),DEFAULT_BACKGROUND_RUN_RESOURCE_SNAPSHOT_INTERVAL_MS=3e3,DEFAULT_BACKGROUND_RUN_FORCE_KILL_DELAY_MS=3e3,DEFAULT_BACKGROUND_RUN_HEARTBEAT_STALE_MS=3e4,DEFAULT_BACKGROUND_RUN_LOG_TAIL_LINES=100,PROC_STAT_TICKS_PER_SECOND=100;function nowMs(){return Date.now()}function normalizeCommandArgs(args){return args.map(entry=>entry.trim()).filter(entry=>entry.length>0)}function summarizeCommandLabel(args){const joined=args.join(" ").replaceAll(/\s+/g," ").trim();return joined.length<=180?joined:`${joined.slice(0,177)}...`}function buildRunId(){const timePart=Date.now().toString(36),randomPart=randomBytes(3).toString("hex");return`tr-${timePart}-${randomPart}`}function buildBackgroundTestRunFingerprint(kind,commandArgs,pmRoot){const payload={kind,command:normalizeCommandArgs(commandArgs),pm_root:path.resolve(pmRoot)};return createHash("sha256").update(JSON.stringify(payload)).digest("hex")}function isPidRunning(pid){if(!Number.isInteger(pid)||!pid||pid<=0)return!1;try{return process.kill(pid,0),!0}catch(error){return(typeof error=="object"&&error!==null&&"code"in error?error.code:void 0)==="EPERM"}}async function ensureBackgroundRunStorage(pmRoot){await ensureDir(getTestRunsPath(pmRoot)),await ensureDir(getTestRunsRecordsPath(pmRoot)),await ensureDir(getTestRunsStdoutPath(pmRoot)),await ensureDir(getTestRunsStderrPath(pmRoot)),await ensureDir(getTestRunsResultsPath(pmRoot))}async function parseBackgroundRunRecord(raw,recordPath){try{const parsed=JSON.parse(raw);if(!parsed||typeof parsed!="object"||typeof parsed.id!="string")throw new Error("invalid run record payload");return parsed}catch(error){throw new PmCliError(`Failed to parse background test run record at ${recordPath}: ${error instanceof Error?error.message:String(error)}`,EXIT_CODE.GENERIC_FAILURE)}}async function writeBackgroundRunRecord(pmRoot,record){const next={...record,updated_at:nowIso()};await writeFileAtomic(getTestRunRecordPath(pmRoot,record.id),`${JSON.stringify(next,null,2)}
|
|
2
|
+
`)}async function readBackgroundTestRunRecord(pmRoot,runId){const recordPath=getTestRunRecordPath(pmRoot,runId),raw=await readFileIfExists(recordPath);return raw?parseBackgroundRunRecord(raw,recordPath):null}async function listBackgroundRunRecordPaths(pmRoot){const recordsRoot=getTestRunsRecordsPath(pmRoot);return await pathExists(recordsRoot)?(await fs.readdir(recordsRoot,{withFileTypes:!0})).filter(entry=>entry.isFile()&&entry.name.endsWith(".json")).map(entry=>path.join(recordsRoot,entry.name)).sort((left,right)=>right.localeCompare(left)):[]}function parseLinuxRssStatus(raw){const match=raw.match(/^VmRSS:\s+(\d+)\s+kB$/m);if(match)return Number.parseInt(match[1],10)*1024}async function readLinuxRssBytes(pid){if(process.platform==="linux")try{const raw=await fs.readFile(`/proc/${pid}/status`,"utf8");return parseLinuxRssStatus(raw)}catch{return}}function parseLinuxCpuStat(raw){const closeParenIndex=raw.lastIndexOf(")");if(closeParenIndex<0)return{};const parts=raw.slice(closeParenIndex+2).trim().split(/\s+/),utimeTicks=Number.parseInt(parts[11],10),stimeTicks=Number.parseInt(parts[12],10);return!Number.isFinite(utimeTicks)||!Number.isFinite(stimeTicks)?{}:{cpu_user_seconds:utimeTicks/PROC_STAT_TICKS_PER_SECOND,cpu_system_seconds:stimeTicks/PROC_STAT_TICKS_PER_SECOND}}async function readLinuxCpuSeconds(pid){if(process.platform!=="linux")return{};try{const raw=await fs.readFile(`/proc/${pid}/stat`,"utf8");return parseLinuxCpuStat(raw)}catch{return{}}}async function buildResourceSnapshot(record){const pid=record.child_pid??record.worker_pid;if(!isPidRunning(pid))return;const rssBytes=await readLinuxRssBytes(pid),cpu=await readLinuxCpuSeconds(pid),startedAtMs=record.started_at?Date.parse(record.started_at):Number.NaN,uptimeSeconds=Number.isFinite(startedAtMs)?Math.max(0,(nowMs()-startedAtMs)/1e3):void 0;return{recorded_at:nowIso(),rss_bytes:rssBytes,cpu_user_seconds:cpu.cpu_user_seconds,cpu_system_seconds:cpu.cpu_system_seconds,uptime_seconds:uptimeSeconds}}function readCount(value){return typeof value=="number"&&Number.isFinite(value)?value:0}function evaluateWorkerResult(kind,payload){if(!payload||typeof payload!="object")return{summary:{passed:0,failed:1,skipped:0},parsedResult:null};const record=payload;if(kind==="test-all"){const totals=record.totals??{};return{summary:{items:typeof totals.items=="number"?totals.items:void 0,linked_tests:typeof totals.linked_tests=="number"?totals.linked_tests:void 0,passed:readCount(totals.passed),failed:readCount(totals.failed),skipped:readCount(totals.skipped),fail_on_skipped_triggered:record.fail_on_skipped_triggered===!0?!0:void 0},parsedResult:payload}}const runResults=Array.isArray(record.run_results)?record.run_results:[];let passed=0,failed=0,skipped=0;for(const entry of runResults){if(!entry||typeof entry!="object")continue;const status=entry.status;if(status==="passed"){passed+=1;continue}if(status==="failed"){failed+=1;continue}skipped+=1}return{summary:{passed,failed,skipped,fail_on_skipped_triggered:record.fail_on_skipped_triggered===!0?!0:void 0},parsedResult:payload}}function parseProgressLine(stderrLine){const line=stderrLine.trim();if(line.length===0)return null;const testAllMatch=line.match(/\[pm test-all\]\s+item\s+(\d+)\/(\d+)\s+(start|end)\s+id=([^\s]+)/i);if(testAllMatch){const itemIndex=Number.parseInt(testAllMatch[1],10),itemTotal=Number.parseInt(testAllMatch[2],10);return{item_index:itemIndex,item_total:itemTotal,item_id:testAllMatch[4],linked_test_index:void 0,linked_test_total:void 0,current_command:void 0,elapsed_ms:void 0,heartbeat_at:nowIso(),phase:testAllMatch[3]?.toLowerCase()==="end"?"finished":"running"}}const linkedTestMatch=line.match(/\[pm test\]\s+linked-test\s+(\d+)\/(\d+)\s+(start|running|end)(?:.*elapsed_ms=(\d+))?/i);if(!linkedTestMatch)return null;const index=Number.parseInt(linkedTestMatch[1],10),total=Number.parseInt(linkedTestMatch[2],10),elapsed=linkedTestMatch[4]?Number.parseInt(linkedTestMatch[4],10):void 0,commandMatch=line.match(/\scommand="((?:\\.|[^"\\])*)"/),currentCommand=commandMatch?commandMatch[1].replaceAll('\\"','"').replaceAll("\\\\","\\"):void 0;return{linked_test_index:index,linked_test_total:total,current_command:currentCommand,elapsed_ms:Number.isFinite(elapsed)?elapsed:void 0,heartbeat_at:nowIso(),phase:linkedTestMatch[3]?.toLowerCase()==="end"?"finished":"running"}}function splitLines(value){return value.split(/\r?\n/).map(entry=>entry.trimEnd()).filter(entry=>entry.length>0)}function tailLines(value,limit){if(limit<=0)return[];const lines=splitLines(value);return lines.length<=limit?lines:lines.slice(lines.length-limit)}async function resolveBackgroundCliEntry(cwd){const configured=process.env.PM_BACKGROUND_CLI_ENTRY?.trim();if(configured&&configured.length>0){const resolvedConfigured=path.resolve(cwd,configured);if(await pathExists(resolvedConfigured))return resolvedConfigured}const distEntry=path.resolve(cwd,"dist","cli.js");if(await pathExists(distEntry))return distEntry;const argvEntry=process.argv[1]?.trim();if(argvEntry&&argvEntry.length>0){const resolvedArgvEntry=path.resolve(cwd,argvEntry);if(await pathExists(resolvedArgvEntry))return resolvedArgvEntry}throw new PmCliError("Unable to resolve a CLI entrypoint for background test runs. Build the project or set PM_BACKGROUND_CLI_ENTRY.",EXIT_CODE.GENERIC_FAILURE)}async function refreshRunIfStale(pmRoot,record){if(!BACKGROUND_RUN_ACTIVE_STATUSES.has(record.status)||isPidRunning(record.worker_pid)||record.finished_at)return record;const next={...record,status:"failed",finished_at:nowIso(),error:record.error??"Background test run worker exited before writing terminal status."};return await writeBackgroundRunRecord(pmRoot,next),next}async function startBackgroundTestRun(options){await ensureBackgroundRunStorage(options.pmRoot);const normalizedArgs=normalizeCommandArgs(options.commandArgs);if(normalizedArgs.length===0)throw new PmCliError("Background test run requires command arguments.",EXIT_CODE.USAGE);const fingerprint=buildBackgroundTestRunFingerprint(options.kind,normalizedArgs,options.pmRoot),existingRuns=await listBackgroundTestRuns(options.pmRoot,{});for(const existing of existingRuns){const refreshed=await refreshRunIfStale(options.pmRoot,existing);if(refreshed.fingerprint===fingerprint&&!(!BACKGROUND_RUN_ACTIVE_STATUSES.has(refreshed.status)||!isPidRunning(refreshed.worker_pid)))return{started:!1,run:{...refreshed,duplicate_of:refreshed.id},duplicate_of:refreshed.id}}const runId=buildRunId(),createdAt=nowIso(),stdoutPath=getTestRunStdoutPath(options.pmRoot,runId),stderrPath=getTestRunStderrPath(options.pmRoot,runId),resultPath=getTestRunResultPath(options.pmRoot,runId);await fs.writeFile(stdoutPath,"","utf8"),await fs.writeFile(stderrPath,"","utf8");const record={id:runId,kind:options.kind,status:"queued",created_at:createdAt,updated_at:createdAt,requested_by:options.requestedBy,fingerprint,command_args:normalizedArgs,command_label:summarizeCommandLabel(normalizedArgs),pm_root:options.pmRoot,global_pm_root:options.globalPmRoot,target_id:options.targetId,status_filter:options.statusFilter,attempt:typeof options.attempt=="number"&&Number.isFinite(options.attempt)&&options.attempt>=1?Math.floor(options.attempt):1,resumed_from:options.resumedFrom,resumed_by:options.resumedBy,stdout_path:stdoutPath,stderr_path:stderrPath,result_path:resultPath,progress:{phase:"queued",message:"Queued for background execution.",heartbeat_at:createdAt}};return await writeBackgroundRunRecord(options.pmRoot,record),{started:!0,run:record}}async function spawnBackgroundTestRunWorker(options){const record=await readBackgroundTestRunRecord(options.pmRoot,options.runId);if(!record)throw new PmCliError(`Background test run ${options.runId} not found`,EXIT_CODE.NOT_FOUND);if(BACKGROUND_RUN_TERMINAL_STATUSES.has(record.status))throw new PmCliError(`Background test run ${record.id} is already terminal (${record.status}).`,EXIT_CODE.CONFLICT);const cliEntry=await resolveBackgroundCliEntry(process.cwd()),args=[];options.noExtensions===!0&&args.push("--no-extensions"),args.push("--path",record.pm_root,"test-runs-worker",record.id);const env={...process.env,PM_PATH:record.pm_root,PM_GLOBAL_PATH:record.global_pm_root,PM_BACKGROUND_TEST_RUN_ID:record.id,PM_BACKGROUND_TEST_RUN_ATTEMPT:String(record.attempt),PM_BACKGROUND_TEST_RUN_RESUMED_FROM:record.resumed_from??"",FORCE_COLOR:"0"},child=spawn(process.execPath,[cliEntry,...args],{cwd:process.cwd(),env,detached:!0,stdio:"ignore",windowsHide:!0});child.unref();const next={...record,status:"queued",worker_pid:child.pid,progress:{phase:"queued",message:"Worker process started.",heartbeat_at:nowIso()}};return await writeBackgroundRunRecord(options.pmRoot,next),next}async function appendFileOrdered(queue,filePath,text){await queue,await fs.appendFile(filePath,text,"utf8")}function resolvePositiveEnvInteger(name,fallback){const parsed=Number.parseInt(process.env[name]??"",10);return Number.isFinite(parsed)&&parsed>0?parsed:fallback}function buildBackgroundWorkerEnv(record){return{...process.env,PM_PATH:record.pm_root,PM_GLOBAL_PATH:record.global_pm_root,FORCE_COLOR:"0"}}function buildBackgroundWorkerChildArgs(record,noExtensions){return noExtensions?["--no-extensions",...record.command_args]:[...record.command_args]}function createBackgroundRunRecordWriteScheduler(pmRoot,record){let writeQueue=Promise.resolve();return{schedule(){writeQueue=writeQueue.then(async()=>{try{await writeBackgroundRunRecord(pmRoot,record)}catch{}})},async flush(){await writeQueue}}}function requestChildSignal(child,signal){try{child.kill(signal)}catch{}}async function requestBackgroundWorkerStop(record,child,state,scheduleRecordWrite){state.stopRequested||(state.stopRequested=!0,record.stop_requested_at=nowIso(),record.progress={...record.progress,phase:"stopping",message:"Stop requested for background run.",heartbeat_at:nowIso()},scheduleRecordWrite(),requestChildSignal(child,"SIGTERM"),setTimeout(()=>requestChildSignal(child,"SIGKILL"),resolvePositiveEnvInteger("PM_BACKGROUND_RUN_FORCE_KILL_DELAY_MS",DEFAULT_BACKGROUND_RUN_FORCE_KILL_DELAY_MS)).unref?.())}function buildItemBackgroundProgress(line,progressPatch,phase){return{phase,message:line,heartbeat_at:nowIso(),item_index:progressPatch.item_index,item_total:progressPatch.item_total,item_id:progressPatch.item_id,linked_test_index:void 0,linked_test_total:void 0,current_command:void 0,elapsed_ms:void 0}}function buildLinkedTestBackgroundProgress(line,record,progressPatch,phase){return{phase,message:line,heartbeat_at:nowIso(),item_index:progressPatch.item_index??record.progress?.item_index,item_total:progressPatch.item_total??record.progress?.item_total,item_id:progressPatch.item_id??record.progress?.item_id,linked_test_index:progressPatch.linked_test_index,linked_test_total:progressPatch.linked_test_total,current_command:progressPatch.current_command,elapsed_ms:progressPatch.elapsed_ms}}function applyBackgroundWorkerProgressLine(record,line,stopRequested){const progressPatch=parseProgressLine(line);if(!progressPatch)return!1;const phase=record.progress?.phase==="stopping"?"stopping":"running";return record.progress=progressPatch.item_id?buildItemBackgroundProgress(line,progressPatch,phase):buildLinkedTestBackgroundProgress(line,record,progressPatch,phase),progressPatch.phase==="finished"&&!stopRequested&&(record.progress.phase="running"),!0}function parseBackgroundWorkerStdout(stdoutBuffer){if(stdoutBuffer.trim().length===0)return null;try{return JSON.parse(stdoutBuffer)}catch{return null}}function resolveBackgroundWorkerFinalStatus(record,stopRequested){return stopRequested?"stopped":record.exit_code===0&&(record.summary?.failed??0)===0&&record.summary?.fail_on_skipped_triggered!==!0?"passed":"failed"}function buildFinishedBackgroundProgress(record,stopRequested){return{phase:"finished",message:stopRequested?"Background run stopped.":`Background run finished with status=${record.status}.`,heartbeat_at:nowIso(),item_index:record.progress?.item_index,item_total:record.progress?.item_total,item_id:record.progress?.item_id,linked_test_index:record.progress?.linked_test_index,linked_test_total:record.progress?.linked_test_total,current_command:record.progress?.current_command,elapsed_ms:record.progress?.elapsed_ms}}async function writeBackgroundWorkerResult(record,parsedResult,stdoutBuffer){if(parsedResult!==null){await writeFileAtomic(record.result_path,`${JSON.stringify(parsedResult,null,2)}
|
|
3
3
|
`);return}await writeFileAtomic(record.result_path,`${JSON.stringify({parse_error:"Background run output was not valid JSON.",stdout_excerpt:tailLines(stdoutBuffer,DEFAULT_BACKGROUND_RUN_LOG_TAIL_LINES)},null,2)}
|
|
4
|
-
`)}async function runBackgroundTestRunWorker(pmRoot,runId,noExtensions
|
|
4
|
+
`)}async function runBackgroundTestRunWorker(pmRoot,runId,noExtensions=!1){const loaded=await readBackgroundTestRunRecord(pmRoot,runId);if(!loaded)throw new PmCliError(`Background test run ${runId} not found`,EXIT_CODE.NOT_FOUND);const record={...loaded,status:"running",started_at:loaded.started_at??nowIso(),worker_pid:process.pid,progress:{phase:"running",message:"Worker started.",heartbeat_at:nowIso()}},cliEntry=await resolveBackgroundCliEntry(process.cwd()),env=buildBackgroundWorkerEnv(record);await writeBackgroundRunRecord(pmRoot,record);const childArgs=buildBackgroundWorkerChildArgs(record,noExtensions),child=spawn(process.execPath,[cliEntry,...childArgs],{cwd:process.cwd(),env,detached:!1,stdio:["ignore","pipe","pipe"],windowsHide:!0});record.child_pid=child.pid;const recordWriteScheduler=createBackgroundRunRecordWriteScheduler(pmRoot,record),scheduleRecordWrite=recordWriteScheduler.schedule;let stdoutWriteQueue=Promise.resolve(),stderrWriteQueue=Promise.resolve(),stdoutBuffer="",stderrBuffer="";const stopState={stopRequested:!1},onSignal=()=>{requestBackgroundWorkerStop(record,child,stopState,scheduleRecordWrite)};process.on("SIGTERM",onSignal),process.on("SIGINT",onSignal);const resourceTimer=setInterval(()=>{(async()=>(record.resource=await buildResourceSnapshot(record),record.progress.heartbeat_at=nowIso(),scheduleRecordWrite()))()},resolvePositiveEnvInteger("PM_BACKGROUND_RUN_RESOURCE_INTERVAL_MS",DEFAULT_BACKGROUND_RUN_RESOURCE_SNAPSHOT_INTERVAL_MS));resourceTimer.unref?.(),child.stdout?.on("data",chunk=>{const text=chunk.toString("utf8");stdoutBuffer+=text,stdoutWriteQueue=appendFileOrdered(stdoutWriteQueue,record.stdout_path,text)}),child.stderr?.on("data",chunk=>{const text=chunk.toString("utf8");stderrWriteQueue=appendFileOrdered(stderrWriteQueue,record.stderr_path,text),stderrBuffer+=text;const parts=stderrBuffer.split(/\r?\n/);stderrBuffer=parts.pop();let progressChanged=!1;for(const part of parts){const line=part.trimEnd();line.length>0&&applyBackgroundWorkerProgressLine(record,line,stopState.stopRequested)&&(progressChanged=!0)}progressChanged&&scheduleRecordWrite()});let exitCode=null,signal=null;try{({code:exitCode,signal}=await new Promise(resolve=>{child.on("close",(code,closeSignal)=>{resolve({code,signal:closeSignal})})}))}finally{clearInterval(resourceTimer),process.off("SIGTERM",onSignal),process.off("SIGINT",onSignal)}await stdoutWriteQueue,await stderrWriteQueue;const trailingStderrLine=stderrBuffer.trimEnd();trailingStderrLine.length>0&&applyBackgroundWorkerProgressLine(record,trailingStderrLine,stopState.stopRequested)&&scheduleRecordWrite(),stderrBuffer="";const parsedResult=parseBackgroundWorkerStdout(stdoutBuffer),evaluated=evaluateWorkerResult(record.kind,parsedResult);return record.summary=evaluated.summary,record.exit_code=typeof exitCode=="number"?exitCode:void 0,record.signal=signal??void 0,record.finished_at=nowIso(),record.status=resolveBackgroundWorkerFinalStatus(record,stopState.stopRequested),record.progress=buildFinishedBackgroundProgress(record,stopState.stopRequested),record.resource=await buildResourceSnapshot(record),await writeBackgroundWorkerResult(record,parsedResult,stdoutBuffer),await writeBackgroundRunRecord(pmRoot,record),await recordWriteScheduler.flush(),record}async function listBackgroundTestRuns(pmRoot,options){const recordPaths=await listBackgroundRunRecordPaths(pmRoot),runs=[];for(const recordPath of recordPaths){const raw=await readFileIfExists(recordPath);if(!raw)continue;const parsed=await parseBackgroundRunRecord(raw,recordPath);runs.push(parsed)}const refreshed=[];for(const run of runs)refreshed.push(await refreshRunIfStale(pmRoot,run));const sorted=(options.status?refreshed.filter(entry=>entry.status===options.status):refreshed).sort((left,right)=>{const byUpdated=Date.parse(right.updated_at)-Date.parse(left.updated_at);return Number.isFinite(byUpdated)&&byUpdated!==0?byUpdated:right.id.localeCompare(left.id)}),limit=typeof options.limit=="number"&&options.limit>=0?options.limit:void 0;return limit===void 0?sorted:sorted.slice(0,limit)}async function getBackgroundTestRunStatus(pmRoot,runId){const loaded=await readBackgroundTestRunRecord(pmRoot,runId);if(!loaded)throw new PmCliError(`Background test run ${runId} not found`,EXIT_CODE.NOT_FOUND);const refreshed=await refreshRunIfStale(pmRoot,loaded),workerAlive=isPidRunning(refreshed.worker_pid),childAlive=isPidRunning(refreshed.child_pid);refreshed.status==="running"&&!childAlive&&!refreshed.finished_at&&!workerAlive&&(refreshed.status="failed",refreshed.finished_at=nowIso(),refreshed.error=refreshed.error??"Background run process exited unexpectedly.",await writeBackgroundRunRecord(pmRoot,refreshed)),refreshed.status==="running"&&(refreshed.resource=await buildResourceSnapshot(refreshed),await writeBackgroundRunRecord(pmRoot,refreshed));const heartbeatAt=refreshed.progress?.heartbeat_at,heartbeatAtMs=heartbeatAt?Date.parse(heartbeatAt):Number.NaN,lagMs=Number.isFinite(heartbeatAtMs)?Math.max(0,nowMs()-heartbeatAtMs):void 0,staleMs=Number.parseInt(process.env.PM_BACKGROUND_RUN_HEARTBEAT_STALE_MS??"",10),staleThresholdMs=Number.isFinite(staleMs)&&staleMs>0?staleMs:DEFAULT_BACKGROUND_RUN_HEARTBEAT_STALE_MS,healthState=refreshed.status==="running"?lagMs!==void 0&&lagMs>staleThresholdMs?"stale":"healthy":"inactive";return{run:refreshed,health:{state:healthState,last_heartbeat_at:heartbeatAt,heartbeat_lag_ms:lagMs,worker_alive:workerAlive,child_alive:childAlive}}}function sendBackgroundRunStopSignal(record,force){const signal=force?"SIGKILL":"SIGTERM";if(!isPidRunning(record.worker_pid)||!record.worker_pid)return"none";try{return process.kill(record.worker_pid,signal),signal}catch{return"none"}}function buildStoppingBackgroundProgress(record,signalSent){return{phase:"stopping",message:signalSent==="none"?"Run marked stopped.":`Stop requested via ${signalSent}.`,heartbeat_at:nowIso(),item_index:record.progress?.item_index,item_total:record.progress?.item_total,item_id:record.progress?.item_id,linked_test_index:record.progress?.linked_test_index,linked_test_total:record.progress?.linked_test_total,current_command:record.progress?.current_command,elapsed_ms:record.progress?.elapsed_ms}}async function stopBackgroundTestRun(pmRoot,runId,force=!1){const loaded=await readBackgroundTestRunRecord(pmRoot,runId);if(!loaded)throw new PmCliError(`Background test run ${runId} not found`,EXIT_CODE.NOT_FOUND);const refreshed=await refreshRunIfStale(pmRoot,loaded);if(BACKGROUND_RUN_TERMINAL_STATUSES.has(refreshed.status))return{run:refreshed,signal_sent:"none"};const signalSent=sendBackgroundRunStopSignal(refreshed,force);return signalSent==="none"&&(refreshed.status="stopped",refreshed.finished_at=refreshed.finished_at??nowIso()),refreshed.stop_requested_at=nowIso(),refreshed.progress=buildStoppingBackgroundProgress(refreshed,signalSent),await writeBackgroundRunRecord(pmRoot,refreshed),{run:refreshed,signal_sent:signalSent}}async function resumeBackgroundTestRun(pmRoot,runId,requestedBy,noExtensions=!1){const loaded=await readBackgroundTestRunRecord(pmRoot,runId);if(!loaded)throw new PmCliError(`Background test run ${runId} not found`,EXIT_CODE.NOT_FOUND);const refreshed=await refreshRunIfStale(pmRoot,loaded);if(!BACKGROUND_RUN_TERMINAL_STATUSES.has(refreshed.status))throw new PmCliError(`Background test run ${runId} is not terminal and cannot be resumed.`,EXIT_CODE.CONFLICT);const started=await startBackgroundTestRun({pmRoot:refreshed.pm_root,globalPmRoot:refreshed.global_pm_root,kind:refreshed.kind,commandArgs:refreshed.command_args,requestedBy,targetId:refreshed.target_id,statusFilter:refreshed.status_filter,resumedFrom:refreshed.id,resumedBy:requestedBy,attempt:refreshed.attempt+1});if(!started.started)return started.run;const spawned=await spawnBackgroundTestRunWorker({pmRoot,runId:started.run.id,noExtensions}),prior={...refreshed,resumed_by:spawned.id};return await writeBackgroundRunRecord(pmRoot,prior),spawned}async function readBackgroundTestRunLogs(pmRoot,runId,stream,tail){const loaded=await readBackgroundTestRunRecord(pmRoot,runId);if(!loaded)throw new PmCliError(`Background test run ${runId} not found`,EXIT_CODE.NOT_FOUND);const resolvedTail=typeof tail=="number"&&Number.isFinite(tail)&&tail>=0?Math.floor(tail):DEFAULT_BACKGROUND_RUN_LOG_TAIL_LINES,stdoutRaw=stream==="stdout"||stream==="both"?await readFileIfExists(loaded.stdout_path)??"":"",stderrRaw=stream==="stderr"||stream==="both"?await readFileIfExists(loaded.stderr_path)??"":"";return{run:loaded,stream,tail:resolvedTail,stdout:stream==="stdout"||stream==="both"?tailLines(stdoutRaw,resolvedTail):[],stderr:stream==="stderr"||stream==="both"?tailLines(stderrRaw,resolvedTail):[]}}const _testOnly={buildResourceSnapshot,evaluateWorkerResult,isPidRunning,parseLinuxCpuStat,parseLinuxRssStatus,parseProgressLine,readLinuxCpuSeconds,readLinuxRssBytes,refreshRunIfStale,splitLines,tailLines};export{_testOnly,buildBackgroundTestRunFingerprint,getBackgroundTestRunStatus,listBackgroundTestRuns,readBackgroundTestRunLogs,readBackgroundTestRunRecord,resumeBackgroundTestRun,runBackgroundTestRunWorker,spawnBackgroundTestRunWorker,startBackgroundTestRun,stopBackgroundTestRun};
|
|
5
5
|
//# sourceMappingURL=background-runs.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="b74444c7-c283-52b2-b65f-b0a086ff2b53")}catch{}})();import{mutateItem}from"../store/item-store.js";import{compareTimestampStrings}from"../shared/time.js";const DEFAULT_TRACKED_TEST_RUN_HISTORY_LIMIT=20;function trackedTestRunHistoryLimit(){const raw=process.env.PM_TRACKED_TEST_RUN_HISTORY_LIMIT;if(!raw||raw.trim().length===0)return DEFAULT_TRACKED_TEST_RUN_HISTORY_LIMIT;const parsed=Number.parseInt(raw,10);return!Number.isFinite(parsed)||parsed<=0?DEFAULT_TRACKED_TEST_RUN_HISTORY_LIMIT:parsed}function buildTrackedTestRunHistory(entries){const normalized=[...entries].filter(entry=>entry.run_id.trim().length>0&&entry.started_at.trim().length>0&&entry.finished_at.trim().length>0&&entry.recorded_at.trim().length>0).sort((left,right)=>{const byRecorded=compareTimestampStrings(left.recorded_at,right.recorded_at);if(byRecorded!==0)return byRecorded;const byRunId=left.run_id.localeCompare(right.run_id);return byRunId!==0?byRunId:left.kind.localeCompare(right.kind)}),historyLimit=trackedTestRunHistoryLimit();return normalized.length>historyLimit?normalized.slice(normalized.length-historyLimit):normalized}async function appendTrackedTestRunSummary(options){await mutateItem({pmRoot:options.pmRoot,settings:options.settings,id:options.itemId,op:"test_run_track",author:options.author,message:options.message,force:!1,mutate(document){const current=document.metadata.test_runs??[];return document.metadata.test_runs=buildTrackedTestRunHistory([...current,options.entry]),{changedFields:["test_runs"]}}})}export{appendTrackedTestRunSummary,buildTrackedTestRunHistory};
|
|
2
2
|
//# sourceMappingURL=item-test-run-tracking.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="2661c74e-3e73-50f5-80a2-f103ff0cf2d4")}catch{}})();import{EXIT_CODE}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";const MAX_SELECTOR_ENTRY_LABEL_LENGTH=100;function parseOnlyIndexValue(raw,optionName="--only-index"){const value=typeof raw=="number"?raw:Number(String(raw).trim());if(!Number.isInteger(value)||value<1)throw new PmCliError(`${optionName} requires a 1-based integer index into the linked-test list (got "${raw}"). Use pm test <id> --list to inspect positions.`,EXIT_CODE.USAGE);return value}function summarizeSelectorEntry(entry){const normalized=(entry.command??entry.path??"<no command>").replaceAll(/\s+/g," ").trim()||"<no command>";return normalized.length<=MAX_SELECTOR_ENTRY_LABEL_LENGTH?normalized:`${normalized.slice(0,MAX_SELECTOR_ENTRY_LABEL_LENGTH-3)}...`}function describeLinkedTestEntries(tests){return tests.map((entry,index)=>`${index+1}. ${summarizeSelectorEntry(entry)}`).join("; ")}function activeSelectorKinds(selector){const kinds=[];return selector.match!==void 0&&kinds.push("match"),selector.onlyIndex!==void 0&&kinds.push("only-index"),selector.onlyLast===!0&&kinds.push("only-last"),kinds}function entryMatchesSubstring(entry,needle){const command=entry.command?.toLowerCase()??"",entryPath=entry.path?.toLowerCase()??"";return command.includes(needle)||entryPath.includes(needle)}function resolveLinkedTestRunSelection(tests,selector){const kinds=activeSelectorKinds(selector);if(kinds.length===0)return{selector:null,requested:null,selected:tests,selected_indexes:tests.map((_,index)=>index+1),selected_count:tests.length,skipped_count:0};if(kinds.length>1)throw new PmCliError(`Combine at most one linked-test selector per run: ${kinds.map(kind2=>`--${kind2}`).join(" and ")} were provided. Pick one of --match, --only-index, --only-last.`,EXIT_CODE.USAGE);const kind=kinds[0];if(tests.length===0)throw new PmCliError(`--${kind} matched no linked tests because this item has none. Add one first with --add, --command, or --add-json.`,EXIT_CODE.USAGE);if(kind==="match"){const needle=selector.match.trim().toLowerCase();if(needle.length===0)throw new PmCliError("--match requires a non-empty substring to match against linked-test command/path values",EXIT_CODE.USAGE);const selectedIndexes=[],selected=[];for(let index=0;index<tests.length;index+=1)entryMatchesSubstring(tests[index],needle)&&(selected.push(tests[index]),selectedIndexes.push(index+1));if(selected.length===0)throw new PmCliError(`--match "${selector.match}" matched none of the ${tests.length} linked test(s). Available entries: ${describeLinkedTestEntries(tests)}`,EXIT_CODE.USAGE);return{selector:"match",requested:selector.match,selected,selected_indexes:selectedIndexes,selected_count:selected.length,skipped_count:tests.length-selected.length}}if(kind==="only-index"){const index=parseOnlyIndexValue(selector.onlyIndex);if(index>tests.length)throw new PmCliError(`--only-index ${index} is out of range: this item has ${tests.length} linked test(s). Available entries: ${describeLinkedTestEntries(tests)}`,EXIT_CODE.USAGE);return{selector:"only-index",requested:String(index),selected:[tests[index-1]],selected_indexes:[index],selected_count:1,skipped_count:tests.length-1}}return{selector:"only-last",requested:"last",selected:[tests[tests.length-1]],selected_indexes:[tests.length],selected_count:1,skipped_count:tests.length-1}}export{describeLinkedTestEntries,parseOnlyIndexValue,resolveLinkedTestRunSelection};
|
|
2
2
|
//# sourceMappingURL=run-selectors.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="de43e8e6-d7ef-53cc-94b0-ccdf1c4f94a3")}catch{}})();const DEFAULT_ESTIMATE_MINUTES_BY_TYPE={Epic:2880,Feature:480,Story:480,Milestone:2880,Task:120,Issue:60,Bug:60,Chore:30,Decision:15,Plan:120},FALLBACK_ESTIMATE_MINUTES=120;function isHonoredMinutes(value){return typeof value=="number"&&Number.isFinite(value)&&value>0}function toLowercasedLookup(source){const lookup=new Map;for(const[key,value]of Object.entries(source))lookup.set(key.toLowerCase(),value);return lookup}const BUILTIN_LOWERCASED_LOOKUP=toLowercasedLookup(DEFAULT_ESTIMATE_MINUTES_BY_TYPE),OVERRIDE_LOOKUP_CACHE=new WeakMap;function lowercasedOverrideLookup(overrides){const cached=OVERRIDE_LOOKUP_CACHE.get(overrides);if(cached)return cached;const lookup=toLowercasedLookup(overrides);return OVERRIDE_LOOKUP_CACHE.set(overrides,lookup),lookup}function resolveEstimateDefaultMinutes(type,overrides){const key=(type??"").trim().toLowerCase();if(key.length===0)return FALLBACK_ESTIMATE_MINUTES;if(overrides){const overrideValue=lowercasedOverrideLookup(overrides).get(key);if(isHonoredMinutes(overrideValue))return Math.floor(overrideValue)}const builtinValue=BUILTIN_LOWERCASED_LOOKUP.get(key);return isHonoredMinutes(builtinValue)?Math.floor(builtinValue):FALLBACK_ESTIMATE_MINUTES}function normalizeEstimateDefaultOverrides(raw){const normalized={};if(raw===null||typeof raw!="object"||Array.isArray(raw))return normalized;for(const[rawKey,rawValue]of Object.entries(raw)){const key=rawKey.trim();key.length===0||!isHonoredMinutes(rawValue)||(normalized[key]=Math.floor(rawValue))}return normalized}export{DEFAULT_ESTIMATE_MINUTES_BY_TYPE,FALLBACK_ESTIMATE_MINUTES,normalizeEstimateDefaultOverrides,resolveEstimateDefaultMinutes};
|
|
2
2
|
//# sourceMappingURL=estimate-defaults.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="8c3bbe6d-dcce-5b1a-8352-1472ab1ed6e2")}catch{}})();import{EXIT_CODE}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{resolveEstimateDefaultMinutes}from"./estimate-defaults.js";const DEFAULT_GRANTED_FIX_SCOPES=["metadata","resolution"],SUPPORTED_FIX_SCOPES=["metadata","resolution","estimates","timestamps","lifecycle"],DEFAULT_RESOLUTION_BACKFILL_VALUE="completed";function quoteForCommand(value){return`"${value.replaceAll("\\","\\\\").replaceAll('"','\\"')}"`}function toMeaningfulValue(value){const trimmed=value?.trim();return trimmed!==void 0&&trimmed.length>0?trimmed:void 0}function planResolutionBackfillFixes(rows){const fixes=[];for(const row of rows){if(!row.missing_fields.includes("resolution"))continue;const value=toMeaningfulValue(row.close_reason)??DEFAULT_RESOLUTION_BACKFILL_VALUE;fixes.push({item_id:row.id,check:"resolution",field:"resolution",kind:"set_resolution",value,command:`pm update ${row.id} --resolution ${quoteForCommand(value)}`,gate:"resolution"})}return fixes}function planCloseReasonBackfillFixes(rows){const fixes=[];for(const row of rows){const value=toMeaningfulValue(row.resolution);value!==void 0&&fixes.push({item_id:row.id,check:"metadata",field:"close_reason",kind:"set_close_reason",value,command:`pm update ${row.id} --close-reason ${quoteForCommand(value)}`,gate:"metadata"})}return fixes}function planEstimateBackfillFixes(rows,overrides){return rows.map(row=>{const minutes=resolveEstimateDefaultMinutes(row.type,overrides);return{item_id:row.id,check:"metadata",field:"estimated_minutes",kind:"set_estimate",value:String(minutes),command:`pm update ${row.id} --estimate ${minutes}`,gate:"estimates"}})}function planTerminalParentFixes(rows){return rows.map(row=>row.grandparent_id!==void 0&&row.grandparent_active===!0?{item_id:row.id,check:"lifecycle",field:"parent",kind:"reparent",parent_id:row.grandparent_id,command:`pm update ${row.id} --parent ${row.grandparent_id}`,gate:"lifecycle"}:{item_id:row.id,check:"lifecycle",field:"parent",kind:"unset_parent",command:`pm update ${row.id} --unset parent`,gate:"lifecycle"})}function planStaleLinkPruneFixes(rows){const fixes=[];for(const row of rows){if(row.classification!=="deleted")continue;const noun=row.link_kind==="files"?"files":"docs";fixes.push({item_id:row.item_id,check:"files",field:row.link_kind,kind:row.link_kind==="files"?"prune_file_link":"prune_doc_link",path:row.path,command:`pm ${noun} ${row.item_id} --remove ${quoteForCommand(row.path)}`})}return fixes}function resolveGrantedFixScopes(rawScopes){const tokens=(rawScopes??[]).flatMap(raw=>raw.split(",")).map(raw=>raw.trim()).filter(raw=>raw.length>0);if(tokens.length===0){if(rawScopes!==void 0&&rawScopes.length>0)throw new PmCliError(`--fix-scope values must not be empty. Supported values: ${SUPPORTED_FIX_SCOPES.join(", ")}.`,EXIT_CODE.USAGE);return new Set(DEFAULT_GRANTED_FIX_SCOPES)}const granted=new Set;for(const raw of tokens){const normalized=raw.toLowerCase().replaceAll("-","_");if(SUPPORTED_FIX_SCOPES.includes(normalized)){granted.add(normalized);continue}throw new PmCliError(`Unknown --fix-scope value "${raw}". Supported values: ${SUPPORTED_FIX_SCOPES.join(", ")}.`,EXIT_CODE.USAGE)}return granted}function partitionFixesByGrant(fixes,granted){const applicable=[],gated=[];for(const fix of fixes)fix.gate!==void 0&&!granted.has(fix.gate)?gated.push(fix):applicable.push(fix);return{applicable,gated}}function toFixOutputRow(fix){return{item_id:fix.item_id,check:fix.check,field:fix.field,command:fix.command,...fix.gate!==void 0?{gate:fix.gate}:{}}}export{DEFAULT_GRANTED_FIX_SCOPES,SUPPORTED_FIX_SCOPES,partitionFixesByGrant,planCloseReasonBackfillFixes,planEstimateBackfillFixes,planResolutionBackfillFixes,planStaleLinkPruneFixes,planTerminalParentFixes,resolveGrantedFixScopes,toFixOutputRow};
|
|
2
2
|
//# sourceMappingURL=fix-planning.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="6f94fb3c-3d6c-5543-a2f0-e12680459e71")}catch{}})();const REMOTE_ARTIFACT_REFERENCE_PATTERN=/^[a-z][a-z0-9+.-]+:\/\//i;function isRemoteLinkedArtifactReference(path){return REMOTE_ARTIFACT_REFERENCE_PATTERN.test(path.trim())}export{isRemoteLinkedArtifactReference};
|
|
2
2
|
//# sourceMappingURL=linked-artifact-reference.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3c32504d-254c-5156-a41f-8ffd8e49107f")}catch{}})();function buildMissingByTypeCounts(occurrences){const countsByType=new Map;for(const occurrence of occurrences){let fieldCounts=countsByType.get(occurrence.item_type);fieldCounts||(fieldCounts=new Map,countsByType.set(occurrence.item_type,fieldCounts)),fieldCounts.set(occurrence.field,(fieldCounts.get(occurrence.field)??0)+1)}const result={};for(const type of[...countsByType.keys()].sort((left,right)=>left.localeCompare(right))){const fieldCounts=countsByType.get(type),fields={};for(const field of[...fieldCounts.keys()].sort((left,right)=>left.localeCompare(right)))fields[field]=fieldCounts.get(field);result[type]=fields}return result}export{buildMissingByTypeCounts};
|
|
2
2
|
//# sourceMappingURL=missing-by-type.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="34d28b31-b098-5ffd-b39b-2e11de150ac1")}catch{}})();function preferClassification(current,next){return current==="malformed"||next==="malformed"?"malformed":current==="moved"||next==="moved"?"moved":"deleted"}function ownerKey(input){return`${input.item_id} ${input.link_kind}`}function buildMissingLinkedPathRows(rows,lookup){const buckets=new Map;for(const row of rows){const bucket=buckets.get(row.path);bucket?(bucket.classification=preferClassification(bucket.classification,row.classification),bucket.owners.set(ownerKey(row),row)):buckets.set(row.path,{classification:row.classification,owners:new Map([[ownerKey(row),row]])})}return[...buckets.entries()].sort(([left],[right])=>left.localeCompare(right)).map(([path,bucket])=>({path,classification:bucket.classification,items:[...bucket.owners.values()].map(owner=>{const metadata=lookup(owner.item_id);return{id:owner.item_id,type:metadata?.type??"Unknown",title:metadata?.title??"",status:metadata?.status??"",field:owner.link_kind}}).sort((leftOwner,rightOwner)=>{const byId=leftOwner.id.localeCompare(rightOwner.id);return byId!==0?byId:leftOwner.field.localeCompare(rightOwner.field)})}))}function escapeTitle(title){return title.replace(/\\/g,"\\\\").replace(/"/g,'\\"')}function summarizeMissingLinkedPathRows(rows){const lines=[];for(const row of rows)for(const owner of row.items)lines.push(`${row.path}:${row.classification} owner=${owner.id} status=${owner.status} field=${owner.field} title="${escapeTitle(owner.title)}"`);return lines}export{buildMissingLinkedPathRows,summarizeMissingLinkedPathRows};
|
|
2
2
|
//# sourceMappingURL=missing-link-owners.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c577e41b-6642-554a-bc4d-0c22170c1e24")}catch{}})();const DEFAULT_STALE_PATH_CANDIDATE_LIMIT=3;function basenameOf(relativePath){const lastSlash=Math.max(relativePath.lastIndexOf("/"),relativePath.lastIndexOf("\\"));return lastSlash===-1?relativePath:relativePath.slice(lastSlash+1)}function classifyStaleLinkedPaths(stalePaths,candidateFiles,candidateLimit=3){const limit=Number.isFinite(candidateLimit)&&candidateLimit>=1?Math.floor(candidateLimit):3,candidatesByBasename=new Map;for(const candidate of candidateFiles){const basename=basenameOf(candidate);if(basename.length===0)continue;const bucket=candidatesByBasename.get(basename);bucket?bucket.push(candidate):candidatesByBasename.set(basename,[candidate])}return stalePaths.map(stalePath=>{if(stalePath.includes(",")||stalePath.replace(/^[a-z]:[\\/]/i,"").includes(":"))return{path:stalePath,classification:"malformed",candidates:[],candidates_truncated:!1};const matches=(candidatesByBasename.get(basenameOf(stalePath))??[]).filter(candidate=>candidate!==stalePath).sort((left,right)=>left.localeCompare(right));return matches.length===0?{path:stalePath,classification:"deleted",candidates:[],candidates_truncated:!1}:{path:stalePath,classification:"moved",candidates:matches.slice(0,limit),candidates_truncated:matches.length>limit}})}function summarizeStaleLinkedPathClassifications(classified){return classified.map(entry=>entry.classification==="moved"?`${entry.path}:moved:${entry.candidates[0]}`:`${entry.path}:${entry.classification}`)}export{DEFAULT_STALE_PATH_CANDIDATE_LIMIT,classifyStaleLinkedPaths,summarizeStaleLinkedPathClassifications};
|
|
2
2
|
//# sourceMappingURL=stale-file-classification.js.map
|