@unbrained/pm-cli 2026.9.7 → 2026.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/pm-developer/SKILL.md +12 -4
- package/.agents/skills/pm-developer/references/MULTI_AGENT_MERGE.md +19 -10
- package/.agents/skills/pm-extensions/SKILL.md +6 -0
- package/.agents/skills/pm-sdk/SKILL.md +11 -2
- package/.agents/skills/pm-user/SKILL.md +5 -0
- package/.agents/skills/pm-user/references/ECOSYSTEM_PLANNING.md +95 -0
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +211 -181
- package/dist/cli/after-command-context-usage.js +1 -48
- package/dist/cli/argv-utils.js +1 -40
- package/dist/cli/bootstrap-args.js +1 -9
- package/dist/cli/bundle-integrity.js +2 -110
- package/dist/cli/commander-usage.js +11 -771
- package/dist/cli/commands/activity.js +1 -9
- package/dist/cli/commands/aggregate.js +1 -5
- package/dist/cli/commands/append.js +1 -5
- package/dist/cli/commands/claim.js +1 -5
- package/dist/cli/commands/close-many.js +1 -5
- package/dist/cli/commands/close.js +1 -9
- package/dist/cli/commands/comments.js +1 -5
- package/dist/cli/commands/config.js +1 -9
- package/dist/cli/commands/context.js +1 -9
- package/dist/cli/commands/contracts.js +1 -5
- package/dist/cli/commands/copy.js +1 -9
- package/dist/cli/commands/create.js +1 -9
- package/dist/cli/commands/delete.js +1 -9
- package/dist/cli/commands/deps.js +1 -9
- package/dist/cli/commands/docs.js +1 -9
- package/dist/cli/commands/duplicates.js +1 -9
- package/dist/cli/commands/eval.js +1 -9
- package/dist/cli/commands/extension/describe.js +1 -5
- package/dist/cli/commands/extension/scaffold.js +1 -5
- package/dist/cli/commands/extension/shared.js +1 -5
- package/dist/cli/commands/extension.js +1 -9
- package/dist/cli/commands/files.js +1 -9
- package/dist/cli/commands/focus.js +1 -9
- package/dist/cli/commands/gc.js +1 -9
- package/dist/cli/commands/get.js +1 -9
- package/dist/cli/commands/graph.js +1 -10
- package/dist/cli/commands/health.js +1 -9
- package/dist/cli/commands/history-compact.js +1 -10
- package/dist/cli/commands/history-redact.js +1 -11
- package/dist/cli/commands/history-repair.js +1 -10
- package/dist/cli/commands/history.js +1 -5
- package/dist/cli/commands/index.js +1 -58
- package/dist/cli/commands/init-agent-guidance.js +1 -9
- package/dist/cli/commands/init.js +1 -9
- package/dist/cli/commands/learnings.js +1 -5
- package/dist/cli/commands/lifecycle-transitions.js +1 -5
- package/dist/cli/commands/list.js +1 -9
- package/dist/cli/commands/merge.js +1 -11
- package/dist/cli/commands/next.js +1 -9
- package/dist/cli/commands/notes.js +1 -5
- package/dist/cli/commands/plan.js +1 -9
- package/dist/cli/commands/profile.js +1 -9
- package/dist/cli/commands/restore.js +1 -9
- package/dist/cli/commands/scheduling-shortcuts.js +1 -9
- package/dist/cli/commands/schema.js +1 -10
- package/dist/cli/commands/search.js +1 -9
- package/dist/cli/commands/stats.js +1 -9
- package/dist/cli/commands/telemetry.js +1 -9
- package/dist/cli/commands/test-all.js +1 -9
- package/dist/cli/commands/test-runs.js +1 -9
- package/dist/cli/commands/test.js +1 -9
- package/dist/cli/commands/update-many.js +1 -5
- package/dist/cli/commands/update.js +1 -9
- package/dist/cli/commands/upgrade.js +1 -5
- package/dist/cli/commands/validate.js +1 -15
- package/dist/cli/context-intent-invocation.js +1 -20
- package/dist/cli/description-stdin.js +1 -17
- package/dist/cli/error-guidance.js +1 -1353
- package/dist/cli/extension-command-help.js +5 -636
- package/dist/cli/extension-command-options.js +1 -427
- package/dist/cli/extension-recovery.js +1 -126
- package/dist/cli/help-content.js +2 -1001
- package/dist/cli/help-json-payload.js +4 -570
- package/dist/cli/main.d.ts +4 -0
- package/dist/cli/main.js +5 -2573
- package/dist/cli/migration-gates.js +1 -289
- package/dist/cli/public.js +1 -20
- package/dist/cli/register-annotations.js +1 -270
- package/dist/cli/register-assurance.js +1 -62
- package/dist/cli/register-files-lookup.js +1 -56
- package/dist/cli/register-history-activity.d.ts +8 -0
- package/dist/cli/register-history-activity.js +2 -0
- package/dist/cli/register-history-author.js +1 -38
- package/dist/cli/register-history-maintenance.d.ts +9 -0
- package/dist/cli/register-history-maintenance.js +2 -0
- package/dist/cli/register-list-query.js +10 -943
- package/dist/cli/register-mutation-options.js +1 -9
- package/dist/cli/register-mutation.js +19 -1893
- package/dist/cli/register-operations.js +1 -920
- package/dist/cli/register-setup.js +1 -716
- package/dist/cli/register-structured-mutation.js +1 -196
- package/dist/cli/registration-helpers.js +1 -5
- package/dist/cli/runtime-compatibility-boundary.js +4 -42
- package/dist/cli/schema-registration-helpers.js +1 -73
- package/dist/cli/search-refresh.js +1 -13
- package/dist/cli/stats-analytics-json.js +1 -68
- package/dist/cli/telemetry-flush.js +1 -10
- package/dist/cli-bundle/bundle-manifest.json +164 -156
- package/dist/cli-bundle/chunks/chunk-3BZZA6A3.js +5 -0
- package/dist/cli-bundle/chunks/chunk-AMRDVX36.js +235 -0
- package/dist/cli-bundle/chunks/chunk-DAM4CBBR.js +2202 -0
- package/dist/cli-bundle/chunks/{chunk-WYRZZ5ZE.js → chunk-DEZPZOQ7.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-FLDWYEND.js +77 -0
- package/dist/cli-bundle/chunks/{chunk-NPN5I67J.js → chunk-G5ADGQ2D.js} +3 -3
- package/dist/cli-bundle/chunks/chunk-JAAEYHUA.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-JX4DH4WC.js → chunk-KR3RP4FH.js} +3 -3
- package/dist/cli-bundle/chunks/chunk-LEZOUXG6.js +2 -0
- package/dist/cli-bundle/chunks/chunk-NSAPNEYH.js +2 -0
- package/dist/cli-bundle/chunks/chunk-QOEKOECV.js +29 -0
- package/dist/cli-bundle/chunks/chunk-RHSFOMHU.js +2 -0
- package/dist/cli-bundle/chunks/chunk-XOD2PCB6.js +20 -0
- package/dist/cli-bundle/chunks/{chunk-JT6XF6GE.js → chunk-YVEQ2AMO.js} +4 -4
- package/dist/cli-bundle/chunks/register-list-query-KSK3R63M.js +11 -0
- package/dist/cli-bundle/chunks/register-mutation-IQ5C7U6O.js +20 -0
- package/dist/cli-bundle/chunks/{register-operations-I5W3KMGB.js → register-operations-DWVHR2NC.js} +2 -2
- package/dist/cli-bundle/chunks/register-setup-BQ5SVD4B.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-3WRPWLA7.js +3 -0
- package/dist/cli-bundle/focused-chunks/chunk-7MBUII7U.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-COPBO5HW.js +8 -0
- package/dist/cli-bundle/focused-chunks/chunk-DUN4IXYN.js +20 -0
- package/dist/cli-bundle/focused-chunks/{chunk-LIJIA4TY.js → chunk-EE5QSM4Z.js} +3 -3
- package/dist/cli-bundle/focused-chunks/chunk-HJVARYM3.js +6 -0
- package/dist/cli-bundle/focused-chunks/chunk-IAUOUGVR.js +177 -0
- package/dist/cli-bundle/focused-chunks/chunk-KOOMJ54F.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-MZDXX7JY.js +56 -0
- package/dist/cli-bundle/focused-chunks/{chunk-M6PBRFSH.js → chunk-OPFHFGDD.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-QHNETP77.js +9 -0
- package/dist/cli-bundle/focused-chunks/{chunk-3BZEOXLT.js → chunk-RMWES4M6.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-RXT4P5QH.js +10 -0
- package/dist/cli-bundle/focused-chunks/chunk-SDOL6FM2.js +12 -0
- package/dist/cli-bundle/focused-chunks/chunk-SQV4AAUC.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-PEFABF7E.js → chunk-WE3IUNIW.js} +3 -3
- package/dist/cli-bundle/focused-chunks/chunk-YALOUBWJ.js +2 -0
- package/dist/cli-bundle/main.js +20 -20
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +2 -2
- package/dist/cli-bundle/sdk-core.js +29 -29
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +42 -42
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +11 -11
- package/dist/cli.js +1 -104
- package/dist/core/checkpoint/checkpoint-gc.js +1 -169
- package/dist/core/checkpoint/mutation-checkpoint.js +2 -133
- package/dist/core/config/nested-settings.js +1 -534
- package/dist/core/config/positional-value.js +1 -109
- package/dist/core/diagnostics/remediation.js +1 -506
- package/dist/core/extensions/activation-summary-markdown.js +2 -145
- package/dist/core/extensions/activation-summary.js +1 -92
- package/dist/core/extensions/activation-transaction.js +1 -46
- package/dist/core/extensions/capability-usage.js +1 -173
- package/dist/core/extensions/command-hook-context.js +1 -13
- package/dist/core/extensions/command-metadata-contract.js +1 -22
- package/dist/core/extensions/command-visibility-tier.js +1 -29
- package/dist/core/extensions/contribution-inventory.js +1 -173
- package/dist/core/extensions/exporter-output-contract.js +1 -66
- package/dist/core/extensions/extension-candidate.js +1 -18
- package/dist/core/extensions/extension-capability-aliases.js +1 -158
- package/dist/core/extensions/extension-hook-runtime.js +1 -699
- package/dist/core/extensions/extension-policy.js +1 -599
- package/dist/core/extensions/extension-registries.js +1 -62
- package/dist/core/extensions/extension-runtime-helpers.js +1 -33
- package/dist/core/extensions/extension-types.js +1 -102
- package/dist/core/extensions/flag-definition-validation.js +1 -52
- package/dist/core/extensions/flag-value-types.js +1 -64
- package/dist/core/extensions/index.js +1 -526
- package/dist/core/extensions/item-field-types.js +1 -39
- package/dist/core/extensions/item-fields.js +1 -261
- package/dist/core/extensions/loader.js +1 -2223
- package/dist/core/extensions/manifest-schema.js +1 -69
- package/dist/core/extensions/module-graph-snapshot.js +1 -33
- package/dist/core/extensions/preflight-ownership.js +1 -41
- package/dist/core/extensions/registration-validation.js +1 -82
- package/dist/core/extensions/registration-values.js +1 -209
- package/dist/core/extensions/reserved-host-flags.js +1 -36
- package/dist/core/extensions/runtime-registrations.js +1 -67
- package/dist/core/extensions/service-ownership.js +1 -19
- package/dist/core/extensions/version-compat.js +1 -216
- package/dist/core/fs/fs-utils.js +2 -158
- package/dist/core/fs/host-environment-errors.js +1 -141
- package/dist/core/fs/index.js +1 -9
- package/dist/core/fs/path-utils.js +1 -17
- package/dist/core/governance/content-fields.js +1 -160
- package/dist/core/governance/issue-codes.js +1 -151
- package/dist/core/governance/metadata-coverage.js +1 -358
- package/dist/core/history/drift-cache.js +3 -72
- package/dist/core/history/drift-scan.js +1 -342
- package/dist/core/history/event-classification.js +1 -109
- package/dist/core/history/event-index.js +8 -784
- package/dist/core/history/history-compact-bulk.js +1 -104
- package/dist/core/history/history-diff.js +1 -158
- package/dist/core/history/history-rewrite.d.ts +6 -1
- package/dist/core/history/history-rewrite.js +1 -107
- package/dist/core/history/history-storage-stats.js +1 -102
- package/dist/core/history/history-stream-policy.js +1 -62
- package/dist/core/history/history.js +2 -617
- package/dist/core/history/identity.js +1 -30
- package/dist/core/history/index.js +1 -9
- package/dist/core/history/projection.js +1 -196
- package/dist/core/history/read.d.ts +9 -0
- package/dist/core/history/read.js +1 -57
- package/dist/core/history/replay.js +2 -439
- package/dist/core/history/version-address.js +1 -32
- package/dist/core/history/workspace-history.js +2 -433
- package/dist/core/io/body-file.js +1 -62
- package/dist/core/io/bulk-ids-input.js +1 -112
- package/dist/core/item/actionability.js +1 -327
- package/dist/core/item/dependency-reference.js +1 -20
- package/dist/core/item/id.js +1 -112
- package/dist/core/item/index.js +1 -12
- package/dist/core/item/item-format-version.js +1 -78
- package/dist/core/item/item-format.js +5 -1473
- package/dist/core/item/item-record.js +1 -23
- package/dist/core/item/item-type-definition.js +1 -133
- package/dist/core/item/parent-reference-policy.js +1 -57
- package/dist/core/item/parse.js +2 -603
- package/dist/core/item/plan-lifecycle.js +1 -19
- package/dist/core/item/priority.js +1 -61
- package/dist/core/item/sprint-release-format.js +1 -38
- package/dist/core/item/status-filter.js +1 -115
- package/dist/core/item/status.js +1 -43
- package/dist/core/item/toon-decode.js +1 -29
- package/dist/core/item/type-registry.js +1 -715
- package/dist/core/item/type-synonyms.js +1 -38
- package/dist/core/lock/index.js +1 -9
- package/dist/core/lock/lock-gc.js +1 -240
- package/dist/core/lock/lock.js +3 -590
- package/dist/core/output/mutation-projection.js +1 -217
- package/dist/core/output/output-control.js +1 -25
- package/dist/core/output/output.js +11 -494
- package/dist/core/output/query-summary.js +1 -58
- package/dist/core/output/tabular.js +1 -77
- package/dist/core/packages/manifest.js +1 -244
- package/dist/core/packages/root.js +1 -84
- package/dist/core/profile/profile-describe.js +1 -83
- package/dist/core/profile/profile-lint.js +1 -415
- package/dist/core/profile/profile-plan.js +0 -0
- package/dist/core/profile/profile-presets.js +1 -370
- package/dist/core/reproducibility/context.js +1 -82
- package/dist/core/schema/fields-file.js +2 -288
- package/dist/core/schema/item-types-file.js +2 -296
- package/dist/core/schema/runtime-field-filters.js +1 -49
- package/dist/core/schema/runtime-field-values.js +1 -313
- package/dist/core/schema/runtime-schema.js +2 -826
- package/dist/core/schema/status-defs-file.js +2 -227
- package/dist/core/schema/status-token.js +1 -31
- package/dist/core/schema/type-inference.js +1 -95
- package/dist/core/schema/type-presets.js +1 -87
- package/dist/core/schema/type-workflows.js +1 -104
- package/dist/core/search/background-refresh.js +2 -286
- package/dist/core/search/bm25.js +1 -146
- package/dist/core/search/cache.js +2 -534
- package/dist/core/search/corpus.js +1 -311
- package/dist/core/search/embedding-batches.js +1 -163
- package/dist/core/search/eval.js +1 -225
- package/dist/core/search/http-client.js +1 -75
- package/dist/core/search/providers.js +1 -242
- package/dist/core/search/relevance.js +1 -244
- package/dist/core/search/semantic-defaults.js +1 -199
- package/dist/core/search/staleness.js +1 -30
- package/dist/core/search/vector-stores.js +2 -664
- package/dist/core/search/vectorization-metadata.js +1 -81
- package/dist/core/sentry/helpers.js +1 -272
- package/dist/core/sentry/instrument.js +1 -387
- package/dist/core/session/session-state.js +1 -260
- package/dist/core/shared/agent-session-context.js +1 -133
- package/dist/core/shared/author.js +1 -1172
- package/dist/core/shared/command-types.js +1 -4
- package/dist/core/shared/conflict-markers.js +1 -31
- package/dist/core/shared/constants.js +1 -405
- package/dist/core/shared/errors.js +1 -20
- package/dist/core/shared/html-entity-decode.js +1 -131
- package/dist/core/shared/index.js +1 -12
- package/dist/core/shared/item-metadata-contract.js +1 -89
- package/dist/core/shared/lazy-module.js +1 -16
- package/dist/core/shared/levenshtein.js +1 -61
- package/dist/core/shared/memo.js +1 -19
- package/dist/core/shared/numeric-parsers.js +1 -20
- package/dist/core/shared/option-alias-visibility.js +1 -67
- package/dist/core/shared/primitives.js +1 -127
- package/dist/core/shared/serial-queue.js +1 -79
- package/dist/core/shared/serialization.js +1 -210
- package/dist/core/shared/split-comma-list.js +1 -30
- package/dist/core/shared/text-normalization.js +1 -38
- package/dist/core/shared/time.js +1 -306
- package/dist/core/store/index.js +1 -12
- package/dist/core/store/item-format-migration.js +1 -125
- package/dist/core/store/item-metadata-cache.js +1 -1116
- package/dist/core/store/item-metadata-query-index.js +9 -394
- package/dist/core/store/item-metadata-read-work.js +1 -43
- package/dist/core/store/item-store.js +1 -693
- package/dist/core/store/paths.d.ts +1 -1
- package/dist/core/store/paths.js +1 -214
- package/dist/core/store/settings-read-cache.js +1 -85
- package/dist/core/store/settings-validator.js +1 -421
- package/dist/core/store/settings.js +3 -1309
- package/dist/core/store/tracker-preflight.js +1 -141
- package/dist/core/telemetry/consent.js +5 -108
- package/dist/core/telemetry/observability.js +1 -246
- package/dist/core/telemetry/runtime.js +4 -1988
- package/dist/core/test/background-runs.js +4 -945
- package/dist/core/test/item-test-run-tracking.js +1 -63
- package/dist/core/test/run-selectors.js +1 -120
- package/dist/core/validate/estimate-defaults.js +1 -89
- package/dist/core/validate/fix-planning.js +1 -189
- package/dist/core/validate/linked-artifact-reference.js +1 -36
- package/dist/core/validate/missing-by-type.js +1 -34
- package/dist/core/validate/missing-link-owners.js +1 -95
- package/dist/core/validate/stale-file-classification.js +1 -82
- package/dist/mcp/http-server.js +5 -448
- package/dist/mcp/legacy-adapter.js +1 -77
- package/dist/mcp/runtime-capabilities.js +1 -200
- package/dist/mcp/server.js +4 -1233
- package/dist/mcp/tool-definitions.js +1 -804
- package/dist/sdk/actionability.js +1 -13
- package/dist/sdk/agent/closed-domain-contracts.js +1 -161
- package/dist/sdk/agent/command-recovery.js +1 -59
- package/dist/sdk/agent/command-suggestions.js +1 -66
- package/dist/sdk/agent/create-option-policy.js +1 -31
- package/dist/sdk/agent/identity-config.js +1 -106
- package/dist/sdk/agent/item-addressing.js +1 -207
- package/dist/sdk/agent/refusal-closure-census.js +1 -151
- package/dist/sdk/agent/refusal-closure.js +1 -133
- package/dist/sdk/agent/refusal-corpus-contracts.js +1 -193
- package/dist/sdk/agent/refusal-reachability.js +1 -593
- package/dist/sdk/agent/subcommand-recovery.js +1 -83
- package/dist/sdk/agent/task-transcript-contracts.js +1 -197
- package/dist/sdk/agent/tracker-preflight-contracts.js +1 -126
- package/dist/sdk/agent-capability-contracts.js +1 -428
- package/dist/sdk/agent-session-context.js +1 -9
- package/dist/sdk/annotations.js +1 -448
- package/dist/sdk/author-attribution.js +1 -468
- package/dist/sdk/authoring.js +1 -20
- package/dist/sdk/cli-bootstrap.js +1 -838
- package/dist/sdk/cli-contracts/agent-output-contracts.d.ts +1 -1
- package/dist/sdk/cli-contracts/agent-output-contracts.js +4 -476
- package/dist/sdk/cli-contracts/bootstrap-command-scanner.js +1 -79
- package/dist/sdk/cli-contracts/command-aliases.d.ts +4 -0
- package/dist/sdk/cli-contracts/command-aliases.js +1 -107
- package/dist/sdk/cli-contracts/command-exit-contracts.js +1 -151
- package/dist/sdk/cli-contracts/commander-mutation-options.js +1 -1081
- package/dist/sdk/cli-contracts/commander-types.js +1 -159
- package/dist/sdk/cli-contracts/completeness.js +1 -393
- package/dist/sdk/cli-contracts/enum-contracts.js +1 -222
- package/dist/sdk/cli-contracts/flag-contracts.js +1 -1947
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +1 -347
- package/dist/sdk/cli-contracts/grammar-contracts.js +1 -986
- package/dist/sdk/cli-contracts/registration-helpers.js +7 -990
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +5 -0
- package/dist/sdk/cli-contracts/runtime-contracts.js +1 -2090
- package/dist/sdk/cli-contracts/schemas/assurance-definition.js +1 -324
- package/dist/sdk/cli-contracts/string-lists.js +1 -16
- package/dist/sdk/cli-contracts/tool-option-contracts.js +1 -461
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +1 -2167
- package/dist/sdk/cli-contracts/tool-schema.d.ts +3 -1
- package/dist/sdk/cli-contracts/tool-schema.js +1 -1664
- package/dist/sdk/cli-contracts/typed-action-inputs.js +1 -4
- package/dist/sdk/cli-contracts.d.ts +1 -1
- package/dist/sdk/cli-contracts.js +1 -17
- package/dist/sdk/cli-program.js +1 -49
- package/dist/sdk/command-line.d.ts +2 -5
- package/dist/sdk/command-line.js +1 -78
- package/dist/sdk/comments.js +1 -133
- package/dist/sdk/compile-cache.js +1 -73
- package/dist/sdk/completion.js +157 -837
- package/dist/sdk/compose.js +1 -1090
- package/dist/sdk/config.js +1 -1204
- package/dist/sdk/context/recency.js +1 -33
- package/dist/sdk/context/semantic-session-attribution.js +1 -82
- package/dist/sdk/context/usage-egress.js +1 -29
- package/dist/sdk/context/usage-ledger.js +3 -185
- package/dist/sdk/context-intent-contracts.js +1 -709
- package/dist/sdk/context-intent-runtime.js +1 -115
- package/dist/sdk/context-packing.js +1 -218
- package/dist/sdk/context-relevance.js +1 -503
- package/dist/sdk/context-signal-store.js +2 -426
- package/dist/sdk/context-usage.js +1 -367
- package/dist/sdk/contracts.js +1 -23
- package/dist/sdk/core-governance.js +1 -14
- package/dist/sdk/core.js +1 -14
- package/dist/sdk/corpus-shape.js +1 -401
- package/dist/sdk/define.js +1 -220
- package/dist/sdk/dependencies.js +1 -718
- package/dist/sdk/dependency-flag-validation.js +1 -156
- package/dist/sdk/dependency-provenance.js +1 -135
- package/dist/sdk/docs.js +1 -14
- package/dist/sdk/duplicates.js +1 -40
- package/dist/sdk/environment/agent-environment.js +1 -466
- package/dist/sdk/environment/host-environment-errors.js +1 -8
- package/dist/sdk/environment/project-runtime-compatibility.js +1 -481
- package/dist/sdk/environment/source-context.js +1 -28
- package/dist/sdk/environment/tracker-preflight.js +1 -9
- package/dist/sdk/error-code-catalog.js +1 -153
- package/dist/sdk/error-runtime.js +1 -58
- package/dist/sdk/errors.js +1 -58
- package/dist/sdk/eval.js +1 -190
- package/dist/sdk/extension/author-manifest.js +1 -92
- package/dist/sdk/extension/bundled-catalog.js +1 -332
- package/dist/sdk/extension/concurrency.js +1 -25
- package/dist/sdk/extension/copy-scope.d.ts +2 -0
- package/dist/sdk/extension/copy-scope.js +2 -0
- package/dist/sdk/extension/custom-field-collisions.js +1 -30
- package/dist/sdk/extension/describe.js +3 -189
- package/dist/sdk/extension/doctor.js +1 -606
- package/dist/sdk/extension/install-plan.d.ts +69 -0
- package/dist/sdk/extension/install-plan.js +2 -0
- package/dist/sdk/extension/install-receipts.d.ts +7 -0
- package/dist/sdk/extension/install-receipts.js +2 -0
- package/dist/sdk/extension/install-runtime.js +3 -313
- package/dist/sdk/extension/install-snapshot.js +1 -66
- package/dist/sdk/extension/install-sources.js +5 -1057
- package/dist/sdk/extension/managed-state.js +2 -252
- package/dist/sdk/extension/migrations.js +2 -174
- package/dist/sdk/extension/output-ownership.js +1 -25
- package/dist/sdk/extension/runtime-summary.js +1 -18
- package/dist/sdk/extension/scaffold.js +4 -2308
- package/dist/sdk/extension/shared.js +1 -147
- package/dist/sdk/extension/source-resolution.js +1 -65
- package/dist/sdk/extension/update-check.js +1 -67
- package/dist/sdk/extension-command-context.js +1 -44
- package/dist/sdk/extension-contracts.js +1 -73
- package/dist/sdk/extension.d.ts +7 -2
- package/dist/sdk/extension.js +1 -2196
- package/dist/sdk/files.js +1 -535
- package/dist/sdk/flag-invocation-contracts.d.ts +0 -5
- package/dist/sdk/flag-invocation-contracts.js +1 -344
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1 -2224
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -2236
- package/dist/sdk/generated-error-code-catalog.js +1 -16
- package/dist/sdk/governance/assurance-action-contracts.js +1 -4
- package/dist/sdk/governance/assurance-action.js +1 -411
- package/dist/sdk/governance/assurance-limits.js +1 -10
- package/dist/sdk/governance/assurance-mutation-error.js +1 -81
- package/dist/sdk/governance/assurance-presets.js +1 -135
- package/dist/sdk/governance/assurance-runtime.js +1 -238
- package/dist/sdk/governance/assurance.js +4 -1182
- package/dist/sdk/governance/boundary-fixtures.js +1 -200
- package/dist/sdk/governance/coverage-assurance.js +1 -60
- package/dist/sdk/governance/defect-recurrence-coverage.js +1 -188
- package/dist/sdk/governance/defect-recurrence-graph.js +1 -120
- package/dist/sdk/governance/defect-recurrence-signals.js +1 -24
- package/dist/sdk/governance/defect-recurrence.js +1 -623
- package/dist/sdk/governance/extension-host-version.js +1 -115
- package/dist/sdk/governance/gc.js +1 -368
- package/dist/sdk/governance/health.js +1 -2367
- package/dist/sdk/governance/hierarchy-validation.js +1 -108
- package/dist/sdk/governance/linked-file-report.js +1 -71
- package/dist/sdk/governance/merge-receipt-history.js +1 -206
- package/dist/sdk/governance/provenance-health.js +1 -282
- package/dist/sdk/governance/reindex.js +4 -761
- package/dist/sdk/governance/stale-work.js +1 -82
- package/dist/sdk/governance/status-role-diagnostics.js +1 -35
- package/dist/sdk/governance/storage-integrity.js +1 -280
- package/dist/sdk/governance/tracked-runtime-cache.js +1 -106
- package/dist/sdk/governance/upgrade.js +2 -327
- package/dist/sdk/governance/validate-history-drift.js +1 -81
- package/dist/sdk/governance/validate-item-reader.js +1 -17
- package/dist/sdk/governance/validate-normalization.js +1 -36
- package/dist/sdk/governance/validate.js +1 -2261
- package/dist/sdk/governance/workspace-position.js +1 -163
- package/dist/sdk/governance.d.ts +1 -0
- package/dist/sdk/governance.js +1 -31
- package/dist/sdk/graph/adapter.js +1 -181
- package/dist/sdk/graph/analytics.js +1 -474
- package/dist/sdk/graph/assembly.js +1 -377
- package/dist/sdk/graph/cache.js +1 -160
- package/dist/sdk/graph/centrality.js +1 -258
- package/dist/sdk/graph/conformance.js +1 -130
- package/dist/sdk/graph/deadline-scheduling.d.ts +90 -0
- package/dist/sdk/graph/deadline-scheduling.js +2 -0
- package/dist/sdk/graph/durable-cache.d.ts +1 -1
- package/dist/sdk/graph/durable-cache.js +1 -361
- package/dist/sdk/graph/governance-contracts.js +1 -34
- package/dist/sdk/graph/governance.d.ts +13 -1
- package/dist/sdk/graph/governance.js +1 -735
- package/dist/sdk/graph/hierarchy-integrity.js +1 -310
- package/dist/sdk/graph/index.d.ts +3 -2
- package/dist/sdk/graph/index.js +1 -26
- package/dist/sdk/graph/lifecycle-coverage.d.ts +32 -0
- package/dist/sdk/graph/lifecycle-coverage.js +2 -0
- package/dist/sdk/graph/mutation-advisory.js +1 -176
- package/dist/sdk/graph/remediation.js +1 -197
- package/dist/sdk/graph/run.d.ts +15 -1
- package/dist/sdk/graph/run.js +1 -768
- package/dist/sdk/graph/scheduling.js +1 -124
- package/dist/sdk/graph/traversal.js +1 -284
- package/dist/sdk/graph/workspace-relationship-kind-registry.js +1 -27
- package/dist/sdk/graph.js +1 -15
- package/dist/sdk/guide-topics.js +1 -707
- package/dist/sdk/guide.js +1 -279
- package/dist/sdk/history/maintenance.d.ts +71 -0
- package/dist/sdk/history/maintenance.js +2 -0
- package/dist/sdk/history/salvage.js +2 -247
- package/dist/sdk/history/subject.d.ts +19 -0
- package/dist/sdk/history/subject.js +2 -0
- package/dist/sdk/history-analytics.js +1 -282
- package/dist/sdk/history-compact.js +1 -527
- package/dist/sdk/history-mcp.js +1 -68
- package/dist/sdk/history-provenance.js +1 -182
- package/dist/sdk/history-read.js +1 -96
- package/dist/sdk/history-redact.d.ts +1 -14
- package/dist/sdk/history-redact.js +1 -643
- package/dist/sdk/history-repair.d.ts +5 -0
- package/dist/sdk/history-repair.js +1 -657
- package/dist/sdk/improvement-ledger-validation.js +1 -62
- package/dist/sdk/improvement-ledger.js +2 -257
- package/dist/sdk/index.d.ts +4 -0
- package/dist/sdk/index.js +1 -183
- package/dist/sdk/init-agent-guidance.js +2 -496
- package/dist/sdk/init.js +2 -820
- package/dist/sdk/invocation-author.js +1 -39
- package/dist/sdk/item-children.js +1 -90
- package/dist/sdk/item-metadata-index.js +1 -15
- package/dist/sdk/item-schedule.js +1 -27
- package/dist/sdk/item-transaction.js +1 -396
- package/dist/sdk/learnings.js +1 -29
- package/dist/sdk/lifecycle/append.js +2 -53
- package/dist/sdk/lifecycle/claim.d.ts +2 -0
- package/dist/sdk/lifecycle/claim.js +1 -242
- package/dist/sdk/lifecycle/close-many.js +1 -438
- package/dist/sdk/lifecycle/close.js +1 -468
- package/dist/sdk/lifecycle/copy.js +1 -212
- package/dist/sdk/lifecycle/create.js +1 -1949
- package/dist/sdk/lifecycle/delete.js +1 -45
- package/dist/sdk/lifecycle/event-validation-messages.js +1 -91
- package/dist/sdk/lifecycle/focus.js +1 -91
- package/dist/sdk/lifecycle/hierarchy-mutation-lock.js +1 -24
- package/dist/sdk/lifecycle/legacy-none-tokens.js +1 -149
- package/dist/sdk/lifecycle/lifecycle-transitions.js +1 -40
- package/dist/sdk/lifecycle/mcp-actions.d.ts +2 -0
- package/dist/sdk/lifecycle/mcp-actions.js +1 -51
- package/dist/sdk/lifecycle/metadata-normalizers.js +1 -46
- package/dist/sdk/lifecycle/mutation-command-options.js +1 -9
- package/dist/sdk/lifecycle/plan.js +1 -1606
- package/dist/sdk/lifecycle/recurrence-parsers.js +1 -147
- package/dist/sdk/lifecycle/reopen.js +1 -68
- package/dist/sdk/lifecycle/repeatable-metadata-parsers.js +1 -143
- package/dist/sdk/lifecycle/restore.d.ts +1 -0
- package/dist/sdk/lifecycle/restore.js +1 -330
- package/dist/sdk/lifecycle/shared-unset-fields.js +1 -295
- package/dist/sdk/lifecycle/update-many.js +1 -861
- package/dist/sdk/lifecycle/update.js +1 -2136
- package/dist/sdk/lifecycle-completion.js +1 -92
- package/dist/sdk/lifecycle-policy.js +1 -120
- package/dist/sdk/linked-artifacts.js +1 -530
- package/dist/sdk/mcp/apps.js +4 -133
- package/dist/sdk/mcp/authorization.js +1 -404
- package/dist/sdk/mcp/discovery.js +1 -494
- package/dist/sdk/mcp/interactions.js +1 -336
- package/dist/sdk/mcp/protocol.d.ts +7 -0
- package/dist/sdk/mcp/protocol.js +1 -184
- package/dist/sdk/mcp/skills.js +1 -389
- package/dist/sdk/mcp/subscriptions.js +1 -211
- package/dist/sdk/mcp/tasks.js +2 -430
- package/dist/sdk/mcp/transport.js +1 -260
- package/dist/sdk/merge/abandoned-receipts.js +1 -46
- package/dist/sdk/merge/driver.js +1 -212
- package/dist/sdk/merge/index.js +1 -16
- package/dist/sdk/merge/install.js +3 -561
- package/dist/sdk/merge/receipt-file-boundary.js +1 -46
- package/dist/sdk/merge/receipt-operation.js +1 -96
- package/dist/sdk/merge/receipt-schema.js +1 -397
- package/dist/sdk/merge/receipts.js +4 -525
- package/dist/sdk/merge/reconcile.js +1 -352
- package/dist/sdk/merge/three-way.js +3 -775
- package/dist/sdk/merge.js +1 -10
- package/dist/sdk/mutation-events.js +1 -292
- package/dist/sdk/mutation-guard.js +1 -216
- package/dist/sdk/notes.js +1 -139
- package/dist/sdk/output-contracts.js +1 -172
- package/dist/sdk/output-projection.js +1 -430
- package/dist/sdk/output-token-accounting.js +1 -140
- package/dist/sdk/output.js +1 -64
- package/dist/sdk/ownership-source.js +1 -21
- package/dist/sdk/package-import-adapters.js +1 -442
- package/dist/sdk/package-migrations.js +1 -20
- package/dist/sdk/package-runtime-options.js +1 -80
- package/dist/sdk/pagination.js +1 -162
- package/dist/sdk/profile.js +1 -454
- package/dist/sdk/provenance.js +1 -258
- package/dist/sdk/public-surface.json +1 -1
- package/dist/sdk/query/activity.js +1 -401
- package/dist/sdk/query/aggregate.d.ts +16 -0
- package/dist/sdk/query/aggregate.js +1 -390
- package/dist/sdk/query/calendar.js +1 -964
- package/dist/sdk/query/complete-list.js +1 -215
- package/dist/sdk/query/context.js +1 -1702
- package/dist/sdk/query/duplicate-candidates.js +1 -70
- package/dist/sdk/query/get.js +1 -450
- package/dist/sdk/query/history.js +1 -186
- package/dist/sdk/query/item-filter-options.js +1 -9
- package/dist/sdk/query/light-metadata.js +1 -18
- package/dist/sdk/query/list-filter-shared.js +1 -81
- package/dist/sdk/query/list.js +1 -1304
- package/dist/sdk/query/multi-value-filters.js +1 -78
- package/dist/sdk/query/next.js +1 -513
- package/dist/sdk/query/parsers.js +1 -44
- package/dist/sdk/query/projection-contracts.js +1 -184
- package/dist/sdk/query/search-contracts.js +1 -230
- package/dist/sdk/query/search-pagination.js +1 -35
- package/dist/sdk/query/search-rendering.js +1 -105
- package/dist/sdk/query/search.js +2 -1987
- package/dist/sdk/query.js +1 -35
- package/dist/sdk/read-output/continuation.js +1 -194
- package/dist/sdk/read-output-budget.js +1 -135
- package/dist/sdk/read-output-contracts.js +1 -1225
- package/dist/sdk/read-output-rows.js +1 -186
- package/dist/sdk/read-output-session.js +1 -208
- package/dist/sdk/relationship-analytics.js +1 -410
- package/dist/sdk/relationship-context.js +1 -284
- package/dist/sdk/relationship-history.js +4 -519
- package/dist/sdk/relationship-kinds/contract.js +1 -22
- package/dist/sdk/relationship-migration.js +1 -77
- package/dist/sdk/relationships.js +1 -579
- package/dist/sdk/reproducibility/process.js +1 -87
- package/dist/sdk/runtime-action-aliases.js +1 -59
- package/dist/sdk/runtime-extended-actions.js +1 -177
- package/dist/sdk/runtime-input.js +1 -614
- package/dist/sdk/runtime-primitives.js +1 -84
- package/dist/sdk/runtime-public-contracts.js +1 -4
- package/dist/sdk/runtime-stats-options.js +1 -38
- package/dist/sdk/runtime.js +1 -1928
- package/dist/sdk/scheduling-shortcuts.js +1 -63
- package/dist/sdk/schema-migration.js +3 -856
- package/dist/sdk/schema.js +1 -1376
- package/dist/sdk/search-refresh-worker.js +1 -18
- package/dist/sdk/similarity-scoring.js +1 -53
- package/dist/sdk/similarity.js +1 -326
- package/dist/sdk/start-task-status.js +1 -14
- package/dist/sdk/stats.js +1 -270
- package/dist/sdk/structured-mutations.js +1 -580
- package/dist/sdk/telemetry-flush.js +1 -13
- package/dist/sdk/telemetry.js +1 -405
- package/dist/sdk/templates.js +2 -292
- package/dist/sdk/test/batch.js +2 -509
- package/dist/sdk/test/entry.js +1 -70
- package/dist/sdk/test/execution.js +6 -2211
- package/dist/sdk/test/linked-command-detection.js +1 -546
- package/dist/sdk/test/measurements.js +1 -91
- package/dist/sdk/test/parsers.js +1 -545
- package/dist/sdk/test/runs.js +1 -193
- package/dist/sdk/test/trust.js +2 -206
- package/dist/sdk/testing.js +4 -1391
- package/dist/sdk/traceability/runtime-files-lookup.js +1 -32
- package/dist/sdk/traceability/source-traceability.js +1 -292
- package/dist/sdk/tracker-root-discovery.js +1 -9
- package/dist/sdk/workspace-contracts-cache.js +1 -28
- package/dist/sdk/workspace-contracts.js +1 -33
- package/dist/sdk/workspace-memory.js +2 -318
- package/dist/sdk/workspace-recipe.js +1 -71
- package/dist/sdk/workspace-snapshot.js +4 -613
- package/dist/sdk/workspace-transaction-gc.js +1 -149
- package/dist/sdk/workspace-transaction.js +2 -363
- package/dist/sdk/workspace.js +3 -127
- package/dist/types/index.js +1 -9
- package/dist/types.js +1 -245
- package/docs/AGENT_GUIDE.md +1 -1
- package/docs/CONTEXT_ALGORITHM_PORTFOLIO.md +167 -0
- package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +9 -3
- package/docs/EXTENSIONS.md +1 -0
- package/docs/HISTORY_MAINTENANCE.md +125 -0
- package/docs/MCP_2026_07_28_CONFORMANCE.md +20 -10
- package/docs/PACKAGE_EVIDENCE.md +92 -0
- package/docs/PLANNING_MEASUREMENTS.md +183 -0
- package/docs/README.md +3 -0
- package/docs/SCRIPTING.md +21 -0
- package/docs/TESTING.md +23 -0
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +5 -5
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +2 -2
- package/marketplace.json +2 -2
- package/package.json +1 -1
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/scripts/finalize-build.mjs +45 -3
- package/dist/cli-bundle/chunks/chunk-AZDFJGH6.js +0 -9
- package/dist/cli-bundle/chunks/chunk-BAX2BYUW.js +0 -2111
- package/dist/cli-bundle/chunks/chunk-CKOL5U7J.js +0 -77
- package/dist/cli-bundle/chunks/chunk-OF76PSDQ.js +0 -5
- package/dist/cli-bundle/chunks/chunk-QUWFABDM.js +0 -232
- package/dist/cli-bundle/chunks/chunk-QWRRFYK3.js +0 -2
- package/dist/cli-bundle/chunks/chunk-RWWBOWJ5.js +0 -2
- package/dist/cli-bundle/chunks/chunk-WGAOYSYH.js +0 -40
- package/dist/cli-bundle/chunks/chunk-WI2AYPA7.js +0 -2
- package/dist/cli-bundle/chunks/register-list-query-5JL52D33.js +0 -11
- package/dist/cli-bundle/chunks/register-mutation-ZPG7KMVP.js +0 -20
- package/dist/cli-bundle/chunks/register-setup-H4SVAVX7.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-AL5ON6K6.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-CHC2IDXA.js +0 -6
- package/dist/cli-bundle/focused-chunks/chunk-CK6QFAPZ.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-EZR3GHFE.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-H2WJWK7L.js +0 -56
- package/dist/cli-bundle/focused-chunks/chunk-NTPY5GSO.js +0 -3
- package/dist/cli-bundle/focused-chunks/chunk-P5O7MP5Y.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-PDMW2E36.js +0 -177
- package/dist/cli-bundle/focused-chunks/chunk-QTVCLMSZ.js +0 -6
- package/dist/cli-bundle/focused-chunks/chunk-QTZRBUYA.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-SGQST3PQ.js +0 -12
- package/dist/cli-bundle/focused-chunks/chunk-UKHASMMP.js +0 -10
- package/dist/cli-bundle/focused-chunks/chunk-ZPEKQHOC.js +0 -2
|
@@ -1,434 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Records singleton workspace documents in the same append-only, hash-chained
|
|
5
|
-
* HistoryEntry format used by item mutations.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="4df21a17-43c0-5b63-adf3-657699e6a058")}catch(e){}}();
|
|
9
|
-
import fs from "node:fs/promises";
|
|
10
|
-
import path from "node:path";
|
|
11
|
-
import { readFileIfExists, writeFileAtomic } from "../fs/fs-utils.js";
|
|
12
|
-
import { acquireLock } from "../lock/lock.js";
|
|
13
|
-
import { EMPTY_CANONICAL_DOCUMENT, EXIT_CODE } from "../shared/constants.js";
|
|
14
|
-
import { PmCliError } from "../shared/errors.js";
|
|
15
|
-
import { stableStringify } from "../shared/serialization.js";
|
|
16
|
-
import { nowIso } from "../shared/time.js";
|
|
17
|
-
import { appendHistoryEntry, createHistoryEntry } from "./history.js";
|
|
18
|
-
import { readHistoryEntries } from "./read.js";
|
|
19
|
-
import { cloneEmptyReplayDocument, replayToItemDocument, tryApplyReplayPatch, verifyHistoryChain, } from "./replay.js";
|
|
20
|
-
/** Synthetic item id used to expose the singleton workspace audit stream. */
|
|
21
|
-
export const WORKSPACE_HISTORY_ID = "_workspace";
|
|
22
|
-
/** Return the canonical workspace history stream path. */
|
|
23
|
-
export function getWorkspaceHistoryPath(pmRoot) {
|
|
24
|
-
return path.join(pmRoot, "history", `${WORKSPACE_HISTORY_ID}.jsonl`);
|
|
25
|
-
}
|
|
26
|
-
function workspaceDocument(documents, timestamp) {
|
|
27
|
-
const metadata = {
|
|
28
|
-
id: WORKSPACE_HISTORY_ID,
|
|
29
|
-
title: "Workspace state",
|
|
30
|
-
description: "Audited singleton workspace document state.",
|
|
31
|
-
type: "Chore",
|
|
32
|
-
status: "open",
|
|
33
|
-
priority: 2,
|
|
34
|
-
tags: ["workspace-history"],
|
|
35
|
-
created_at: timestamp,
|
|
36
|
-
updated_at: timestamp,
|
|
37
|
-
documents,
|
|
38
|
-
};
|
|
39
|
-
return { metadata, body: "" };
|
|
40
|
-
}
|
|
41
|
-
function replayWorkspaceEntries(entries, count = entries.length) {
|
|
42
|
-
let replay = cloneEmptyReplayDocument();
|
|
43
|
-
for (const entry of entries.slice(0, count)) {
|
|
44
|
-
const applied = tryApplyReplayPatch(replay, entry.patch);
|
|
45
|
-
replay = applied.document;
|
|
46
|
-
}
|
|
47
|
-
return replayToItemDocument(replay);
|
|
48
|
-
}
|
|
49
|
-
/** Read the governed document map from one replayed workspace document. */
|
|
50
|
-
function workspaceDocuments(document) {
|
|
51
|
-
return "documents" in document.metadata &&
|
|
52
|
-
typeof document.metadata.documents === "object" &&
|
|
53
|
-
document.metadata.documents !== null &&
|
|
54
|
-
!Array.isArray(document.metadata.documents)
|
|
55
|
-
? document.metadata.documents
|
|
56
|
-
: {};
|
|
57
|
-
}
|
|
58
|
-
/** Refuse a workspace mutation or replay whose append-only chain is invalid. */
|
|
59
|
-
function throwWorkspaceHistoryVerificationFailure(errors) {
|
|
60
|
-
throw new PmCliError(`Workspace history verification failed: ${errors.join(", ")}`, EXIT_CODE.CONFLICT, {
|
|
61
|
-
code: "workspace_history_chain_invalid",
|
|
62
|
-
reason: "workspace_history_chain_verification_failed",
|
|
63
|
-
verification_errors: [...errors],
|
|
64
|
-
required: "Repair the _workspace history chain before reading, reconciling, restoring, or appending audited singleton state.",
|
|
65
|
-
why: "Continuing against an unverifiable append-only stream could hide or compound workspace state corruption.",
|
|
66
|
-
examples: [
|
|
67
|
-
"pm history _workspace --verify --json",
|
|
68
|
-
"pm validate --check-history-drift --fix-hints --json",
|
|
69
|
-
],
|
|
70
|
-
nextSteps: [
|
|
71
|
-
"Inspect the exact verification_errors and preserve the corrupt stream as evidence.",
|
|
72
|
-
"Use the history-drift remediation returned by validate before retrying the refused operation.",
|
|
73
|
-
],
|
|
74
|
-
recovery: {
|
|
75
|
-
recovery_mode: "compact",
|
|
76
|
-
next_best_command: "pm history _workspace --verify --json",
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
/** Resolve a governed singleton path and reject paths outside the tracker root. */
|
|
81
|
-
function resolveGovernedDocumentPath(pmRoot, filePath) {
|
|
82
|
-
const absolutePath = path.resolve(filePath);
|
|
83
|
-
const documentPath = path.relative(pmRoot, absolutePath).replaceAll("\\", "/");
|
|
84
|
-
if (documentPath.length === 0 ||
|
|
85
|
-
documentPath === ".." ||
|
|
86
|
-
documentPath.startsWith("../") ||
|
|
87
|
-
path.isAbsolute(documentPath)) {
|
|
88
|
-
throw new TypeError("Workspace history document path must stay inside the tracker root");
|
|
89
|
-
}
|
|
90
|
-
return { documentPath, absolutePath };
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Compare every singleton represented by the verified workspace stream with
|
|
94
|
-
* its current on-disk JSON. Hash-chain verification proves recorded ordering;
|
|
95
|
-
* this state-agreement check separately proves that every current singleton
|
|
96
|
-
* mutation is represented by that chain.
|
|
97
|
-
*/
|
|
98
|
-
export async function inspectWorkspaceHistoryState(pmRoot) {
|
|
99
|
-
const entries = await readHistoryEntries(getWorkspaceHistoryPath(pmRoot), WORKSPACE_HISTORY_ID);
|
|
100
|
-
const verification = verifyHistoryChain(entries);
|
|
101
|
-
if (!verification.ok) {
|
|
102
|
-
throwWorkspaceHistoryVerificationFailure(verification.errors);
|
|
103
|
-
}
|
|
104
|
-
const documents = workspaceDocuments(entries.length === 0
|
|
105
|
-
? EMPTY_CANONICAL_DOCUMENT
|
|
106
|
-
: replayWorkspaceEntries(entries));
|
|
107
|
-
const matching = [];
|
|
108
|
-
const mismatched = [];
|
|
109
|
-
const missing = [];
|
|
110
|
-
const unreadable = [];
|
|
111
|
-
for (const documentPath of Object.keys(documents).sort()) {
|
|
112
|
-
let raw;
|
|
113
|
-
try {
|
|
114
|
-
const resolved = resolveGovernedDocumentPath(pmRoot, path.resolve(pmRoot, documentPath));
|
|
115
|
-
raw = await readFileIfExists(resolved.absolutePath);
|
|
116
|
-
if (raw === null) {
|
|
117
|
-
missing.push(documentPath);
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
const current = JSON.parse(raw);
|
|
121
|
-
(stableStringify(current) === stableStringify(documents[documentPath])
|
|
122
|
-
? matching
|
|
123
|
-
: mismatched).push(documentPath);
|
|
124
|
-
}
|
|
125
|
-
catch {
|
|
126
|
-
unreadable.push(documentPath);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return {
|
|
130
|
-
ok: mismatched.length === 0 &&
|
|
131
|
-
missing.length === 0 &&
|
|
132
|
-
unreadable.length === 0,
|
|
133
|
-
document_count: Object.keys(documents).length,
|
|
134
|
-
matching_documents: matching,
|
|
135
|
-
mismatched_documents: mismatched,
|
|
136
|
-
missing_documents: missing,
|
|
137
|
-
unreadable_documents: unreadable,
|
|
138
|
-
};
|
|
139
|
-
}
|
|
140
|
-
/**
|
|
141
|
-
* Append one workspace document mutation while the caller holds the dedicated
|
|
142
|
-
* workspace-history lock.
|
|
143
|
-
*/
|
|
144
|
-
async function appendWorkspaceHistoryChangeLocked(change) {
|
|
145
|
-
const historyPath = getWorkspaceHistoryPath(change.pmRoot);
|
|
146
|
-
const entries = await readHistoryEntries(historyPath, WORKSPACE_HISTORY_ID);
|
|
147
|
-
const verification = verifyHistoryChain(entries);
|
|
148
|
-
if (!verification.ok) {
|
|
149
|
-
throwWorkspaceHistoryVerificationFailure(verification.errors);
|
|
150
|
-
}
|
|
151
|
-
const idempotentEntry = change.idempotencyKey === undefined
|
|
152
|
-
? undefined
|
|
153
|
-
: entries.find((entry) => entry.op === `${change.op}:${change.idempotencyKey}`);
|
|
154
|
-
if (idempotentEntry) {
|
|
155
|
-
return { entry: idempotentEntry, historyPath };
|
|
156
|
-
}
|
|
157
|
-
const timestamp = nowIso();
|
|
158
|
-
const beforeDocument = entries.length === 0
|
|
159
|
-
? EMPTY_CANONICAL_DOCUMENT
|
|
160
|
-
: replayWorkspaceEntries(entries);
|
|
161
|
-
const priorDocuments = workspaceDocuments(beforeDocument);
|
|
162
|
-
const recordedBefore = priorDocuments[change.documentPath];
|
|
163
|
-
if (recordedBefore !== undefined &&
|
|
164
|
-
stableStringify(recordedBefore) !== stableStringify(change.before)) {
|
|
165
|
-
throw new PmCliError(`Workspace history state for "${change.documentPath}" changed outside the audited mutation path.`, EXIT_CODE.CONFLICT, {
|
|
166
|
-
code: "workspace_history_state_conflict",
|
|
167
|
-
reason: "out_of_band_workspace_state",
|
|
168
|
-
required: "Reconcile the singleton document with its matching _workspace history state before retrying the mutation.",
|
|
169
|
-
why: "Accepting the write would make the append-only audit stream describe a state that was not actually observed.",
|
|
170
|
-
examples: [
|
|
171
|
-
"pm history _workspace --verify",
|
|
172
|
-
"pm validate --check-history-drift --fix-hints",
|
|
173
|
-
],
|
|
174
|
-
nextSteps: [
|
|
175
|
-
"Review the version-control change that altered the singleton and preserve the intended document plus its matching workspace history.",
|
|
176
|
-
"Rerun the original mutation only after the on-disk singleton agrees with the latest audited workspace state.",
|
|
177
|
-
],
|
|
178
|
-
recovery: {
|
|
179
|
-
recovery_mode: "compact",
|
|
180
|
-
next_best_command: "pm history _workspace --verify",
|
|
181
|
-
},
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
const afterDocument = workspaceDocument({ ...priorDocuments, [change.documentPath]: change.after }, entries.length === 0 ? timestamp : beforeDocument.metadata.created_at);
|
|
185
|
-
const entry = createHistoryEntry({
|
|
186
|
-
nowIso: timestamp,
|
|
187
|
-
author: change.author,
|
|
188
|
-
op: change.idempotencyKey === undefined
|
|
189
|
-
? change.op
|
|
190
|
-
: `${change.op}:${change.idempotencyKey}`,
|
|
191
|
-
before: beforeDocument,
|
|
192
|
-
after: afterDocument,
|
|
193
|
-
message: change.message,
|
|
194
|
-
});
|
|
195
|
-
await appendHistoryEntry(historyPath, entry);
|
|
196
|
-
return { entry, historyPath };
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Append one workspace document mutation under the dedicated workspace-history
|
|
200
|
-
* lock. Existing history is verified and replayed before the new entry is
|
|
201
|
-
* derived, so concurrent writers cannot fork the chain.
|
|
202
|
-
*/
|
|
203
|
-
export async function appendWorkspaceHistoryChange(change) {
|
|
204
|
-
const release = await acquireLock(change.pmRoot, "workspace-history", change.lockTtlSeconds, change.author, false, false, change.lockWaitMs);
|
|
205
|
-
try {
|
|
206
|
-
return await appendWorkspaceHistoryChangeLocked(change);
|
|
207
|
-
}
|
|
208
|
-
finally {
|
|
209
|
-
await release();
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
/** Append a verified no-state-change event to the workspace audit stream. */
|
|
213
|
-
export async function appendWorkspaceAuditEvent(options) {
|
|
214
|
-
const release = await acquireLock(options.pmRoot, "workspace-history", options.lockTtlSeconds, options.author, false, false, options.lockWaitMs);
|
|
215
|
-
try {
|
|
216
|
-
const historyPath = getWorkspaceHistoryPath(options.pmRoot);
|
|
217
|
-
const entries = await readHistoryEntries(historyPath, WORKSPACE_HISTORY_ID);
|
|
218
|
-
const verification = verifyHistoryChain(entries);
|
|
219
|
-
if (!verification.ok) {
|
|
220
|
-
throwWorkspaceHistoryVerificationFailure(verification.errors);
|
|
221
|
-
}
|
|
222
|
-
const beforeDocument = entries.length === 0
|
|
223
|
-
? EMPTY_CANONICAL_DOCUMENT
|
|
224
|
-
: replayWorkspaceEntries(entries);
|
|
225
|
-
const entry = createHistoryEntry({
|
|
226
|
-
nowIso: nowIso(),
|
|
227
|
-
author: options.author,
|
|
228
|
-
op: options.op,
|
|
229
|
-
before: beforeDocument,
|
|
230
|
-
after: beforeDocument,
|
|
231
|
-
message: options.message,
|
|
232
|
-
context: options.context,
|
|
233
|
-
});
|
|
234
|
-
await appendHistoryEntry(historyPath, entry);
|
|
235
|
-
return { entry, historyPath };
|
|
236
|
-
}
|
|
237
|
-
finally {
|
|
238
|
-
await release();
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Atomically serialize a JSON singleton snapshot, write, history append, and
|
|
243
|
-
* compensation under the workspace-history lock.
|
|
244
|
-
*/
|
|
245
|
-
async function writeWorkspaceJsonWithHistoryLocked(params, beforeRaw) {
|
|
246
|
-
if (beforeRaw === params.raw)
|
|
247
|
-
return false;
|
|
248
|
-
const before = beforeRaw === null ? null : JSON.parse(beforeRaw);
|
|
249
|
-
const after = JSON.parse(params.raw);
|
|
250
|
-
await writeFileAtomic(params.filePath, params.raw);
|
|
251
|
-
try {
|
|
252
|
-
if (beforeRaw !== null || params.recordCreation !== false) {
|
|
253
|
-
await appendWorkspaceHistoryChangeLocked({
|
|
254
|
-
pmRoot: params.pmRoot,
|
|
255
|
-
documentPath: path
|
|
256
|
-
.relative(params.pmRoot, params.filePath)
|
|
257
|
-
.replaceAll("\\", "/"),
|
|
258
|
-
before,
|
|
259
|
-
after,
|
|
260
|
-
op: params.op,
|
|
261
|
-
author: params.author,
|
|
262
|
-
lockTtlSeconds: params.lockTtlSeconds,
|
|
263
|
-
lockWaitMs: params.lockWaitMs,
|
|
264
|
-
message: params.message,
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
catch (error) {
|
|
269
|
-
if (beforeRaw === null) {
|
|
270
|
-
await fs.rm(params.filePath, { force: true });
|
|
271
|
-
}
|
|
272
|
-
else {
|
|
273
|
-
await writeFileAtomic(params.filePath, beforeRaw);
|
|
274
|
-
}
|
|
275
|
-
throw error;
|
|
276
|
-
}
|
|
277
|
-
return true;
|
|
278
|
-
}
|
|
279
|
-
/**
|
|
280
|
-
* Derive and persist an audited singleton mutation from one lock-protected
|
|
281
|
-
* before-state, preventing read-modify-write callers from losing updates.
|
|
282
|
-
*/
|
|
283
|
-
export async function mutateWorkspaceJsonWithHistory(params) {
|
|
284
|
-
const release = await acquireLock(params.pmRoot, "workspace-history", params.lockTtlSeconds, params.author, false, false, params.lockWaitMs);
|
|
285
|
-
try {
|
|
286
|
-
const beforeRaw = await readFileIfExists(params.filePath);
|
|
287
|
-
const mutation = await params.mutate(beforeRaw);
|
|
288
|
-
return {
|
|
289
|
-
changed: await writeWorkspaceJsonWithHistoryLocked({ ...params, raw: mutation.raw }, beforeRaw),
|
|
290
|
-
result: mutation.result,
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
finally {
|
|
294
|
-
await release();
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
/**
|
|
298
|
-
* Atomically persist one caller-serialized JSON singleton and its audit entry
|
|
299
|
-
* under the workspace-history lock, with compensation if history append fails.
|
|
300
|
-
*/
|
|
301
|
-
export async function writeWorkspaceJsonWithHistory(params) {
|
|
302
|
-
const release = await acquireLock(params.pmRoot, "workspace-history", params.lockTtlSeconds, params.author, false, false, params.lockWaitMs);
|
|
303
|
-
try {
|
|
304
|
-
return await writeWorkspaceJsonWithHistoryLocked(params, await readFileIfExists(params.filePath));
|
|
305
|
-
}
|
|
306
|
-
finally {
|
|
307
|
-
await release();
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
/**
|
|
311
|
-
* Append an authorized reconciliation event that adopts a reviewed on-disk
|
|
312
|
-
* singleton after an out-of-band change. The existing stream is never edited:
|
|
313
|
-
* its latest replayed state becomes the event before-state and the reviewed
|
|
314
|
-
* singleton becomes the after-state, with the authorizing Decision recorded in
|
|
315
|
-
* structured context.
|
|
316
|
-
*/
|
|
317
|
-
export async function reconcileWorkspaceJsonHistory(options) {
|
|
318
|
-
const authorizationDecision = options.authorizationDecision.trim();
|
|
319
|
-
if (!authorizationDecision) {
|
|
320
|
-
throw new TypeError("Workspace history reconciliation requires an authorization decision");
|
|
321
|
-
}
|
|
322
|
-
const release = await acquireLock(options.pmRoot, "workspace-history", options.lockTtlSeconds, options.author, false, false, options.lockWaitMs);
|
|
323
|
-
try {
|
|
324
|
-
const { documentPath, absolutePath } = resolveGovernedDocumentPath(options.pmRoot, options.filePath);
|
|
325
|
-
const historyPath = getWorkspaceHistoryPath(options.pmRoot);
|
|
326
|
-
const entries = await readHistoryEntries(historyPath, WORKSPACE_HISTORY_ID);
|
|
327
|
-
const verification = verifyHistoryChain(entries);
|
|
328
|
-
if (!verification.ok) {
|
|
329
|
-
throwWorkspaceHistoryVerificationFailure(verification.errors);
|
|
330
|
-
}
|
|
331
|
-
const beforeDocument = replayWorkspaceEntries(entries);
|
|
332
|
-
const priorDocuments = workspaceDocuments(beforeDocument);
|
|
333
|
-
if (!Object.hasOwn(priorDocuments, documentPath)) {
|
|
334
|
-
throw new TypeError(`Workspace history does not govern document ${documentPath}`);
|
|
335
|
-
}
|
|
336
|
-
const raw = await readFileIfExists(absolutePath);
|
|
337
|
-
if (raw === null) {
|
|
338
|
-
throw new TypeError(`Workspace history document is missing: ${documentPath}`);
|
|
339
|
-
}
|
|
340
|
-
const current = JSON.parse(raw);
|
|
341
|
-
if (stableStringify(priorDocuments[documentPath]) === stableStringify(current)) {
|
|
342
|
-
return { changed: false, historyPath };
|
|
343
|
-
}
|
|
344
|
-
const timestamp = nowIso();
|
|
345
|
-
const entry = createHistoryEntry({
|
|
346
|
-
nowIso: timestamp,
|
|
347
|
-
author: options.author,
|
|
348
|
-
op: options.op,
|
|
349
|
-
before: beforeDocument,
|
|
350
|
-
after: workspaceDocument({ ...priorDocuments, [documentPath]: current }, beforeDocument.metadata.created_at),
|
|
351
|
-
message: options.message,
|
|
352
|
-
context: {
|
|
353
|
-
reason: "out_of_band_workspace_state_reconciliation",
|
|
354
|
-
document_path: documentPath,
|
|
355
|
-
authorization_decision: authorizationDecision,
|
|
356
|
-
},
|
|
357
|
-
});
|
|
358
|
-
await appendHistoryEntry(historyPath, entry);
|
|
359
|
-
return { changed: true, entry, historyPath };
|
|
360
|
-
}
|
|
361
|
-
finally {
|
|
362
|
-
await release();
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
/**
|
|
366
|
-
* Restore one governed JSON singleton to the value recorded at a one-based
|
|
367
|
-
* workspace history version, then append the restore as a new history state so
|
|
368
|
-
* replay remains forward-only and independently verifiable.
|
|
369
|
-
*/
|
|
370
|
-
export async function restoreWorkspaceJsonFromHistory(options) {
|
|
371
|
-
const release = await acquireLock(options.pmRoot, "workspace-history", options.lockTtlSeconds, options.author, false, false, options.lockWaitMs);
|
|
372
|
-
try {
|
|
373
|
-
const { documentPath, absolutePath } = resolveGovernedDocumentPath(options.pmRoot, options.filePath);
|
|
374
|
-
const entries = await readHistoryEntries(getWorkspaceHistoryPath(options.pmRoot), WORKSPACE_HISTORY_ID);
|
|
375
|
-
const verification = verifyHistoryChain(entries);
|
|
376
|
-
if (!verification.ok) {
|
|
377
|
-
throwWorkspaceHistoryVerificationFailure(verification.errors);
|
|
378
|
-
}
|
|
379
|
-
if (!Number.isInteger(options.targetVersion) ||
|
|
380
|
-
options.targetVersion < 1 ||
|
|
381
|
-
options.targetVersion > entries.length) {
|
|
382
|
-
throw new TypeError(`Invalid workspace history target version: ${String(options.targetVersion)}`);
|
|
383
|
-
}
|
|
384
|
-
const target = workspaceDocuments(replayWorkspaceEntries(entries, options.targetVersion))[documentPath];
|
|
385
|
-
if (target === undefined) {
|
|
386
|
-
throw new TypeError(`Workspace history version ${options.targetVersion} does not contain ${documentPath}`);
|
|
387
|
-
}
|
|
388
|
-
const beforeRaw = await readFileIfExists(absolutePath);
|
|
389
|
-
const targetRaw = `${JSON.stringify(target, null, 2)}\n`;
|
|
390
|
-
if (beforeRaw === targetRaw)
|
|
391
|
-
return {
|
|
392
|
-
document_path: documentPath,
|
|
393
|
-
restored_from_version: options.targetVersion,
|
|
394
|
-
changed: false,
|
|
395
|
-
};
|
|
396
|
-
const beforeDocument = replayWorkspaceEntries(entries);
|
|
397
|
-
const timestamp = nowIso();
|
|
398
|
-
const entry = createHistoryEntry({
|
|
399
|
-
nowIso: timestamp,
|
|
400
|
-
author: options.author,
|
|
401
|
-
op: options.op,
|
|
402
|
-
before: beforeDocument,
|
|
403
|
-
after: workspaceDocument({ ...workspaceDocuments(beforeDocument), [documentPath]: target }, beforeDocument.metadata.created_at),
|
|
404
|
-
message: options.message,
|
|
405
|
-
context: {
|
|
406
|
-
reason: "workspace_state_restore",
|
|
407
|
-
document_path: documentPath,
|
|
408
|
-
restored_from_version: options.targetVersion,
|
|
409
|
-
replaced_out_of_band_state: true,
|
|
410
|
-
},
|
|
411
|
-
});
|
|
412
|
-
await writeFileAtomic(absolutePath, targetRaw);
|
|
413
|
-
try {
|
|
414
|
-
await appendHistoryEntry(getWorkspaceHistoryPath(options.pmRoot), entry);
|
|
415
|
-
}
|
|
416
|
-
catch (error) {
|
|
417
|
-
if (beforeRaw === null)
|
|
418
|
-
await fs.rm(absolutePath, { force: true });
|
|
419
|
-
else
|
|
420
|
-
await writeFileAtomic(absolutePath, beforeRaw);
|
|
421
|
-
throw error;
|
|
422
|
-
}
|
|
423
|
-
return {
|
|
424
|
-
document_path: documentPath,
|
|
425
|
-
restored_from_version: options.targetVersion,
|
|
426
|
-
changed: true,
|
|
427
|
-
};
|
|
428
|
-
}
|
|
429
|
-
finally {
|
|
430
|
-
await release();
|
|
431
|
-
}
|
|
432
|
-
}
|
|
1
|
+
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e2a2001e-b162-599e-b262-76d2223a343c")}catch(e2){}})();import fs from"node:fs/promises";import path from"node:path";import{readFileIfExists,writeFileAtomic}from"../fs/fs-utils.js";import{acquireLock}from"../lock/lock.js";import{EMPTY_CANONICAL_DOCUMENT,EXIT_CODE}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{stableStringify}from"../shared/serialization.js";import{nowIso}from"../shared/time.js";import{appendHistoryEntry,createHistoryEntry}from"./history.js";import{readHistoryEntries}from"./read.js";import{cloneEmptyReplayDocument,replayToItemDocument,tryApplyReplayPatch,verifyHistoryChain}from"./replay.js";const WORKSPACE_HISTORY_ID="_workspace";function getWorkspaceHistoryPath(pmRoot){return path.join(pmRoot,"history",`${WORKSPACE_HISTORY_ID}.jsonl`)}function workspaceDocument(documents,timestamp){const metadata={id:WORKSPACE_HISTORY_ID,title:"Workspace state",description:"Audited singleton workspace document state.",type:"Chore",status:"open",priority:2,tags:["workspace-history"],created_at:timestamp,updated_at:timestamp,documents};return{metadata,body:""}}function replayWorkspaceEntries(entries,count=entries.length){let replay=cloneEmptyReplayDocument();for(const entry of entries.slice(0,count)){const applied=tryApplyReplayPatch(replay,entry.patch);replay=applied.document}return replayToItemDocument(replay)}function workspaceDocuments(document){return"documents"in document.metadata&&typeof document.metadata.documents==="object"&&document.metadata.documents!==null&&!Array.isArray(document.metadata.documents)?document.metadata.documents:{}}function throwWorkspaceHistoryVerificationFailure(errors){throw new PmCliError(`Workspace history verification failed: ${errors.join(", ")}`,EXIT_CODE.CONFLICT,{code:"workspace_history_chain_invalid",reason:"workspace_history_chain_verification_failed",verification_errors:[...errors],required:"Repair the _workspace history chain before reading, reconciling, restoring, or appending audited singleton state.",why:"Continuing against an unverifiable append-only stream could hide or compound workspace state corruption.",examples:["pm history _workspace --verify --json","pm validate --check-history-drift --fix-hints --json"],nextSteps:["Inspect the exact verification_errors and preserve the corrupt stream as evidence.","Use the history-drift remediation returned by validate before retrying the refused operation."],recovery:{recovery_mode:"compact",next_best_command:"pm history _workspace --verify --json"}})}function resolveGovernedDocumentPath(pmRoot,filePath){const absolutePath=path.resolve(filePath);const documentPath=path.relative(pmRoot,absolutePath).replaceAll("\\","/");if(documentPath.length===0||documentPath===".."||documentPath.startsWith("../")||path.isAbsolute(documentPath)){throw new TypeError("Workspace history document path must stay inside the tracker root")}return{documentPath,absolutePath}}async function inspectWorkspaceHistoryState(pmRoot){const entries=await readHistoryEntries(getWorkspaceHistoryPath(pmRoot),WORKSPACE_HISTORY_ID);const verification=verifyHistoryChain(entries);if(!verification.ok){throwWorkspaceHistoryVerificationFailure(verification.errors)}const documents=workspaceDocuments(entries.length===0?EMPTY_CANONICAL_DOCUMENT:replayWorkspaceEntries(entries));const matching=[];const mismatched=[];const missing=[];const unreadable=[];for(const documentPath of Object.keys(documents).sort()){let raw;try{const resolved=resolveGovernedDocumentPath(pmRoot,path.resolve(pmRoot,documentPath));raw=await readFileIfExists(resolved.absolutePath);if(raw===null){missing.push(documentPath);continue}const current=JSON.parse(raw);(stableStringify(current)===stableStringify(documents[documentPath])?matching:mismatched).push(documentPath)}catch{unreadable.push(documentPath)}}return{ok:mismatched.length===0&&missing.length===0&&unreadable.length===0,document_count:Object.keys(documents).length,matching_documents:matching,mismatched_documents:mismatched,missing_documents:missing,unreadable_documents:unreadable}}async function appendWorkspaceHistoryChangeLocked(change){const historyPath=getWorkspaceHistoryPath(change.pmRoot);const entries=await readHistoryEntries(historyPath,WORKSPACE_HISTORY_ID);const verification=verifyHistoryChain(entries);if(!verification.ok){throwWorkspaceHistoryVerificationFailure(verification.errors)}const idempotentEntry=change.idempotencyKey===void 0?void 0:entries.find(entry2=>entry2.op===`${change.op}:${change.idempotencyKey}`);if(idempotentEntry){return{entry:idempotentEntry,historyPath}}const timestamp=nowIso();const beforeDocument=entries.length===0?EMPTY_CANONICAL_DOCUMENT:replayWorkspaceEntries(entries);const priorDocuments=workspaceDocuments(beforeDocument);const recordedBefore=priorDocuments[change.documentPath];if(recordedBefore!==void 0&&stableStringify(recordedBefore)!==stableStringify(change.before)){throw new PmCliError(`Workspace history state for "${change.documentPath}" changed outside the audited mutation path.`,EXIT_CODE.CONFLICT,{code:"workspace_history_state_conflict",reason:"out_of_band_workspace_state",required:"Reconcile the singleton document with its matching _workspace history state before retrying the mutation.",why:"Accepting the write would make the append-only audit stream describe a state that was not actually observed.",examples:["pm history _workspace --verify","pm validate --check-history-drift --fix-hints"],nextSteps:["Review the version-control change that altered the singleton and preserve the intended document plus its matching workspace history.","Rerun the original mutation only after the on-disk singleton agrees with the latest audited workspace state."],recovery:{recovery_mode:"compact",next_best_command:"pm history _workspace --verify"}})}const afterDocument=workspaceDocument({...priorDocuments,[change.documentPath]:change.after},entries.length===0?timestamp:beforeDocument.metadata.created_at);const entry=createHistoryEntry({nowIso:timestamp,author:change.author,op:change.idempotencyKey===void 0?change.op:`${change.op}:${change.idempotencyKey}`,before:beforeDocument,after:afterDocument,message:change.message});await appendHistoryEntry(historyPath,entry);return{entry,historyPath}}async function appendWorkspaceHistoryChange(change){const release=await acquireLock(change.pmRoot,"workspace-history",change.lockTtlSeconds,change.author,false,false,change.lockWaitMs);try{return await appendWorkspaceHistoryChangeLocked(change)}finally{await release()}}async function appendWorkspaceAuditEvent(options){const release=await acquireLock(options.pmRoot,"workspace-history",options.lockTtlSeconds,options.author,false,false,options.lockWaitMs);try{const historyPath=getWorkspaceHistoryPath(options.pmRoot);const entries=await readHistoryEntries(historyPath,WORKSPACE_HISTORY_ID);const verification=verifyHistoryChain(entries);if(!verification.ok){throwWorkspaceHistoryVerificationFailure(verification.errors)}const beforeDocument=entries.length===0?EMPTY_CANONICAL_DOCUMENT:replayWorkspaceEntries(entries);const entry=createHistoryEntry({nowIso:nowIso(),author:options.author,op:options.op,before:beforeDocument,after:beforeDocument,message:options.message,context:options.context});await appendHistoryEntry(historyPath,entry);return{entry,historyPath}}finally{await release()}}async function writeWorkspaceJsonWithHistoryLocked(params,beforeRaw){if(beforeRaw===params.raw)return false;const before=beforeRaw===null?null:JSON.parse(beforeRaw);const after=JSON.parse(params.raw);await writeFileAtomic(params.filePath,params.raw);try{if(beforeRaw!==null||params.recordCreation!==false){await appendWorkspaceHistoryChangeLocked({pmRoot:params.pmRoot,documentPath:path.relative(params.pmRoot,params.filePath).replaceAll("\\","/"),before,after,op:params.op,author:params.author,lockTtlSeconds:params.lockTtlSeconds,lockWaitMs:params.lockWaitMs,message:params.message})}}catch(error){if(beforeRaw===null){await fs.rm(params.filePath,{force:true})}else{await writeFileAtomic(params.filePath,beforeRaw)}throw error}return true}async function mutateWorkspaceJsonWithHistory(params){const release=await acquireLock(params.pmRoot,"workspace-history",params.lockTtlSeconds,params.author,false,false,params.lockWaitMs);try{const beforeRaw=await readFileIfExists(params.filePath);const mutation=await params.mutate(beforeRaw);return{changed:await writeWorkspaceJsonWithHistoryLocked({...params,raw:mutation.raw},beforeRaw),result:mutation.result}}finally{await release()}}async function writeWorkspaceJsonWithHistory(params){const release=await acquireLock(params.pmRoot,"workspace-history",params.lockTtlSeconds,params.author,false,false,params.lockWaitMs);try{return await writeWorkspaceJsonWithHistoryLocked(params,await readFileIfExists(params.filePath))}finally{await release()}}async function reconcileWorkspaceJsonHistory(options){const authorizationDecision=options.authorizationDecision.trim();if(!authorizationDecision){throw new TypeError("Workspace history reconciliation requires an authorization decision")}const release=await acquireLock(options.pmRoot,"workspace-history",options.lockTtlSeconds,options.author,false,false,options.lockWaitMs);try{const{documentPath,absolutePath}=resolveGovernedDocumentPath(options.pmRoot,options.filePath);const historyPath=getWorkspaceHistoryPath(options.pmRoot);const entries=await readHistoryEntries(historyPath,WORKSPACE_HISTORY_ID);const verification=verifyHistoryChain(entries);if(!verification.ok){throwWorkspaceHistoryVerificationFailure(verification.errors)}const beforeDocument=replayWorkspaceEntries(entries);const priorDocuments=workspaceDocuments(beforeDocument);if(!Object.hasOwn(priorDocuments,documentPath)){throw new TypeError(`Workspace history does not govern document ${documentPath}`)}const raw=await readFileIfExists(absolutePath);if(raw===null){throw new TypeError(`Workspace history document is missing: ${documentPath}`)}const current=JSON.parse(raw);if(stableStringify(priorDocuments[documentPath])===stableStringify(current)){return{changed:false,historyPath}}const timestamp=nowIso();const entry=createHistoryEntry({nowIso:timestamp,author:options.author,op:options.op,before:beforeDocument,after:workspaceDocument({...priorDocuments,[documentPath]:current},beforeDocument.metadata.created_at),message:options.message,context:{reason:"out_of_band_workspace_state_reconciliation",document_path:documentPath,authorization_decision:authorizationDecision}});await appendHistoryEntry(historyPath,entry);return{changed:true,entry,historyPath}}finally{await release()}}async function restoreWorkspaceJsonFromHistory(options){const release=await acquireLock(options.pmRoot,"workspace-history",options.lockTtlSeconds,options.author,false,false,options.lockWaitMs);try{const{documentPath,absolutePath}=resolveGovernedDocumentPath(options.pmRoot,options.filePath);const entries=await readHistoryEntries(getWorkspaceHistoryPath(options.pmRoot),WORKSPACE_HISTORY_ID);const verification=verifyHistoryChain(entries);if(!verification.ok){throwWorkspaceHistoryVerificationFailure(verification.errors)}if(!Number.isInteger(options.targetVersion)||options.targetVersion<1||options.targetVersion>entries.length){throw new TypeError(`Invalid workspace history target version: ${String(options.targetVersion)}`)}const target=workspaceDocuments(replayWorkspaceEntries(entries,options.targetVersion))[documentPath];if(target===void 0){throw new TypeError(`Workspace history version ${options.targetVersion} does not contain ${documentPath}`)}const beforeRaw=await readFileIfExists(absolutePath);const targetRaw=`${JSON.stringify(target,null,2)}
|
|
2
|
+
`;if(beforeRaw===targetRaw)return{document_path:documentPath,restored_from_version:options.targetVersion,changed:false};const beforeDocument=replayWorkspaceEntries(entries);const timestamp=nowIso();const entry=createHistoryEntry({nowIso:timestamp,author:options.author,op:options.op,before:beforeDocument,after:workspaceDocument({...workspaceDocuments(beforeDocument),[documentPath]:target},beforeDocument.metadata.created_at),message:options.message,context:{reason:"workspace_state_restore",document_path:documentPath,restored_from_version:options.targetVersion,replaced_out_of_band_state:true}});await writeFileAtomic(absolutePath,targetRaw);try{await appendHistoryEntry(getWorkspaceHistoryPath(options.pmRoot),entry)}catch(error){if(beforeRaw===null)await fs.rm(absolutePath,{force:true});else await writeFileAtomic(absolutePath,beforeRaw);throw error}return{document_path:documentPath,restored_from_version:options.targetVersion,changed:true}}finally{await release()}}export{WORKSPACE_HISTORY_ID,appendWorkspaceAuditEvent,appendWorkspaceHistoryChange,getWorkspaceHistoryPath,inspectWorkspaceHistoryState,mutateWorkspaceJsonWithHistory,reconcileWorkspaceJsonHistory,restoreWorkspaceJsonFromHistory,writeWorkspaceJsonWithHistory};
|
|
433
3
|
//# sourceMappingURL=workspace-history.js.map
|
|
434
|
-
//# debugId=4df21a17-43c0-5b63-adf3-657699e6a058
|
|
@@ -1,63 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* @module core/io/body-file
|
|
3
|
-
*
|
|
4
|
-
* Reads command body content from files, stdin, and inline arguments.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="a97ee152-4d20-54f1-add9-fdb991ab6b33")}catch(e){}}();
|
|
8
|
-
import { readFile } from "node:fs/promises";
|
|
9
|
-
import { EXIT_CODE } from "../shared/constants.js";
|
|
10
|
-
import { PmCliError } from "../shared/errors.js";
|
|
11
|
-
import { createStdinTokenResolver } from "../item/parse.js";
|
|
12
|
-
const defaultBodyFileReader = (path) => readFile(path, "utf8");
|
|
13
|
-
/** Implements resolve body file content for the public runtime surface of this module. */
|
|
14
|
-
export async function resolveBodyFileContent(bodyFile, inlineBody, readFileImpl = defaultBodyFileReader) {
|
|
15
|
-
// Mutual exclusion: --body and --body-file both define the body, so accepting
|
|
16
|
-
// both silently would hide which one wins. Fail with an actionable message.
|
|
17
|
-
if (inlineBody !== undefined) {
|
|
18
|
-
throw new PmCliError("--body and --body-file are mutually exclusive; provide the body inline with --body or from a file with --body-file, not both.", EXIT_CODE.USAGE, {
|
|
19
|
-
code: "body_file_conflicts_with_body",
|
|
20
|
-
required: "Choose exactly one body source.",
|
|
21
|
-
why: "Both --body and --body-file set the item body; allowing both would make the effective body ambiguous.",
|
|
22
|
-
nextSteps: [
|
|
23
|
-
"Re-run with only --body <text> or only --body-file <path>.",
|
|
24
|
-
],
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
const path = bodyFile.trim();
|
|
28
|
-
if (path.length === 0) {
|
|
29
|
-
throw new PmCliError("--body-file requires a file path.", EXIT_CODE.USAGE, {
|
|
30
|
-
code: "body_file_missing_path",
|
|
31
|
-
required: "Pass a readable file path: --body-file <path>.",
|
|
32
|
-
why: "An empty --body-file value has no file to read the body from.",
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
if (path === "-") {
|
|
36
|
-
return (await createStdinTokenResolver().resolveValue("-", "--body-file"));
|
|
37
|
-
}
|
|
38
|
-
try {
|
|
39
|
-
return await readFileImpl(path);
|
|
40
|
-
}
|
|
41
|
-
catch (error) {
|
|
42
|
-
// Preserve the underlying errno (ENOENT/EACCES/EISDIR/...) so the failure
|
|
43
|
-
// is debuggable, and tailor the directory case (a real footgun: pointing
|
|
44
|
-
// --body-file at a folder) to an exact message instead of a generic one.
|
|
45
|
-
const errno = error?.code;
|
|
46
|
-
const isDirectory = errno === "EISDIR";
|
|
47
|
-
const detail = errno ? ` (${errno})` : "";
|
|
48
|
-
throw new PmCliError(isDirectory
|
|
49
|
-
? `--body-file "${path}" is a directory, not a file. Point it at a readable file.`
|
|
50
|
-
: `--body-file could not read "${path}"${detail}. Check that the file exists and is readable.`, EXIT_CODE.NOT_FOUND, {
|
|
51
|
-
code: "body_file_unreadable",
|
|
52
|
-
required: "Point --body-file at an existing, readable file.",
|
|
53
|
-
why: `The body content is loaded from the file at the supplied path, so an unreadable path cannot produce a body${errno ? ` (underlying error: ${errno})` : ""}.`,
|
|
54
|
-
nextSteps: [
|
|
55
|
-
`Verify the path: ls -l "${path}"`,
|
|
56
|
-
"Or pipe the body with --body-file -.",
|
|
57
|
-
"Or pass the body inline with --body <text>.",
|
|
58
|
-
],
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}
|
|
1
|
+
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e6571e4b-c436-5af7-be01-c3fce3a9c5d3")}catch(e2){}})();import{readFile}from"node:fs/promises";import{EXIT_CODE}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{createStdinTokenResolver}from"../item/parse.js";const defaultBodyFileReader=path=>readFile(path,"utf8");async function resolveBodyFileContent(bodyFile,inlineBody,readFileImpl=defaultBodyFileReader){if(inlineBody!==void 0){throw new PmCliError("--body and --body-file are mutually exclusive; provide the body inline with --body or from a file with --body-file, not both.",EXIT_CODE.USAGE,{code:"body_file_conflicts_with_body",required:"Choose exactly one body source.",why:"Both --body and --body-file set the item body; allowing both would make the effective body ambiguous.",nextSteps:["Re-run with only --body <text> or only --body-file <path>."]})}const path=bodyFile.trim();if(path.length===0){throw new PmCliError("--body-file requires a file path.",EXIT_CODE.USAGE,{code:"body_file_missing_path",required:"Pass a readable file path: --body-file <path>.",why:"An empty --body-file value has no file to read the body from."})}if(path==="-"){return await createStdinTokenResolver().resolveValue("-","--body-file")}try{return await readFileImpl(path)}catch(error){const errno=error?.code;const isDirectory=errno==="EISDIR";const detail=errno?` (${errno})`:"";throw new PmCliError(isDirectory?`--body-file "${path}" is a directory, not a file. Point it at a readable file.`:`--body-file could not read "${path}"${detail}. Check that the file exists and is readable.`,EXIT_CODE.NOT_FOUND,{code:"body_file_unreadable",required:"Point --body-file at an existing, readable file.",why:`The body content is loaded from the file at the supplied path, so an unreadable path cannot produce a body${errno?` (underlying error: ${errno})`:""}.`,nextSteps:[`Verify the path: ls -l "${path}"`,"Or pipe the body with --body-file -.","Or pass the body inline with --body <text>."]})}}export{resolveBodyFileContent};
|
|
62
2
|
//# sourceMappingURL=body-file.js.map
|
|
63
|
-
//# debugId=a97ee152-4d20-54f1-add9-fdb991ab6b33
|
|
@@ -1,113 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
* @module core/io/bulk-ids-input
|
|
3
|
-
*
|
|
4
|
-
* Normalizes bulk item-id selectors supplied inline, through stdin, or from an
|
|
5
|
-
* argv-referenced file. Presentation layers can share the parser while MCP and
|
|
6
|
-
* embedded SDK callers keep passing transport-native arrays.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="411f4336-eb02-5167-9dce-ea99822a8a14")}catch(e){}}();
|
|
10
|
-
import { readFile } from "node:fs/promises";
|
|
11
|
-
import { createStdinTokenResolver } from "../item/parse.js";
|
|
12
|
-
import { EXIT_CODE } from "../shared/constants.js";
|
|
13
|
-
import { PmCliError } from "../shared/errors.js";
|
|
14
|
-
const defaultFileReader = (path) => readFile(path, "utf8");
|
|
15
|
-
const defaultStdinReader = async (optionName) => (await createStdinTokenResolver().resolveValue("-", optionName));
|
|
16
|
-
/** Parse comma- or line-delimited item IDs with stable first-seen deduplication. */
|
|
17
|
-
export function parseBulkIdsText(raw) {
|
|
18
|
-
return [
|
|
19
|
-
...new Set(raw
|
|
20
|
-
.split(/[,\r\n]+/)
|
|
21
|
-
.map((entry) => entry.trim())
|
|
22
|
-
.filter((entry) => entry.length > 0)),
|
|
23
|
-
];
|
|
24
|
-
}
|
|
25
|
-
function normalizeBulkIdsArray(value) {
|
|
26
|
-
const entries = [];
|
|
27
|
-
for (const entry of value) {
|
|
28
|
-
if (typeof entry === "string") {
|
|
29
|
-
entries.push(entry);
|
|
30
|
-
}
|
|
31
|
-
else if (typeof entry === "number" && Number.isFinite(entry)) {
|
|
32
|
-
entries.push(String(entry));
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
return "";
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
const ids = parseBulkIdsText(entries.join("\n"));
|
|
39
|
-
return ids.length > 0 ? ids.join(",") : "";
|
|
40
|
-
}
|
|
41
|
-
/** Normalize SDK/MCP scalar-or-array ID input into the list query's CSV form. */
|
|
42
|
-
export function normalizeBulkIdsValue(value) {
|
|
43
|
-
if (value === undefined) {
|
|
44
|
-
return undefined;
|
|
45
|
-
}
|
|
46
|
-
if (typeof value === "number") {
|
|
47
|
-
// Preserve an explicitly supplied but invalid numeric selector as blank so
|
|
48
|
-
// the bulk lifecycle's fail-closed empty-ID guard rejects it. Returning
|
|
49
|
-
// undefined here would erase the allowlist and could broaden a mutation to
|
|
50
|
-
// every item matched by the remaining filters.
|
|
51
|
-
return Number.isFinite(value) ? String(value) : "";
|
|
52
|
-
}
|
|
53
|
-
if (Array.isArray(value)) {
|
|
54
|
-
return normalizeBulkIdsArray(value);
|
|
55
|
-
}
|
|
56
|
-
if (typeof value !== "string") {
|
|
57
|
-
return "";
|
|
58
|
-
}
|
|
59
|
-
const ids = parseBulkIdsText(value);
|
|
60
|
-
return ids.length > 0 ? ids.join(",") : "";
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Resolve one CLI `--ids` value. `-` reads newline/comma-delimited stdin and
|
|
64
|
-
* `@path` reads the same grammar from a UTF-8 file; ordinary argv text accepts
|
|
65
|
-
* the grammar inline. The return value is canonical CSV for existing list
|
|
66
|
-
* filtering and unmatched-id accounting.
|
|
67
|
-
*/
|
|
68
|
-
export async function resolveCliBulkIdsInput(value, optionName = "--ids", readers = {}) {
|
|
69
|
-
if (value === undefined) {
|
|
70
|
-
return undefined;
|
|
71
|
-
}
|
|
72
|
-
const trimmed = value.trim();
|
|
73
|
-
let raw = value;
|
|
74
|
-
try {
|
|
75
|
-
if (trimmed === "-") {
|
|
76
|
-
raw = await (readers.readStdin ?? defaultStdinReader)(optionName);
|
|
77
|
-
}
|
|
78
|
-
else if (trimmed.startsWith("@")) {
|
|
79
|
-
const path = trimmed.slice(1).trim();
|
|
80
|
-
if (path.length === 0) {
|
|
81
|
-
throw new PmCliError(`${optionName} @path requires a non-empty file path.`, EXIT_CODE.USAGE, {
|
|
82
|
-
code: "bulk_ids_input_missing_path",
|
|
83
|
-
required: `Pass ${optionName} @<path>, ${optionName} -, or inline IDs.`,
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
raw = await (readers.readFile ?? defaultFileReader)(path);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
catch (error) {
|
|
90
|
-
if (error instanceof PmCliError) {
|
|
91
|
-
throw error;
|
|
92
|
-
}
|
|
93
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
94
|
-
throw new PmCliError(`${optionName} could not read ${trimmed === "-" ? "stdin" : `"${trimmed.slice(1).trim()}"`}: ${detail}`, EXIT_CODE.NOT_FOUND, {
|
|
95
|
-
code: "bulk_ids_input_unreadable",
|
|
96
|
-
required: `Provide readable newline/comma-delimited IDs via ${optionName} -, ${optionName} @<path>, or inline argv text.`,
|
|
97
|
-
nextSteps: [
|
|
98
|
-
`Retry with inline IDs: ${optionName} pm-a1b2,pm-c3d4`,
|
|
99
|
-
`Or pipe IDs: pm list --id-only | pm update-many ${optionName} - --dry-run`,
|
|
100
|
-
],
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
const normalized = normalizeBulkIdsValue(raw);
|
|
104
|
-
if (normalized !== "") {
|
|
105
|
-
return normalized;
|
|
106
|
-
}
|
|
107
|
-
throw new PmCliError(`${optionName} requires at least one non-empty item ID.`, EXIT_CODE.USAGE, {
|
|
108
|
-
code: "bulk_ids_input_empty",
|
|
109
|
-
required: `Provide one or more comma- or newline-delimited IDs through argv, stdin, or @path.`,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
1
|
+
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="854a0596-b0ec-5d2e-85b1-5444d8d7b622")}catch(e2){}})();import{readFile}from"node:fs/promises";import{createStdinTokenResolver}from"../item/parse.js";import{EXIT_CODE}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";const defaultFileReader=path=>readFile(path,"utf8");const defaultStdinReader=async optionName=>await createStdinTokenResolver().resolveValue("-",optionName);function parseBulkIdsText(raw){return[...new Set(raw.split(/[,\r\n]+/).map(entry=>entry.trim()).filter(entry=>entry.length>0))]}function normalizeBulkIdsArray(value){const entries=[];for(const entry of value){if(typeof entry==="string"){entries.push(entry)}else if(typeof entry==="number"&&Number.isFinite(entry)){entries.push(String(entry))}else{return""}}const ids=parseBulkIdsText(entries.join("\n"));return ids.length>0?ids.join(","):""}function normalizeBulkIdsValue(value){if(value===void 0){return void 0}if(typeof value==="number"){return Number.isFinite(value)?String(value):""}if(Array.isArray(value)){return normalizeBulkIdsArray(value)}if(typeof value!=="string"){return""}const ids=parseBulkIdsText(value);return ids.length>0?ids.join(","):""}async function resolveCliBulkIdsInput(value,optionName="--ids",readers={}){if(value===void 0){return void 0}const trimmed=value.trim();let raw=value;try{if(trimmed==="-"){raw=await(readers.readStdin??defaultStdinReader)(optionName)}else if(trimmed.startsWith("@")){const path=trimmed.slice(1).trim();if(path.length===0){throw new PmCliError(`${optionName} @path requires a non-empty file path.`,EXIT_CODE.USAGE,{code:"bulk_ids_input_missing_path",required:`Pass ${optionName} @<path>, ${optionName} -, or inline IDs.`})}raw=await(readers.readFile??defaultFileReader)(path)}}catch(error){if(error instanceof PmCliError){throw error}const detail=error instanceof Error?error.message:String(error);throw new PmCliError(`${optionName} could not read ${trimmed==="-"?"stdin":`"${trimmed.slice(1).trim()}"`}: ${detail}`,EXIT_CODE.NOT_FOUND,{code:"bulk_ids_input_unreadable",required:`Provide readable newline/comma-delimited IDs via ${optionName} -, ${optionName} @<path>, or inline argv text.`,nextSteps:[`Retry with inline IDs: ${optionName} pm-a1b2,pm-c3d4`,`Or pipe IDs: pm list --id-only | pm update-many ${optionName} - --dry-run`]})}const normalized=normalizeBulkIdsValue(raw);if(normalized!==""){return normalized}throw new PmCliError(`${optionName} requires at least one non-empty item ID.`,EXIT_CODE.USAGE,{code:"bulk_ids_input_empty",required:`Provide one or more comma- or newline-delimited IDs through argv, stdin, or @path.`})}export{normalizeBulkIdsValue,parseBulkIdsText,resolveCliBulkIdsInput};
|
|
112
2
|
//# sourceMappingURL=bulk-ids-input.js.map
|
|
113
|
-
//# debugId=411f4336-eb02-5167-9dce-ea99822a8a14
|