@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,230 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* @module core/history/event-index
|
|
3
|
-
*
|
|
4
|
-
* Maintains a rebuildable SQLite projection over append-only history streams
|
|
5
|
-
* for cursor-resumable cross-item mutation event reads.
|
|
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]="72b285a7-970e-5965-bacf-a4e0cfc5f060")}catch(e){}}();
|
|
9
|
-
import fs from "node:fs/promises";
|
|
10
|
-
import path from "node:path";
|
|
11
|
-
import { randomUUID } from "node:crypto";
|
|
12
|
-
import { createRequire } from "node:module";
|
|
13
|
-
import { isFileMissingError } from "../fs/fs-utils.js";
|
|
14
|
-
import { acquireLock, captureProcessIdentity, isProcessIdentityAlive, } from "../lock/lock.js";
|
|
15
|
-
import { EXIT_CODE } from "../shared/constants.js";
|
|
16
|
-
import { PmCliError } from "../shared/errors.js";
|
|
17
|
-
import { isMillisecondPrecisionRfc3339DateTime } from "../shared/time.js";
|
|
18
|
-
import { readHistoryEntries } from "./read.js";
|
|
19
|
-
import { classifyHistoryEvent } from "./event-classification.js";
|
|
20
|
-
const EVENT_INDEX_FILENAME = "history-event-index.sqlite";
|
|
21
|
-
const EVENT_INDEX_VERSION = "5";
|
|
22
|
-
const AUTHORITATIVE_HISTORY_CACHE_LIMIT = 8;
|
|
23
|
-
const HISTORY_EVENT_INDEX_LOCK_ID = "history-event-index";
|
|
24
|
-
const HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS = 300;
|
|
25
|
-
const HISTORY_EVENT_INDEX_LOCK_WAIT_MS = 30_000;
|
|
26
|
-
const HISTORY_EVENT_INDEX_INVALIDATION_LOCK_ID = "history-event-index-invalidation";
|
|
27
|
-
const HISTORY_EVENT_INDEX_INVALIDATION_DIRECTORY = "history-event-index-invalidations";
|
|
28
|
-
const HISTORY_EVENT_INDEX_INVALIDATION_MAX_UNVERIFIED_AGE_MS = HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS * 2 * 1_000;
|
|
29
|
-
const HISTORY_INDEX_LOCK_CONTENDED = Symbol("history-index-lock-contended");
|
|
30
|
-
const authoritativeHistoryCaches = new Map();
|
|
31
|
-
function eventIndexPath(pmRoot) {
|
|
32
|
-
return path.join(pmRoot, "runtime", EVENT_INDEX_FILENAME);
|
|
33
|
-
}
|
|
34
|
-
function historyEventIndexInvalidationDirectory(pmRoot) {
|
|
35
|
-
return path.join(pmRoot, "runtime", HISTORY_EVENT_INDEX_INVALIDATION_DIRECTORY);
|
|
36
|
-
}
|
|
37
|
-
async function listHistoryEventIndexInvalidations(pmRoot) {
|
|
38
|
-
const entries = await fs
|
|
39
|
-
.readdir(historyEventIndexInvalidationDirectory(pmRoot))
|
|
40
|
-
.catch((error) => {
|
|
41
|
-
if (isFileMissingError(error))
|
|
42
|
-
return [];
|
|
43
|
-
throw error;
|
|
44
|
-
});
|
|
45
|
-
return {
|
|
46
|
-
pending: entries.filter((name) => name.endsWith(".pending")).sort(),
|
|
47
|
-
committed: entries.filter((name) => name.endsWith(".committed")).sort(),
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
/** Remove only pending markers proven abandoned by the caller's invalidation-lock ownership. */
|
|
51
|
-
async function recoverAbandonedHistoryEventIndexInvalidations(pmRoot) {
|
|
52
|
-
const invalidations = await listHistoryEventIndexInvalidations(pmRoot);
|
|
53
|
-
const pending = (await Promise.all(invalidations.pending.map(async (name) => {
|
|
54
|
-
const owner = /^(\d+)-(unknown|\d+)-(\d+)-.+\.pending$/u.exec(name);
|
|
55
|
-
if (owner !== null) {
|
|
56
|
-
const processStartIdentity = owner[2];
|
|
57
|
-
if (await isProcessIdentityAlive({
|
|
58
|
-
pid: Number(owner[1]),
|
|
59
|
-
...(processStartIdentity === "unknown"
|
|
60
|
-
? {}
|
|
61
|
-
: { process_start_identity: processStartIdentity }),
|
|
62
|
-
}, Math.max(0, Date.now() - Number(owner[3])), HISTORY_EVENT_INDEX_INVALIDATION_MAX_UNVERIFIED_AGE_MS)) {
|
|
63
|
-
return name;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
await fs.rm(path.join(historyEventIndexInvalidationDirectory(pmRoot), name), {
|
|
67
|
-
force: true,
|
|
68
|
-
});
|
|
69
|
-
return null;
|
|
70
|
-
}))).filter((name) => name !== null);
|
|
71
|
-
return { pending, committed: invalidations.committed };
|
|
72
|
-
}
|
|
73
|
-
async function withHistoryEventIndexInvalidationLock(pmRoot, operation) {
|
|
74
|
-
const release = await acquireLock(pmRoot, HISTORY_EVENT_INDEX_INVALIDATION_LOCK_ID, HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS, `history-event-index-invalidation:${process.pid}`, false, false, HISTORY_EVENT_INDEX_LOCK_WAIT_MS);
|
|
75
|
-
try {
|
|
76
|
-
return await operation();
|
|
77
|
-
}
|
|
78
|
-
finally {
|
|
79
|
-
await release();
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
async function beginHistoryEventIndexInvalidation(pmRoot) {
|
|
83
|
-
const directory = historyEventIndexInvalidationDirectory(pmRoot);
|
|
84
|
-
await fs.mkdir(directory, { recursive: true });
|
|
85
|
-
const token = randomUUID();
|
|
86
|
-
const processIdentity = await captureProcessIdentity();
|
|
87
|
-
const pendingPath = path.join(directory, `${processIdentity.pid}-${processIdentity.process_start_identity ?? "unknown"}-${Date.now()}-${token}.pending`);
|
|
88
|
-
await fs.writeFile(pendingPath, "pending\n", { flag: "wx" });
|
|
89
|
-
return {
|
|
90
|
-
pendingPath,
|
|
91
|
-
committedPath: path.join(directory, `${token}.committed`),
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
function sameInvalidationNames(left, right) {
|
|
95
|
-
return (left.length === right.length &&
|
|
96
|
-
left.every((name, index) => name === right[index]));
|
|
97
|
-
}
|
|
98
|
-
async function invalidateHistoryEventIndex(pmRoot) {
|
|
99
|
-
try {
|
|
100
|
-
await fs.rm(eventIndexPath(pmRoot), { force: true });
|
|
101
|
-
}
|
|
102
|
-
catch {
|
|
103
|
-
// The authoritative append already committed. A retained projection remains
|
|
104
|
-
// unusable because its recorded stream byte size no longer matches authority.
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
async function withHistoryEventIndexLock(pmRoot, operation) {
|
|
108
|
-
const release = await acquireLock(pmRoot, HISTORY_EVENT_INDEX_LOCK_ID, HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS, `history-event-index:${process.pid}`, false, false, HISTORY_EVENT_INDEX_LOCK_WAIT_MS);
|
|
109
|
-
try {
|
|
110
|
-
return await operation();
|
|
111
|
-
}
|
|
112
|
-
finally {
|
|
113
|
-
await release();
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
async function readAuthoritativeHistorySnapshot(pmRoot) {
|
|
117
|
-
const historyRoot = path.join(pmRoot, "history");
|
|
118
|
-
const entries = await fs
|
|
119
|
-
.readdir(historyRoot, { withFileTypes: true })
|
|
120
|
-
.catch((error) => {
|
|
121
|
-
if (typeof error === "object" &&
|
|
122
|
-
error !== null &&
|
|
123
|
-
"code" in error &&
|
|
124
|
-
error.code === "ENOENT") {
|
|
125
|
-
return [];
|
|
126
|
-
}
|
|
127
|
-
throw error;
|
|
128
|
-
});
|
|
129
|
-
const cached = authoritativeHistoryCaches.get(pmRoot) ?? {
|
|
130
|
-
streams: new Map(),
|
|
131
|
-
ordered_events: [],
|
|
132
|
-
};
|
|
133
|
-
const presentStreams = new Set();
|
|
134
|
-
let changed = !authoritativeHistoryCaches.has(pmRoot);
|
|
135
|
-
for (const historyFile of entries
|
|
136
|
-
.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl"))
|
|
137
|
-
.sort((left, right) => left.name.localeCompare(right.name))) {
|
|
138
|
-
const streamId = historyFile.name.slice(0, -".jsonl".length);
|
|
139
|
-
presentStreams.add(streamId);
|
|
140
|
-
const historyPath = path.join(historyRoot, historyFile.name);
|
|
141
|
-
const stats = await fs.stat(historyPath, { bigint: true });
|
|
142
|
-
const signature = [
|
|
143
|
-
stats.dev,
|
|
144
|
-
stats.ino,
|
|
145
|
-
stats.size,
|
|
146
|
-
stats.mtimeNs,
|
|
147
|
-
stats.ctimeNs,
|
|
148
|
-
].join(":");
|
|
149
|
-
if (cached.streams.get(streamId)?.signature === signature)
|
|
150
|
-
continue;
|
|
151
|
-
const history = await readIndexableHistoryEntries(historyPath, streamId);
|
|
152
|
-
cached.streams.set(streamId, {
|
|
153
|
-
signature,
|
|
154
|
-
byte_size: Number(stats.size),
|
|
155
|
-
events: history.map((entry, streamOffset) => ({
|
|
156
|
-
stream_id: streamId,
|
|
157
|
-
stream_offset: streamOffset,
|
|
158
|
-
entry,
|
|
159
|
-
})),
|
|
160
|
-
});
|
|
161
|
-
changed = true;
|
|
162
|
-
}
|
|
163
|
-
for (const streamId of cached.streams.keys()) {
|
|
164
|
-
if (!presentStreams.has(streamId)) {
|
|
165
|
-
cached.streams.delete(streamId);
|
|
166
|
-
changed = true;
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
if (changed) {
|
|
170
|
-
cached.ordered_events = [...cached.streams.values()]
|
|
171
|
-
.flatMap((stream) => stream.events)
|
|
172
|
-
.sort(compareHistoryEventPosition);
|
|
173
|
-
}
|
|
174
|
-
authoritativeHistoryCaches.delete(pmRoot);
|
|
175
|
-
authoritativeHistoryCaches.set(pmRoot, cached);
|
|
176
|
-
if (authoritativeHistoryCaches.size > AUTHORITATIVE_HISTORY_CACHE_LIMIT) {
|
|
177
|
-
const oldestRoot = authoritativeHistoryCaches.keys().next().value;
|
|
178
|
-
authoritativeHistoryCaches.delete(oldestRoot);
|
|
179
|
-
}
|
|
180
|
-
return {
|
|
181
|
-
events: cached.ordered_events,
|
|
182
|
-
stream_byte_sizes: new Map([...cached.streams].map(([streamId, stream]) => [
|
|
183
|
-
streamId,
|
|
184
|
-
stream.byte_size,
|
|
185
|
-
])),
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
async function readIndexableHistoryEntries(historyPath, streamId) {
|
|
189
|
-
const entries = await readHistoryEntries(historyPath, streamId);
|
|
190
|
-
for (const [index, entry] of entries.entries()) {
|
|
191
|
-
if (typeof entry.ts !== "string" ||
|
|
192
|
-
!isMillisecondPrecisionRfc3339DateTime(entry.ts.trim())) {
|
|
193
|
-
throw new PmCliError(`History for ${streamId} contains an invalid or sub-millisecond timestamp at line ${index + 1}. Repair or restore the history stream and retry.`, EXIT_CODE.GENERIC_FAILURE, { code: "history_timestamp_invalid" });
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
return entries.map((entry) => ({
|
|
197
|
-
...entry,
|
|
198
|
-
ts: new Date(entry.ts.trim()).toISOString(),
|
|
199
|
-
}));
|
|
200
|
-
}
|
|
201
|
-
async function readAuthoritativeHistoryEvents(pmRoot) {
|
|
202
|
-
return (await readAuthoritativeHistorySnapshot(pmRoot)).events;
|
|
203
|
-
}
|
|
204
|
-
function loadDatabaseSync(loadModule) {
|
|
205
|
-
try {
|
|
206
|
-
const loaded = loadModule(["node", "sqlite"].join(":"));
|
|
207
|
-
return loaded.DatabaseSync ?? null;
|
|
208
|
-
}
|
|
209
|
-
catch {
|
|
210
|
-
return null;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
function loadStableDatabaseSync(nodeVersion, loadModule) {
|
|
214
|
-
const nodeMajor = Number.parseInt(nodeVersion, 10);
|
|
215
|
-
return Number.isFinite(nodeMajor) && nodeMajor >= 22
|
|
216
|
-
? loadDatabaseSync(loadModule)
|
|
217
|
-
: null;
|
|
218
|
-
}
|
|
219
|
-
let RuntimeDatabaseSync;
|
|
220
|
-
function resolveDatabaseSync() {
|
|
221
|
-
if (RuntimeDatabaseSync !== undefined)
|
|
222
|
-
return RuntimeDatabaseSync;
|
|
223
|
-
RuntimeDatabaseSync = loadStableDatabaseSync(process.versions.node, createRequire(import.meta.url));
|
|
224
|
-
return RuntimeDatabaseSync;
|
|
225
|
-
}
|
|
226
|
-
function createSchema(database) {
|
|
227
|
-
database.exec(`
|
|
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]="542d77d0-7bb8-5ed0-a1da-09de33d3767f")}catch(e2){}})();import fs from"node:fs/promises";import path from"node:path";import{randomUUID}from"node:crypto";import{createRequire}from"node:module";import{isFileMissingError}from"../fs/fs-utils.js";import{acquireLock,captureProcessIdentity,isProcessIdentityAlive}from"../lock/lock.js";import{EXIT_CODE}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{isMillisecondPrecisionRfc3339DateTime}from"../shared/time.js";import{readHistoryEntries}from"./read.js";import{classifyHistoryEvent}from"./event-classification.js";const EVENT_INDEX_FILENAME="history-event-index.sqlite";const EVENT_INDEX_VERSION="5";const AUTHORITATIVE_HISTORY_CACHE_LIMIT=8;const HISTORY_EVENT_INDEX_LOCK_ID="history-event-index";const HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS=300;const HISTORY_EVENT_INDEX_LOCK_WAIT_MS=3e4;const HISTORY_EVENT_INDEX_INVALIDATION_LOCK_ID="history-event-index-invalidation";const HISTORY_EVENT_INDEX_INVALIDATION_DIRECTORY="history-event-index-invalidations";const HISTORY_EVENT_INDEX_INVALIDATION_MAX_UNVERIFIED_AGE_MS=HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS*2*1e3;const HISTORY_INDEX_LOCK_CONTENDED=Symbol("history-index-lock-contended");const authoritativeHistoryCaches=new Map;function eventIndexPath(pmRoot){return path.join(pmRoot,"runtime",EVENT_INDEX_FILENAME)}function historyEventIndexInvalidationDirectory(pmRoot){return path.join(pmRoot,"runtime",HISTORY_EVENT_INDEX_INVALIDATION_DIRECTORY)}async function listHistoryEventIndexInvalidations(pmRoot){const entries=await fs.readdir(historyEventIndexInvalidationDirectory(pmRoot)).catch(error=>{if(isFileMissingError(error))return[];throw error});return{pending:entries.filter(name=>name.endsWith(".pending")).sort(),committed:entries.filter(name=>name.endsWith(".committed")).sort()}}async function recoverAbandonedHistoryEventIndexInvalidations(pmRoot){const invalidations=await listHistoryEventIndexInvalidations(pmRoot);const pending=(await Promise.all(invalidations.pending.map(async name=>{const owner=/^(\d+)-(unknown|\d+)-(\d+)-.+\.pending$/u.exec(name);if(owner!==null){const processStartIdentity=owner[2];if(await isProcessIdentityAlive({pid:Number(owner[1]),...processStartIdentity==="unknown"?{}:{process_start_identity:processStartIdentity}},Math.max(0,Date.now()-Number(owner[3])),HISTORY_EVENT_INDEX_INVALIDATION_MAX_UNVERIFIED_AGE_MS)){return name}}await fs.rm(path.join(historyEventIndexInvalidationDirectory(pmRoot),name),{force:true});return null}))).filter(name=>name!==null);return{pending,committed:invalidations.committed}}async function withHistoryEventIndexInvalidationLock(pmRoot,operation){const release=await acquireLock(pmRoot,HISTORY_EVENT_INDEX_INVALIDATION_LOCK_ID,HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS,`history-event-index-invalidation:${process.pid}`,false,false,HISTORY_EVENT_INDEX_LOCK_WAIT_MS);try{return await operation()}finally{await release()}}async function beginHistoryEventIndexInvalidation(pmRoot){const directory=historyEventIndexInvalidationDirectory(pmRoot);await fs.mkdir(directory,{recursive:true});const token=randomUUID();const processIdentity=await captureProcessIdentity();const pendingPath=path.join(directory,`${processIdentity.pid}-${processIdentity.process_start_identity??"unknown"}-${Date.now()}-${token}.pending`);await fs.writeFile(pendingPath,"pending\n",{flag:"wx"});return{pendingPath,committedPath:path.join(directory,`${token}.committed`)}}function sameInvalidationNames(left,right){return left.length===right.length&&left.every((name,index)=>name===right[index])}async function invalidateHistoryEventIndex(pmRoot){try{await fs.rm(eventIndexPath(pmRoot),{force:true})}catch{}}async function withHistoryEventIndexLock(pmRoot,operation){const release=await acquireLock(pmRoot,HISTORY_EVENT_INDEX_LOCK_ID,HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS,`history-event-index:${process.pid}`,false,false,HISTORY_EVENT_INDEX_LOCK_WAIT_MS);try{return await operation()}finally{await release()}}async function readAuthoritativeHistorySnapshot(pmRoot){const historyRoot=path.join(pmRoot,"history");const entries=await fs.readdir(historyRoot,{withFileTypes:true}).catch(error=>{if(typeof error==="object"&&error!==null&&"code"in error&&error.code==="ENOENT"){return[]}throw error});const cached=authoritativeHistoryCaches.get(pmRoot)??{streams:new Map,ordered_events:[]};const presentStreams=new Set;let changed=!authoritativeHistoryCaches.has(pmRoot);for(const historyFile of entries.filter(entry=>entry.isFile()&&entry.name.endsWith(".jsonl")).sort((left,right)=>left.name.localeCompare(right.name))){const streamId=historyFile.name.slice(0,-".jsonl".length);presentStreams.add(streamId);const historyPath=path.join(historyRoot,historyFile.name);const stats=await fs.stat(historyPath,{bigint:true});const signature=[stats.dev,stats.ino,stats.size,stats.mtimeNs,stats.ctimeNs].join(":");if(cached.streams.get(streamId)?.signature===signature)continue;const history=await readIndexableHistoryEntries(historyPath,streamId);cached.streams.set(streamId,{signature,byte_size:Number(stats.size),events:history.map((entry,streamOffset)=>({stream_id:streamId,stream_offset:streamOffset,entry}))});changed=true}for(const streamId of cached.streams.keys()){if(!presentStreams.has(streamId)){cached.streams.delete(streamId);changed=true}}if(changed){cached.ordered_events=[...cached.streams.values()].flatMap(stream=>stream.events).sort(compareHistoryEventPosition)}authoritativeHistoryCaches.delete(pmRoot);authoritativeHistoryCaches.set(pmRoot,cached);if(authoritativeHistoryCaches.size>AUTHORITATIVE_HISTORY_CACHE_LIMIT){const oldestRoot=authoritativeHistoryCaches.keys().next().value;authoritativeHistoryCaches.delete(oldestRoot)}return{events:cached.ordered_events,stream_byte_sizes:new Map([...cached.streams].map(([streamId,stream])=>[streamId,stream.byte_size]))}}async function readIndexableHistoryEntries(historyPath,streamId){const entries=await readHistoryEntries(historyPath,streamId);for(const[index,entry]of entries.entries()){if(typeof entry.ts!=="string"||!isMillisecondPrecisionRfc3339DateTime(entry.ts.trim())){throw new PmCliError(`History for ${streamId} contains an invalid or sub-millisecond timestamp at line ${index+1}. Repair or restore the history stream and retry.`,EXIT_CODE.GENERIC_FAILURE,{code:"history_timestamp_invalid"})}}return entries.map(entry=>({...entry,ts:new Date(entry.ts.trim()).toISOString()}))}async function readAuthoritativeHistoryEvents(pmRoot){return(await readAuthoritativeHistorySnapshot(pmRoot)).events}function loadDatabaseSync(loadModule){try{const loaded=loadModule(["node","sqlite"].join(":"));return loaded.DatabaseSync??null}catch{return null}}function loadStableDatabaseSync(nodeVersion,loadModule){const nodeMajor=Number.parseInt(nodeVersion,10);return Number.isFinite(nodeMajor)&&nodeMajor>=22?loadDatabaseSync(loadModule):null}let RuntimeDatabaseSync;function resolveDatabaseSync(){if(RuntimeDatabaseSync!==void 0)return RuntimeDatabaseSync;RuntimeDatabaseSync=loadStableDatabaseSync(process.versions.node,createRequire(import.meta.url));return RuntimeDatabaseSync}function createSchema(database){database.exec(`
|
|
228
2
|
PRAGMA journal_mode = OFF;
|
|
229
3
|
PRAGMA synchronous = OFF;
|
|
230
4
|
CREATE TABLE metadata (
|
|
@@ -259,478 +33,15 @@ function createSchema(database) {
|
|
|
259
33
|
ON events(agent_harness, ts, stream_id, stream_offset);
|
|
260
34
|
CREATE INDEX events_instance_order
|
|
261
35
|
ON events(agent_instance, ts, stream_id, stream_offset);
|
|
262
|
-
`);
|
|
263
|
-
database
|
|
264
|
-
.prepare("INSERT INTO metadata(key, value) VALUES ('version', ?)")
|
|
265
|
-
.run(EVENT_INDEX_VERSION);
|
|
266
|
-
}
|
|
267
|
-
function insertEvent(database, event) {
|
|
268
|
-
const entry = {
|
|
269
|
-
...event.entry,
|
|
270
|
-
ts: new Date(event.entry.ts.trim()).toISOString(),
|
|
271
|
-
};
|
|
272
|
-
database
|
|
273
|
-
.prepare(`INSERT INTO events(
|
|
36
|
+
`);database.prepare("INSERT INTO metadata(key, value) VALUES ('version', ?)").run(EVENT_INDEX_VERSION)}function insertEvent(database,event){const entry={...event.entry,ts:new Date(event.entry.ts.trim()).toISOString()};database.prepare(`INSERT INTO events(
|
|
274
37
|
stream_id, stream_offset, ts, author, agent_harness,
|
|
275
38
|
agent_instance, op, event_class, entry_json
|
|
276
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
277
|
-
|
|
278
|
-
}
|
|
279
|
-
function parseIndexedHistoryEvent(row) {
|
|
280
|
-
const entry = JSON.parse(String(row.entry_json));
|
|
281
|
-
if (typeof entry.ts !== "string" ||
|
|
282
|
-
!isMillisecondPrecisionRfc3339DateTime(entry.ts.trim())) {
|
|
283
|
-
return null;
|
|
284
|
-
}
|
|
285
|
-
return {
|
|
286
|
-
stream_id: String(row.stream_id),
|
|
287
|
-
stream_offset: Number(row.stream_offset),
|
|
288
|
-
entry: { ...entry, ts: new Date(entry.ts.trim()).toISOString() },
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
function upsertStreamByteSize(database, streamId, byteSize) {
|
|
292
|
-
database
|
|
293
|
-
.prepare(`INSERT INTO streams(stream_id, byte_size) VALUES (?, ?)
|
|
294
|
-
ON CONFLICT(stream_id) DO UPDATE SET byte_size = excluded.byte_size`)
|
|
295
|
-
.run(streamId, byteSize);
|
|
296
|
-
}
|
|
297
|
-
/** Rebuild the complete optional event projection from authoritative streams. */
|
|
298
|
-
export async function rebuildHistoryEventIndex(pmRoot) {
|
|
299
|
-
const Database = resolveDatabaseSync();
|
|
300
|
-
if (!Database)
|
|
301
|
-
return false;
|
|
302
|
-
return withHistoryEventIndexLock(pmRoot, async () => {
|
|
303
|
-
let invalidations;
|
|
304
|
-
try {
|
|
305
|
-
invalidations = await withHistoryEventIndexInvalidationLock(pmRoot, () => recoverAbandonedHistoryEventIndexInvalidations(pmRoot));
|
|
306
|
-
}
|
|
307
|
-
catch (error) {
|
|
308
|
-
if (error instanceof PmCliError && error.code === "lock_conflict") {
|
|
309
|
-
return false;
|
|
310
|
-
}
|
|
311
|
-
throw error;
|
|
312
|
-
}
|
|
313
|
-
if (invalidations.pending.length > 0)
|
|
314
|
-
return false;
|
|
315
|
-
const targetPath = eventIndexPath(pmRoot);
|
|
316
|
-
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
317
|
-
const temporaryPath = `${targetPath}.${randomUUID()}.tmp`;
|
|
318
|
-
let database;
|
|
319
|
-
try {
|
|
320
|
-
database = new Database(temporaryPath);
|
|
321
|
-
createSchema(database);
|
|
322
|
-
database.exec("BEGIN IMMEDIATE");
|
|
323
|
-
const authoritative = await readAuthoritativeHistorySnapshot(pmRoot);
|
|
324
|
-
for (const event of authoritative.events) {
|
|
325
|
-
insertEvent(database, event);
|
|
326
|
-
}
|
|
327
|
-
for (const [streamId, byteSize] of authoritative.stream_byte_sizes) {
|
|
328
|
-
upsertStreamByteSize(database, streamId, byteSize);
|
|
329
|
-
}
|
|
330
|
-
database.exec("COMMIT");
|
|
331
|
-
database.close();
|
|
332
|
-
database = undefined;
|
|
333
|
-
const published = await withHistoryEventIndexInvalidationLock(pmRoot, async () => {
|
|
334
|
-
const current = await recoverAbandonedHistoryEventIndexInvalidations(pmRoot);
|
|
335
|
-
if (current.pending.length > 0 ||
|
|
336
|
-
!sameInvalidationNames(invalidations.committed, current.committed)) {
|
|
337
|
-
return false;
|
|
338
|
-
}
|
|
339
|
-
await fs.rm(targetPath, { force: true });
|
|
340
|
-
await fs.rename(temporaryPath, targetPath);
|
|
341
|
-
await Promise.all(invalidations.committed.map((name) => fs.rm(path.join(historyEventIndexInvalidationDirectory(pmRoot), name), { force: true })));
|
|
342
|
-
return true;
|
|
343
|
-
});
|
|
344
|
-
if (!published)
|
|
345
|
-
await fs.rm(temporaryPath, { force: true });
|
|
346
|
-
return published;
|
|
347
|
-
}
|
|
348
|
-
catch (error) {
|
|
349
|
-
database?.close();
|
|
350
|
-
await fs.rm(temporaryPath, { force: true });
|
|
351
|
-
throw error;
|
|
352
|
-
}
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
function matchesSet(value, accepted) {
|
|
356
|
-
return !accepted || accepted.length === 0 || accepted.includes(value);
|
|
357
|
-
}
|
|
358
|
-
function compareHistoryEventPosition(left, right) {
|
|
359
|
-
return (left.entry.ts.localeCompare(right.entry.ts) ||
|
|
360
|
-
left.stream_id.localeCompare(right.stream_id) ||
|
|
361
|
-
left.stream_offset - right.stream_offset);
|
|
362
|
-
}
|
|
363
|
-
function canonicalHistoryQueryTimestamp(value) {
|
|
364
|
-
const milliseconds = Date.parse(value);
|
|
365
|
-
return Number.isFinite(milliseconds)
|
|
366
|
-
? new Date(milliseconds).toISOString()
|
|
367
|
-
: value;
|
|
368
|
-
}
|
|
369
|
-
function isInsideHistoryEventWindow(event, query) {
|
|
370
|
-
if (query.after_ts !== undefined &&
|
|
371
|
-
query.after_stream_id !== undefined &&
|
|
372
|
-
query.after_stream_offset !== undefined) {
|
|
373
|
-
if (compareHistoryEventPosition(event, {
|
|
374
|
-
stream_id: query.after_stream_id,
|
|
375
|
-
stream_offset: query.after_stream_offset,
|
|
376
|
-
entry: {
|
|
377
|
-
...event.entry,
|
|
378
|
-
ts: canonicalHistoryQueryTimestamp(query.after_ts),
|
|
379
|
-
},
|
|
380
|
-
}) <= 0) {
|
|
381
|
-
return false;
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
else if (query.since_ts !== undefined &&
|
|
385
|
-
event.entry.ts < canonicalHistoryQueryTimestamp(query.since_ts)) {
|
|
386
|
-
return false;
|
|
387
|
-
}
|
|
388
|
-
return true;
|
|
389
|
-
}
|
|
390
|
-
function matchesHistoryEventHarness(event, query) {
|
|
391
|
-
if (!query.harnesses || query.harnesses.length === 0)
|
|
392
|
-
return true;
|
|
393
|
-
if (query.harnesses.includes(event.entry.agent_harness ?? ""))
|
|
394
|
-
return true;
|
|
395
|
-
return (event.entry.agent_harness === undefined &&
|
|
396
|
-
(query.harness_alias_authors ?? []).includes(event.entry.author));
|
|
397
|
-
}
|
|
398
|
-
function matchesHistoryEventQuery(event, query) {
|
|
399
|
-
if (!isInsideHistoryEventWindow(event, query) ||
|
|
400
|
-
!matchesSet(event.entry.op, query.ops) ||
|
|
401
|
-
!matchesSet(event.entry.author, query.authors) ||
|
|
402
|
-
!matchesSet(event.entry.agent_instance ?? "", query.agent_instances) ||
|
|
403
|
-
!matchesSet(event.stream_id, query.stream_ids) ||
|
|
404
|
-
!matchesHistoryEventHarness(event, query)) {
|
|
405
|
-
return false;
|
|
406
|
-
}
|
|
407
|
-
return (query.provenance ?? []).every((predicate) => {
|
|
408
|
-
const value = event.entry.agent_provenance?.[predicate.dimension]?.value;
|
|
409
|
-
return value !== undefined && predicate.values.includes(value);
|
|
410
|
-
});
|
|
411
|
-
}
|
|
412
|
-
/**
|
|
413
|
-
* Query authoritative history streams when the optional SQLite accelerator is
|
|
414
|
-
* unavailable. The result preserves the index contract at higher read cost.
|
|
415
|
-
*/
|
|
416
|
-
export async function queryHistoryEventStreams(pmRoot, query) {
|
|
417
|
-
const limit = Math.max(0, Math.floor(query.limit));
|
|
418
|
-
const rows = (await readAuthoritativeHistoryEvents(pmRoot))
|
|
419
|
-
.filter((event) => matchesHistoryEventQuery(event, query))
|
|
420
|
-
.slice(0, limit + 1);
|
|
421
|
-
return {
|
|
422
|
-
events: rows.slice(0, query.limit),
|
|
423
|
-
has_more: rows.length > query.limit,
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
|
-
* Serialize an authoritative append with its optional SQLite projection.
|
|
428
|
-
* The database write lock spans the file append and size capture, so compliant
|
|
429
|
-
* cross-process writers cannot certify a newer stream size with older rows.
|
|
430
|
-
*/
|
|
431
|
-
export async function appendHistoryEntryWithEventIndex(historyPath, entry, append) {
|
|
432
|
-
const pmRoot = path.dirname(path.dirname(historyPath));
|
|
433
|
-
const Database = resolveDatabaseSync();
|
|
434
|
-
if (!Database) {
|
|
435
|
-
await append();
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
438
|
-
let authoritativeAppendCommitted = false;
|
|
439
|
-
try {
|
|
440
|
-
await withHistoryEventIndexLock(pmRoot, async () => {
|
|
441
|
-
const targetPath = eventIndexPath(pmRoot);
|
|
442
|
-
try {
|
|
443
|
-
await fs.access(targetPath);
|
|
444
|
-
}
|
|
445
|
-
catch {
|
|
446
|
-
await append();
|
|
447
|
-
return;
|
|
448
|
-
}
|
|
449
|
-
let database;
|
|
450
|
-
try {
|
|
451
|
-
database = new Database(targetPath);
|
|
452
|
-
const version = database
|
|
453
|
-
.prepare("SELECT value FROM metadata WHERE key = 'version'")
|
|
454
|
-
.get();
|
|
455
|
-
if (version?.value !== EVENT_INDEX_VERSION) {
|
|
456
|
-
throw new TypeError("Unsupported history event index version");
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
catch {
|
|
460
|
-
database?.close();
|
|
461
|
-
await fs.rm(targetPath, { force: true });
|
|
462
|
-
await append();
|
|
463
|
-
return;
|
|
464
|
-
}
|
|
465
|
-
try {
|
|
466
|
-
database.exec("PRAGMA busy_timeout = 5000");
|
|
467
|
-
database.exec("BEGIN IMMEDIATE");
|
|
468
|
-
}
|
|
469
|
-
catch (error) {
|
|
470
|
-
database.close();
|
|
471
|
-
throw error;
|
|
472
|
-
}
|
|
473
|
-
let appended = false;
|
|
474
|
-
try {
|
|
475
|
-
await append();
|
|
476
|
-
appended = true;
|
|
477
|
-
authoritativeAppendCommitted = true;
|
|
478
|
-
const streamId = path.basename(historyPath, ".jsonl");
|
|
479
|
-
const offset = database
|
|
480
|
-
.prepare("SELECT COALESCE(MAX(stream_offset), -1) + 1 AS value FROM events WHERE stream_id = ?")
|
|
481
|
-
.get(streamId);
|
|
482
|
-
insertEvent(database, {
|
|
483
|
-
stream_id: streamId,
|
|
484
|
-
stream_offset: Number(offset.value),
|
|
485
|
-
entry,
|
|
486
|
-
});
|
|
487
|
-
upsertStreamByteSize(database, streamId, (await fs.stat(historyPath)).size);
|
|
488
|
-
database.exec("COMMIT");
|
|
489
|
-
database.close();
|
|
490
|
-
}
|
|
491
|
-
catch (error) {
|
|
492
|
-
database?.close();
|
|
493
|
-
if (!appended)
|
|
494
|
-
throw error;
|
|
495
|
-
await invalidateHistoryEventIndex(pmRoot);
|
|
496
|
-
}
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
catch (error) {
|
|
500
|
-
if (authoritativeAppendCommitted) {
|
|
501
|
-
await invalidateHistoryEventIndex(pmRoot);
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
504
|
-
if (!(error instanceof PmCliError) || error.code !== "lock_conflict") {
|
|
505
|
-
throw error;
|
|
506
|
-
}
|
|
507
|
-
let pendingMarkerPath;
|
|
508
|
-
try {
|
|
509
|
-
await withHistoryEventIndexInvalidationLock(pmRoot, async () => {
|
|
510
|
-
const marker = await beginHistoryEventIndexInvalidation(pmRoot);
|
|
511
|
-
pendingMarkerPath = marker.pendingPath;
|
|
512
|
-
try {
|
|
513
|
-
await append();
|
|
514
|
-
authoritativeAppendCommitted = true;
|
|
515
|
-
}
|
|
516
|
-
catch (appendError) {
|
|
517
|
-
await fs.rm(marker.pendingPath, { force: true });
|
|
518
|
-
throw appendError;
|
|
519
|
-
}
|
|
520
|
-
await fs.rename(marker.pendingPath, marker.committedPath);
|
|
521
|
-
await invalidateHistoryEventIndex(pmRoot);
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
catch (fallbackError) {
|
|
525
|
-
if (authoritativeAppendCommitted) {
|
|
526
|
-
await invalidateHistoryEventIndex(pmRoot);
|
|
527
|
-
try {
|
|
528
|
-
await fs.rm(pendingMarkerPath, { force: true });
|
|
529
|
-
}
|
|
530
|
-
catch {
|
|
531
|
-
// The authoritative append is durable; marker cleanup is best effort.
|
|
532
|
-
}
|
|
533
|
-
return;
|
|
534
|
-
}
|
|
535
|
-
throw fallbackError;
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
/** Invalidate the optional event projection after a non-append rewrite. */
|
|
540
|
-
export async function removeHistoryEventIndexForHistoryPath(historyPath) {
|
|
541
|
-
await fs.rm(eventIndexPath(path.dirname(path.dirname(historyPath))), {
|
|
542
|
-
force: true,
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
function appendSetPredicate(clauses, parameters, column, values) {
|
|
546
|
-
if (!values || values.length === 0)
|
|
547
|
-
return;
|
|
548
|
-
clauses.push(`${column} IN (${values.map(() => "?").join(", ")})`);
|
|
549
|
-
parameters.push(...values);
|
|
550
|
-
}
|
|
551
|
-
function appendHarnessPredicate(clauses, parameters, harnesses, aliasAuthors) {
|
|
552
|
-
if (!harnesses || harnesses.length === 0)
|
|
553
|
-
return;
|
|
554
|
-
const harnessPlaceholders = harnesses.map(() => "?").join(", ");
|
|
555
|
-
const aliases = aliasAuthors ?? [];
|
|
556
|
-
if (aliases.length > 0) {
|
|
557
|
-
clauses.push(`(agent_harness IN (${harnessPlaceholders}) OR (agent_harness IS NULL AND author IN (${aliases.map(() => "?").join(", ")})))`);
|
|
558
|
-
parameters.push(...harnesses, ...aliases);
|
|
559
|
-
return;
|
|
560
|
-
}
|
|
561
|
-
clauses.push(`agent_harness IN (${harnessPlaceholders})`);
|
|
562
|
-
parameters.push(...harnesses);
|
|
563
|
-
}
|
|
564
|
-
/** Query the optional event projection without scanning history streams. */
|
|
565
|
-
export async function queryHistoryEventIndex(pmRoot, query) {
|
|
566
|
-
const Database = resolveDatabaseSync();
|
|
567
|
-
if (!Database)
|
|
568
|
-
return null;
|
|
569
|
-
const clauses = [];
|
|
570
|
-
const parameters = [];
|
|
571
|
-
if (query.after_ts !== undefined &&
|
|
572
|
-
query.after_stream_id !== undefined &&
|
|
573
|
-
query.after_stream_offset !== undefined) {
|
|
574
|
-
clauses.push("(ts > ? OR (ts = ? AND stream_id > ?) OR (ts = ? AND stream_id = ? AND stream_offset > ?))");
|
|
575
|
-
const afterTimestamp = canonicalHistoryQueryTimestamp(query.after_ts);
|
|
576
|
-
parameters.push(afterTimestamp, afterTimestamp, query.after_stream_id, afterTimestamp, query.after_stream_id, query.after_stream_offset);
|
|
577
|
-
}
|
|
578
|
-
else if (query.since_ts !== undefined) {
|
|
579
|
-
clauses.push("ts >= ?");
|
|
580
|
-
parameters.push(canonicalHistoryQueryTimestamp(query.since_ts));
|
|
581
|
-
}
|
|
582
|
-
appendSetPredicate(clauses, parameters, "op", query.ops);
|
|
583
|
-
appendSetPredicate(clauses, parameters, "author", query.authors);
|
|
584
|
-
appendHarnessPredicate(clauses, parameters, query.harnesses, query.harness_alias_authors);
|
|
585
|
-
appendSetPredicate(clauses, parameters, "agent_instance", query.agent_instances);
|
|
586
|
-
for (const predicate of query.provenance ?? []) {
|
|
587
|
-
clauses.push(`json_extract(entry_json, '$.agent_provenance.${predicate.dimension}.value') IN (${predicate.values.map(() => "?").join(", ")})`);
|
|
588
|
-
parameters.push(...predicate.values);
|
|
589
|
-
}
|
|
590
|
-
appendSetPredicate(clauses, parameters, "stream_id", query.stream_ids);
|
|
591
|
-
const where = clauses.length === 0 ? "" : ` WHERE ${clauses.join(" AND ")}`;
|
|
592
|
-
let database;
|
|
593
|
-
try {
|
|
594
|
-
return await withHistoryEventIndexLock(pmRoot, async () => {
|
|
595
|
-
return withHistoryEventIndexInvalidationLock(pmRoot, async () => {
|
|
596
|
-
const invalidations = await recoverAbandonedHistoryEventIndexInvalidations(pmRoot);
|
|
597
|
-
if (invalidations.pending.length > 0 ||
|
|
598
|
-
invalidations.committed.length > 0) {
|
|
599
|
-
return null;
|
|
600
|
-
}
|
|
601
|
-
database = new Database(eventIndexPath(pmRoot), { readOnly: true });
|
|
602
|
-
const version = database
|
|
603
|
-
.prepare("SELECT value FROM metadata WHERE key = 'version'")
|
|
604
|
-
.get();
|
|
605
|
-
const validationStreamIds = await historyIndexValidationStreamIds(database, pmRoot, query.stream_ids);
|
|
606
|
-
if (version?.value !== EVENT_INDEX_VERSION ||
|
|
607
|
-
!(await historyIndexMatchesStreamSizes(database, pmRoot, validationStreamIds))) {
|
|
608
|
-
database.close();
|
|
609
|
-
database = undefined;
|
|
610
|
-
return null;
|
|
611
|
-
}
|
|
612
|
-
const rows = database
|
|
613
|
-
.prepare(`SELECT stream_id, stream_offset, entry_json
|
|
39
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(event.stream_id,event.stream_offset,entry.ts,entry.author,entry.agent_harness??null,entry.agent_instance??null,entry.op,classifyHistoryEvent(entry),JSON.stringify(entry))}function parseIndexedHistoryEvent(row){const entry=JSON.parse(String(row.entry_json));if(typeof entry.ts!=="string"||!isMillisecondPrecisionRfc3339DateTime(entry.ts.trim())){return null}return{stream_id:String(row.stream_id),stream_offset:Number(row.stream_offset),entry:{...entry,ts:new Date(entry.ts.trim()).toISOString()}}}function upsertStreamByteSize(database,streamId,byteSize){database.prepare(`INSERT INTO streams(stream_id, byte_size) VALUES (?, ?)
|
|
40
|
+
ON CONFLICT(stream_id) DO UPDATE SET byte_size = excluded.byte_size`).run(streamId,byteSize)}async function rebuildHistoryEventIndex(pmRoot){const Database=resolveDatabaseSync();if(!Database)return false;return withHistoryEventIndexLock(pmRoot,async()=>{let invalidations;try{invalidations=await withHistoryEventIndexInvalidationLock(pmRoot,()=>recoverAbandonedHistoryEventIndexInvalidations(pmRoot))}catch(error){if(error instanceof PmCliError&&error.code==="lock_conflict"){return false}throw error}if(invalidations.pending.length>0)return false;const targetPath=eventIndexPath(pmRoot);await fs.mkdir(path.dirname(targetPath),{recursive:true});const temporaryPath=`${targetPath}.${randomUUID()}.tmp`;let database;try{database=new Database(temporaryPath);createSchema(database);database.exec("BEGIN IMMEDIATE");const authoritative=await readAuthoritativeHistorySnapshot(pmRoot);for(const event of authoritative.events){insertEvent(database,event)}for(const[streamId,byteSize]of authoritative.stream_byte_sizes){upsertStreamByteSize(database,streamId,byteSize)}database.exec("COMMIT");database.close();database=void 0;const published=await withHistoryEventIndexInvalidationLock(pmRoot,async()=>{const current=await recoverAbandonedHistoryEventIndexInvalidations(pmRoot);if(current.pending.length>0||!sameInvalidationNames(invalidations.committed,current.committed)){return false}await fs.rm(targetPath,{force:true});await fs.rename(temporaryPath,targetPath);await Promise.all(invalidations.committed.map(name=>fs.rm(path.join(historyEventIndexInvalidationDirectory(pmRoot),name),{force:true})));return true});if(!published)await fs.rm(temporaryPath,{force:true});return published}catch(error){database?.close();await fs.rm(temporaryPath,{force:true});throw error}})}function matchesSet(value,accepted){return!accepted||accepted.length===0||accepted.includes(value)}function compareHistoryEventPosition(left,right){return left.entry.ts.localeCompare(right.entry.ts)||left.stream_id.localeCompare(right.stream_id)||left.stream_offset-right.stream_offset}function canonicalHistoryQueryTimestamp(value){const milliseconds=Date.parse(value);return Number.isFinite(milliseconds)?new Date(milliseconds).toISOString():value}function isInsideHistoryEventWindow(event,query){if(query.after_ts!==void 0&&query.after_stream_id!==void 0&&query.after_stream_offset!==void 0){if(compareHistoryEventPosition(event,{stream_id:query.after_stream_id,stream_offset:query.after_stream_offset,entry:{...event.entry,ts:canonicalHistoryQueryTimestamp(query.after_ts)}})<=0){return false}}else if(query.since_ts!==void 0&&event.entry.ts<canonicalHistoryQueryTimestamp(query.since_ts)){return false}return true}function matchesHistoryEventHarness(event,query){if(!query.harnesses||query.harnesses.length===0)return true;if(query.harnesses.includes(event.entry.agent_harness??""))return true;return event.entry.agent_harness===void 0&&(query.harness_alias_authors??[]).includes(event.entry.author)}function matchesHistoryEventQuery(event,query){if(!isInsideHistoryEventWindow(event,query)||!matchesSet(event.entry.op,query.ops)||!matchesSet(event.entry.author,query.authors)||!matchesSet(event.entry.agent_instance??"",query.agent_instances)||!matchesSet(event.stream_id,query.stream_ids)||!matchesHistoryEventHarness(event,query)){return false}return(query.provenance??[]).every(predicate=>{const value=event.entry.agent_provenance?.[predicate.dimension]?.value;return value!==void 0&&predicate.values.includes(value)})}async function queryHistoryEventStreams(pmRoot,query){const limit=Math.max(0,Math.floor(query.limit));const rows=(await readAuthoritativeHistoryEvents(pmRoot)).filter(event=>matchesHistoryEventQuery(event,query)).slice(0,limit+1);return{events:rows.slice(0,query.limit),has_more:rows.length>query.limit}}async function appendHistoryEntryWithEventIndex(historyPath,entry,append){const pmRoot=path.dirname(path.dirname(historyPath));const Database=resolveDatabaseSync();if(!Database){await append();return}let authoritativeAppendCommitted=false;try{await withHistoryEventIndexLock(pmRoot,async()=>{const targetPath=eventIndexPath(pmRoot);try{await fs.access(targetPath)}catch{await append();return}let database;try{database=new Database(targetPath);const version=database.prepare("SELECT value FROM metadata WHERE key = 'version'").get();if(version?.value!==EVENT_INDEX_VERSION){throw new TypeError("Unsupported history event index version")}}catch{database?.close();await fs.rm(targetPath,{force:true});await append();return}try{database.exec("PRAGMA busy_timeout = 5000");database.exec("BEGIN IMMEDIATE")}catch(error){database.close();throw error}let appended=false;try{await append();appended=true;authoritativeAppendCommitted=true;const streamId=path.basename(historyPath,".jsonl");const offset=database.prepare("SELECT COALESCE(MAX(stream_offset), -1) + 1 AS value FROM events WHERE stream_id = ?").get(streamId);insertEvent(database,{stream_id:streamId,stream_offset:Number(offset.value),entry});upsertStreamByteSize(database,streamId,(await fs.stat(historyPath)).size);database.exec("COMMIT");database.close()}catch(error){database?.close();if(!appended)throw error;await invalidateHistoryEventIndex(pmRoot)}})}catch(error){if(authoritativeAppendCommitted){await invalidateHistoryEventIndex(pmRoot);return}if(!(error instanceof PmCliError)||error.code!=="lock_conflict"){throw error}let pendingMarkerPath;try{await withHistoryEventIndexInvalidationLock(pmRoot,async()=>{const marker=await beginHistoryEventIndexInvalidation(pmRoot);pendingMarkerPath=marker.pendingPath;try{await append();authoritativeAppendCommitted=true}catch(appendError){await fs.rm(marker.pendingPath,{force:true});throw appendError}await fs.rename(marker.pendingPath,marker.committedPath);await invalidateHistoryEventIndex(pmRoot)})}catch(fallbackError){if(authoritativeAppendCommitted){await invalidateHistoryEventIndex(pmRoot);try{await fs.rm(pendingMarkerPath,{force:true})}catch{}return}throw fallbackError}}}async function removeHistoryEventIndexForHistoryPath(historyPath){await fs.rm(eventIndexPath(path.dirname(path.dirname(historyPath))),{force:true})}function appendSetPredicate(clauses,parameters,column,values){if(!values||values.length===0)return;clauses.push(`${column} IN (${values.map(()=>"?").join(", ")})`);parameters.push(...values)}function appendHarnessPredicate(clauses,parameters,harnesses,aliasAuthors){if(!harnesses||harnesses.length===0)return;const harnessPlaceholders=harnesses.map(()=>"?").join(", ");const aliases=aliasAuthors??[];if(aliases.length>0){clauses.push(`(agent_harness IN (${harnessPlaceholders}) OR (agent_harness IS NULL AND author IN (${aliases.map(()=>"?").join(", ")})))`);parameters.push(...harnesses,...aliases);return}clauses.push(`agent_harness IN (${harnessPlaceholders})`);parameters.push(...harnesses)}async function openSettledHistoryEventIndex(pmRoot,Database){const invalidations=await recoverAbandonedHistoryEventIndexInvalidations(pmRoot);if(invalidations.pending.length>0||invalidations.committed.length>0){return void 0}const database=new Database(eventIndexPath(pmRoot),{readOnly:true});try{const version=database.prepare("SELECT value FROM metadata WHERE key = 'version'").get();if(version?.value===EVENT_INDEX_VERSION)return database}catch(error){database.close();throw error}database.close();return void 0}async function queryHistoryEventIndex(pmRoot,query){const Database=resolveDatabaseSync();if(!Database)return null;const clauses=[];const parameters=[];if(query.after_ts!==void 0&&query.after_stream_id!==void 0&&query.after_stream_offset!==void 0){clauses.push("(ts > ? OR (ts = ? AND stream_id > ?) OR (ts = ? AND stream_id = ? AND stream_offset > ?))");const afterTimestamp=canonicalHistoryQueryTimestamp(query.after_ts);parameters.push(afterTimestamp,afterTimestamp,query.after_stream_id,afterTimestamp,query.after_stream_id,query.after_stream_offset)}else if(query.since_ts!==void 0){clauses.push("ts >= ?");parameters.push(canonicalHistoryQueryTimestamp(query.since_ts))}appendSetPredicate(clauses,parameters,"op",query.ops);appendSetPredicate(clauses,parameters,"author",query.authors);appendHarnessPredicate(clauses,parameters,query.harnesses,query.harness_alias_authors);appendSetPredicate(clauses,parameters,"agent_instance",query.agent_instances);for(const predicate of query.provenance??[]){clauses.push(`json_extract(entry_json, '$.agent_provenance.${predicate.dimension}.value') IN (${predicate.values.map(()=>"?").join(", ")})`);parameters.push(...predicate.values)}appendSetPredicate(clauses,parameters,"stream_id",query.stream_ids);const where=clauses.length===0?"":` WHERE ${clauses.join(" AND ")}`;let database;try{return await withHistoryEventIndexLock(pmRoot,async()=>{return withHistoryEventIndexInvalidationLock(pmRoot,async()=>{database=await openSettledHistoryEventIndex(pmRoot,Database);if(!database)return null;const validationStreamIds=await historyIndexValidationStreamIds(database,pmRoot,query.stream_ids);if(!await historyIndexMatchesStreamSizes(database,pmRoot,validationStreamIds)){database.close();database=void 0;return null}const rows=database.prepare(`SELECT stream_id, stream_offset, entry_json
|
|
614
41
|
FROM events${where}
|
|
615
42
|
ORDER BY ts, stream_id, stream_offset
|
|
616
|
-
LIMIT ?`)
|
|
617
|
-
|
|
618
|
-
const events = rows.slice(0, query.limit).map(parseIndexedHistoryEvent);
|
|
619
|
-
database.close();
|
|
620
|
-
database = undefined;
|
|
621
|
-
return events.includes(null)
|
|
622
|
-
? null
|
|
623
|
-
: {
|
|
624
|
-
events: events,
|
|
625
|
-
has_more: rows.length > query.limit,
|
|
626
|
-
};
|
|
627
|
-
});
|
|
628
|
-
});
|
|
629
|
-
}
|
|
630
|
-
catch {
|
|
631
|
-
database?.close();
|
|
632
|
-
return null;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
function collectLatestSubstantiveEvents(events, requested) {
|
|
636
|
-
const latest = Object.create(null);
|
|
637
|
-
for (const event of events) {
|
|
638
|
-
if (!requested.has(event.stream_id) ||
|
|
639
|
-
classifyHistoryEvent(event.entry) !== "substantive") {
|
|
640
|
-
continue;
|
|
641
|
-
}
|
|
642
|
-
const current = latest[event.stream_id];
|
|
643
|
-
if (current === undefined ||
|
|
644
|
-
compareHistoryEventPosition(current, event) < 0) {
|
|
645
|
-
latest[event.stream_id] = event;
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
return latest;
|
|
649
|
-
}
|
|
650
|
-
async function readHistoryStreamByteSize(pmRoot, streamId) {
|
|
651
|
-
if (path.basename(streamId) !== streamId)
|
|
652
|
-
return null;
|
|
653
|
-
try {
|
|
654
|
-
return (await fs.stat(path.join(pmRoot, "history", `${streamId}.jsonl`)))
|
|
655
|
-
.size;
|
|
656
|
-
}
|
|
657
|
-
catch (error) {
|
|
658
|
-
if (isFileMissingError(error))
|
|
659
|
-
return 0;
|
|
660
|
-
throw error;
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
async function historyIndexMatchesStreamSizes(database, pmRoot, streamIds) {
|
|
664
|
-
for (let start = 0; start < streamIds.length; start += 500) {
|
|
665
|
-
const chunk = streamIds.slice(start, start + 500);
|
|
666
|
-
const storedSizes = new Map(database
|
|
667
|
-
.prepare(`SELECT stream_id, byte_size FROM streams
|
|
668
|
-
WHERE stream_id IN (${chunk.map(() => "?").join(", ")})`)
|
|
669
|
-
.all(...chunk)
|
|
670
|
-
.map((row) => [String(row.stream_id), Number(row.byte_size)]));
|
|
671
|
-
const currentSizes = await Promise.all(chunk.map((streamId) => readHistoryStreamByteSize(pmRoot, streamId)));
|
|
672
|
-
for (const [index, currentSize] of currentSizes.entries()) {
|
|
673
|
-
if (currentSize === null)
|
|
674
|
-
return false;
|
|
675
|
-
const streamId = chunk[index];
|
|
676
|
-
const storedSize = storedSizes.get(streamId);
|
|
677
|
-
if (currentSize === 0 && storedSize === undefined)
|
|
678
|
-
continue;
|
|
679
|
-
if (currentSize !== storedSize)
|
|
680
|
-
return false;
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
return true;
|
|
684
|
-
}
|
|
685
|
-
async function historyIndexValidationStreamIds(database, pmRoot, requestedStreamIds) {
|
|
686
|
-
if (requestedStreamIds && requestedStreamIds.length > 0) {
|
|
687
|
-
return [
|
|
688
|
-
...new Set(requestedStreamIds.filter((streamId) => streamId.trim().length > 0)),
|
|
689
|
-
];
|
|
690
|
-
}
|
|
691
|
-
const indexed = database
|
|
692
|
-
.prepare("SELECT stream_id FROM streams")
|
|
693
|
-
.all()
|
|
694
|
-
.map((row) => String(row.stream_id));
|
|
695
|
-
const authoritative = await fs
|
|
696
|
-
.readdir(path.join(pmRoot, "history"), { withFileTypes: true })
|
|
697
|
-
.then((entries) => entries
|
|
698
|
-
.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl"))
|
|
699
|
-
.map((entry) => entry.name.slice(0, -".jsonl".length)))
|
|
700
|
-
.catch((error) => {
|
|
701
|
-
if (isFileMissingError(error))
|
|
702
|
-
return [];
|
|
703
|
-
throw error;
|
|
704
|
-
});
|
|
705
|
-
return [...new Set([...indexed, ...authoritative])];
|
|
706
|
-
}
|
|
707
|
-
async function readIndexedLatestSubstantiveEvents(Database, pmRoot, streamIds, requested) {
|
|
708
|
-
if (!Database)
|
|
709
|
-
return null;
|
|
710
|
-
let database;
|
|
711
|
-
try {
|
|
712
|
-
return await withHistoryEventIndexLock(pmRoot, async () => {
|
|
713
|
-
return withHistoryEventIndexInvalidationLock(pmRoot, async () => {
|
|
714
|
-
const invalidations = await recoverAbandonedHistoryEventIndexInvalidations(pmRoot);
|
|
715
|
-
if (invalidations.pending.length > 0 ||
|
|
716
|
-
invalidations.committed.length > 0) {
|
|
717
|
-
return null;
|
|
718
|
-
}
|
|
719
|
-
database = new Database(eventIndexPath(pmRoot), { readOnly: true });
|
|
720
|
-
const version = database
|
|
721
|
-
.prepare("SELECT value FROM metadata WHERE key = 'version'")
|
|
722
|
-
.get();
|
|
723
|
-
if (version?.value !== EVENT_INDEX_VERSION ||
|
|
724
|
-
!(await historyIndexMatchesStreamSizes(database, pmRoot, streamIds))) {
|
|
725
|
-
database.close();
|
|
726
|
-
database = undefined;
|
|
727
|
-
return null;
|
|
728
|
-
}
|
|
729
|
-
const indexed = [];
|
|
730
|
-
for (let start = 0; start < streamIds.length; start += 500) {
|
|
731
|
-
const chunk = streamIds.slice(start, start + 500);
|
|
732
|
-
const rows = database
|
|
733
|
-
.prepare(`SELECT stream_id, stream_offset, entry_json
|
|
43
|
+
LIMIT ?`).all(...parameters,Math.max(0,Math.floor(query.limit))+1);const events=rows.slice(0,query.limit).map(parseIndexedHistoryEvent);database.close();database=void 0;return events.includes(null)?null:{events,has_more:rows.length>query.limit}})})}catch{database?.close();return null}}function collectLatestSubstantiveEvents(events,requested){const latest=Object.create(null);for(const event of events){if(!requested.has(event.stream_id)||classifyHistoryEvent(event.entry)!=="substantive"){continue}const current=latest[event.stream_id];if(current===void 0||compareHistoryEventPosition(current,event)<0){latest[event.stream_id]=event}}return latest}async function readHistoryStreamByteSize(pmRoot,streamId){if(path.basename(streamId)!==streamId)return null;try{return(await fs.stat(path.join(pmRoot,"history",`${streamId}.jsonl`))).size}catch(error){if(isFileMissingError(error))return 0;throw error}}async function historyIndexMatchesStreamSizes(database,pmRoot,streamIds){for(let start=0;start<streamIds.length;start+=500){const chunk=streamIds.slice(start,start+500);const storedSizes=new Map(database.prepare(`SELECT stream_id, byte_size FROM streams
|
|
44
|
+
WHERE stream_id IN (${chunk.map(()=>"?").join(", ")})`).all(...chunk).map(row=>[String(row.stream_id),Number(row.byte_size)]));const currentSizes=await Promise.all(chunk.map(streamId=>readHistoryStreamByteSize(pmRoot,streamId)));for(const[index,currentSize]of currentSizes.entries()){if(currentSize===null)return false;const streamId=chunk[index];const storedSize=storedSizes.get(streamId);if(currentSize===0&&storedSize===void 0)continue;if(currentSize!==storedSize)return false}}return true}async function historyIndexValidationStreamIds(database,pmRoot,requestedStreamIds){if(requestedStreamIds&&requestedStreamIds.length>0){return[...new Set(requestedStreamIds.filter(streamId=>streamId.trim().length>0))]}const indexed=database.prepare("SELECT stream_id FROM streams").all().map(row=>String(row.stream_id));const authoritative=await fs.readdir(path.join(pmRoot,"history"),{withFileTypes:true}).then(entries=>entries.filter(entry=>entry.isFile()&&entry.name.endsWith(".jsonl")).map(entry=>entry.name.slice(0,-".jsonl".length))).catch(error=>{if(isFileMissingError(error))return[];throw error});return[...new Set([...indexed,...authoritative])]}async function readIndexedLatestSubstantiveEvents(Database,pmRoot,streamIds,requested){if(!Database)return null;let database;try{return await withHistoryEventIndexLock(pmRoot,async()=>{return withHistoryEventIndexInvalidationLock(pmRoot,async()=>{database=await openSettledHistoryEventIndex(pmRoot,Database);if(!database)return null;if(!await historyIndexMatchesStreamSizes(database,pmRoot,streamIds)){database.close();database=void 0;return null}const indexed=[];for(let start=0;start<streamIds.length;start+=500){const chunk=streamIds.slice(start,start+500);const rows=database.prepare(`SELECT stream_id, stream_offset, entry_json
|
|
734
45
|
FROM (
|
|
735
46
|
SELECT stream_id, stream_offset, entry_json,
|
|
736
47
|
ROW_NUMBER() OVER (
|
|
@@ -739,94 +50,7 @@ async function readIndexedLatestSubstantiveEvents(Database, pmRoot, streamIds, r
|
|
|
739
50
|
) AS recency_rank
|
|
740
51
|
FROM events
|
|
741
52
|
WHERE event_class = 'substantive'
|
|
742
|
-
AND stream_id IN (${chunk.map(()
|
|
53
|
+
AND stream_id IN (${chunk.map(()=>"?").join(", ")})
|
|
743
54
|
)
|
|
744
|
-
WHERE recency_rank = 1`)
|
|
745
|
-
.all(...chunk);
|
|
746
|
-
const parsed = rows.map(parseIndexedHistoryEvent);
|
|
747
|
-
if (parsed.includes(null)) {
|
|
748
|
-
database.close();
|
|
749
|
-
database = undefined;
|
|
750
|
-
return null;
|
|
751
|
-
}
|
|
752
|
-
indexed.push(...parsed);
|
|
753
|
-
}
|
|
754
|
-
database.close();
|
|
755
|
-
database = undefined;
|
|
756
|
-
return collectLatestSubstantiveEvents(indexed, requested);
|
|
757
|
-
});
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
catch (error) {
|
|
761
|
-
database?.close();
|
|
762
|
-
if (error instanceof PmCliError && error.code === "lock_conflict") {
|
|
763
|
-
return HISTORY_INDEX_LOCK_CONTENDED;
|
|
764
|
-
}
|
|
765
|
-
return null;
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
/**
|
|
769
|
-
* Read one latest substantive coordinate per requested stream. The optional
|
|
770
|
-
* SQLite projection is preferred; individual authoritative streams are the
|
|
771
|
-
* fail-closed fallback and remain the source of truth.
|
|
772
|
-
*/
|
|
773
|
-
export async function readLatestSubstantiveHistoryEvents(pmRoot, streamIds) {
|
|
774
|
-
const uniqueIds = [
|
|
775
|
-
...new Set(streamIds.filter((id) => id.trim().length > 0 && path.basename(id) === id)),
|
|
776
|
-
];
|
|
777
|
-
if (uniqueIds.length === 0)
|
|
778
|
-
return {};
|
|
779
|
-
const requested = new Set(uniqueIds);
|
|
780
|
-
const Database = resolveDatabaseSync();
|
|
781
|
-
const indexed = await readIndexedLatestSubstantiveEvents(Database, pmRoot, uniqueIds, requested);
|
|
782
|
-
if (indexed !== null && indexed !== HISTORY_INDEX_LOCK_CONTENDED) {
|
|
783
|
-
return indexed;
|
|
784
|
-
}
|
|
785
|
-
if (Database && indexed !== HISTORY_INDEX_LOCK_CONTENDED) {
|
|
786
|
-
try {
|
|
787
|
-
if (await rebuildHistoryEventIndex(pmRoot)) {
|
|
788
|
-
const rebuilt = await readIndexedLatestSubstantiveEvents(Database, pmRoot, uniqueIds, requested);
|
|
789
|
-
if (rebuilt !== null && rebuilt !== HISTORY_INDEX_LOCK_CONTENDED) {
|
|
790
|
-
return rebuilt;
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
catch {
|
|
795
|
-
// A corrupt unrelated stream must not prevent requested authoritative reads.
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
const authoritative = [];
|
|
799
|
-
await Promise.all(uniqueIds.map(async (streamId) => {
|
|
800
|
-
const historyPath = path.join(pmRoot, "history", `${streamId}.jsonl`);
|
|
801
|
-
const entries = await readIndexableHistoryEntries(historyPath, streamId).catch((error) => {
|
|
802
|
-
if (error instanceof PmCliError &&
|
|
803
|
-
error.code === "history_timestamp_invalid") {
|
|
804
|
-
return [];
|
|
805
|
-
}
|
|
806
|
-
throw error;
|
|
807
|
-
});
|
|
808
|
-
entries.forEach((entry, streamOffset) => {
|
|
809
|
-
authoritative.push({
|
|
810
|
-
stream_id: streamId,
|
|
811
|
-
stream_offset: streamOffset,
|
|
812
|
-
entry,
|
|
813
|
-
});
|
|
814
|
-
});
|
|
815
|
-
}));
|
|
816
|
-
return collectLatestSubstantiveEvents(authoritative, requested);
|
|
817
|
-
}
|
|
818
|
-
/** Test-only dependency seam for runtimes without `node:sqlite`. */
|
|
819
|
-
export const _testOnly = {
|
|
820
|
-
collectLatestSubstantiveEvents,
|
|
821
|
-
loadDatabaseSync,
|
|
822
|
-
loadStableDatabaseSync,
|
|
823
|
-
setDatabaseSync(databaseSync) {
|
|
824
|
-
const previous = RuntimeDatabaseSync;
|
|
825
|
-
RuntimeDatabaseSync = databaseSync;
|
|
826
|
-
return () => {
|
|
827
|
-
RuntimeDatabaseSync = previous;
|
|
828
|
-
};
|
|
829
|
-
},
|
|
830
|
-
};
|
|
55
|
+
WHERE recency_rank = 1`).all(...chunk);const parsed=rows.map(parseIndexedHistoryEvent);if(parsed.includes(null)){database.close();database=void 0;return null}indexed.push(...parsed)}database.close();database=void 0;return collectLatestSubstantiveEvents(indexed,requested)})})}catch(error){database?.close();if(error instanceof PmCliError&&error.code==="lock_conflict"){return HISTORY_INDEX_LOCK_CONTENDED}return null}}async function readLatestSubstantiveHistoryEvents(pmRoot,streamIds){const uniqueIds=[...new Set(streamIds.filter(id=>id.trim().length>0&&path.basename(id)===id))];if(uniqueIds.length===0)return{};const requested=new Set(uniqueIds);const Database=resolveDatabaseSync();const indexed=await readIndexedLatestSubstantiveEvents(Database,pmRoot,uniqueIds,requested);if(indexed!==null&&indexed!==HISTORY_INDEX_LOCK_CONTENDED){return indexed}if(Database&&indexed!==HISTORY_INDEX_LOCK_CONTENDED){try{if(await rebuildHistoryEventIndex(pmRoot)){const rebuilt=await readIndexedLatestSubstantiveEvents(Database,pmRoot,uniqueIds,requested);if(rebuilt!==null&&rebuilt!==HISTORY_INDEX_LOCK_CONTENDED){return rebuilt}}}catch{}}const authoritative=[];await Promise.all(uniqueIds.map(async streamId=>{const historyPath=path.join(pmRoot,"history",`${streamId}.jsonl`);const entries=await readIndexableHistoryEntries(historyPath,streamId).catch(error=>{if(error instanceof PmCliError&&error.code==="history_timestamp_invalid"){return[]}throw error});entries.forEach((entry,streamOffset)=>{authoritative.push({stream_id:streamId,stream_offset:streamOffset,entry})})}));return collectLatestSubstantiveEvents(authoritative,requested)}const _testOnly={collectLatestSubstantiveEvents,loadDatabaseSync,loadStableDatabaseSync,setDatabaseSync(databaseSync){const previous=RuntimeDatabaseSync;RuntimeDatabaseSync=databaseSync;return()=>{RuntimeDatabaseSync=previous}}};export{_testOnly,appendHistoryEntryWithEventIndex,queryHistoryEventIndex,queryHistoryEventStreams,readLatestSubstantiveHistoryEvents,rebuildHistoryEventIndex,removeHistoryEventIndexForHistoryPath};
|
|
831
56
|
//# sourceMappingURL=event-index.js.map
|
|
832
|
-
//# debugId=72b285a7-970e-5965-bacf-a4e0cfc5f060
|