@unbrained/pm-cli 2026.10.15 → 2026.10.18
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/references/COMMAND_PLAYBOOK.md +1 -1
- package/.claude-plugin/marketplace.json +1 -1
- package/AGENTS.md +1 -0
- package/CHANGELOG.md +45 -0
- package/dist/cli/extension-command-options.d.ts +3 -1
- package/dist/cli/extension-command-options.js +1 -1
- package/dist/cli/help-content.js +2 -2
- package/dist/cli/register-list-query.js +2 -2
- package/dist/cli/register-mutation.js +2 -2
- package/dist/cli/register-operations.js +1 -1
- package/dist/cli/register-structured-mutation.d.ts +0 -5
- package/dist/cli/register-structured-mutation.js +1 -1
- package/dist/cli/runtime/invocation-options.js +1 -1
- package/dist/cli-bundle/bundle-manifest.json +1 -1
- package/dist/cli-bundle/chunks/{chunk-7VHINXZP.js → chunk-4GA4MUTE.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-RJ5N44WY.js → chunk-4V6ONLI6.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-LNKLQYBG.js → chunk-6VZKYJW7.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-7PATQWTH.js +20 -0
- package/dist/cli-bundle/chunks/chunk-7WIEAGDS.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-52EZH2QQ.js → chunk-AETP4JEM.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-WBBW3WQX.js → chunk-FIJOSX2C.js} +28 -28
- package/dist/cli-bundle/chunks/chunk-LUKVNL72.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-NC3QVGDD.js → chunk-OJ77ZQN3.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-PYRREEUB.js +30 -0
- package/dist/cli-bundle/chunks/chunk-RHQJ6VWC.js +237 -0
- package/dist/cli-bundle/chunks/{chunk-N56CAQBU.js → chunk-RNABUEFB.js} +52 -52
- package/dist/cli-bundle/chunks/chunk-TO6CIV4C.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-JGKTOBVB.js → chunk-ZZED447K.js} +4 -4
- package/dist/cli-bundle/chunks/{register-list-query-FKKFQ66D.js → register-list-query-PUCVYYBD.js} +7 -7
- package/dist/cli-bundle/chunks/register-mutation-GGGVBXD5.js +20 -0
- package/dist/cli-bundle/chunks/{register-operations-GEQ2H7PS.js → register-operations-NRZ6Q4QE.js} +2 -2
- package/dist/cli-bundle/chunks/{register-setup-PSJTQBBO.js → register-setup-MV3P3YSF.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-2MPQUMTF.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-H3P77KVU.js → chunk-5UKCSZWT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-4KQFMOM7.js → chunk-A4ZHHTEX.js} +5 -5
- package/dist/cli-bundle/focused-chunks/{chunk-5OO54BIV.js → chunk-B4YLP5ZB.js} +3 -3
- package/dist/cli-bundle/focused-chunks/chunk-BFEMT5U3.js +20 -0
- package/dist/cli-bundle/focused-chunks/{chunk-THYQR3ON.js → chunk-FW7CSSKL.js} +61 -61
- package/dist/cli-bundle/focused-chunks/{chunk-3RNUMVK4.js → chunk-HYPRPSYD.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-FQKPOZKS.js → chunk-IRVL4UXR.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-Q4VNCTR2.js → chunk-L55KQ2KT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-52I2SNKJ.js → chunk-MASIOFPG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-RJ3EIHDU.js +26 -0
- package/dist/cli-bundle/focused-chunks/chunk-SEL4Z2OO.js +167 -0
- package/dist/cli-bundle/focused-chunks/{chunk-TYLG5VEB.js → chunk-TB7F4FCR.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-KIIFVULU.js → chunk-TZUIBG3P.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-N6FUKTZS.js → chunk-Z7YIFCNE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-5KRACGBK.js → chunk-ZDBS2DCT.js} +3 -3
- package/dist/cli-bundle/main.js +27 -27
- 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 +23 -23
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +55 -54
- 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 +7 -7
- package/dist/core/extensions/extension-types.d.ts +15 -0
- package/dist/core/extensions/extension-types.js +1 -1
- package/dist/core/extensions/flag-value-types.d.ts +16 -0
- package/dist/core/extensions/flag-value-types.js +1 -1
- package/dist/core/extensions/registration-contracts.js +1 -1
- package/dist/core/history/event-index.d.ts +8 -1
- package/dist/core/history/event-index.js +19 -18
- package/dist/core/item/item-format.js +3 -3
- package/dist/core/lock/lock.d.ts +8 -1
- package/dist/core/lock/lock.js +3 -3
- package/dist/core/output/mutation-projection.d.ts +0 -21
- package/dist/core/output/mutation-projection.js +1 -1
- package/dist/core/output/output.js +2 -2
- package/dist/core/schema/type-workflows.d.ts +1 -1
- package/dist/core/schema/type-workflows.js +1 -1
- package/dist/core/shared/text-normalization.d.ts +2 -0
- package/dist/core/shared/text-normalization.js +1 -1
- package/dist/core/store/item-mutation-precondition.d.ts +11 -0
- package/dist/core/store/item-mutation-precondition.js +2 -0
- package/dist/core/store/item-store.js +1 -1
- package/dist/core/store/paths.js +1 -1
- package/dist/core/telemetry/policy.d.ts +2 -0
- package/dist/core/telemetry/policy.js +1 -1
- package/dist/core/telemetry/runtime.d.ts +5 -3
- package/dist/core/telemetry/runtime.js +3 -3
- package/dist/mcp/server.js +1 -1
- package/dist/mcp/tool-definitions.js +1 -1
- package/dist/sdk/cli-contracts/agent-output-contracts.js +1 -1
- package/dist/sdk/cli-contracts/flag-contracts.js +1 -1
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +1 -1
- package/dist/sdk/cli-contracts/registration-helpers.d.ts +1 -1
- package/dist/sdk/cli-contracts/registration-helpers.js +1 -1
- package/dist/sdk/cli-contracts/tool-schema.d.ts +2 -2
- package/dist/sdk/cli-contracts/tool-schema.js +1 -1
- package/dist/sdk/context-intent-contracts.js +1 -1
- package/dist/sdk/core.d.ts +2 -1
- package/dist/sdk/core.js +1 -1
- package/dist/sdk/generated/generated-error-code-catalog-part-1.js +1 -1
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -1
- package/dist/sdk/governance/health/projection.d.ts +37 -0
- package/dist/sdk/governance/health/projection.js +2 -0
- package/dist/sdk/governance/health.d.ts +7 -18
- package/dist/sdk/governance/health.js +2 -2
- package/dist/sdk/guide-topics.js +1 -1
- package/dist/sdk/index.d.ts +2 -1
- package/dist/sdk/index.js +1 -1
- package/dist/sdk/item-transaction.d.ts +72 -9
- package/dist/sdk/item-transaction.js +1 -1
- package/dist/sdk/lifecycle/claim.d.ts +15 -1
- package/dist/sdk/lifecycle/claim.js +1 -1
- package/dist/sdk/lifecycle/close.d.ts +2 -8
- package/dist/sdk/lifecycle/close.js +1 -1
- package/dist/sdk/lifecycle/core-item-fields.d.ts +6 -0
- package/dist/sdk/lifecycle/core-item-fields.js +2 -0
- package/dist/sdk/lifecycle/mcp-actions.js +1 -1
- package/dist/sdk/lifecycle/mutation-option-validation.d.ts +2 -0
- package/dist/sdk/lifecycle/mutation-option-validation.js +2 -0
- package/dist/sdk/lifecycle/release-handoff.d.ts +12 -0
- package/dist/sdk/lifecycle/release-handoff.js +2 -0
- package/dist/sdk/lifecycle/structured-mutation-plan.d.ts +33 -0
- package/dist/sdk/lifecycle/structured-mutation-plan.js +2 -0
- package/dist/sdk/lifecycle/task-composition.d.ts +2 -2
- package/dist/sdk/lifecycle/task-composition.js +1 -1
- package/dist/sdk/lifecycle/update.d.ts +3 -11
- package/dist/sdk/lifecycle/update.js +1 -1
- package/dist/sdk/lifecycle/workflow-transition.d.ts +13 -0
- package/dist/sdk/lifecycle/workflow-transition.js +2 -0
- package/dist/sdk/lifecycle-policy.d.ts +12 -2
- package/dist/sdk/lifecycle-policy.js +1 -1
- package/dist/sdk/mutation-events.js +1 -1
- package/dist/sdk/public-surface.json +1 -1
- package/dist/sdk/query/list.d.ts +2 -0
- package/dist/sdk/query/list.js +1 -1
- package/dist/sdk/read-output-budget.js +1 -1
- package/dist/sdk/runtime-input.js +1 -1
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +1 -1
- package/dist/sdk/runtime.d.ts +8 -8
- package/dist/sdk/runtime.js +1 -1
- package/dist/sdk/structured-mutations.d.ts +52 -1
- package/dist/sdk/structured-mutations.js +1 -1
- package/dist/sdk/workspace-transaction.js +2 -2
- package/dist/types.d.ts +2 -2
- package/dist/types.js +1 -1
- package/docs/AGENT_GUIDE.md +33 -4
- package/docs/CLOSE_EVIDENCE_RECOVERY.md +16 -7
- package/docs/COMMANDS.md +111 -10
- package/docs/CONFIGURATION.md +22 -1
- package/docs/DEVELOPMENT_DEPENDENCY_SECURITY.md +22 -3
- package/docs/ECOSYSTEM_PLANNING_REVIEW.md +5 -1
- package/docs/EXTENSIONS.md +1 -1
- package/docs/OUTPUT_PROJECTION_CONTRACTS.md +10 -0
- package/docs/RELEASING.md +8 -1
- package/docs/SDK.md +114 -2
- package/docs/SDK_CONTEXT_COORDINATION.md +71 -7
- package/docs/SDK_STORAGE_LIFECYCLE.md +24 -2
- package/docs/TESTING.md +23 -0
- package/docs/examples/ci/github-actions-pm-extension-gate.yml +1 -1
- package/docs/examples/ci/gitlab-ci-pm-extension-gate.yml +1 -1
- package/docs/examples/ci/jenkins-pm-extension-gate.Jenkinsfile +1 -1
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +1 -1
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +16 -3
- package/marketplace.json +1 -1
- package/node_modules/@opentelemetry/core/package.json +2 -1
- package/node_modules/@opentelemetry/instrumentation/package.json +2 -1
- package/node_modules/@opentelemetry/resources/package.json +2 -1
- package/node_modules/@opentelemetry/sdk-trace/package.json +2 -1
- package/node_modules/@opentelemetry/sdk-trace-base/package.json +2 -1
- package/node_modules/@sentry/core/build/cjs/client.js +5 -4
- package/node_modules/@sentry/core/build/cjs/tracing/ai/gen-ai-attributes.js +0 -4
- package/node_modules/@sentry/core/build/cjs/tracing/ai/utils.js +33 -23
- package/node_modules/@sentry/core/build/cjs/tracing/anthropic-ai/index.js +7 -6
- package/node_modules/@sentry/core/build/cjs/tracing/anthropic-ai/streaming.js +3 -1
- package/node_modules/@sentry/core/build/cjs/tracing/google-genai/index.js +13 -14
- package/node_modules/@sentry/core/build/cjs/tracing/google-genai/streaming.js +6 -1
- package/node_modules/@sentry/core/build/cjs/tracing/langchain/utils.js +71 -21
- package/node_modules/@sentry/core/build/cjs/tracing/langgraph/utils.js +23 -33
- package/node_modules/@sentry/core/build/cjs/tracing/openai/streaming.js +6 -0
- package/node_modules/@sentry/core/build/cjs/tracing/openai/utils.js +11 -0
- package/node_modules/@sentry/core/build/cjs/tracing/workers-ai/utils.js +1 -1
- package/node_modules/@sentry/core/build/cjs/utils/eventUtils.js +4 -0
- package/node_modules/@sentry/core/build/cjs/utils/prepareEvent.js +2 -2
- package/node_modules/@sentry/core/build/cjs/utils/version.js +1 -1
- package/node_modules/@sentry/core/build/esm/client.js +6 -5
- package/node_modules/@sentry/core/build/esm/package.json +1 -1
- package/node_modules/@sentry/core/build/esm/tracing/ai/gen-ai-attributes.js +1 -3
- package/node_modules/@sentry/core/build/esm/tracing/ai/utils.js +34 -24
- package/node_modules/@sentry/core/build/esm/tracing/anthropic-ai/index.js +8 -7
- package/node_modules/@sentry/core/build/esm/tracing/anthropic-ai/streaming.js +3 -1
- package/node_modules/@sentry/core/build/esm/tracing/google-genai/index.js +15 -16
- package/node_modules/@sentry/core/build/esm/tracing/google-genai/streaming.js +6 -1
- package/node_modules/@sentry/core/build/esm/tracing/langchain/utils.js +73 -24
- package/node_modules/@sentry/core/build/esm/tracing/langgraph/utils.js +24 -34
- package/node_modules/@sentry/core/build/esm/tracing/openai/streaming.js +6 -0
- package/node_modules/@sentry/core/build/esm/tracing/openai/utils.js +11 -0
- package/node_modules/@sentry/core/build/esm/tracing/workers-ai/utils.js +2 -2
- package/node_modules/@sentry/core/build/esm/utils/eventUtils.js +4 -1
- package/node_modules/@sentry/core/build/esm/utils/prepareEvent.js +2 -2
- package/node_modules/@sentry/core/build/esm/utils/version.js +1 -1
- package/node_modules/@sentry/core/build/types/tracing/ai/utils.d.ts +3 -7
- package/node_modules/@sentry/core/build/types/tracing/anthropic-ai/types.d.ts +2 -2
- package/node_modules/@sentry/core/build/types/tracing/langchain/types.d.ts +15 -0
- package/node_modules/@sentry/core/build/types/tracing/langchain/utils.d.ts +1 -0
- package/node_modules/@sentry/core/build/types/tracing/langgraph/utils.d.ts +2 -0
- package/node_modules/@sentry/core/build/types/tracing/openai/types.d.ts +2 -0
- package/node_modules/@sentry/core/build/types/utils/eventUtils.d.ts +2 -1
- package/node_modules/@sentry/core/build/types-ts3.8/tracing/ai/utils.d.ts +3 -7
- package/node_modules/@sentry/core/build/types-ts3.8/tracing/anthropic-ai/types.d.ts +2 -2
- package/node_modules/@sentry/core/build/types-ts3.8/tracing/langchain/types.d.ts +15 -0
- package/node_modules/@sentry/core/build/types-ts3.8/tracing/langchain/utils.d.ts +1 -0
- package/node_modules/@sentry/core/build/types-ts3.8/tracing/langgraph/utils.d.ts +2 -0
- package/node_modules/@sentry/core/build/types-ts3.8/tracing/openai/types.d.ts +2 -0
- package/node_modules/@sentry/core/build/types-ts3.8/utils/eventUtils.d.ts +2 -1
- package/node_modules/@sentry/core/package.json +1 -1
- package/node_modules/@sentry/node/build/esm/package.json +1 -1
- package/node_modules/@sentry/node/package.json +5 -5
- package/node_modules/@sentry/node-core/build/cjs/integrations/anr/index.js +1 -1
- package/node_modules/@sentry/node-core/build/cjs/integrations/local-variables/local-variables-async.js +1 -1
- package/node_modules/@sentry/node-core/build/esm/integrations/anr/index.js +1 -1
- package/node_modules/@sentry/node-core/build/esm/integrations/anr/worker-script.js +2 -2
- package/node_modules/@sentry/node-core/build/esm/integrations/local-variables/local-variables-async.js +1 -1
- package/node_modules/@sentry/node-core/build/esm/integrations/local-variables/worker-script.js +1 -1
- package/node_modules/@sentry/node-core/build/esm/package.json +1 -1
- package/node_modules/@sentry/node-core/package.json +10 -4
- package/node_modules/@sentry/opentelemetry/build/esm/package.json +1 -1
- package/node_modules/@sentry/opentelemetry/package.json +5 -2
- package/node_modules/@sentry/server-utils/build/THIRD-PARTY-LICENSES.txt +55 -55
- package/node_modules/@sentry/server-utils/build/esm/package.json +1 -1
- package/node_modules/@sentry/server-utils/package.json +2 -2
- package/node_modules/@toon-format/toon/README.md +10 -41
- package/node_modules/@toon-format/toon/dist/index.d.mts +12 -36
- package/node_modules/@toon-format/toon/dist/index.mjs +134 -202
- package/node_modules/@toon-format/toon/package.json +2 -2
- package/node_modules/debug/package.json +3 -0
- package/node_modules/fdir/package.json +3 -0
- package/node_modules/has-flag/index.d.ts +39 -0
- package/node_modules/has-flag/index.js +8 -0
- package/node_modules/has-flag/license +9 -0
- package/node_modules/has-flag/package.json +46 -0
- package/node_modules/has-flag/readme.md +89 -0
- package/node_modules/supports-color/browser.js +5 -0
- package/node_modules/supports-color/index.js +135 -0
- package/node_modules/supports-color/license +9 -0
- package/node_modules/supports-color/package.json +53 -0
- package/node_modules/supports-color/readme.md +76 -0
- package/package.json +5 -4
- 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-claude/package.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/pm-codex/package.json +1 -1
- package/plugins/pm-codex/plugin.json +1 -1
- package/runtime-dependencies.json +1 -1
- package/dist/cli-bundle/chunks/chunk-7OEGNA4X.js +0 -20
- package/dist/cli-bundle/chunks/chunk-EMEEHV2Y.js +0 -2
- package/dist/cli-bundle/chunks/chunk-JSUJWIHQ.js +0 -30
- package/dist/cli-bundle/chunks/chunk-VIMQCFCK.js +0 -2
- package/dist/cli-bundle/chunks/chunk-X2H6UR26.js +0 -236
- package/dist/cli-bundle/chunks/register-mutation-EWMMVZJB.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-5TBAVZDR.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-HTA3TNC3.js +0 -26
- package/dist/cli-bundle/focused-chunks/chunk-JKBH7YGX.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-PDYE7QDX.js +0 -166
- package/docs/ecosystem-review-2026-09-28.json +0 -1
|
@@ -788,6 +788,13 @@ media_type?:string;
|
|
|
788
788
|
}
|
|
789
789
|
/** Restricts flag value type values accepted by command, SDK, and storage contracts. */
|
|
790
790
|
export type FlagValueType = "string" | "number" | "boolean";
|
|
791
|
+
/**
|
|
792
|
+
* How a typed scalar flag treats a value token that does not coerce under its
|
|
793
|
+
* declared `value_type`. `coerce` (default, compatible) forwards the original
|
|
794
|
+
* token to the handler for its own validation; `strict` refuses the invocation
|
|
795
|
+
* with a typed usage error before the handler runs.
|
|
796
|
+
*/
|
|
797
|
+
export type FlagValueValidation = "coerce" | "strict";
|
|
791
798
|
/** Documents the flag definition payload exchanged by command, SDK, and package integrations. */
|
|
792
799
|
export interface FlagDefinition {
|
|
793
800
|
/** Value that configures or reports long for this contract. */
|
|
@@ -818,6 +825,14 @@ list?:boolean;
|
|
|
818
825
|
repeatable?:boolean;
|
|
819
826
|
/** Default value applied when the flag is omitted. Surfaced to runtime contracts and help output. A `list` flag may default to an array of scalars (e.g. `["a", "b"]`); the array is flattened/coerced like any list value. */
|
|
820
827
|
default?:string | number | boolean | Array<string | number | boolean>;
|
|
828
|
+
/**
|
|
829
|
+
* Scalar validation policy for `number`/`boolean` flags. `strict` refuses a
|
|
830
|
+
* malformed value token (`--limit abc`, `--enabled maybe`, or a value-less
|
|
831
|
+
* `--limit`) before dispatch; `coerce` (default) keeps the historical
|
|
832
|
+
* behaviour of forwarding the raw token. Switch presence (`--verbose`,
|
|
833
|
+
* `--no-verbose`) and the legacy `bool` optional-value grammar are unaffected.
|
|
834
|
+
*/
|
|
835
|
+
value_validation?:FlagValueValidation;
|
|
821
836
|
}
|
|
822
837
|
/** Documents the schema field definition payload exchanged by command, SDK, and package integrations. */
|
|
823
838
|
export interface SchemaFieldDefinition {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="826dab45-600c-58df-a150-eacecfb6ef95")}catch{}})();const KNOWN_EXTENSION_CAPABILITIES=["commands","renderers","hooks","schema","importers","search","parser","preflight","services"],EXTENSION_CAPABILITY_CONTRACT_VERSION=2,EXTENSION_CAPABILITY_LEGACY_ALIASES=Object.freeze({migration:"schema",validation:"schema"}),EXTENSION_CAPABILITY_CONTRACT=Object.freeze({version:2,capabilities:[...KNOWN_EXTENSION_CAPABILITIES],legacy_aliases:{...EXTENSION_CAPABILITY_LEGACY_ALIASES}}),KNOWN_EXTENSION_POLICY_MODES=["off","warn","enforce"],KNOWN_EXTENSION_TRUST_MODES=["off","warn","enforce"],KNOWN_EXTENSION_SANDBOX_PROFILES=["none","restricted","strict"],KNOWN_PM_MAX_VERSION_EXCEEDED_MODES=["block","warn"],KNOWN_EXTENSION_POLICY_SURFACES=["commands.override","commands.handler","hooks.beforecommand","hooks.beforemutation","hooks.aftercommand","hooks.onwrite","hooks.onread","hooks.onindex","schema.flags","schema.itemfields","schema.itemtypes","schema.relationshipkinds","schema.migrations","schema.profiles","parser.override","preflight.override","services.override","renderers.override","importers.importer","importers.exporter","search.provider","search.vectorstore","services.assuranceprovider"],KNOWN_EXTENSION_SERVICE_NAMES=["output_format","error_format","help_format","lock_acquire","lock_release","history_append","item_store_write","item_store_delete","context_relevance","command_result"];function createDefaultExtensionGovernancePolicy(){return{mode:"off",trust_mode:"off",require_provenance:!1,trusted_extensions:[],default_sandbox_profile:"none",allowed_extensions:[],blocked_extensions:[],allowed_capabilities:[],blocked_capabilities:[],allowed_surfaces:[],blocked_surfaces:[],allowed_commands:[],blocked_commands:[],allowed_actions:[],blocked_actions:[],allowed_services:[],blocked_services:[],extension_overrides:[]}}export{EXTENSION_CAPABILITY_CONTRACT,EXTENSION_CAPABILITY_CONTRACT_VERSION,EXTENSION_CAPABILITY_LEGACY_ALIASES,KNOWN_EXTENSION_CAPABILITIES,KNOWN_EXTENSION_POLICY_MODES,KNOWN_EXTENSION_POLICY_SURFACES,KNOWN_EXTENSION_SANDBOX_PROFILES,KNOWN_EXTENSION_SERVICE_NAMES,KNOWN_EXTENSION_TRUST_MODES,KNOWN_PM_MAX_VERSION_EXCEEDED_MODES,createDefaultExtensionGovernancePolicy};
|
|
2
2
|
//# sourceMappingURL=extension-types.js.map
|
|
@@ -19,3 +19,19 @@ export declare function resolveExtensionFlagValueContract(definition:Readonly<Fl
|
|
|
19
19
|
export declare function flattenFlagListValue(value:unknown):unknown[];
|
|
20
20
|
/** Whether a scalar flag default would cleanly coerce under the declared kind, mirroring the runtime coercion rules in `coerceLooseCommandOptionsWithFlagDefinitions`. Used to reject contradictory definitions (e.g. `value_type: "number"` with `default: "abc"`) at registration instead of letting an untyped value pass through to activation. */
|
|
21
21
|
export declare function isFlagDefaultValueCoercible(value:string | number | boolean,kind:FlagValueKind):boolean;
|
|
22
|
+
/** One refused scalar token, described for a typed usage error. */
|
|
23
|
+
export interface FlagScalarValueFailure {
|
|
24
|
+
/** Declared kind the token failed to satisfy. */
|
|
25
|
+
kind:Exclude<FlagValueKind,"string">;
|
|
26
|
+
/** Original token as the caller supplied it (`true` when the flag carried no value). */
|
|
27
|
+
received:unknown;
|
|
28
|
+
/** Accepted token grammar, for the recovery message. */
|
|
29
|
+
expected:string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Describe why a coerced scalar is still malformed under a `number` or
|
|
33
|
+
* `boolean` kind, or return null when it coerced cleanly. A value-less
|
|
34
|
+
* occurrence (`true`) of a `number` flag is malformed; a value-less occurrence
|
|
35
|
+
* of a `boolean` flag is switch presence and is accepted.
|
|
36
|
+
*/
|
|
37
|
+
export declare function describeFlagScalarValueFailure(value:unknown,kind:Exclude<FlagValueKind,"string">):FlagScalarValueFailure | null;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="5c3049c3-1d5a-5e7e-a070-35340737a6ab")}catch{}})();import{parseExtensionLongFlagToken}from"./flag-definition-validation.js";const FLAG_VALUE_KIND_BY_ALIAS=Object.freeze({string:"string",number:"number",int:"number",integer:"number",float:"number",boolean:"boolean",bool:"boolean"});function resolveFlagValueKind(raw){if(typeof raw!="string")return null;const alias=raw.trim().toLowerCase();return Object.hasOwn(FLAG_VALUE_KIND_BY_ALIAS,alias)?FLAG_VALUE_KIND_BY_ALIAS[alias]:null}function hasExtensionFlagValueMetadata(definition,inlineName,declaredType){return!!(definition.value_name?.trim()||inlineName||declaredType||definition.required===!0||definition.list===!0||definition.repeatable===!0)}function declaredExtensionFlagType(definition){return(definition.value_type?.trim()||definition.type?.trim())?.toLowerCase()}function resolveExtensionFlagValueContract(definition){const declaredType=declaredExtensionFlagType(definition),valueType=resolveFlagValueKind(declaredType),inline=parseExtensionLongFlagToken(definition.long),declaredName=definition.value_name?.trim()||null,takesValue=!(valueType==="boolean"&&declaredType!=="bool")&&hasExtensionFlagValueMetadata(definition,inline?.valueName,declaredType),optionalValue=inline?.valueName?inline.optional:declaredType==="bool";return{value_type:valueType,value_arity:takesValue?optionalValue?"optional":"required":"none",value_name:takesValue?declaredName??inline?.valueName??"value":null}}function flattenFlagListValue(value){const entries=[],collect=input=>{if(Array.isArray(input)){for(const item of input)collect(item);return}if(typeof input=="string"){for(const part of input.split(",")){const trimmed=part.trim();trimmed.length>0&&entries.push(trimmed)}return}input!=null&&entries.push(input)};return collect(value),entries}function isFlagDefaultValueCoercible(value,kind){return kind==="string"?!0:kind==="number"?typeof value=="number"?Number.isFinite(value):typeof value=="string"&&value.trim().length>0&&Number.isFinite(Number(value)):typeof value=="boolean"?!0:typeof value=="string"&&["true","false","1","0"].includes(value.trim().toLowerCase())}function describeFlagScalarValueFailure(value,kind){return kind==="number"?typeof value=="number"&&Number.isFinite(value)?null:{kind,received:value,expected:"a finite number"}:typeof value=="boolean"?null:{kind,received:value,expected:"true, false, 1, or 0"}}export{describeFlagScalarValueFailure,flattenFlagListValue,isFlagDefaultValueCoercible,resolveExtensionFlagValueContract,resolveFlagValueKind};
|
|
2
2
|
//# sourceMappingURL=flag-value-types.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="bc1e888a-4274-5d8d-9077-89ca5341172c")}catch{}})();import{describeExtensionLongFlagFailure,findExtensionFlagTokenFailure}from"./flag-definition-validation.js";import{flattenFlagListValue,isFlagDefaultValueCoercible,resolveFlagValueKind}from"./flag-value-types.js";import{KNOWN_ITEM_FIELD_TYPES,normalizeItemFieldType,suggestKnownItemFieldType}from"./item-field-types.js";import{asRegistrationRecord,assertOptionalBooleanField,assertOptionalFlagDefaultField,assertOptionalStringArrayField,assertOptionalStringField}from"./registration-validation.js";import{assertNonEmptyRegistrationString,normalizeRegistrationRecordList}from"./registration-values.js";const FLAG_DEFINITION_KEYS=new Set(["default","description","enabled","list","long","repeatable","required","short","type","value_name","value_type","visible"]);function normalizeFlagDefinitions(name,value){return normalizeRegistrationRecordList(name,value).map(record=>(record.repeatable===!0&&(record.list=!0),record))}function normalizeCommandActionName(value){return value.trim().toLowerCase().replace(/[\s_]+/g,"-").replace(/[^a-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function resolveCommandDefinitionAction(commandPath,action){if(action===void 0)return commandPath.replace(/\s+/g,"-");if(typeof action!="string"||action.trim().length===0)throw new TypeError("registerCommand definition.action must be a non-empty string when provided");const normalized=normalizeCommandActionName(action);if(normalized.length===0)throw new TypeError("registerCommand definition.action must contain alphanumeric characters");return normalized}function normalizeCommandDefinitionArguments(value){if(value===void 0)return[];if(!Array.isArray(value))throw new TypeError("registerCommand definition.arguments must be an array when provided");const normalized=[];for(const[index,entry]of value.entries()){const record=asRegistrationRecord(`registerCommand definition.arguments[${index}]`,entry),name=assertNonEmptyRegistrationString(`registerCommand definition.arguments[${index}].name`,record.name);if(assertOptionalBooleanField(`registerCommand definition.arguments[${index}].required`,record.required),assertOptionalBooleanField(`registerCommand definition.arguments[${index}].variadic`,record.variadic),assertOptionalStringField(`registerCommand definition.arguments[${index}].description`,record.description),name.includes(" "))throw new TypeError(`registerCommand definition.arguments[${index}].name must not contain spaces`);const definition={name};record.required===!0&&(definition.required=!0),record.variadic===!0&&(definition.variadic=!0),typeof record.description=="string"&&(definition.description=record.description.trim()),normalized.push(definition)}const variadicIndexes=normalized.map((argument,index)=>argument.variadic?index:-1).filter(index=>index>=0);if(variadicIndexes.length>1)throw new TypeError("registerCommand definition.arguments supports at most one variadic argument");if(variadicIndexes.length===1&&variadicIndexes[0]!==normalized.length-1)throw new TypeError("registerCommand definition.arguments variadic argument must be the final argument");return normalized}function validateFlagDefinitions(flags){if(!Array.isArray(flags))throw new TypeError("registerFlags flags requires an array of object definitions");for(const[index,raw]of flags.entries()){const record=asRegistrationRecord(`registerFlags flags[${index}]`,raw),unknownKeys=Object.keys(record).filter(key=>!FLAG_DEFINITION_KEYS.has(key)).sort((left,right)=>left.localeCompare(right));if(unknownKeys.length>0)throw new TypeError(`registerFlags flags[${index}] contains unknown field(s): ${unknownKeys.join(", ")}`);const long=record.long,short=record.short;if(long===void 0&&short===void 0)throw new TypeError(`registerFlags flags[${index}] requires at least one of long or short`);assertOptionalStringField(`registerFlags flags[${index}].long`,long),assertOptionalStringField(`registerFlags flags[${index}].short`,short);const tokenFinding=findExtensionFlagTokenFailure(long,short);if(tokenFinding!==null)throw new TypeError(`registerFlags flags[${index}] ${describeExtensionLongFlagFailure(tokenFinding.token,tokenFinding.failure)}`);if(assertOptionalStringField(`registerFlags flags[${index}].value_name`,record.value_name),assertOptionalStringField(`registerFlags flags[${index}].description`,record.description),assertOptionalBooleanField(`registerFlags flags[${index}].required`,record.required),assertOptionalBooleanField(`registerFlags flags[${index}].enabled`,record.enabled),assertOptionalBooleanField(`registerFlags flags[${index}].visible`,record.visible),assertOptionalBooleanField(`registerFlags flags[${index}].list`,record.list),assertOptionalBooleanField(`registerFlags flags[${index}].repeatable`,record.repeatable),record.list!==void 0&&record.repeatable!==void 0&&record.list!==record.repeatable)throw new TypeError(`registerFlags flags[${index}].list and repeatable must match when both are provided`);if(assertOptionalFlagDefaultField(`registerFlags flags[${index}].default`,record.default),Array.isArray(record.default)&&record.list!==!0&&record.repeatable!==!0)throw new TypeError(`registerFlags flags[${index}].default cannot be an array unless list is true.`);assertFlagValueTypeAndDefault(`registerFlags flags[${index}]`,record)}}function assertFlagValueTypeAndDefault(label,record){const declaredType=(typeof record.value_type=="string"?record.value_type:void 0)??(typeof record.type=="string"?record.type:void 0);if(declaredType===void 0)return;const kind=resolveFlagValueKind(declaredType);if(kind===null)throw new TypeError(`${label} value_type "${declaredType}" is not a known flag value type (expected one of: string, number, boolean).`);if(record.default===void 0)return;const defaults=record.list===!0||record.repeatable===!0?flattenFlagListValue(record.default):[record.default];for(const[defaultIndex,defaultValue]of defaults.entries())if(!isFlagDefaultValueCoercible(defaultValue,kind)){const suffix=defaults.length>1?`default[${defaultIndex}]`:"default";throw new TypeError(`${label}.${suffix} (${JSON.stringify(defaultValue)}) is not coercible to ${kind}.`)}}function validateItemFieldDefinitions(fields){if(!Array.isArray(fields))throw new TypeError("registerItemFields fields requires an array of object definitions");for(const[index,raw]of fields.entries()){const record=asRegistrationRecord(`registerItemFields fields[${index}]`,raw);assertNonEmptyRegistrationString(`registerItemFields fields[${index}].name`,record.name);const fieldType=assertNonEmptyRegistrationString(`registerItemFields fields[${index}].type`,record.type);if(normalizeItemFieldType(fieldType)===null){const suggestion=suggestKnownItemFieldType(fieldType),hint=suggestion?` Did you mean "${suggestion}"?`:"";throw new TypeError(`registerItemFields fields[${index}].type "${fieldType}" is not a known field type (expected one of: ${KNOWN_ITEM_FIELD_TYPES.join(", ")}).${hint}`)}assertOptionalBooleanField(`registerItemFields fields[${index}].optional`,record.optional)}}function validateItemTypeCommandOptionPolicies(typeIndex,value){if(value===void 0)return;const label=`registerItemTypes types[${typeIndex}].command_option_policies`;if(!Array.isArray(value))throw new TypeError(`${label} must be an array when provided`);for(const[policyIndex,rawPolicy]of value.entries()){const at=`${label}[${policyIndex}]`,policy=asRegistrationRecord(at,rawPolicy);assertNonEmptyRegistrationString(`${at}.command`,policy.command),assertNonEmptyRegistrationString(`${at}.option`,policy.option),assertOptionalBooleanField(`${at}.enabled`,policy.enabled),assertOptionalBooleanField(`${at}.required`,policy.required),assertOptionalBooleanField(`${at}.visible`,policy.visible)}}function validateItemTypeOptions(typeIndex,value){if(value===void 0)return;const label=`registerItemTypes types[${typeIndex}].options`;if(!Array.isArray(value))throw new TypeError(`${label} must be an array when provided`);for(const[optionIndex,rawOption]of value.entries()){const at=`${label}[${optionIndex}]`,option=asRegistrationRecord(at,rawOption);assertNonEmptyRegistrationString(`${at}.key`,option.key),assertOptionalStringArrayField(`${at}.values`,option.values),assertOptionalBooleanField(`${at}.required`,option.required),assertOptionalStringArrayField(`${at}.aliases`,option.aliases)}}function validateItemTypeDefinitions(types){if(!Array.isArray(types))throw new TypeError("registerItemTypes types requires an array of object definitions");for(const[typeIndex,raw]of types.entries()){const at=`registerItemTypes types[${typeIndex}]`,record=asRegistrationRecord(at,raw);assertNonEmptyRegistrationString(`${at}.name`,record.name),assertOptionalStringField(`${at}.folder`,record.folder),assertOptionalStringArrayField(`${at}.aliases`,record.aliases),assertOptionalStringArrayField(`${at}.required_create_fields`,record.required_create_fields),assertOptionalStringArrayField(`${at}.required_create_repeatables`,record.required_create_repeatables),validateItemTypeCommandOptionPolicies(typeIndex,record.command_option_policies),validateItemTypeOptions(typeIndex,record.options)}}function validateMigrationDefinition(definition){const record=asRegistrationRecord("registerMigration definition",definition);if(record.id!==void 0&&typeof record.id!="string")throw new TypeError("registerMigration definition.id must be a string when provided");if(record.description!==void 0&&typeof record.description!="string")throw new TypeError("registerMigration definition.description must be a string when provided");if(record.status!==void 0&&typeof record.status!="string")throw new TypeError("registerMigration definition.status must be a string when provided");if(assertOptionalBooleanField("registerMigration definition.mandatory",record.mandatory),record.run!==void 0&&typeof record.run!="function")throw new TypeError("registerMigration definition.run must be a function when provided")}const PROJECT_PROFILE_DIMENSIONS=["types","statuses","fields","workflows","config","templates","packages"],PROJECT_PROFILE_ENTRY_VALIDATORS={types:(at,entry)=>{if(entry.name!==void 0&&typeof entry.name!="string")throw new TypeError(`${at}.name must be a string when provided`)},workflows:(at,entry)=>{if(typeof entry.type!="string")throw new TypeError(`${at}.type must be a string`);if(!Array.isArray(entry.allowed_transitions))throw new TypeError(`${at}.allowed_transitions must be an array`);for(const[pairIndex,pair]of entry.allowed_transitions.entries())if(!Array.isArray(pair))throw new TypeError(`${at}.allowed_transitions[${pairIndex}] must be a [from, to] array`)},templates:(at,entry)=>{if(typeof entry.name!="string")throw new TypeError(`${at}.name must be a string`);if(typeof entry.options!="object"||entry.options===null||Array.isArray(entry.options))throw new TypeError(`${at}.options must be an object`)},packages:(at,entry)=>{if(typeof entry.spec!="string")throw new TypeError(`${at}.spec must be a string`)}};function validateProjectProfileDefinition(profile){const record=asRegistrationRecord("registerProfile profile",profile);if(assertNonEmptyRegistrationString("registerProfile profile.name",record.name),assertNonEmptyRegistrationString("registerProfile profile.title",record.title),record.summary!==void 0&&typeof record.summary!="string")throw new TypeError("registerProfile profile.summary must be a string when provided");for(const dimension of PROJECT_PROFILE_DIMENSIONS){const value=record[dimension];if(value!==void 0){if(!Array.isArray(value))throw new TypeError(`registerProfile profile.${dimension} must be an array when provided`);for(const[index,entry]of value.entries()){if(typeof entry!="object"||entry===null||Array.isArray(entry))throw new TypeError(`registerProfile profile.${dimension}[${index}] must be an object`);PROJECT_PROFILE_ENTRY_VALIDATORS[dimension]?.(`registerProfile profile.${dimension}[${index}]`,entry)}}}}function applyProjectProfileDefaults(profile){profile.summary===void 0&&(profile.summary="");for(const dimension of PROJECT_PROFILE_DIMENSIONS)profile[dimension]===void 0&&(profile[dimension]=[]);return profile}export{applyProjectProfileDefaults,assertFlagValueTypeAndDefault,normalizeCommandDefinitionArguments,normalizeFlagDefinitions,resolveCommandDefinitionAction,validateFlagDefinitions,validateItemFieldDefinitions,validateItemTypeDefinitions,validateMigrationDefinition,validateProjectProfileDefinition};
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="4abca948-e9ba-52b5-b63c-a20fc344980a")}catch{}})();import{describeExtensionLongFlagFailure,findExtensionFlagTokenFailure}from"./flag-definition-validation.js";import{flattenFlagListValue,isFlagDefaultValueCoercible,resolveFlagValueKind}from"./flag-value-types.js";import{KNOWN_ITEM_FIELD_TYPES,normalizeItemFieldType,suggestKnownItemFieldType}from"./item-field-types.js";import{asRegistrationRecord,assertOptionalBooleanField,assertOptionalFlagDefaultField,assertOptionalStringArrayField,assertOptionalStringField}from"./registration-validation.js";import{assertNonEmptyRegistrationString,normalizeRegistrationRecordList}from"./registration-values.js";const FLAG_DEFINITION_KEYS=new Set(["default","description","enabled","list","long","repeatable","required","short","type","value_name","value_type","value_validation","visible"]);function normalizeFlagDefinitions(name,value){return normalizeRegistrationRecordList(name,value).map(record=>(record.repeatable===!0&&(record.list=!0),record))}function normalizeCommandActionName(value){return value.trim().toLowerCase().replace(/[\s_]+/g,"-").replace(/[^a-z0-9-]/g,"-").replace(/-+/g,"-").replace(/^-+|-+$/g,"")}function resolveCommandDefinitionAction(commandPath,action){if(action===void 0)return commandPath.replace(/\s+/g,"-");if(typeof action!="string"||action.trim().length===0)throw new TypeError("registerCommand definition.action must be a non-empty string when provided");const normalized=normalizeCommandActionName(action);if(normalized.length===0)throw new TypeError("registerCommand definition.action must contain alphanumeric characters");return normalized}function normalizeCommandDefinitionArguments(value){if(value===void 0)return[];if(!Array.isArray(value))throw new TypeError("registerCommand definition.arguments must be an array when provided");const normalized=[];for(const[index,entry]of value.entries()){const record=asRegistrationRecord(`registerCommand definition.arguments[${index}]`,entry),name=assertNonEmptyRegistrationString(`registerCommand definition.arguments[${index}].name`,record.name);if(assertOptionalBooleanField(`registerCommand definition.arguments[${index}].required`,record.required),assertOptionalBooleanField(`registerCommand definition.arguments[${index}].variadic`,record.variadic),assertOptionalStringField(`registerCommand definition.arguments[${index}].description`,record.description),name.includes(" "))throw new TypeError(`registerCommand definition.arguments[${index}].name must not contain spaces`);const definition={name};record.required===!0&&(definition.required=!0),record.variadic===!0&&(definition.variadic=!0),typeof record.description=="string"&&(definition.description=record.description.trim()),normalized.push(definition)}const variadicIndexes=normalized.map((argument,index)=>argument.variadic?index:-1).filter(index=>index>=0);if(variadicIndexes.length>1)throw new TypeError("registerCommand definition.arguments supports at most one variadic argument");if(variadicIndexes.length===1&&variadicIndexes[0]!==normalized.length-1)throw new TypeError("registerCommand definition.arguments variadic argument must be the final argument");return normalized}function validateFlagDefinitions(flags){if(!Array.isArray(flags))throw new TypeError("registerFlags flags requires an array of object definitions");for(const[index,raw]of flags.entries()){const record=asRegistrationRecord(`registerFlags flags[${index}]`,raw),unknownKeys=Object.keys(record).filter(key=>!FLAG_DEFINITION_KEYS.has(key)).sort((left,right)=>left.localeCompare(right));if(unknownKeys.length>0)throw new TypeError(`registerFlags flags[${index}] contains unknown field(s): ${unknownKeys.join(", ")}`);const long=record.long,short=record.short;if(long===void 0&&short===void 0)throw new TypeError(`registerFlags flags[${index}] requires at least one of long or short`);assertOptionalStringField(`registerFlags flags[${index}].long`,long),assertOptionalStringField(`registerFlags flags[${index}].short`,short);const tokenFinding=findExtensionFlagTokenFailure(long,short);if(tokenFinding!==null)throw new TypeError(`registerFlags flags[${index}] ${describeExtensionLongFlagFailure(tokenFinding.token,tokenFinding.failure)}`);if(assertOptionalStringField(`registerFlags flags[${index}].value_name`,record.value_name),assertOptionalStringField(`registerFlags flags[${index}].description`,record.description),assertOptionalBooleanField(`registerFlags flags[${index}].required`,record.required),assertOptionalBooleanField(`registerFlags flags[${index}].enabled`,record.enabled),assertOptionalBooleanField(`registerFlags flags[${index}].visible`,record.visible),assertOptionalBooleanField(`registerFlags flags[${index}].list`,record.list),assertOptionalBooleanField(`registerFlags flags[${index}].repeatable`,record.repeatable),record.list!==void 0&&record.repeatable!==void 0&&record.list!==record.repeatable)throw new TypeError(`registerFlags flags[${index}].list and repeatable must match when both are provided`);if(assertOptionalFlagDefaultField(`registerFlags flags[${index}].default`,record.default),Array.isArray(record.default)&&record.list!==!0&&record.repeatable!==!0)throw new TypeError(`registerFlags flags[${index}].default cannot be an array unless list is true.`);assertFlagValueTypeAndDefault(`registerFlags flags[${index}]`,record),assertFlagValueValidation(`registerFlags flags[${index}]`,record)}}function assertFlagValueValidation(label,record){if(record.value_validation===void 0)return;if(record.value_validation!=="coerce"&&record.value_validation!=="strict")throw new TypeError(`${label}.value_validation must be "coerce" or "strict" (received ${JSON.stringify(record.value_validation)}).`);if(record.value_validation!=="strict")return;const declaredType=(typeof record.value_type=="string"?record.value_type:void 0)??(typeof record.type=="string"?record.type:void 0),kind=declaredType===void 0?null:resolveFlagValueKind(declaredType);if(kind!=="number"&&kind!=="boolean")throw new TypeError(`${label}.value_validation "strict" requires value_type "number" or "boolean" (string values are never malformed).`)}function assertFlagValueTypeAndDefault(label,record){const declaredType=(typeof record.value_type=="string"?record.value_type:void 0)??(typeof record.type=="string"?record.type:void 0);if(declaredType===void 0)return;const kind=resolveFlagValueKind(declaredType);if(kind===null)throw new TypeError(`${label} value_type "${declaredType}" is not a known flag value type (expected one of: string, number, boolean).`);if(record.default===void 0)return;const defaults=record.list===!0||record.repeatable===!0?flattenFlagListValue(record.default):[record.default];for(const[defaultIndex,defaultValue]of defaults.entries())if(!isFlagDefaultValueCoercible(defaultValue,kind)){const suffix=defaults.length>1?`default[${defaultIndex}]`:"default";throw new TypeError(`${label}.${suffix} (${JSON.stringify(defaultValue)}) is not coercible to ${kind}.`)}}function validateItemFieldDefinitions(fields){if(!Array.isArray(fields))throw new TypeError("registerItemFields fields requires an array of object definitions");for(const[index,raw]of fields.entries()){const record=asRegistrationRecord(`registerItemFields fields[${index}]`,raw);assertNonEmptyRegistrationString(`registerItemFields fields[${index}].name`,record.name);const fieldType=assertNonEmptyRegistrationString(`registerItemFields fields[${index}].type`,record.type);if(normalizeItemFieldType(fieldType)===null){const suggestion=suggestKnownItemFieldType(fieldType),hint=suggestion?` Did you mean "${suggestion}"?`:"";throw new TypeError(`registerItemFields fields[${index}].type "${fieldType}" is not a known field type (expected one of: ${KNOWN_ITEM_FIELD_TYPES.join(", ")}).${hint}`)}assertOptionalBooleanField(`registerItemFields fields[${index}].optional`,record.optional)}}function validateItemTypeCommandOptionPolicies(typeIndex,value){if(value===void 0)return;const label=`registerItemTypes types[${typeIndex}].command_option_policies`;if(!Array.isArray(value))throw new TypeError(`${label} must be an array when provided`);for(const[policyIndex,rawPolicy]of value.entries()){const at=`${label}[${policyIndex}]`,policy=asRegistrationRecord(at,rawPolicy);assertNonEmptyRegistrationString(`${at}.command`,policy.command),assertNonEmptyRegistrationString(`${at}.option`,policy.option),assertOptionalBooleanField(`${at}.enabled`,policy.enabled),assertOptionalBooleanField(`${at}.required`,policy.required),assertOptionalBooleanField(`${at}.visible`,policy.visible)}}function validateItemTypeOptions(typeIndex,value){if(value===void 0)return;const label=`registerItemTypes types[${typeIndex}].options`;if(!Array.isArray(value))throw new TypeError(`${label} must be an array when provided`);for(const[optionIndex,rawOption]of value.entries()){const at=`${label}[${optionIndex}]`,option=asRegistrationRecord(at,rawOption);assertNonEmptyRegistrationString(`${at}.key`,option.key),assertOptionalStringArrayField(`${at}.values`,option.values),assertOptionalBooleanField(`${at}.required`,option.required),assertOptionalStringArrayField(`${at}.aliases`,option.aliases)}}function validateItemTypeDefinitions(types){if(!Array.isArray(types))throw new TypeError("registerItemTypes types requires an array of object definitions");for(const[typeIndex,raw]of types.entries()){const at=`registerItemTypes types[${typeIndex}]`,record=asRegistrationRecord(at,raw);assertNonEmptyRegistrationString(`${at}.name`,record.name),assertOptionalStringField(`${at}.folder`,record.folder),assertOptionalStringArrayField(`${at}.aliases`,record.aliases),assertOptionalStringArrayField(`${at}.required_create_fields`,record.required_create_fields),assertOptionalStringArrayField(`${at}.required_create_repeatables`,record.required_create_repeatables),validateItemTypeCommandOptionPolicies(typeIndex,record.command_option_policies),validateItemTypeOptions(typeIndex,record.options)}}function validateMigrationDefinition(definition){const record=asRegistrationRecord("registerMigration definition",definition);if(record.id!==void 0&&typeof record.id!="string")throw new TypeError("registerMigration definition.id must be a string when provided");if(record.description!==void 0&&typeof record.description!="string")throw new TypeError("registerMigration definition.description must be a string when provided");if(record.status!==void 0&&typeof record.status!="string")throw new TypeError("registerMigration definition.status must be a string when provided");if(assertOptionalBooleanField("registerMigration definition.mandatory",record.mandatory),record.run!==void 0&&typeof record.run!="function")throw new TypeError("registerMigration definition.run must be a function when provided")}const PROJECT_PROFILE_DIMENSIONS=["types","statuses","fields","workflows","config","templates","packages"],PROJECT_PROFILE_ENTRY_VALIDATORS={types:(at,entry)=>{if(entry.name!==void 0&&typeof entry.name!="string")throw new TypeError(`${at}.name must be a string when provided`)},workflows:(at,entry)=>{if(typeof entry.type!="string")throw new TypeError(`${at}.type must be a string`);if(!Array.isArray(entry.allowed_transitions))throw new TypeError(`${at}.allowed_transitions must be an array`);for(const[pairIndex,pair]of entry.allowed_transitions.entries())if(!Array.isArray(pair))throw new TypeError(`${at}.allowed_transitions[${pairIndex}] must be a [from, to] array`)},templates:(at,entry)=>{if(typeof entry.name!="string")throw new TypeError(`${at}.name must be a string`);if(typeof entry.options!="object"||entry.options===null||Array.isArray(entry.options))throw new TypeError(`${at}.options must be an object`)},packages:(at,entry)=>{if(typeof entry.spec!="string")throw new TypeError(`${at}.spec must be a string`)}};function validateProjectProfileDefinition(profile){const record=asRegistrationRecord("registerProfile profile",profile);if(assertNonEmptyRegistrationString("registerProfile profile.name",record.name),assertNonEmptyRegistrationString("registerProfile profile.title",record.title),record.summary!==void 0&&typeof record.summary!="string")throw new TypeError("registerProfile profile.summary must be a string when provided");for(const dimension of PROJECT_PROFILE_DIMENSIONS){const value=record[dimension];if(value!==void 0){if(!Array.isArray(value))throw new TypeError(`registerProfile profile.${dimension} must be an array when provided`);for(const[index,entry]of value.entries()){if(typeof entry!="object"||entry===null||Array.isArray(entry))throw new TypeError(`registerProfile profile.${dimension}[${index}] must be an object`);PROJECT_PROFILE_ENTRY_VALIDATORS[dimension]?.(`registerProfile profile.${dimension}[${index}]`,entry)}}}}function applyProjectProfileDefaults(profile){profile.summary===void 0&&(profile.summary="");for(const dimension of PROJECT_PROFILE_DIMENSIONS)profile[dimension]===void 0&&(profile[dimension]=[]);return profile}export{applyProjectProfileDefaults,assertFlagValueTypeAndDefault,normalizeCommandDefinitionArguments,normalizeFlagDefinitions,resolveCommandDefinitionAction,validateFlagDefinitions,validateItemFieldDefinitions,validateItemTypeDefinitions,validateMigrationDefinition,validateProjectProfileDefinition};
|
|
2
2
|
//# sourceMappingURL=registration-contracts.js.map
|
|
@@ -51,7 +51,9 @@ has_more:boolean;
|
|
|
51
51
|
/** Latest substantive immutable event for each requested history stream. */
|
|
52
52
|
export type LatestSubstantiveHistoryEvents = Readonly<Record<string,IndexedHistoryEvent>>;
|
|
53
53
|
/** Rebuild the complete optional event projection from authoritative streams. */
|
|
54
|
-
export declare function rebuildHistoryEventIndex(pmRoot:string
|
|
54
|
+
export declare function rebuildHistoryEventIndex(pmRoot:string,options?:{
|
|
55
|
+
lockWaitMs?:number;
|
|
56
|
+
}):Promise<boolean>;
|
|
55
57
|
/**
|
|
56
58
|
* Query authoritative history streams when the optional SQLite accelerator is
|
|
57
59
|
* unavailable. The result preserves the index contract at higher read cost.
|
|
@@ -65,6 +67,11 @@ export declare function queryHistoryEventStreams(pmRoot:string,query:HistoryEven
|
|
|
65
67
|
export declare function appendHistoryEntryWithEventIndex(historyPath:string,entry:HistoryEntry,append:() => Promise<void>):Promise<void>;
|
|
66
68
|
/** Invalidate the optional event projection after a non-append rewrite. */
|
|
67
69
|
export declare function removeHistoryEventIndexForHistoryPath(historyPath:string):Promise<void>;
|
|
70
|
+
/** Distinguish repairable cache absence/damage from transient concurrent writes. */
|
|
71
|
+
export declare function readHistoryEventIndexPage(pmRoot:string,query:HistoryEventIndexQuery):Promise<{
|
|
72
|
+
result:HistoryEventIndexQueryResult | null;
|
|
73
|
+
repair_needed:boolean;
|
|
74
|
+
}>;
|
|
68
75
|
/** Query the optional event projection without scanning history streams. */
|
|
69
76
|
export declare function queryHistoryEventIndex(pmRoot:string,query:HistoryEventIndexQuery):Promise<HistoryEventIndexQueryResult | null>;
|
|
70
77
|
declare function collectLatestSubstantiveEvents(events:readonly IndexedHistoryEvent[],requested:ReadonlySet<string>):Record<string,IndexedHistoryEvent>;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
-
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="641c311a-5de1-579a-ba44-b9a49978dfe0")}catch{}})();import fs from"node:fs/promises";import path from"node:path";import{randomUUID}from"node:crypto";import{createRequire}from"node:module";import{setImmediate as yieldToEventLoop}from"node:timers/promises";import{isFileMissingError}from"../fs/fs-utils.js";import{acquireLock,captureProcessIdentity,isProcessIdentityAlive,hasUnexpiredLockOwner}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";import{loadDatabaseSync,loadStableDatabaseSync}from"../store/sqlite-runtime.js";const EVENT_INDEX_FILENAME="history-event-index.sqlite",EVENT_INDEX_VERSION="6",AUTHORITATIVE_HISTORY_CACHE_LIMIT=8,HISTORY_EVENT_INDEX_LOCK_ID="history-event-index",HISTORY_EVENT_INDEX_APPEND_OWNER_PREFIX="history-event-index:append:",HISTORY_EVENT_INDEX_REPAIR_COOLDOWN_MS=5e3,HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS=300,HISTORY_EVENT_INDEX_LOCK_WAIT_MS=3e4,HISTORY_EVENT_INDEX_INVALIDATION_LOCK_ID="history-event-index-invalidation",HISTORY_EVENT_INDEX_INVALIDATION_DIRECTORY="history-event-index-invalidations",HISTORY_EVENT_INDEX_INVALIDATION_MAX_UNVERIFIED_AGE_MS=HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS*2*1e3,HISTORY_INDEX_CHANGED=Symbol("history-index-changed"),authoritativeHistoryCaches=new Map;function eventIndexPath(pmRoot){return path.join(pmRoot,"runtime",EVENT_INDEX_FILENAME)}function refusedHistoryRepairPath(pmRoot){return path.join(pmRoot,"runtime","history-event-index-repair-deferred")}async function hasRecentRefusedHistoryRepair(pmRoot){try{const deferredAt=Number(await fs.readFile(refusedHistoryRepairPath(pmRoot),"utf8")),age=Date.now()-deferredAt;return age>=0&&age<HISTORY_EVENT_INDEX_REPAIR_COOLDOWN_MS}catch{return!1}}async function deferAutomaticHistoryRepair(pmRoot){try{await fs.writeFile(refusedHistoryRepairPath(pmRoot),`${Date.now()}
|
|
2
|
+
`)}catch{}}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);return{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}return await fs.rm(path.join(historyEventIndexInvalidationDirectory(pmRoot),name),{force:!0}),null}))).filter(name=>name!==null),committed:invalidations.committed}}async function withHistoryEventIndexInvalidationLock(pmRoot,operation,waitMs=HISTORY_EVENT_INDEX_LOCK_WAIT_MS){const release=await acquireLock(pmRoot,HISTORY_EVENT_INDEX_INVALIDATION_LOCK_ID,HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS,`history-event-index-invalidation:${process.pid}`,!1,!1,waitMs,waitMs===0?{maxWaitMs:0}:void 0);try{return await operation()}finally{await release()}}async function beginHistoryEventIndexInvalidation(pmRoot){const directory=historyEventIndexInvalidationDirectory(pmRoot);await fs.mkdir(directory,{recursive:!0});const token=randomUUID(),processIdentity=await captureProcessIdentity(),pendingPath=path.join(directory,`${processIdentity.pid}-${processIdentity.process_start_identity??"unknown"}-${Date.now()}-${token}.pending`);return await fs.writeFile(pendingPath,`pending
|
|
3
|
+
`,{flag:"wx"}),{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:!0})}catch{}}async function recordHistoryEventIndexInvalidation(pmRoot,retainCache){const directory=historyEventIndexInvalidationDirectory(pmRoot);await fs.mkdir(directory,{recursive:!0}),await fs.writeFile(path.join(directory,`${randomUUID()}${retainCache?".contended":""}.committed`),`committed
|
|
4
|
+
`,{flag:"wx"}),retainCache||await invalidateHistoryEventIndex(pmRoot)}function hasContendedHistoryEventIndexInvalidation(invalidations){return invalidations.committed.some(name=>name.endsWith(".contended.committed"))}function hasNativeHistoryEventIndexContention(pmRoot,Database){let database;try{return database=new Database(eventIndexPath(pmRoot)),database.exec("PRAGMA busy_timeout = 0"),database.exec("BEGIN EXCLUSIVE"),!1}catch(error){return isHistoryIndexSqliteContention(error)}finally{database?.close()}}async function historyEventIndexAppendIsActive(pmRoot,invalidations){return invalidations.pending.length>0||await hasUnexpiredLockOwner(pmRoot,HISTORY_EVENT_INDEX_LOCK_ID,HISTORY_EVENT_INDEX_APPEND_OWNER_PREFIX)}async function withHistoryEventIndexLock(pmRoot,operation,waitMs=HISTORY_EVENT_INDEX_LOCK_WAIT_MS,purpose="rebuild"){const release=await acquireLock(pmRoot,HISTORY_EVENT_INDEX_LOCK_ID,HISTORY_EVENT_INDEX_LOCK_TTL_SECONDS,`history-event-index:${purpose}:${process.pid}`,!1,!1,waitMs,waitMs===0?{maxWaitMs:0}:void 0);try{return await operation()}finally{await release()}}async function readAuthoritativeHistorySnapshot(pmRoot){const historyRoot=path.join(pmRoot,"history"),entries=await fs.readdir(historyRoot,{withFileTypes:!0}).catch(error=>{if(typeof error=="object"&&error!==null&&"code"in error&&error.code==="ENOENT")return[];throw error}),cached=authoritativeHistoryCaches.get(pmRoot)??{streams:new Map,ordered_events:[]},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,-6);presentStreams.add(streamId);const historyPath=path.join(historyRoot,historyFile.name),stats=await fs.stat(historyPath,{bigint:!0}),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=!0}for(const streamId of cached.streams.keys())presentStreams.has(streamId)||(cached.streams.delete(streamId),changed=!0);if(changed&&(cached.ordered_events=[...cached.streams.values()].flatMap(stream=>stream.events).sort(compareHistoryEventPosition)),authoritativeHistoryCaches.delete(pmRoot),authoritativeHistoryCaches.set(pmRoot,cached),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}let RuntimeDatabaseSync;function resolveDatabaseSync(){return RuntimeDatabaseSync!==void 0||(RuntimeDatabaseSync=loadStableDatabaseSync(process.versions.node,createRequire(import.meta.url))),RuntimeDatabaseSync}function createSchema(database){database.exec(`
|
|
3
5
|
PRAGMA journal_mode = OFF;
|
|
4
6
|
PRAGMA synchronous = OFF;
|
|
5
7
|
CREATE TABLE metadata (
|
|
@@ -38,20 +40,19 @@
|
|
|
38
40
|
stream_id, stream_offset, ts, author, agent_harness,
|
|
39
41
|
agent_instance, op, event_class, entry_json
|
|
40
42
|
) 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));return typeof entry.ts!="string"||!isMillisecondPrecisionRfc3339DateTime(entry.ts.trim())?null:{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 (?, ?)
|
|
41
|
-
ON CONFLICT(stream_id) DO UPDATE SET byte_size = excluded.byte_size`).run(streamId,byteSize)}async function rebuildHistoryEventIndex(pmRoot){const Database=resolveDatabaseSync();return Database?withHistoryEventIndexLock(pmRoot,async()=>{let invalidations;try{invalidations=await withHistoryEventIndexInvalidationLock(pmRoot,()=>recoverAbandonedHistoryEventIndexInvalidations(pmRoot))}catch(error){if(error instanceof PmCliError&&error.code==="lock_conflict")return!1;throw error}if(invalidations.pending.length>0)return!1;const targetPath=eventIndexPath(pmRoot);await fs.mkdir(path.dirname(targetPath),{recursive:!0});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);return current.pending.length>0||!sameInvalidationNames(invalidations.committed,current.committed)?!1:(await fs.rm(targetPath,{force:!0}),await fs.rename(temporaryPath,targetPath),await Promise.all(invalidations.committed.map(name=>fs.rm(path.join(historyEventIndexInvalidationDirectory(pmRoot),name),{force:!0}))),!0)});return published||await fs.rm(temporaryPath,{force:!0}),published}catch(error){throw database?.close(),await fs.rm(temporaryPath,{force:!0}),error}}):!1}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!1}else if(query.since_ts!==void 0&&event.entry.ts<canonicalHistoryQueryTimestamp(query.since_ts))return!1;return!0}function matchesHistoryEventHarness(event,query){return!query.harnesses||query.harnesses.length===0||query.harnesses.includes(event.entry.agent_harness??"")?!0:event.entry.agent_harness===void 0&&(query.harness_alias_authors??[]).includes(event.entry.author)}function matchesHistoryEventQuery(event,query){return!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)?!1:(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)),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)),Database=resolveDatabaseSync();if(!Database){await append();return}let authoritativeAppendCommitted=!1;try{await withHistoryEventIndexLock(pmRoot,async()=>{const targetPath=eventIndexPath(pmRoot);try{await fs.access(targetPath)}catch{await append();return}let database;try{if(database=new Database(targetPath),database.prepare("SELECT value FROM metadata WHERE key = 'version'").get()?.value!==EVENT_INDEX_VERSION)throw new TypeError("Unsupported history event index version")}catch{database?.close(),await fs.rm(targetPath,{force:!0}),await append();return}try{database.exec("PRAGMA busy_timeout = 5000"),database.exec("BEGIN IMMEDIATE")}catch(error){throw database.close(),error}let appended=!1;try{await append(),appended=!0,authoritativeAppendCommitted=!0;const streamId=path.basename(historyPath,".jsonl"),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){if(database?.close(),!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=!0}catch(appendError){throw await fs.rm(marker.pendingPath,{force:!0}),appendError}await fs.rename(marker.pendingPath,marker.committedPath),await invalidateHistoryEventIndex(pmRoot)})}catch(fallbackError){if(authoritativeAppendCommitted){await invalidateHistoryEventIndex(pmRoot);try{await fs.rm(pendingMarkerPath,{force:!0})}catch{}return}throw fallbackError}}}async function removeHistoryEventIndexForHistoryPath(historyPath){await fs.rm(eventIndexPath(path.dirname(path.dirname(historyPath))),{force:!0})}function appendSetPredicate(clauses,parameters,column,values){!values||values.length===0||(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(", "),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;const database=new Database(eventIndexPath(pmRoot),{readOnly:!0});try{if(database.prepare("SELECT value FROM metadata WHERE key = 'version'").get()?.value===EVENT_INDEX_VERSION)return database}catch(error){throw database.close(),error}database.close()}async function queryHistoryEventIndex(pmRoot,query){const Database=resolveDatabaseSync();if(!Database)return null;const clauses=[],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 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()=>withHistoryEventIndexInvalidationLock(pmRoot,async()=>{if(database=await openSettledHistoryEventIndex(pmRoot,Database),!database)return null;const validationStreamIds=await historyIndexValidationStreamIds(database,pmRoot,query.stream_ids);if(!await historyIndexMatchesStreamSizes(database,pmRoot,validationStreamIds))return database.close(),database=void 0,null;const rows=database.prepare(`SELECT stream_id, stream_offset, entry_json
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
WHERE recency_rank = 1`).all(...chunk).map(parseIndexedHistoryEvent);if(parsed.includes(null))return database.close(),database=void 0,null;indexed.push(...parsed)}return database.close(),database=void 0,collectLatestSubstantiveEvents(indexed,requested)}))}catch(error){return database?.close(),error instanceof PmCliError&&error.code==="lock_conflict"?HISTORY_INDEX_LOCK_CONTENDED: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),Database=resolveDatabaseSync(),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=[];return await Promise.all(uniqueIds.map(async streamId=>{const historyPath=path.join(pmRoot,"history",`${streamId}.jsonl`);(await readIndexableHistoryEntries(historyPath,streamId).catch(error=>{if(error instanceof PmCliError&&error.code==="history_timestamp_invalid")return[];throw error})).forEach((entry,streamOffset)=>{authoritative.push({stream_id:streamId,stream_offset:streamOffset,entry})})})),collectLatestSubstantiveEvents(authoritative,requested)}const _testOnly={collectLatestSubstantiveEvents,loadDatabaseSync,loadStableDatabaseSync,setDatabaseSync(databaseSync){const previous=RuntimeDatabaseSync;return RuntimeDatabaseSync=databaseSync,()=>{RuntimeDatabaseSync=previous}}};export{_testOnly,appendHistoryEntryWithEventIndex,queryHistoryEventIndex,queryHistoryEventStreams,readLatestSubstantiveHistoryEvents,rebuildHistoryEventIndex,removeHistoryEventIndexForHistoryPath};
|
|
43
|
+
ON CONFLICT(stream_id) DO UPDATE SET byte_size = excluded.byte_size`).run(streamId,byteSize)}async function rebuildHistoryEventIndex(pmRoot,options={}){const Database=resolveDatabaseSync();return Database?withHistoryEventIndexLock(pmRoot,async()=>{let invalidations;try{invalidations=await withHistoryEventIndexInvalidationLock(pmRoot,()=>recoverAbandonedHistoryEventIndexInvalidations(pmRoot),options.lockWaitMs)}catch(error){if(error instanceof PmCliError&&error.code==="lock_conflict")return!1;throw error}if(invalidations.pending.length>0||hasContendedHistoryEventIndexInvalidation(invalidations)&&hasNativeHistoryEventIndexContention(pmRoot,Database))return!1;const targetPath=eventIndexPath(pmRoot);await fs.mkdir(path.dirname(targetPath),{recursive:!0});const temporaryPath=`${targetPath}.${randomUUID()}.tmp`;let database;try{database=new Database(temporaryPath),createSchema(database),database.exec("BEGIN IMMEDIATE");const authoritative=await readAuthoritativeHistorySnapshot(pmRoot);await populateHistoryEventIndex(database,authoritative),database.exec("COMMIT"),database.close(),database=void 0;const published=await withHistoryEventIndexInvalidationLock(pmRoot,async()=>{const current=await recoverAbandonedHistoryEventIndexInvalidations(pmRoot);return current.pending.length>0||!sameInvalidationNames(invalidations.committed,current.committed)||hasContendedHistoryEventIndexInvalidation(current)&&hasNativeHistoryEventIndexContention(pmRoot,Database)?!1:(await fs.rm(targetPath,{force:!0}),await fs.rename(temporaryPath,targetPath),!0)},options.lockWaitMs);return published&&await Promise.all(invalidations.committed.map(name=>fs.rm(path.join(historyEventIndexInvalidationDirectory(pmRoot),name),{force:!0}))),published||(await deferAutomaticHistoryRepair(pmRoot),await fs.rm(temporaryPath,{force:!0})),published}catch(error){throw await deferAutomaticHistoryRepair(pmRoot),database?.close(),await fs.rm(temporaryPath,{force:!0}),error}},options.lockWaitMs):!1}async function populateHistoryEventIndex(database,snapshot){let inserted=0;for(const event of snapshot.events)insertEvent(database,event),++inserted%500===0&&await yieldToEventLoop();for(const[streamId,byteSize]of snapshot.stream_byte_sizes)upsertStreamByteSize(database,streamId,byteSize),++inserted%500===0&&await yieldToEventLoop()}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!1}else if(query.since_ts!==void 0&&event.entry.ts<canonicalHistoryQueryTimestamp(query.since_ts))return!1;return!0}function matchesHistoryEventHarness(event,query){return!query.harnesses||query.harnesses.length===0||query.harnesses.includes(event.entry.agent_harness??"")?!0:event.entry.agent_harness===void 0&&(query.harness_alias_authors??[]).includes(event.entry.author)}function matchesHistoryEventQuery(event,query){return!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)?!1:(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)),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 historyEventIndexHasAppendBase(database,historyPath){const stored=database.prepare("SELECT byte_size FROM streams WHERE stream_id = ?").get(path.basename(historyPath,".jsonl"));let actualSize=0;try{actualSize=(await fs.stat(historyPath)).size}catch(error){if(!isFileMissingError(error))throw error}return Number(stored?.byte_size??0)===actualSize}async function appendHistoryEntryWithEventIndex(historyPath,entry,append){const pmRoot=path.dirname(path.dirname(historyPath)),Database=resolveDatabaseSync();let authoritativeAppendCommitted=!1;const appendAuthoritative=async()=>{await append(),authoritativeAppendCommitted=!0};if(!Database){await appendUnindexedHistory(pmRoot,appendAuthoritative);return}try{await withHistoryEventIndexLock(pmRoot,async()=>{const targetPath=eventIndexPath(pmRoot);try{await fs.access(targetPath)}catch{await appendAuthoritative();return}let database;try{if(database=new Database(targetPath),database.prepare("SELECT value FROM metadata WHERE key = 'version'").get()?.value!==EVENT_INDEX_VERSION)throw new TypeError("Unsupported history event index version");if(!await historyEventIndexHasAppendBase(database,historyPath))throw new TypeError("Stale history event index append base")}catch(error){if(database?.close(),isHistoryIndexSqliteContention(error))throw error;await recordHistoryEventIndexInvalidation(pmRoot,!0),await appendAuthoritative();return}try{database.exec("PRAGMA busy_timeout = 0"),database.exec("BEGIN IMMEDIATE")}catch(error){throw database.close(),error}let appended=!1;try{await appendAuthoritative(),appended=!0;const streamId=path.basename(historyPath,".jsonl"),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){if(database?.close(),!appended)throw error;await recordHistoryEventIndexInvalidation(pmRoot,isHistoryIndexSqliteContention(error))}},0,"append")}catch(error){if(authoritativeAppendCommitted){await invalidateHistoryEventIndex(pmRoot);return}if(!isHistoryIndexWriteContention(error))throw error;await appendUnindexedHistory(pmRoot,appendAuthoritative,isHistoryIndexSqliteContention(error))}}async function appendUnindexedHistory(pmRoot,append,nativeContention=!1){let authoritativeAppendCommitted=!1,pendingMarkerPath;try{await withHistoryEventIndexInvalidationLock(pmRoot,async()=>{const contended=nativeContention||hasContendedHistoryEventIndexInvalidation(await listHistoryEventIndexInvalidations(pmRoot)),marker=await beginHistoryEventIndexInvalidation(pmRoot);pendingMarkerPath=marker.pendingPath;try{await append(),authoritativeAppendCommitted=!0}catch(appendError){throw await fs.rm(marker.pendingPath,{force:!0}),appendError}await fs.rename(marker.pendingPath,contended?marker.committedPath.replace(/\.committed$/u,".contended.committed"):marker.committedPath),contended||await invalidateHistoryEventIndex(pmRoot)})}catch(fallbackError){if(authoritativeAppendCommitted){await invalidateHistoryEventIndex(pmRoot);try{await fs.rm(pendingMarkerPath,{force:!0})}catch{}return}throw fallbackError}}async function removeHistoryEventIndexForHistoryPath(historyPath){await fs.rm(eventIndexPath(path.dirname(path.dirname(historyPath))),{force:!0})}function appendSetPredicate(clauses,parameters,column,values){!values||values.length===0||(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(", "),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 readHistoryEventIndexSnapshot(pmRoot,Database,requestedStreamIds,read){let database;try{const invalidations=await listHistoryEventIndexInvalidations(pmRoot);if(await historyEventIndexAppendIsActive(pmRoot,invalidations))return HISTORY_INDEX_CHANGED;const before=await historyEventIndexSignature(pmRoot);if(invalidations.committed.length>0)return hasContendedHistoryEventIndexInvalidation(invalidations)&&hasNativeHistoryEventIndexContention(pmRoot,Database)?HISTORY_INDEX_CHANGED:null;if(database=new Database(eventIndexPath(pmRoot),{readOnly:!0}),database.exec("BEGIN"),database.prepare("SELECT value FROM metadata WHERE key = 'version'").get()?.value!==EVENT_INDEX_VERSION)return null;const result=read(database);if(result===null)return null;const storedSizes=readHistoryEventIndexStreamSizes(database,requestedStreamIds),completed=database;database=void 0,completed.close();const streamIds=await historyIndexValidationStreamIds([...storedSizes.keys()],pmRoot,requestedStreamIds),sizesMatch=await historyIndexMatchesStreamSizes(storedSizes,pmRoot,streamIds),current=await listHistoryEventIndexInvalidations(pmRoot);return current.committed.length>0||await historyEventIndexAppendIsActive(pmRoot,current)||before!==await historyEventIndexSignature(pmRoot)?HISTORY_INDEX_CHANGED:sizesMatch?result:null}catch(error){return isHistoryIndexSqliteContention(error)?HISTORY_INDEX_CHANGED:null}finally{database?.close()}}function isHistoryIndexSqliteContention(error){return typeof error=="object"&&error!==null&&"errcode"in error&&[5,6].includes(error.errcode)}function isHistoryIndexWriteContention(error){return isHistoryIndexSqliteContention(error)||error instanceof PmCliError&&error.code==="lock_conflict"}function readHistoryEventIndexStreamSizes(database,requestedStreamIds){const storedSizes=new Map,ids=requestedStreamIds&&requestedStreamIds.length>0?[...new Set(requestedStreamIds)]:void 0;if(ids===void 0)for(const row of database.prepare("SELECT stream_id, byte_size FROM streams").all())storedSizes.set(String(row.stream_id),Number(row.byte_size));else for(let start=0;start<ids.length;start+=500){const chunk=ids.slice(start,start+500);for(const row of database.prepare(`SELECT stream_id, byte_size FROM streams WHERE stream_id IN (${chunk.map(()=>"?").join(", ")})`).all(...chunk))storedSizes.set(String(row.stream_id),Number(row.byte_size))}return storedSizes}async function historyEventIndexSignature(pmRoot){const stats=await fs.stat(eventIndexPath(pmRoot),{bigint:!0});return[stats.dev,stats.ino,stats.size,stats.mtimeNs,stats.ctimeNs].join(":")}async function readHistoryEventIndexPage(pmRoot,query){const Database=resolveDatabaseSync();if(!Database)return{result:null,repair_needed:!1};const clauses=[],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 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 ")}`,attempt=await readHistoryEventIndexSnapshot(pmRoot,Database,query.stream_ids,database=>{const rows=database.prepare(`SELECT stream_id, stream_offset, entry_json
|
|
44
|
+
FROM events${where}
|
|
45
|
+
ORDER BY ts, stream_id, stream_offset
|
|
46
|
+
LIMIT ?`).all(...parameters,Math.max(0,Math.floor(query.limit))+1),events=rows.slice(0,query.limit).map(parseIndexedHistoryEvent);return events.includes(null)?null:{events,has_more:rows.length>query.limit}});return{result:attempt===HISTORY_INDEX_CHANGED?null:attempt,repair_needed:attempt===null&&!await hasRecentRefusedHistoryRepair(pmRoot)}}async function queryHistoryEventIndex(pmRoot,query){return(await readHistoryEventIndexPage(pmRoot,query)).result}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];(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(storedSizes,pmRoot,streamIds){for(let start=0;start<streamIds.length;start+=500){const chunk=streamIds.slice(start,start+500),currentSizes=await Promise.all(chunk.map(streamId=>readHistoryStreamByteSize(pmRoot,streamId)));for(const[index,currentSize]of currentSizes.entries()){if(currentSize===null)return!1;const streamId=chunk[index],storedSize=storedSizes.get(streamId);if(!(currentSize===0&&storedSize===void 0)&¤tSize!==storedSize)return!1}}return!0}async function historyIndexValidationStreamIds(indexed,pmRoot,requestedStreamIds){if(requestedStreamIds&&requestedStreamIds.length>0)return[...new Set(requestedStreamIds.filter(streamId=>streamId.trim().length>0))];const authoritative=await fs.readdir(path.join(pmRoot,"history"),{withFileTypes:!0}).then(entries=>entries.filter(entry=>entry.isFile()&&entry.name.endsWith(".jsonl")).map(entry=>entry.name.slice(0,-6))).catch(error=>{if(isFileMissingError(error))return[];throw error});return[...new Set([...indexed,...authoritative])]}async function readIndexedLatestSubstantiveEvents(Database,pmRoot,streamIds,requested){return Database?readHistoryEventIndexSnapshot(pmRoot,Database,streamIds,database=>{const indexed=[];for(let start=0;start<streamIds.length;start+=500){const chunk=streamIds.slice(start,start+500),parsed=database.prepare(`SELECT stream_id, stream_offset, entry_json
|
|
47
|
+
FROM (
|
|
48
|
+
SELECT stream_id, stream_offset, entry_json,
|
|
49
|
+
ROW_NUMBER() OVER (
|
|
50
|
+
PARTITION BY stream_id
|
|
51
|
+
ORDER BY ts DESC, stream_offset DESC
|
|
52
|
+
) AS recency_rank
|
|
53
|
+
FROM events
|
|
54
|
+
WHERE event_class = 'substantive'
|
|
55
|
+
AND stream_id IN (${chunk.map(()=>"?").join(", ")})
|
|
56
|
+
)
|
|
57
|
+
WHERE recency_rank = 1`).all(...chunk).map(parseIndexedHistoryEvent);if(parsed.includes(null))return null;indexed.push(...parsed)}return collectLatestSubstantiveEvents(indexed,requested)}):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),Database=resolveDatabaseSync(),indexed=await readIndexedLatestSubstantiveEvents(Database,pmRoot,uniqueIds,requested);if(indexed!==null&&indexed!==HISTORY_INDEX_CHANGED)return indexed;if(Database&&indexed!==HISTORY_INDEX_CHANGED&&!await hasRecentRefusedHistoryRepair(pmRoot))try{if(await rebuildHistoryEventIndex(pmRoot,{lockWaitMs:0})){const rebuilt=await readIndexedLatestSubstantiveEvents(Database,pmRoot,uniqueIds,requested);if(rebuilt!==null&&rebuilt!==HISTORY_INDEX_CHANGED)return rebuilt}}catch{}const authoritative=[];return await Promise.all(uniqueIds.map(async streamId=>{const historyPath=path.join(pmRoot,"history",`${streamId}.jsonl`);(await readIndexableHistoryEntries(historyPath,streamId).catch(error=>{if(error instanceof PmCliError&&error.code==="history_timestamp_invalid")return[];throw error})).forEach((entry,streamOffset)=>{authoritative.push({stream_id:streamId,stream_offset:streamOffset,entry})})})),collectLatestSubstantiveEvents(authoritative,requested)}const _testOnly={collectLatestSubstantiveEvents,loadDatabaseSync,loadStableDatabaseSync,setDatabaseSync(databaseSync){const previous=RuntimeDatabaseSync;return RuntimeDatabaseSync=databaseSync,()=>{RuntimeDatabaseSync=previous}}};export{_testOnly,appendHistoryEntryWithEventIndex,queryHistoryEventIndex,queryHistoryEventStreams,readHistoryEventIndexPage,readLatestSubstantiveHistoryEvents,rebuildHistoryEventIndex,removeHistoryEventIndexForHistoryPath};
|
|
57
58
|
//# sourceMappingURL=event-index.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="fb315276-2021-54aa-a880-5b4eb508e8d6")}catch{}})();import{encode as encodeToon}from"@toon-format/toon";import{isDeepStrictEqual}from"node:util";import{CONFIDENCE_TEXT_VALUES,ISSUE_SEVERITY_VALUES,PLAN_STEP_STATUS_VALUES,RECURRENCE_FREQUENCY_VALUES,RECURRENCE_WEEKDAY_VALUES,STATUS_VALUES,weekdayOrderIndex}from"../../types/index.js";import{coerceRuntimeFieldValue}from"../schema/runtime-field-values.js";import{resolveRuntimeFieldRegistry,resolveRuntimeStatusRegistry}from"../schema/runtime-schema.js";import{BASELINE_ITEM_FORMAT_VERSION,CURRENT_ITEM_FORMAT_VERSION,effectiveItemFormatVersion,normalizeItemFormatVersion}from"./item-format-version.js";import{normalizeStatusInput}from"./status.js";import{decodeToonItemContent}from"./toon-decode.js";import{EXIT_CODE,ITEM_METADATA_KEY_ORDER}from"../shared/constants.js";import{findFirstMergeConflictMarker}from"../shared/conflict-markers.js";import{PmCliError}from"../shared/errors.js";import{orderObject}from"../shared/serialization.js";import{compareTimestampStrings,isTimestampLiteral}from"../shared/time.js";import{coerceFiniteNumber}from"../shared/primitives.js";const LINKED_TEST_PM_CONTEXT_MODE_VALUES=new Set(["schema","tracker","auto","none"]),LINKED_TEST_WORKSPACE_CONTEXT_MODE_VALUES=new Set(["source","isolated","snapshot"]),LINKED_TEST_TRUST_REASON_VALUES=new Set(["legacy","local_mutation","local_source_ref","acknowledged","invalid_provenance","foreign_source_ref"]),ITEM_TEST_RUN_STATUS_VALUES=new Set(["passed","failed","stopped","canceled"]),PLAN_STEP_STATUS_SET=new Set(PLAN_STEP_STATUS_VALUES);function normalizePathValue(value){return value.replaceAll("\\","/")}function firstNonZeroComparison(comparisons){for(const comparison of comparisons)if(comparison!==0)return comparison;return 0}function deleteUndefinedFields(record){for(const[key,value]of Object.entries(record))value===void 0&&delete record[key]}const REQUIRED_STRING_FIELDS=["id","title","description","created_at","updated_at"],STATIC_ITEM_METADATA_FIELD_SET=new Set(ITEM_METADATA_KEY_ORDER);function resolveRuntimeSchemaValidationContext(options){if(options?.schema)return{statusRegistry:resolveRuntimeStatusRegistry(options.schema),fieldRegistry:resolveRuntimeFieldRegistry(options.schema),unknownFieldPolicy:options.schema.unknown_field_policy??"allow",extensionFieldNames:new Set(options.extensionFieldNames??[]),onWarning:options.onWarning}}function runtimeFieldRequiredForType(definition,typeName){return definition.required?definition.required_types.length===0?!0:definition.required_types.map(value=>value.toLowerCase()).includes(typeName.trim().toLowerCase()):!1}function validationError(message){const field=message.match(/^([a-z_][\w.]*)\s/u)?.[1];throw new PmCliError(`Invalid item metadata: ${message}`,EXIT_CODE.GENERIC_FAILURE,{code:"item_document_invalid",reason:message.includes("required")?"missing_required_field":"schema_validation_error",...field?{field}:{},required:"Provide an item document whose metadata satisfies the active runtime schema.",why:message})}function documentSyntaxError(format,message){throw new PmCliError(message,EXIT_CODE.GENERIC_FAILURE,{code:"item_document_invalid",reason:"syntax_error",format,required:`Provide a syntactically valid ${format==="toon"?"TOON":"JSON Markdown"} item document.`,why:"The document could not be decoded far enough to validate item metadata."})}function assertSupportedItemFormat(metadata,required){if(!required||typeof metadata!="object"||metadata===null)return;const formatVersion=effectiveItemFormatVersion(metadata);if(!(formatVersion<=CURRENT_ITEM_FORMAT_VERSION))throw new PmCliError(`Stored item uses format version ${formatVersion}; this runtime supports up to ${CURRENT_ITEM_FORMAT_VERSION}. Upgrade pm before reading or changing this item.`,EXIT_CODE.CONFLICT,{code:"item_format_version_unsupported",format_version:formatVersion,required:"Upgrade to a pm runtime supporting the stored item format.",nextSteps:["Preserve the original item and history; do not lower pm_format_version to bypass compatibility checks."]})}function buildKnownItemMetadataKeys(runtimeContext){const knownKeys=new Set(STATIC_ITEM_METADATA_FIELD_SET);for(const definition of runtimeContext.fieldRegistry?.definitions??[])knownKeys.add(definition.metadata_key);for(const fieldName of runtimeContext.extensionFieldNames)knownKeys.add(fieldName);return knownKeys}function assertItemMetadataCondition(condition,message){condition||validationError(message)}function requireItemMetadataRecord(value,message){return(typeof value!="object"||value===null||Array.isArray(value))&&validationError(message),value}function assertTimestampField(record,fieldName){const rawValue=record[fieldName];assertItemMetadataCondition(typeof rawValue=="string",`${fieldName} must be a string`),assertItemMetadataCondition(isTimestampLiteral(rawValue),`${fieldName} must be a valid ISO timestamp`)}function assertPositiveIntegerField(record,fieldName,messagePrefix){const value=record[fieldName];value!==void 0&&assertItemMetadataCondition(typeof value=="number"&&Number.isInteger(value)&&value>=1,`${messagePrefix} must be an integer >= 1`)}function assertOptionalTimestampString(record,fieldName,messagePrefix){const value=record[fieldName];value!==void 0&&(assertItemMetadataCondition(typeof value=="string",`${messagePrefix} must be a string`),assertItemMetadataCondition(isTimestampLiteral(value),`${messagePrefix} must be a valid ISO timestamp`))}function assertRecurrenceWeekdays(value){if(value!==void 0){assertItemMetadataCondition(Array.isArray(value),"event.recurrence.by_weekday must be an array");for(const weekday of value){assertItemMetadataCondition(typeof weekday=="string","event.recurrence.by_weekday entries must be strings");const normalizedWeekday=weekday.trim().toLowerCase();assertItemMetadataCondition(RECURRENCE_WEEKDAY_VALUES.includes(normalizedWeekday),`event.recurrence.by_weekday entries must be one of: ${RECURRENCE_WEEKDAY_VALUES.join(", ")}`)}}}function assertRecurrenceMonthDays(value){if(value!==void 0){assertItemMetadataCondition(Array.isArray(value),"event.recurrence.by_month_day must be an array");for(const day of value)assertItemMetadataCondition(typeof day=="number"&&Number.isInteger(day)&&day>=1&&day<=31,"event.recurrence.by_month_day entries must be integers 1..31")}}function assertRecurrenceExdates(value){if(value!==void 0){assertItemMetadataCondition(Array.isArray(value),"event.recurrence.exdates must be an array");for(const exdate of value)assertItemMetadataCondition(typeof exdate=="string","event.recurrence.exdates entries must be strings"),assertItemMetadataCondition(isTimestampLiteral(exdate),"event.recurrence.exdates entries must be valid ISO timestamps")}}function assertValidRecurrenceRule(recurrence){const recurrenceRecord=requireItemMetadataRecord(recurrence,"event.recurrence must be an object");assertItemMetadataCondition(typeof recurrenceRecord.freq=="string","event.recurrence.freq must be a string");const frequency=recurrenceRecord.freq.trim().toLowerCase();assertItemMetadataCondition(RECURRENCE_FREQUENCY_VALUES.includes(frequency),`event.recurrence.freq must be one of: ${RECURRENCE_FREQUENCY_VALUES.join(", ")}`),assertPositiveIntegerField(recurrenceRecord,"interval","event.recurrence.interval"),assertPositiveIntegerField(recurrenceRecord,"count","event.recurrence.count"),assertOptionalTimestampString(recurrenceRecord,"until","event.recurrence.until"),assertRecurrenceWeekdays(recurrenceRecord.by_weekday),assertRecurrenceMonthDays(recurrenceRecord.by_month_day),assertRecurrenceExdates(recurrenceRecord.exdates)}function assertRequiredItemMetadataFields(record){for(const fieldName of REQUIRED_STRING_FIELDS)assertItemMetadataCondition(typeof record[fieldName]=="string",`${fieldName} is required and must be a string`);const itemType=record.type;assertItemMetadataCondition(typeof itemType=="string"&&itemType.trim().length>0,"type must be a non-empty string");const formatVersion=record.pm_format_version;return formatVersion!==void 0&&assertItemMetadataCondition(typeof formatVersion=="number"&&Number.isInteger(formatVersion)&&formatVersion>=BASELINE_ITEM_FORMAT_VERSION,`pm_format_version must be an integer >= ${BASELINE_ITEM_FORMAT_VERSION}`),itemType}function assertStatusItemMetadataField(record,runtimeContext){const status=record.status;assertItemMetadataCondition(typeof status=="string"&&status.trim().length>0,"status must be a non-empty string");const statusRegistry=runtimeContext?.statusRegistry,normalizedStatus=normalizeStatusInput(status,statusRegistry),statusDomain=statusRegistry?statusRegistry.definitions.map(definition=>definition.id):[...STATUS_VALUES];assertItemMetadataCondition(normalizedStatus!==void 0,`status must be one of: ${statusDomain.join(", ")}`)}function assertPriorityAndTags(record){const priority=record.priority;assertItemMetadataCondition(typeof priority=="number"&&Number.isInteger(priority)&&[0,1,2,3,4].includes(priority),"priority must be an integer 0..4");const tags=record.tags;assertItemMetadataCondition(Array.isArray(tags),"tags must be an array");for(const tag of tags)assertItemMetadataCondition(typeof tag=="string","tags entries must be strings")}function assertConfidenceItemMetadataField(record){const confidence=record.confidence;if(confidence!==void 0){if(typeof confidence=="number"){assertItemMetadataCondition(Number.isInteger(confidence)&&confidence>=0&&confidence<=100,"confidence number value must be an integer 0..100");return}if(typeof confidence=="string"){const normalizedConfidence=confidence.trim().toLowerCase(),isKnownTextConfidence=normalizedConfidence==="med"||CONFIDENCE_TEXT_VALUES.includes(normalizedConfidence);assertItemMetadataCondition(isKnownTextConfidence,`confidence string value must be one of: ${[...CONFIDENCE_TEXT_VALUES,"med"].join(", ")}`);return}assertItemMetadataCondition(!1,"confidence must be a number or string")}}function assertSeverityItemMetadataField(record){const severity=record.severity;if(severity===void 0)return;typeof severity!="string"&&validationError("severity must be a string");const normalizedSeverity=severity.trim().toLowerCase(),isKnownSeverity=normalizedSeverity==="med"||ISSUE_SEVERITY_VALUES.includes(normalizedSeverity);assertItemMetadataCondition(isKnownSeverity,`severity value must be one of: ${[...ISSUE_SEVERITY_VALUES,"med"].join(", ")}`)}function assertRegressionItemMetadataField(record){record.regression!==void 0&&typeof record.regression!="boolean"&&validationError("regression must be a boolean")}function assertReminderEntries(record){const reminders=record.reminders;if(reminders!==void 0){assertItemMetadataCondition(Array.isArray(reminders),"reminders must be an array");for(const reminder of reminders){const reminderRecord=requireItemMetadataRecord(reminder,"reminders entries must be objects");assertItemMetadataCondition(typeof reminderRecord.at=="string","reminder.at must be a string"),assertItemMetadataCondition(isTimestampLiteral(reminderRecord.at),"reminder.at must be a valid ISO timestamp"),assertItemMetadataCondition(typeof reminderRecord.text=="string","reminder.text must be a string"),assertItemMetadataCondition(reminderRecord.text.trim().length>0,"reminder.text must not be empty")}}}function assertEventStringFields(eventRecord){for(const stringField of["title","description","location","timezone"])eventRecord[stringField]!==void 0&&(assertItemMetadataCondition(typeof eventRecord[stringField]=="string",`event.${stringField} must be a string`),assertItemMetadataCondition(eventRecord[stringField].trim().length>0,`event.${stringField} must not be empty`))}function assertEventRecurrence(eventRecord){eventRecord.recurrence!==void 0&&(assertValidRecurrenceRule(eventRecord.recurrence),eventRecord.recurrence.until!==void 0&&assertItemMetadataCondition(compareTimestampStrings(eventRecord.recurrence.until,eventRecord.start_at)>=0,"event.recurrence.until must be at or after event.start_at"))}function assertCalendarEventEntry(event){const eventRecord=requireItemMetadataRecord(event,"events entries must be objects");assertItemMetadataCondition(typeof eventRecord.start_at=="string","event.start_at must be a string"),assertItemMetadataCondition(isTimestampLiteral(eventRecord.start_at),"event.start_at must be a valid ISO timestamp"),eventRecord.end_at!==void 0&&(assertItemMetadataCondition(typeof eventRecord.end_at=="string","event.end_at must be a string"),assertItemMetadataCondition(isTimestampLiteral(eventRecord.end_at),"event.end_at must be a valid ISO timestamp"),assertItemMetadataCondition(compareTimestampStrings(eventRecord.end_at,eventRecord.start_at)>0,"event.end_at must be after event.start_at")),assertEventStringFields(eventRecord),eventRecord.all_day!==void 0&&assertItemMetadataCondition(typeof eventRecord.all_day=="boolean","event.all_day must be a boolean"),assertEventRecurrence(eventRecord)}function assertCalendarEvents(record){const events=record.events;if(events!==void 0){assertItemMetadataCondition(Array.isArray(events),"events must be an array");for(const event of events)assertCalendarEventEntry(event)}}function assertOptionalStringFields(record){for(const fieldName of["source_type","source_owner","design","external_ref"]){const value=record[fieldName];value!==void 0&&assertItemMetadataCondition(typeof value=="string",`${fieldName} must be a string`)}}function assertTypeOptionsField(record){const typeOptions=record.type_options;if(typeOptions===void 0)return;const typeOptionsRecord=requireItemMetadataRecord(typeOptions,"type_options must be an object");for(const[optionKey,optionValue]of Object.entries(typeOptionsRecord))assertItemMetadataCondition(optionKey.trim().length>0,"type_options keys must be non-empty"),assertItemMetadataCondition(typeof optionValue=="string","type_options values must be strings"),assertItemMetadataCondition(optionValue.trim().length>0,"type_options values must be non-empty strings")}function coerceRuntimeItemMetadataFields(record,itemType,runtimeContext){if(runtimeContext?.fieldRegistry)for(const definition of runtimeContext.fieldRegistry.definitions){const fieldValue=record[definition.metadata_key];if(fieldValue===void 0){runtimeFieldRequiredForType(definition,itemType)&&validationError(`missing required schema field: ${definition.metadata_key}`);continue}try{record[definition.metadata_key]=coerceRuntimeFieldValue(definition,fieldValue,`metadata field "${definition.metadata_key}"`,"metadata")}catch(error){validationError(String(error?.message).replace(/^Invalid\s+/u,""))}}}function assertRuntimeUnknownItemMetadataFields(record,runtimeContext){if(!runtimeContext||runtimeContext.unknownFieldPolicy==="allow")return;const knownKeys=buildKnownItemMetadataKeys(runtimeContext),unknownKeys=Object.keys(record).filter(key=>!knownKeys.has(key)).sort((left,right)=>left.localeCompare(right));unknownKeys.length!==0&&(runtimeContext.unknownFieldPolicy==="reject"?validationError(`unknown schema fields are not allowed: ${unknownKeys.join(", ")}`):runtimeContext.onWarning?.(`item_unknown_schema_fields:${unknownKeys.join(",")}`))}function assertValidItemMetadata(itemMetadata,runtimeContext){const record=requireItemMetadataRecord(itemMetadata,"item metadata must be an object"),itemType=assertRequiredItemMetadataFields(record);assertStatusItemMetadataField(record,runtimeContext),assertPriorityAndTags(record),assertConfidenceItemMetadataField(record),assertSeverityItemMetadataField(record),assertRegressionItemMetadataField(record),assertTimestampField(record,"created_at"),assertTimestampField(record,"updated_at"),record.deadline!==void 0&&assertTimestampField(record,"deadline"),assertReminderEntries(record),assertCalendarEvents(record),assertOptionalTimestampString(record,"closed_at","closed_at"),assertOptionalTimestampString(record,"completed_at","completed_at"),assertOptionalStringFields(record),assertTypeOptionsField(record),coerceRuntimeItemMetadataFields(record,itemType,runtimeContext),assertRuntimeUnknownItemMetadataFields(record,runtimeContext)}function sortDependencies(values){if(!(!values||values.length===0))return[...values].map(value=>({id:value.id.trim(),kind:value.kind,created_at:value.created_at,author:value.author?.trim()||void 0,source_kind:value.source_kind?.trim()||void 0,author_source:value.author_source})).sort((a,b)=>{const byCreated=compareTimestampStrings(a.created_at,b.created_at);if(byCreated!==0)return byCreated;const byId=a.id.localeCompare(b.id);if(byId!==0)return byId;const byKind=a.kind.localeCompare(b.kind);return byKind!==0?byKind:(a.source_kind??"").localeCompare(b.source_kind??"")})}function sortLogValues(values){if(!(!values||values.length===0))return[...values].sort((a,b)=>{const byCreated=compareTimestampStrings(a.created_at,b.created_at);if(byCreated!==0)return byCreated;const byText=a.text.localeCompare(b.text);return byText!==0?byText:a.author.localeCompare(b.author)})}function sortReminders(values){if(!values||values.length===0)return;const normalized=[...values].map(value=>({at:value.at,text:value.text.trim()})).filter(value=>value.text.length>0).sort((a,b)=>{const byAt=compareTimestampStrings(a.at,b.at);return byAt!==0?byAt:a.text.localeCompare(b.text)});return normalized.length===0?void 0:normalized}function normalizeRecurrenceRule(value){if(!value)return;const normalizedFrequency=value.freq.trim().toLowerCase();if(!RECURRENCE_FREQUENCY_VALUES.includes(normalizedFrequency))return;const byWeekday=Array.from(new Set((value.by_weekday??[]).map(weekday=>weekday.trim().toLowerCase()).filter(weekday=>RECURRENCE_WEEKDAY_VALUES.includes(weekday)))).sort((a,b)=>weekdayOrderIndex(a)-weekdayOrderIndex(b)),byMonthDay=Array.from(new Set((value.by_month_day??[]).filter(day=>Number.isInteger(day)&&day>=1&&day<=31).map(day=>day))).sort((a,b)=>a-b),exdates=Array.from(new Set((value.exdates??[]).map(timestamp=>timestamp.trim()).filter(timestamp=>isTimestampLiteral(timestamp)))).sort((a,b)=>compareTimestampStrings(a,b)),normalized={freq:normalizedFrequency,interval:value.interval!==void 0&&value.interval>1?value.interval:void 0,count:value.count,until:value.until?.trim()||void 0,by_weekday:byWeekday.length>0?byWeekday:void 0,by_month_day:byMonthDay.length>0?byMonthDay:void 0,exdates:exdates.length>0?exdates:void 0};for(const[key,fieldValue]of Object.entries(normalized))fieldValue===void 0&&delete normalized[key];return normalized}function sortEvents(values){return!Array.isArray(values)||values.length===0?void 0:[...values].map(normalizeCalendarEvent).sort(compareCalendarEvents)}function normalizeCalendarEvent(value){const event={start_at:value.start_at,end_at:value.end_at||void 0,title:value.title?.trim()||void 0,description:value.description?.trim()||void 0,location:value.location?.trim()||void 0,all_day:value.all_day,timezone:value.timezone?.trim()||void 0,recurrence:normalizeRecurrenceRule(value.recurrence)};return deleteUndefinedFields(event),event}function compareCalendarEvents(a,b){return firstNonZeroComparison([compareTimestampStrings(a.start_at,b.start_at),(a.end_at??"").localeCompare(b.end_at??""),(a.title??"").localeCompare(b.title??""),+!!a.all_day-+!!b.all_day,(a.timezone??"").localeCompare(b.timezone??""),(a.location??"").localeCompare(b.location??""),(a.description??"").localeCompare(b.description??""),JSON.stringify(a.recurrence??{}).localeCompare(JSON.stringify(b.recurrence??{}))])}function normalizeFiles(values){if(!(!values||values.length===0))return values.map(value=>({path:normalizePathValue(value.path),scope:value.scope,note:value.note?.trim()||void 0}))}function normalizeTestRunSummaries(values){if(!values||values.length===0)return;const normalized=values.map(normalizeTestRunSummary).filter(value=>value.run_id.length>0&&value.started_at.length>0&&value.finished_at.length>0&&value.recorded_at.length>0).sort((a,b)=>firstNonZeroComparison([compareTimestampStrings(a.recorded_at,b.recorded_at),a.run_id.localeCompare(b.run_id),a.kind.localeCompare(b.kind)]));return normalized.length>0?normalized:void 0}function normalizeNonNegativeInteger(value){return typeof value=="number"&&Number.isFinite(value)&&value>=0?Math.floor(value):void 0}function normalizePositiveInteger(value){return typeof value=="number"&&Number.isFinite(value)&&value>=1?Math.floor(value):void 0}function stringOrEmpty(value){return typeof value=="string"?value:""}function normalizeTestRunMeasurements(value){if(!Array.isArray(value))return;const normalized=value.filter(measurement=>measurement!==null&&typeof measurement=="object"&&typeof measurement.name=="string"&&measurement.name.trim().length>0&&typeof measurement.value=="number"&&Number.isFinite(measurement.value)&&typeof measurement.recorded_at=="string"&&measurement.recorded_at.trim().length>0).map(measurement=>({name:measurement.name.trim(),value:measurement.value,unit:typeof measurement.unit=="string"&&measurement.unit.trim()||void 0,threshold:typeof measurement.threshold=="number"&&Number.isFinite(measurement.threshold)?measurement.threshold:void 0,recorded_at:measurement.recorded_at.trim()})),deduplicated=[...new Map(normalized.map(measurement=>[measurement.name,measurement])).values()].sort((left,right)=>left.name.localeCompare(right.name)).slice(0,32);return deduplicated.length>0?deduplicated:void 0}function normalizeTestRunEnum(value,allowedValues){return typeof value=="string"&&allowedValues.has(value)?value:void 0}function normalizeTestRunExecutions(values){if(!Array.isArray(values))return;const executions=values.filter(execution=>execution&&typeof execution.command=="string"&&execution.command.trim().length>0).slice(0,32).map(execution=>({command:execution.command.trim(),requested_pm_context_mode:normalizeTestRunEnum(execution.requested_pm_context_mode,LINKED_TEST_PM_CONTEXT_MODE_VALUES),pm_context_mode:normalizeTestRunEnum(execution.pm_context_mode,LINKED_TEST_PM_CONTEXT_MODE_VALUES),workspace_context_mode:normalizeTestRunEnum(execution.workspace_context_mode,LINKED_TEST_WORKSPACE_CONTEXT_MODE_VALUES),trust_reason:normalizeTestRunEnum(execution.trust_reason,LINKED_TEST_TRUST_REASON_VALUES)}));return executions.length>0?executions:void 0}function normalizeTestRunSummary(value){const runId=typeof value.run_id=="string"?value.run_id.trim():"",kind=value.kind==="test"||value.kind==="test-all"?value.kind:"test",status=ITEM_TEST_RUN_STATUS_VALUES.has(value.status)?value.status:"failed",summary={run_id:runId,kind,status,started_at:stringOrEmpty(value.started_at),finished_at:stringOrEmpty(value.finished_at),recorded_at:stringOrEmpty(value.recorded_at),attempt:normalizePositiveInteger(value.attempt),resumed_from:value.resumed_from?.trim()||void 0,passed:normalizeNonNegativeInteger(value.passed)??0,failed:normalizeNonNegativeInteger(value.failed)??0,skipped:normalizeNonNegativeInteger(value.skipped)??0,items:normalizeNonNegativeInteger(value.items),linked_tests:normalizeNonNegativeInteger(value.linked_tests),fail_on_skipped_triggered:value.fail_on_skipped_triggered===!0?!0:void 0,measurements:normalizeTestRunMeasurements(value.measurements),executions:normalizeTestRunExecutions(value.executions)};return deleteUndefinedFields(summary),summary}function sortTests(values){if(!(!Array.isArray(values)||values.length===0))return values.map(normalizeLinkedTest)}function normalizeTrimmedStringList(value){if(!Array.isArray(value))return;const normalized=[...new Set(value.filter(entry=>typeof entry=="string").map(entry=>entry.trim()).filter(entry=>entry.length>0))].sort((a,b)=>a.localeCompare(b));return normalized.length>0?normalized:void 0}function isPlainObjectRecord(value){if(!value||typeof value!="object"||Array.isArray(value))return!1;const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}function isUnsafeObjectKey(key){return key==="__proto__"||key==="constructor"||key==="prototype"}function normalizeStringRecord(value){if(!isPlainObjectRecord(value))return;const entries=Object.entries(value).map(([key,recordValue])=>[key.trim(),String(recordValue).trim()]).filter(([key,recordValue])=>key.length>0&&!isUnsafeObjectKey(key)&&recordValue.length>0).sort(([left],[right])=>left.localeCompare(right));return entries.length>0?Object.fromEntries(entries):void 0}function normalizeNumericRecord(value){if(!isPlainObjectRecord(value))return;const entries=Object.entries(value).map(([key,recordValue])=>[key.trim(),Number(recordValue)]).filter(([key,recordValue])=>key.length>0&&!isUnsafeObjectKey(key)&&Number.isFinite(recordValue)).sort(([left],[right])=>left.localeCompare(right));return entries.length>0?Object.fromEntries(entries):void 0}function normalizeLinkedTestContextMode(value){const normalized=value?.trim().toLowerCase();if(!(!normalized||!LINKED_TEST_PM_CONTEXT_MODE_VALUES.has(normalized)))return normalized}function normalizeLinkedTestWorkspaceContextMode(value){const normalized=value?.trim().toLowerCase();if(!(!normalized||!LINKED_TEST_WORKSPACE_CONTEXT_MODE_VALUES.has(normalized)))return normalized}function normalizeLinkedTestProvenance(value,invalid){if(invalid===!0)return{provenance_invalid:!0};if(value===void 0)return{};if(!isPlainObjectRecord(value))return{provenance_invalid:!0};const author=trimStringOrUndefined(value.author),createdAt=trimStringOrUndefined(value.created_at),sourceKind=value.source_kind;return!author||!createdAt||!isTimestampLiteral(createdAt)||sourceKind!=="local_mutation"&&sourceKind!=="merge_union"?{provenance_invalid:!0}:{provenance:{author,created_at:createdAt,source_kind:sourceKind,source_ref:trimStringOrUndefined(value.source_ref)}}}function normalizeLinkedTest(value){const test={command:value.command?.trim()||void 0,path:value.path?normalizePathValue(value.path):void 0,scope:value.scope,timeout_seconds:typeof value.timeout_seconds=="number"&&Number.isFinite(value.timeout_seconds)&&value.timeout_seconds>0?value.timeout_seconds:void 0,pm_context_mode:normalizeLinkedTestContextMode(value.pm_context_mode),workspace_context_mode:normalizeLinkedTestWorkspaceContextMode(value.workspace_context_mode),...normalizeLinkedTestProvenance(value.provenance,value.provenance_invalid),updated_by:trimStringOrUndefined(value.updated_by),updated_at:trimStringOrUndefined(value.updated_at),env_set:normalizeStringRecord(value.env_set),env_clear:normalizeTrimmedStringList(value.env_clear),shared_host_safe:value.shared_host_safe===!0?!0:void 0,assert_stdout_contains:normalizeTrimmedStringList(value.assert_stdout_contains),assert_stdout_regex:normalizeTrimmedStringList(value.assert_stdout_regex),assert_stderr_contains:normalizeTrimmedStringList(value.assert_stderr_contains),assert_stderr_regex:normalizeTrimmedStringList(value.assert_stderr_regex),assert_stdout_min_lines:normalizeNonNegativeInteger(value.assert_stdout_min_lines),assert_json_field_equals:normalizeStringRecord(value.assert_json_field_equals),assert_json_field_gte:normalizeNumericRecord(value.assert_json_field_gte),note:value.note?.trim()||void 0};return deleteUndefinedFields(test),test}function sortDocs(values){if(!(!values||values.length===0))return[...values].map(value=>({path:normalizePathValue(value.path),scope:value.scope,note:value.note?.trim()||void 0})).sort((a,b)=>{const byScope=a.scope.localeCompare(b.scope);if(byScope!==0)return byScope;const byPath=a.path.localeCompare(b.path);return byPath!==0?byPath:(a.note??"").localeCompare(b.note??"")})}function trimStringOrUndefined(value){if(typeof value!="string")return;const trimmed=value.trim();return trimmed.length>0?trimmed:void 0}function normalizePlanStepLinks(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,id=trimStringOrUndefined(record.id),kind=trimStringOrUndefined(record.kind);if(!id||!kind)continue;const link={id,kind},note=trimStringOrUndefined(record.note);note&&(link.note=note),record.required_before_step===!0&&(link.required_before_step=!0),out.push(link)}return out.length>0?out:void 0}function normalizePlanStepFiles(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,path=trimStringOrUndefined(record.path);if(!path)continue;const file={path:normalizePathValue(path)};(record.scope==="project"||record.scope==="global")&&(file.scope=record.scope);const note=trimStringOrUndefined(record.note);note&&(file.note=note),out.push(file)}return out.length>0?out:void 0}function normalizePlanStepTests(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,command=trimStringOrUndefined(record.command),path=trimStringOrUndefined(record.path);if(!command&&!path)continue;const test={};command&&(test.command=command),path&&(test.path=normalizePathValue(path));const note=trimStringOrUndefined(record.note);note&&(test.note=note),out.push(test)}return out.length>0?out:void 0}function normalizePlanStepDocs(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,path=trimStringOrUndefined(record.path);if(!path)continue;const doc={path:normalizePathValue(path)};(record.scope==="project"||record.scope==="global")&&(doc.scope=record.scope);const note=trimStringOrUndefined(record.note);note&&(doc.note=note),out.push(doc)}return out.length>0?out:void 0}function normalizePlanStepEntry(entry){if(entry===null||typeof entry!="object")return;const record=entry,id=trimStringOrUndefined(record.id),title=trimStringOrUndefined(record.title),statusRaw=trimStringOrUndefined(record.status),status=statusRaw&&PLAN_STEP_STATUS_SET.has(statusRaw)?statusRaw:void 0,order=coerceFiniteNumber(record.order)??Number.NaN,created_at=typeof record.created_at=="string"?record.created_at:"",updated_at=typeof record.updated_at=="string"?record.updated_at:"";if(!id||!title||!status||!Number.isFinite(order)||!created_at||!updated_at)return;const step={id,order,title,status,created_at,updated_at};return applyPlanStepOptionalFields(step,record),step}function applyPlanStepOptionalFields(step,record){const stringFields=[["body","body"],["owner","owner"],["evidence","evidence"],["blocked_reason","blocked_reason"],["superseded_by","superseded_by"]];for(const[target,source]of stringFields){const value=trimStringOrUndefined(record[source]);value&&(step[target]=value)}const completedAt=typeof record.completed_at=="string"?record.completed_at:void 0;completedAt&&completedAt.length>0&&(step.completed_at=completedAt);const collectionFields=[["linked_items","linked_items",normalizePlanStepLinks],["files","files",normalizePlanStepFiles],["tests","tests",normalizePlanStepTests],["docs","docs",normalizePlanStepDocs]];for(const[target,source,normalize]of collectionFields){const value=normalize(record[source]);value&&(step[target]=value)}}function normalizePlanSteps(value){if(!Array.isArray(value))return;const out=value.flatMap(entry=>{const step=normalizePlanStepEntry(entry);return step?[step]:[]});return out.sort((left,right)=>left.order-right.order),out.length>0?out:void 0}function normalizePlanDecisions(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,ts=typeof record.ts=="string"?record.ts:"",author=typeof record.author=="string"?record.author:"",decision=trimStringOrUndefined(record.decision);if(!ts||!author||!decision)continue;const item={ts,author,decision},rationale=trimStringOrUndefined(record.rationale);rationale&&(item.rationale=rationale);const evidence=trimStringOrUndefined(record.evidence);evidence&&(item.evidence=evidence);const stepId=trimStringOrUndefined(record.step_id);stepId&&(item.step_id=stepId),out.push(item)}return out.length>0?out:void 0}function normalizePlanDiscoveries(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,ts=typeof record.ts=="string"?record.ts:"",author=typeof record.author=="string"?record.author:"",text=trimStringOrUndefined(record.text);if(!ts||!author||!text)continue;const item={ts,author,text},stepId=trimStringOrUndefined(record.step_id);stepId&&(item.step_id=stepId),out.push(item)}return out.length>0?out:void 0}function normalizePlanValidation(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,text=trimStringOrUndefined(record.text);if(!text)continue;const item={text},command=trimStringOrUndefined(record.command);command&&(item.command=command);const expected=trimStringOrUndefined(record.expected);expected&&(item.expected=expected),out.push(item)}return out.length>0?out:void 0}function normalizeTypeOptions(values){if(!values)return;const normalizedEntries=Object.entries(values).map(([key,value])=>[key.trim(),value.trim()]).filter(([key,value])=>key.length>0&&value.length>0).sort((left,right)=>left[0].localeCompare(right[0]));if(normalizedEntries.length!==0)return Object.fromEntries(normalizedEntries)}function normalizeBody(body){let start=0;for(;start<body.length&&body[start]===`
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="2789e87f-0706-52e8-8f4c-3855c65c618c")}catch{}})();import{encode as encodeToon}from"@toon-format/toon";import{isDeepStrictEqual}from"node:util";import{CONFIDENCE_TEXT_VALUES,ISSUE_SEVERITY_VALUES,PLAN_STEP_STATUS_VALUES,RECURRENCE_FREQUENCY_VALUES,RECURRENCE_WEEKDAY_VALUES,STATUS_VALUES,weekdayOrderIndex}from"../../types/index.js";import{coerceRuntimeFieldValue}from"../schema/runtime-field-values.js";import{resolveRuntimeFieldRegistry,resolveRuntimeStatusRegistry}from"../schema/runtime-schema.js";import{BASELINE_ITEM_FORMAT_VERSION,CURRENT_ITEM_FORMAT_VERSION,effectiveItemFormatVersion,normalizeItemFormatVersion}from"./item-format-version.js";import{normalizeStatusInput}from"./status.js";import{decodeToonItemContent}from"./toon-decode.js";import{EXIT_CODE,ITEM_METADATA_KEY_ORDER}from"../shared/constants.js";import{findFirstMergeConflictMarker}from"../shared/conflict-markers.js";import{PmCliError}from"../shared/errors.js";import{orderObject}from"../shared/serialization.js";import{compareTimestampStrings,isRfc3339DateTime,isTimestampLiteral}from"../shared/time.js";import{coerceFiniteNumber}from"../shared/primitives.js";const LINKED_TEST_PM_CONTEXT_MODE_VALUES=new Set(["schema","tracker","auto","none"]),LINKED_TEST_WORKSPACE_CONTEXT_MODE_VALUES=new Set(["source","isolated","snapshot"]),LINKED_TEST_TRUST_REASON_VALUES=new Set(["legacy","local_mutation","local_source_ref","acknowledged","invalid_provenance","foreign_source_ref"]),ITEM_TEST_RUN_STATUS_VALUES=new Set(["passed","failed","stopped","canceled"]),PLAN_STEP_STATUS_SET=new Set(PLAN_STEP_STATUS_VALUES);function normalizePathValue(value){return value.replaceAll("\\","/")}function firstNonZeroComparison(comparisons){for(const comparison of comparisons)if(comparison!==0)return comparison;return 0}function deleteUndefinedFields(record){for(const[key,value]of Object.entries(record))value===void 0&&delete record[key]}const REQUIRED_STRING_FIELDS=["id","title","description","created_at","updated_at"],STATIC_ITEM_METADATA_FIELD_SET=new Set(ITEM_METADATA_KEY_ORDER);function resolveRuntimeSchemaValidationContext(options){if(options?.schema)return{statusRegistry:resolveRuntimeStatusRegistry(options.schema),fieldRegistry:resolveRuntimeFieldRegistry(options.schema),unknownFieldPolicy:options.schema.unknown_field_policy??"allow",extensionFieldNames:new Set(options.extensionFieldNames??[]),onWarning:options.onWarning}}function runtimeFieldRequiredForType(definition,typeName){return definition.required?definition.required_types.length===0?!0:definition.required_types.map(value=>value.toLowerCase()).includes(typeName.trim().toLowerCase()):!1}function validationError(message){const field=message.match(/^([a-z_][\w.]*)\s/u)?.[1];throw new PmCliError(`Invalid item metadata: ${message}`,EXIT_CODE.GENERIC_FAILURE,{code:"item_document_invalid",reason:message.includes("required")?"missing_required_field":"schema_validation_error",...field?{field}:{},required:"Provide an item document whose metadata satisfies the active runtime schema.",why:message})}function documentSyntaxError(format,message){throw new PmCliError(message,EXIT_CODE.GENERIC_FAILURE,{code:"item_document_invalid",reason:"syntax_error",format,required:`Provide a syntactically valid ${format==="toon"?"TOON":"JSON Markdown"} item document.`,why:"The document could not be decoded far enough to validate item metadata."})}function assertSupportedItemFormat(metadata,required){if(!required||typeof metadata!="object"||metadata===null)return;const formatVersion=effectiveItemFormatVersion(metadata);if(!(formatVersion<=CURRENT_ITEM_FORMAT_VERSION))throw new PmCliError(`Stored item uses format version ${formatVersion}; this runtime supports up to ${CURRENT_ITEM_FORMAT_VERSION}. Upgrade pm before reading or changing this item.`,EXIT_CODE.CONFLICT,{code:"item_format_version_unsupported",format_version:formatVersion,required:"Upgrade to a pm runtime supporting the stored item format.",nextSteps:["Preserve the original item and history; do not lower pm_format_version to bypass compatibility checks."]})}function buildKnownItemMetadataKeys(runtimeContext){const knownKeys=new Set(STATIC_ITEM_METADATA_FIELD_SET);for(const definition of runtimeContext.fieldRegistry?.definitions??[])knownKeys.add(definition.metadata_key);for(const fieldName of runtimeContext.extensionFieldNames)knownKeys.add(fieldName);return knownKeys}function assertItemMetadataCondition(condition,message){condition||validationError(message)}function requireItemMetadataRecord(value,message){return(typeof value!="object"||value===null||Array.isArray(value))&&validationError(message),value}function assertTimestampField(record,fieldName){const rawValue=record[fieldName];assertItemMetadataCondition(typeof rawValue=="string",`${fieldName} must be a string`),assertItemMetadataCondition(isTimestampLiteral(rawValue),`${fieldName} must be a valid ISO timestamp`)}function assertPositiveIntegerField(record,fieldName,messagePrefix){const value=record[fieldName];value!==void 0&&assertItemMetadataCondition(typeof value=="number"&&Number.isInteger(value)&&value>=1,`${messagePrefix} must be an integer >= 1`)}function assertOptionalTimestampString(record,fieldName,messagePrefix){const value=record[fieldName];value!==void 0&&(assertItemMetadataCondition(typeof value=="string",`${messagePrefix} must be a string`),assertItemMetadataCondition(isTimestampLiteral(value),`${messagePrefix} must be a valid ISO timestamp`))}function assertRecurrenceWeekdays(value){if(value!==void 0){assertItemMetadataCondition(Array.isArray(value),"event.recurrence.by_weekday must be an array");for(const weekday of value){assertItemMetadataCondition(typeof weekday=="string","event.recurrence.by_weekday entries must be strings");const normalizedWeekday=weekday.trim().toLowerCase();assertItemMetadataCondition(RECURRENCE_WEEKDAY_VALUES.includes(normalizedWeekday),`event.recurrence.by_weekday entries must be one of: ${RECURRENCE_WEEKDAY_VALUES.join(", ")}`)}}}function assertRecurrenceMonthDays(value){if(value!==void 0){assertItemMetadataCondition(Array.isArray(value),"event.recurrence.by_month_day must be an array");for(const day of value)assertItemMetadataCondition(typeof day=="number"&&Number.isInteger(day)&&day>=1&&day<=31,"event.recurrence.by_month_day entries must be integers 1..31")}}function assertRecurrenceExdates(value){if(value!==void 0){assertItemMetadataCondition(Array.isArray(value),"event.recurrence.exdates must be an array");for(const exdate of value)assertItemMetadataCondition(typeof exdate=="string","event.recurrence.exdates entries must be strings"),assertItemMetadataCondition(isTimestampLiteral(exdate),"event.recurrence.exdates entries must be valid ISO timestamps")}}function assertValidRecurrenceRule(recurrence){const recurrenceRecord=requireItemMetadataRecord(recurrence,"event.recurrence must be an object");assertItemMetadataCondition(typeof recurrenceRecord.freq=="string","event.recurrence.freq must be a string");const frequency=recurrenceRecord.freq.trim().toLowerCase();assertItemMetadataCondition(RECURRENCE_FREQUENCY_VALUES.includes(frequency),`event.recurrence.freq must be one of: ${RECURRENCE_FREQUENCY_VALUES.join(", ")}`),assertPositiveIntegerField(recurrenceRecord,"interval","event.recurrence.interval"),assertPositiveIntegerField(recurrenceRecord,"count","event.recurrence.count"),assertOptionalTimestampString(recurrenceRecord,"until","event.recurrence.until"),assertRecurrenceWeekdays(recurrenceRecord.by_weekday),assertRecurrenceMonthDays(recurrenceRecord.by_month_day),assertRecurrenceExdates(recurrenceRecord.exdates)}function assertRequiredItemMetadataFields(record){for(const fieldName of REQUIRED_STRING_FIELDS)assertItemMetadataCondition(typeof record[fieldName]=="string",`${fieldName} is required and must be a string`);const itemType=record.type;assertItemMetadataCondition(typeof itemType=="string"&&itemType.trim().length>0,"type must be a non-empty string");const formatVersion=record.pm_format_version;return formatVersion!==void 0&&assertItemMetadataCondition(typeof formatVersion=="number"&&Number.isInteger(formatVersion)&&formatVersion>=BASELINE_ITEM_FORMAT_VERSION,`pm_format_version must be an integer >= ${BASELINE_ITEM_FORMAT_VERSION}`),itemType}function assertStatusItemMetadataField(record,runtimeContext){const status=record.status;assertItemMetadataCondition(typeof status=="string"&&status.trim().length>0,"status must be a non-empty string");const statusRegistry=runtimeContext?.statusRegistry,normalizedStatus=normalizeStatusInput(status,statusRegistry),statusDomain=statusRegistry?statusRegistry.definitions.map(definition=>definition.id):[...STATUS_VALUES];assertItemMetadataCondition(normalizedStatus!==void 0,`status must be one of: ${statusDomain.join(", ")}`)}function assertPriorityAndTags(record){const priority=record.priority;assertItemMetadataCondition(typeof priority=="number"&&Number.isInteger(priority)&&[0,1,2,3,4].includes(priority),"priority must be an integer 0..4");const tags=record.tags;assertItemMetadataCondition(Array.isArray(tags),"tags must be an array");for(const tag of tags)assertItemMetadataCondition(typeof tag=="string","tags entries must be strings")}function assertConfidenceItemMetadataField(record){const confidence=record.confidence;if(confidence!==void 0){if(typeof confidence=="number"){assertItemMetadataCondition(Number.isInteger(confidence)&&confidence>=0&&confidence<=100,"confidence number value must be an integer 0..100");return}if(typeof confidence=="string"){const normalizedConfidence=confidence.trim().toLowerCase(),isKnownTextConfidence=normalizedConfidence==="med"||CONFIDENCE_TEXT_VALUES.includes(normalizedConfidence);assertItemMetadataCondition(isKnownTextConfidence,`confidence string value must be one of: ${[...CONFIDENCE_TEXT_VALUES,"med"].join(", ")}`);return}assertItemMetadataCondition(!1,"confidence must be a number or string")}}function assertSeverityItemMetadataField(record){const severity=record.severity;if(severity===void 0)return;typeof severity!="string"&&validationError("severity must be a string");const normalizedSeverity=severity.trim().toLowerCase(),isKnownSeverity=normalizedSeverity==="med"||ISSUE_SEVERITY_VALUES.includes(normalizedSeverity);assertItemMetadataCondition(isKnownSeverity,`severity value must be one of: ${[...ISSUE_SEVERITY_VALUES,"med"].join(", ")}`)}function assertRegressionItemMetadataField(record){record.regression!==void 0&&typeof record.regression!="boolean"&&validationError("regression must be a boolean")}function assertReminderEntries(record){const reminders=record.reminders;if(reminders!==void 0){assertItemMetadataCondition(Array.isArray(reminders),"reminders must be an array");for(const reminder of reminders){const reminderRecord=requireItemMetadataRecord(reminder,"reminders entries must be objects");assertItemMetadataCondition(typeof reminderRecord.at=="string","reminder.at must be a string"),assertItemMetadataCondition(isTimestampLiteral(reminderRecord.at),"reminder.at must be a valid ISO timestamp"),assertItemMetadataCondition(typeof reminderRecord.text=="string","reminder.text must be a string"),assertItemMetadataCondition(reminderRecord.text.trim().length>0,"reminder.text must not be empty")}}}function assertEventStringFields(eventRecord){for(const stringField of["title","description","location","timezone"])eventRecord[stringField]!==void 0&&(assertItemMetadataCondition(typeof eventRecord[stringField]=="string",`event.${stringField} must be a string`),assertItemMetadataCondition(eventRecord[stringField].trim().length>0,`event.${stringField} must not be empty`))}function assertEventRecurrence(eventRecord){eventRecord.recurrence!==void 0&&(assertValidRecurrenceRule(eventRecord.recurrence),eventRecord.recurrence.until!==void 0&&assertItemMetadataCondition(compareTimestampStrings(eventRecord.recurrence.until,eventRecord.start_at)>=0,"event.recurrence.until must be at or after event.start_at"))}function assertCalendarEventEntry(event){const eventRecord=requireItemMetadataRecord(event,"events entries must be objects");assertItemMetadataCondition(typeof eventRecord.start_at=="string","event.start_at must be a string"),assertItemMetadataCondition(isTimestampLiteral(eventRecord.start_at),"event.start_at must be a valid ISO timestamp"),eventRecord.end_at!==void 0&&(assertItemMetadataCondition(typeof eventRecord.end_at=="string","event.end_at must be a string"),assertItemMetadataCondition(isTimestampLiteral(eventRecord.end_at),"event.end_at must be a valid ISO timestamp"),assertItemMetadataCondition(compareTimestampStrings(eventRecord.end_at,eventRecord.start_at)>0,"event.end_at must be after event.start_at")),assertEventStringFields(eventRecord),eventRecord.all_day!==void 0&&assertItemMetadataCondition(typeof eventRecord.all_day=="boolean","event.all_day must be a boolean"),assertEventRecurrence(eventRecord)}function assertCalendarEvents(record){const events=record.events;if(events!==void 0){assertItemMetadataCondition(Array.isArray(events),"events must be an array");for(const event of events)assertCalendarEventEntry(event)}}function assertOptionalStringFields(record){for(const fieldName of["source_type","source_owner","design","external_ref"]){const value=record[fieldName];value!==void 0&&assertItemMetadataCondition(typeof value=="string",`${fieldName} must be a string`)}}function assertTypeOptionsField(record){const typeOptions=record.type_options;if(typeOptions===void 0)return;const typeOptionsRecord=requireItemMetadataRecord(typeOptions,"type_options must be an object");for(const[optionKey,optionValue]of Object.entries(typeOptionsRecord))assertItemMetadataCondition(optionKey.trim().length>0,"type_options keys must be non-empty"),assertItemMetadataCondition(typeof optionValue=="string","type_options values must be strings"),assertItemMetadataCondition(optionValue.trim().length>0,"type_options values must be non-empty strings")}function coerceRuntimeItemMetadataFields(record,itemType,runtimeContext){if(runtimeContext?.fieldRegistry)for(const definition of runtimeContext.fieldRegistry.definitions){const fieldValue=record[definition.metadata_key];if(fieldValue===void 0){runtimeFieldRequiredForType(definition,itemType)&&validationError(`missing required schema field: ${definition.metadata_key}`);continue}try{record[definition.metadata_key]=coerceRuntimeFieldValue(definition,fieldValue,`metadata field "${definition.metadata_key}"`,"metadata")}catch(error){validationError(String(error?.message).replace(/^Invalid\s+/u,""))}}}function assertRuntimeUnknownItemMetadataFields(record,runtimeContext){if(!runtimeContext||runtimeContext.unknownFieldPolicy==="allow")return;const knownKeys=buildKnownItemMetadataKeys(runtimeContext),unknownKeys=Object.keys(record).filter(key=>!knownKeys.has(key)).sort((left,right)=>left.localeCompare(right));unknownKeys.length!==0&&(runtimeContext.unknownFieldPolicy==="reject"?validationError(`unknown schema fields are not allowed: ${unknownKeys.join(", ")}`):runtimeContext.onWarning?.(`item_unknown_schema_fields:${unknownKeys.join(",")}`))}function assertValidItemMetadata(itemMetadata,runtimeContext){const record=requireItemMetadataRecord(itemMetadata,"item metadata must be an object"),itemType=assertRequiredItemMetadataFields(record);assertStatusItemMetadataField(record,runtimeContext),assertPriorityAndTags(record),assertConfidenceItemMetadataField(record),assertSeverityItemMetadataField(record),assertRegressionItemMetadataField(record),assertTimestampField(record,"created_at"),assertTimestampField(record,"updated_at"),record.deadline!==void 0&&assertTimestampField(record,"deadline"),assertReminderEntries(record),assertCalendarEvents(record),assertOptionalTimestampString(record,"closed_at","closed_at"),assertOptionalTimestampString(record,"completed_at","completed_at"),assertOptionalStringFields(record),assertTypeOptionsField(record),coerceRuntimeItemMetadataFields(record,itemType,runtimeContext),assertRuntimeUnknownItemMetadataFields(record,runtimeContext)}function sortDependencies(values){if(!(!values||values.length===0))return[...values].map((value,index)=>(assertItemMetadataCondition(value.created_at===void 0||typeof value.created_at=="string"&&isRfc3339DateTime(value.created_at),`dependencies.${index}.created_at requires a valid timestamp; restore the dependency timestamp from its source record`),{id:value.id.trim(),kind:value.kind,created_at:value.created_at,author:value.author?.trim()||void 0,source_kind:value.source_kind?.trim()||void 0,author_source:value.author_source})).sort((a,b)=>{const byCreated=compareTimestampStrings(a.created_at??"",b.created_at??"");if(byCreated!==0)return byCreated;const byId=a.id.localeCompare(b.id);if(byId!==0)return byId;const byKind=a.kind.localeCompare(b.kind);return byKind!==0?byKind:(a.source_kind??"").localeCompare(b.source_kind??"")})}function sortLogValues(values){if(!(!values||values.length===0))return[...values].sort((a,b)=>{const byCreated=compareTimestampStrings(a.created_at,b.created_at);if(byCreated!==0)return byCreated;const byText=a.text.localeCompare(b.text);return byText!==0?byText:a.author.localeCompare(b.author)})}function sortReminders(values){if(!values||values.length===0)return;const normalized=[...values].map(value=>({at:value.at,text:value.text.trim()})).filter(value=>value.text.length>0).sort((a,b)=>{const byAt=compareTimestampStrings(a.at,b.at);return byAt!==0?byAt:a.text.localeCompare(b.text)});return normalized.length===0?void 0:normalized}function normalizeRecurrenceRule(value){if(!value)return;const normalizedFrequency=value.freq.trim().toLowerCase();if(!RECURRENCE_FREQUENCY_VALUES.includes(normalizedFrequency))return;const byWeekday=Array.from(new Set((value.by_weekday??[]).map(weekday=>weekday.trim().toLowerCase()).filter(weekday=>RECURRENCE_WEEKDAY_VALUES.includes(weekday)))).sort((a,b)=>weekdayOrderIndex(a)-weekdayOrderIndex(b)),byMonthDay=Array.from(new Set((value.by_month_day??[]).filter(day=>Number.isInteger(day)&&day>=1&&day<=31).map(day=>day))).sort((a,b)=>a-b),exdates=Array.from(new Set((value.exdates??[]).map(timestamp=>timestamp.trim()).filter(timestamp=>isTimestampLiteral(timestamp)))).sort((a,b)=>compareTimestampStrings(a,b)),normalized={freq:normalizedFrequency,interval:value.interval!==void 0&&value.interval>1?value.interval:void 0,count:value.count,until:value.until?.trim()||void 0,by_weekday:byWeekday.length>0?byWeekday:void 0,by_month_day:byMonthDay.length>0?byMonthDay:void 0,exdates:exdates.length>0?exdates:void 0};for(const[key,fieldValue]of Object.entries(normalized))fieldValue===void 0&&delete normalized[key];return normalized}function sortEvents(values){return!Array.isArray(values)||values.length===0?void 0:[...values].map(normalizeCalendarEvent).sort(compareCalendarEvents)}function normalizeCalendarEvent(value){const event={start_at:value.start_at,end_at:value.end_at||void 0,title:value.title?.trim()||void 0,description:value.description?.trim()||void 0,location:value.location?.trim()||void 0,all_day:value.all_day,timezone:value.timezone?.trim()||void 0,recurrence:normalizeRecurrenceRule(value.recurrence)};return deleteUndefinedFields(event),event}function compareCalendarEvents(a,b){return firstNonZeroComparison([compareTimestampStrings(a.start_at,b.start_at),(a.end_at??"").localeCompare(b.end_at??""),(a.title??"").localeCompare(b.title??""),+!!a.all_day-+!!b.all_day,(a.timezone??"").localeCompare(b.timezone??""),(a.location??"").localeCompare(b.location??""),(a.description??"").localeCompare(b.description??""),JSON.stringify(a.recurrence??{}).localeCompare(JSON.stringify(b.recurrence??{}))])}function normalizeFiles(values){if(!(!values||values.length===0))return values.map(value=>({path:normalizePathValue(value.path),scope:value.scope,note:value.note?.trim()||void 0}))}function normalizeTestRunSummaries(values){if(!values||values.length===0)return;const normalized=values.map(normalizeTestRunSummary).filter(value=>value.run_id.length>0&&value.started_at.length>0&&value.finished_at.length>0&&value.recorded_at.length>0).sort((a,b)=>firstNonZeroComparison([compareTimestampStrings(a.recorded_at,b.recorded_at),a.run_id.localeCompare(b.run_id),a.kind.localeCompare(b.kind)]));return normalized.length>0?normalized:void 0}function normalizeNonNegativeInteger(value){return typeof value=="number"&&Number.isFinite(value)&&value>=0?Math.floor(value):void 0}function normalizePositiveInteger(value){return typeof value=="number"&&Number.isFinite(value)&&value>=1?Math.floor(value):void 0}function stringOrEmpty(value){return typeof value=="string"?value:""}function normalizeTestRunMeasurements(value){if(!Array.isArray(value))return;const normalized=value.filter(measurement=>measurement!==null&&typeof measurement=="object"&&typeof measurement.name=="string"&&measurement.name.trim().length>0&&typeof measurement.value=="number"&&Number.isFinite(measurement.value)&&typeof measurement.recorded_at=="string"&&measurement.recorded_at.trim().length>0).map(measurement=>({name:measurement.name.trim(),value:measurement.value,unit:typeof measurement.unit=="string"&&measurement.unit.trim()||void 0,threshold:typeof measurement.threshold=="number"&&Number.isFinite(measurement.threshold)?measurement.threshold:void 0,recorded_at:measurement.recorded_at.trim()})),deduplicated=[...new Map(normalized.map(measurement=>[measurement.name,measurement])).values()].sort((left,right)=>left.name.localeCompare(right.name)).slice(0,32);return deduplicated.length>0?deduplicated:void 0}function normalizeTestRunEnum(value,allowedValues){return typeof value=="string"&&allowedValues.has(value)?value:void 0}function normalizeTestRunExecutions(values){if(!Array.isArray(values))return;const executions=values.filter(execution=>execution&&typeof execution.command=="string"&&execution.command.trim().length>0).slice(0,32).map(execution=>({command:execution.command.trim(),requested_pm_context_mode:normalizeTestRunEnum(execution.requested_pm_context_mode,LINKED_TEST_PM_CONTEXT_MODE_VALUES),pm_context_mode:normalizeTestRunEnum(execution.pm_context_mode,LINKED_TEST_PM_CONTEXT_MODE_VALUES),workspace_context_mode:normalizeTestRunEnum(execution.workspace_context_mode,LINKED_TEST_WORKSPACE_CONTEXT_MODE_VALUES),trust_reason:normalizeTestRunEnum(execution.trust_reason,LINKED_TEST_TRUST_REASON_VALUES)}));return executions.length>0?executions:void 0}function normalizeTestRunSummary(value){const runId=typeof value.run_id=="string"?value.run_id.trim():"",kind=value.kind==="test"||value.kind==="test-all"?value.kind:"test",status=ITEM_TEST_RUN_STATUS_VALUES.has(value.status)?value.status:"failed",summary={run_id:runId,kind,status,started_at:stringOrEmpty(value.started_at),finished_at:stringOrEmpty(value.finished_at),recorded_at:stringOrEmpty(value.recorded_at),attempt:normalizePositiveInteger(value.attempt),resumed_from:value.resumed_from?.trim()||void 0,passed:normalizeNonNegativeInteger(value.passed)??0,failed:normalizeNonNegativeInteger(value.failed)??0,skipped:normalizeNonNegativeInteger(value.skipped)??0,items:normalizeNonNegativeInteger(value.items),linked_tests:normalizeNonNegativeInteger(value.linked_tests),fail_on_skipped_triggered:value.fail_on_skipped_triggered===!0?!0:void 0,measurements:normalizeTestRunMeasurements(value.measurements),executions:normalizeTestRunExecutions(value.executions)};return deleteUndefinedFields(summary),summary}function sortTests(values){if(!(!Array.isArray(values)||values.length===0))return values.map(normalizeLinkedTest)}function normalizeTrimmedStringList(value){if(!Array.isArray(value))return;const normalized=[...new Set(value.filter(entry=>typeof entry=="string").map(entry=>entry.trim()).filter(entry=>entry.length>0))].sort((a,b)=>a.localeCompare(b));return normalized.length>0?normalized:void 0}function isPlainObjectRecord(value){if(!value||typeof value!="object"||Array.isArray(value))return!1;const prototype=Object.getPrototypeOf(value);return prototype===Object.prototype||prototype===null}function isUnsafeObjectKey(key){return key==="__proto__"||key==="constructor"||key==="prototype"}function normalizeStringRecord(value){if(!isPlainObjectRecord(value))return;const entries=Object.entries(value).map(([key,recordValue])=>[key.trim(),String(recordValue).trim()]).filter(([key,recordValue])=>key.length>0&&!isUnsafeObjectKey(key)&&recordValue.length>0).sort(([left],[right])=>left.localeCompare(right));return entries.length>0?Object.fromEntries(entries):void 0}function normalizeNumericRecord(value){if(!isPlainObjectRecord(value))return;const entries=Object.entries(value).map(([key,recordValue])=>[key.trim(),Number(recordValue)]).filter(([key,recordValue])=>key.length>0&&!isUnsafeObjectKey(key)&&Number.isFinite(recordValue)).sort(([left],[right])=>left.localeCompare(right));return entries.length>0?Object.fromEntries(entries):void 0}function normalizeLinkedTestContextMode(value){const normalized=value?.trim().toLowerCase();if(!(!normalized||!LINKED_TEST_PM_CONTEXT_MODE_VALUES.has(normalized)))return normalized}function normalizeLinkedTestWorkspaceContextMode(value){const normalized=value?.trim().toLowerCase();if(!(!normalized||!LINKED_TEST_WORKSPACE_CONTEXT_MODE_VALUES.has(normalized)))return normalized}function normalizeLinkedTestProvenance(value,invalid){if(invalid===!0)return{provenance_invalid:!0};if(value===void 0)return{};if(!isPlainObjectRecord(value))return{provenance_invalid:!0};const author=trimStringOrUndefined(value.author),createdAt=trimStringOrUndefined(value.created_at),sourceKind=value.source_kind;return!author||!createdAt||!isTimestampLiteral(createdAt)||sourceKind!=="local_mutation"&&sourceKind!=="merge_union"?{provenance_invalid:!0}:{provenance:{author,created_at:createdAt,source_kind:sourceKind,source_ref:trimStringOrUndefined(value.source_ref)}}}function normalizeLinkedTest(value){const test={command:value.command?.trim()||void 0,path:value.path?normalizePathValue(value.path):void 0,scope:value.scope,timeout_seconds:typeof value.timeout_seconds=="number"&&Number.isFinite(value.timeout_seconds)&&value.timeout_seconds>0?value.timeout_seconds:void 0,pm_context_mode:normalizeLinkedTestContextMode(value.pm_context_mode),workspace_context_mode:normalizeLinkedTestWorkspaceContextMode(value.workspace_context_mode),...normalizeLinkedTestProvenance(value.provenance,value.provenance_invalid),updated_by:trimStringOrUndefined(value.updated_by),updated_at:trimStringOrUndefined(value.updated_at),env_set:normalizeStringRecord(value.env_set),env_clear:normalizeTrimmedStringList(value.env_clear),shared_host_safe:value.shared_host_safe===!0?!0:void 0,assert_stdout_contains:normalizeTrimmedStringList(value.assert_stdout_contains),assert_stdout_regex:normalizeTrimmedStringList(value.assert_stdout_regex),assert_stderr_contains:normalizeTrimmedStringList(value.assert_stderr_contains),assert_stderr_regex:normalizeTrimmedStringList(value.assert_stderr_regex),assert_stdout_min_lines:normalizeNonNegativeInteger(value.assert_stdout_min_lines),assert_json_field_equals:normalizeStringRecord(value.assert_json_field_equals),assert_json_field_gte:normalizeNumericRecord(value.assert_json_field_gte),note:value.note?.trim()||void 0};return deleteUndefinedFields(test),test}function sortDocs(values){if(!(!values||values.length===0))return[...values].map(value=>({path:normalizePathValue(value.path),scope:value.scope,note:value.note?.trim()||void 0})).sort((a,b)=>{const byScope=a.scope.localeCompare(b.scope);if(byScope!==0)return byScope;const byPath=a.path.localeCompare(b.path);return byPath!==0?byPath:(a.note??"").localeCompare(b.note??"")})}function trimStringOrUndefined(value){if(typeof value!="string")return;const trimmed=value.trim();return trimmed.length>0?trimmed:void 0}function normalizePlanStepLinks(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,id=trimStringOrUndefined(record.id),kind=trimStringOrUndefined(record.kind);if(!id||!kind)continue;const link={id,kind},note=trimStringOrUndefined(record.note);note&&(link.note=note),record.required_before_step===!0&&(link.required_before_step=!0),out.push(link)}return out.length>0?out:void 0}function normalizePlanStepFiles(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,path=trimStringOrUndefined(record.path);if(!path)continue;const file={path:normalizePathValue(path)};(record.scope==="project"||record.scope==="global")&&(file.scope=record.scope);const note=trimStringOrUndefined(record.note);note&&(file.note=note),out.push(file)}return out.length>0?out:void 0}function normalizePlanStepTests(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,command=trimStringOrUndefined(record.command),path=trimStringOrUndefined(record.path);if(!command&&!path)continue;const test={};command&&(test.command=command),path&&(test.path=normalizePathValue(path));const note=trimStringOrUndefined(record.note);note&&(test.note=note),out.push(test)}return out.length>0?out:void 0}function normalizePlanStepDocs(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,path=trimStringOrUndefined(record.path);if(!path)continue;const doc={path:normalizePathValue(path)};(record.scope==="project"||record.scope==="global")&&(doc.scope=record.scope);const note=trimStringOrUndefined(record.note);note&&(doc.note=note),out.push(doc)}return out.length>0?out:void 0}function normalizePlanStepEntry(entry){if(entry===null||typeof entry!="object")return;const record=entry,id=trimStringOrUndefined(record.id),title=trimStringOrUndefined(record.title),statusRaw=trimStringOrUndefined(record.status),status=statusRaw&&PLAN_STEP_STATUS_SET.has(statusRaw)?statusRaw:void 0,order=coerceFiniteNumber(record.order)??Number.NaN,created_at=typeof record.created_at=="string"?record.created_at:"",updated_at=typeof record.updated_at=="string"?record.updated_at:"";if(!id||!title||!status||!Number.isFinite(order)||!created_at||!updated_at)return;const step={id,order,title,status,created_at,updated_at};return applyPlanStepOptionalFields(step,record),step}function applyPlanStepOptionalFields(step,record){const stringFields=[["body","body"],["owner","owner"],["evidence","evidence"],["blocked_reason","blocked_reason"],["superseded_by","superseded_by"]];for(const[target,source]of stringFields){const value=trimStringOrUndefined(record[source]);value&&(step[target]=value)}const completedAt=typeof record.completed_at=="string"?record.completed_at:void 0;completedAt&&completedAt.length>0&&(step.completed_at=completedAt);const collectionFields=[["linked_items","linked_items",normalizePlanStepLinks],["files","files",normalizePlanStepFiles],["tests","tests",normalizePlanStepTests],["docs","docs",normalizePlanStepDocs]];for(const[target,source,normalize]of collectionFields){const value=normalize(record[source]);value&&(step[target]=value)}}function normalizePlanSteps(value){if(!Array.isArray(value))return;const out=value.flatMap(entry=>{const step=normalizePlanStepEntry(entry);return step?[step]:[]});return out.sort((left,right)=>left.order-right.order),out.length>0?out:void 0}function normalizePlanDecisions(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,ts=typeof record.ts=="string"?record.ts:"",author=typeof record.author=="string"?record.author:"",decision=trimStringOrUndefined(record.decision);if(!ts||!author||!decision)continue;const item={ts,author,decision},rationale=trimStringOrUndefined(record.rationale);rationale&&(item.rationale=rationale);const evidence=trimStringOrUndefined(record.evidence);evidence&&(item.evidence=evidence);const stepId=trimStringOrUndefined(record.step_id);stepId&&(item.step_id=stepId),out.push(item)}return out.length>0?out:void 0}function normalizePlanDiscoveries(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,ts=typeof record.ts=="string"?record.ts:"",author=typeof record.author=="string"?record.author:"",text=trimStringOrUndefined(record.text);if(!ts||!author||!text)continue;const item={ts,author,text},stepId=trimStringOrUndefined(record.step_id);stepId&&(item.step_id=stepId),out.push(item)}return out.length>0?out:void 0}function normalizePlanValidation(value){if(!Array.isArray(value))return;const out=[];for(const entry of value){if(entry===null||typeof entry!="object")continue;const record=entry,text=trimStringOrUndefined(record.text);if(!text)continue;const item={text},command=trimStringOrUndefined(record.command);command&&(item.command=command);const expected=trimStringOrUndefined(record.expected);expected&&(item.expected=expected),out.push(item)}return out.length>0?out:void 0}function normalizeTypeOptions(values){if(!values)return;const normalizedEntries=Object.entries(values).map(([key,value])=>[key.trim(),value.trim()]).filter(([key,value])=>key.length>0&&value.length>0).sort((left,right)=>left[0].localeCompare(right[0]));if(normalizedEntries.length!==0)return Object.fromEntries(normalizedEntries)}function normalizeBody(body){let start=0;for(;start<body.length&&body[start]===`
|
|
2
2
|
`;)start+=1;return body.slice(start).trimEnd()}function normalizeConfidenceValue(value){if(value===void 0)return;if(typeof value=="number")return value;const normalized=value.trim().toLowerCase();if(normalized==="med")return"medium";if(CONFIDENCE_TEXT_VALUES.includes(normalized))return normalized}function normalizeSeverityValue(value){if(value===void 0)return;const normalized=value.trim().toLowerCase();if(normalized==="med")return"medium";if(ISSUE_SEVERITY_VALUES.includes(normalized))return normalized}function emptyStringToUndefined(value){return value||void 0}function copyExtensionItemMetadataFields(normalized,source){const targetRecord=normalized,sourceRecord=source;for(const[key,value]of Object.entries(sourceRecord))isUnsafeObjectKey(key)||Object.prototype.hasOwnProperty.call(targetRecord,key)||value===void 0||(targetRecord[key]=value)}function coerceNormalizedRuntimeFields(normalized,runtimeContext){if(!runtimeContext?.fieldRegistry)return;const record=normalized;for(const definition of runtimeContext.fieldRegistry.definitions){const currentValue=record[definition.metadata_key];currentValue!==void 0&&(record[definition.metadata_key]=coerceRuntimeFieldValue(definition,currentValue,`metadata field "${definition.metadata_key}"`,"metadata"))}}function assertNormalizedUnknownFields(normalized,runtimeContext){if(!runtimeContext||runtimeContext.unknownFieldPolicy==="allow")return;const knownKeys=buildKnownItemMetadataKeys(runtimeContext),unknownKeys=Object.keys(normalized).filter(key=>!knownKeys.has(key)).sort((left,right)=>left.localeCompare(right));unknownKeys.length>0&&runtimeContext.unknownFieldPolicy==="reject"&&validationError(`unknown schema fields are not allowed: ${unknownKeys.join(", ")}`),unknownKeys.length>0&&runtimeContext.onWarning?.(`item_unknown_schema_fields:${unknownKeys.join(",")}`)}function normalizeItemMetadata(itemMetadata,options={}){const runtimeContext=resolveRuntimeSchemaValidationContext(options),normalizedStatus=normalizeStatusInput(itemMetadata.status,runtimeContext?.statusRegistry)??itemMetadata.status,tags=Array.from(new Set((Array.isArray(itemMetadata.tags)?itemMetadata.tags:[]).filter(tag=>typeof tag=="string").map(tag=>tag.trim().toLowerCase()).filter(Boolean))).sort((a,b)=>a.localeCompare(b)),normalized={id:itemMetadata.id,title:itemMetadata.title,description:itemMetadata.description,type:itemMetadata.type,pm_format_version:normalizeItemFormatVersion(itemMetadata.pm_format_version),source_type:trimStringOrUndefined(itemMetadata.source_type),type_options:normalizeTypeOptions(itemMetadata.type_options),status:normalizedStatus,priority:itemMetadata.priority,tags,created_at:itemMetadata.created_at,updated_at:itemMetadata.updated_at,dependencies:sortDependencies(itemMetadata.dependencies),comments:sortLogValues(itemMetadata.comments),notes:sortLogValues(itemMetadata.notes),learnings:sortLogValues(itemMetadata.learnings),files:normalizeFiles(itemMetadata.files),tests:sortTests(itemMetadata.tests),test_runs:normalizeTestRunSummaries(itemMetadata.test_runs),docs:sortDocs(itemMetadata.docs),deadline:emptyStringToUndefined(itemMetadata.deadline),reminders:sortReminders(itemMetadata.reminders),events:sortEvents(itemMetadata.events),closed_at:emptyStringToUndefined(itemMetadata.closed_at),completed_at:emptyStringToUndefined(itemMetadata.completed_at),assignee:trimStringOrUndefined(itemMetadata.assignee),claim_principal:trimStringOrUndefined(itemMetadata.claim_principal),source_owner:trimStringOrUndefined(itemMetadata.source_owner),author:emptyStringToUndefined(itemMetadata.author),estimated_minutes:itemMetadata.estimated_minutes,acceptance_criteria:itemMetadata.acceptance_criteria??void 0,design:itemMetadata.design??void 0,external_ref:itemMetadata.external_ref??void 0,definition_of_ready:trimStringOrUndefined(itemMetadata.definition_of_ready),order:itemMetadata.order,goal:trimStringOrUndefined(itemMetadata.goal),objective:trimStringOrUndefined(itemMetadata.objective),value:trimStringOrUndefined(itemMetadata.value),impact:trimStringOrUndefined(itemMetadata.impact),outcome:trimStringOrUndefined(itemMetadata.outcome),why_now:trimStringOrUndefined(itemMetadata.why_now),parent:trimStringOrUndefined(itemMetadata.parent),reviewer:trimStringOrUndefined(itemMetadata.reviewer),risk:itemMetadata.risk??void 0,confidence:normalizeConfidenceValue(itemMetadata.confidence),sprint:trimStringOrUndefined(itemMetadata.sprint),release:trimStringOrUndefined(itemMetadata.release),blocked_by:trimStringOrUndefined(itemMetadata.blocked_by),blocked_reason:trimStringOrUndefined(itemMetadata.blocked_reason),unblock_note:trimStringOrUndefined(itemMetadata.unblock_note),reporter:trimStringOrUndefined(itemMetadata.reporter),severity:normalizeSeverityValue(itemMetadata.severity),environment:trimStringOrUndefined(itemMetadata.environment),repro_steps:trimStringOrUndefined(itemMetadata.repro_steps),resolution:trimStringOrUndefined(itemMetadata.resolution),expected_result:trimStringOrUndefined(itemMetadata.expected_result),actual_result:trimStringOrUndefined(itemMetadata.actual_result),affected_version:trimStringOrUndefined(itemMetadata.affected_version),fixed_version:trimStringOrUndefined(itemMetadata.fixed_version),component:trimStringOrUndefined(itemMetadata.component),regression:itemMetadata.regression,customer_impact:trimStringOrUndefined(itemMetadata.customer_impact),close_reason:emptyStringToUndefined(itemMetadata.close_reason),plan_mode:trimStringOrUndefined(itemMetadata.plan_mode),plan_scope:trimStringOrUndefined(itemMetadata.plan_scope),plan_harness:trimStringOrUndefined(itemMetadata.plan_harness),plan_resume_context:trimStringOrUndefined(itemMetadata.plan_resume_context),plan_steps:normalizePlanSteps(itemMetadata.plan_steps),plan_decisions:normalizePlanDecisions(itemMetadata.plan_decisions),plan_discoveries:normalizePlanDiscoveries(itemMetadata.plan_discoveries),plan_validation:normalizePlanValidation(itemMetadata.plan_validation)};return copyExtensionItemMetadataFields(normalized,itemMetadata),coerceNormalizedRuntimeFields(normalized,runtimeContext),assertNormalizedUnknownFields(normalized,runtimeContext),deleteUndefinedFields(normalized),normalized}function orderItemMetadata(itemMetadata){return orderObject(itemMetadata,ITEM_METADATA_KEY_ORDER)}function findJsonObjectEnd(content){let depth=0,inString=!1,escaped=!1;for(let i=0;i<content.length;i+=1){const char=content[i];if(inString){if(escaped){escaped=!1;continue}if(char==="\\"){escaped=!0;continue}char==='"'&&(inString=!1);continue}if(char==='"'){inString=!0;continue}if(char==="{"){depth+=1;continue}if(char==="}"&&(depth-=1,depth===0))return i}return-1}function splitFrontMatter(content){if(!content.startsWith("{"))return{frontMatter:"",body:content};const end=findJsonObjectEnd(content);if(end<0)return{frontMatter:"",body:content};const frontMatter=content.slice(0,end+1),body=content.slice(end+1).replace(/^\r?\n+/,"");return{frontMatter,body}}function stripLeadingYamlDocument(content){const normalizedContent=content.charCodeAt(0)===65279?content.slice(1):content,opener=normalizedContent.match(/^[ \t]*---[ \t]*(?:\r?\n|$)/);if(!opener)return{content:normalizedContent,stripped:!1};let cursor=opener[0].length;for(;cursor<normalizedContent.length;){const nextNewline=normalizedContent.indexOf(`
|
|
3
|
-
`,cursor),lineEnd=nextNewline===-1?normalizedContent.length:nextNewline,line=normalizedContent.slice(cursor,lineEnd).replace(/\r$/,""),afterLine=nextNewline===-1?lineEnd:lineEnd+1;if(line.trim()==="---")return{content:normalizedContent.slice(afterLine).replace(/^\s+/,""),stripped:!0};cursor=afterLine}return{content:normalizedContent,stripped:!1}}function normalizeParsedItemMetadata(itemMetadata,options){return normalizeItemMetadata(itemMetadata,{...options,onWarning:void 0})}function parseJsonMarkdownItemDocument(content,runtimeContext,options={}){const normalized=stripLeadingYamlDocument(content);normalized.stripped&&options.onWarning?.("json_markdown_leading_yaml_frontmatter_ignored");const{frontMatter,body}=splitFrontMatter(normalized.content);frontMatter||(content.trimStart().startsWith("{")&&documentSyntaxError("json_markdown","JSON front matter is not valid JSON"),documentSyntaxError("json_markdown","JSON Markdown item document is missing JSON front matter"));let parsed;try{parsed=JSON.parse(frontMatter)}catch{documentSyntaxError("json_markdown","JSON front matter is not valid JSON")}return assertSupportedItemFormat(parsed,options.requireSupportedFormat),assertValidItemMetadata(parsed,runtimeContext),{metadata:normalizeParsedItemMetadata(parsed,options),body:normalizeBody(body)}}function parseToonItemDocument(content,runtimeContext,options={}){let parsed;try{parsed=decodeToonItemContent(content).value}catch{documentSyntaxError("toon","TOON item document is not valid TOON")}assertItemMetadataCondition(typeof parsed=="object"&&parsed!==null&&!Array.isArray(parsed),"TOON item document must be an object");const record=parsed;if(assertSupportedItemFormat(Object.prototype.hasOwnProperty.call(record,"front_matter")?record.front_matter:record,options.requireSupportedFormat),!REQUIRED_STRING_FIELDS.some(fieldName=>Object.prototype.hasOwnProperty.call(record,fieldName))&&!Object.prototype.hasOwnProperty.call(record,"front_matter")&&documentSyntaxError("toon","TOON input does not have the shape of an item document"),Object.prototype.hasOwnProperty.call(record,"front_matter"))return assertValidItemMetadata(record.front_matter,runtimeContext),assertItemMetadataCondition(record.body===void 0||typeof record.body=="string","TOON item document body must be a string"),{metadata:normalizeParsedItemMetadata(record.front_matter,options),body:normalizeBody(typeof record.body=="string"?record.body:"")};const{body,...itemMetadataRecord}=record;return assertItemMetadataCondition(body===void 0||typeof body=="string","TOON item document body must be a string"),assertValidItemMetadata(itemMetadataRecord,runtimeContext),{metadata:normalizeParsedItemMetadata(itemMetadataRecord,options),body:normalizeBody(typeof body=="string"?body:"")}}function serializeJsonMarkdownItemDocument(document,options={}){const normalizedMetadata=normalizeItemMetadata(document.metadata,options),orderedMetadata=orderItemMetadata(normalizedMetadata),serializedMetadata=JSON.stringify(orderedMetadata,null,2)
|
|
3
|
+
`,cursor),lineEnd=nextNewline===-1?normalizedContent.length:nextNewline,line=normalizedContent.slice(cursor,lineEnd).replace(/\r$/,""),afterLine=nextNewline===-1?lineEnd:lineEnd+1;if(line.trim()==="---")return{content:normalizedContent.slice(afterLine).replace(/^\s+/,""),stripped:!0};cursor=afterLine}return{content:normalizedContent,stripped:!1}}function normalizeParsedItemMetadata(itemMetadata,options){return normalizeItemMetadata(itemMetadata,{...options,onWarning:void 0})}function parseJsonMarkdownItemDocument(content,runtimeContext,options={}){const normalized=stripLeadingYamlDocument(content);normalized.stripped&&options.onWarning?.("json_markdown_leading_yaml_frontmatter_ignored");const{frontMatter,body}=splitFrontMatter(normalized.content);frontMatter||(content.trimStart().startsWith("{")&&documentSyntaxError("json_markdown","JSON front matter is not valid JSON"),documentSyntaxError("json_markdown","JSON Markdown item document is missing JSON front matter"));let parsed;try{parsed=JSON.parse(frontMatter)}catch{documentSyntaxError("json_markdown","JSON front matter is not valid JSON")}return assertSupportedItemFormat(parsed,options.requireSupportedFormat),assertValidItemMetadata(parsed,runtimeContext),{metadata:normalizeParsedItemMetadata(parsed,options),body:normalizeBody(body)}}function parseToonItemDocument(content,runtimeContext,options={}){let parsed;try{parsed=decodeToonItemContent(content).value}catch{documentSyntaxError("toon","TOON item document is not valid TOON")}assertItemMetadataCondition(typeof parsed=="object"&&parsed!==null&&!Array.isArray(parsed),"TOON item document must be an object");const record=parsed;if(assertSupportedItemFormat(Object.prototype.hasOwnProperty.call(record,"front_matter")?record.front_matter:record,options.requireSupportedFormat),!REQUIRED_STRING_FIELDS.some(fieldName=>Object.prototype.hasOwnProperty.call(record,fieldName))&&!Object.prototype.hasOwnProperty.call(record,"front_matter")&&documentSyntaxError("toon","TOON input does not have the shape of an item document"),Object.prototype.hasOwnProperty.call(record,"front_matter"))return assertValidItemMetadata(record.front_matter,runtimeContext),assertItemMetadataCondition(record.body===void 0||typeof record.body=="string","TOON item document body must be a string"),{metadata:normalizeParsedItemMetadata(record.front_matter,options),body:normalizeBody(typeof record.body=="string"?record.body:"")};const{body,...itemMetadataRecord}=record;return assertItemMetadataCondition(body===void 0||typeof body=="string","TOON item document body must be a string"),assertValidItemMetadata(itemMetadataRecord,runtimeContext),{metadata:normalizeParsedItemMetadata(itemMetadataRecord,options),body:normalizeBody(typeof body=="string"?body:"")}}function serializeJsonMarkdownItemDocument(document,options={}){const normalizedMetadata=normalizeItemMetadata(document.metadata,options),orderedMetadata=orderItemMetadata(normalizedMetadata),normalizedBody=normalizeBody(document.body??"");assertWellFormedItemText(JSON.parse(JSON.stringify(orderedMetadata))),assertWellFormedItemText({body:normalizedBody});const serializedMetadata=JSON.stringify(orderedMetadata,null,2);return normalizedBody?`${serializedMetadata}
|
|
4
4
|
|
|
5
5
|
${normalizedBody}
|
|
6
6
|
`:`${serializedMetadata}
|
|
7
|
-
`}function serializeToonItemDocument(document,options={}){const normalizedMetadata=normalizeItemMetadata(document.metadata,options),orderedMetadata=orderItemMetadata(normalizedMetadata),normalizedBody=normalizeBody(document.body??""),payload={...orderedMetadata,body:normalizedBody},encodablePayload=JSON.parse(JSON.stringify(payload))
|
|
7
|
+
`}const LONE_SURROGATE_PATTERN=/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/u;function findIllFormedItemText(value,path){return typeof value=="string"?illFormedText(value,path):value===null||typeof value!="object"?null:Array.isArray(value)?firstIllFormed(value.map((entry,position)=>()=>findIllFormedItemText(entry,`${path}[${position}]`))):firstIllFormed(Object.entries(value).map(([key,entry])=>()=>{const childPath=path?`${path}.${key}`:key;return illFormedText(key,`${childPath} (key)`)??findIllFormedItemText(entry,childPath)}))}function illFormedText(text,path){const index=text.search(LONE_SURROGATE_PATTERN);return index<0?null:{path,index}}function firstIllFormed(probes){for(const probe of probes){const found=probe();if(found!==null)return found}return null}function assertWellFormedItemText(payload){const found=findIllFormedItemText(payload,"");if(found!==null)throw new PmCliError(`Item field ${found.path} contains an unpaired surrogate code unit at index ${found.index}; persisted item text requires well-formed Unicode.`,EXIT_CODE.USAGE,{code:"text_unpaired_surrogate",field:found.path,required:"Provide well-formed UTF-16 text: keep emoji and other astral characters whole and avoid lone \\uD800-\\uDFFF JSON escapes.",why:"Persisted item text must remain well-formed in every supported format; a lone surrogate can cause an unclassified encoder fault.",nextSteps:[`Repair the ${found.path} value (for example String.prototype.toWellFormed() or re-truncate on a character boundary) and retry.`,"Run pm <command> --help --json to review the text fields the command accepts."]})}function serializeToonItemDocument(document,options={}){const normalizedMetadata=normalizeItemMetadata(document.metadata,options),orderedMetadata=orderItemMetadata(normalizedMetadata),normalizedBody=normalizeBody(document.body??""),payload={...orderedMetadata,body:normalizedBody},encodablePayload=JSON.parse(JSON.stringify(payload));assertWellFormedItemText(encodablePayload);const serialized=encodeToon(encodablePayload);let decoded;try{decoded=decodeToonItemContent(serialized).value}catch(error){throw new PmCliError("Refusing to persist a TOON item document that the configured decoder cannot read back.",EXIT_CODE.GENERIC_FAILURE,{code:"item_document_roundtrip_failed",reason:"encode_decode_error",format:"toon",required:"Upgrade or repair the TOON codec before retrying the mutation; no item bytes were written.",why:error instanceof Error?error.message:String(error)})}if(!isDeepStrictEqual(decoded,encodablePayload)){const decodedRecord=typeof decoded=="object"&&decoded!==null&&!Array.isArray(decoded)?decoded:{},field=Object.keys(encodablePayload).find(key=>!isDeepStrictEqual(encodablePayload[key],decodedRecord[key]))??"document";throw new PmCliError(`Refusing to persist a lossy TOON item document; round-trip mismatch at field "${field}".`,EXIT_CODE.GENERIC_FAILURE,{code:"item_document_roundtrip_failed",reason:"encode_decode_mismatch",format:"toon",field,required:"Upgrade or repair the TOON codec before retrying the mutation; no item bytes were written.",why:"The encoded document decoded to a value different from the canonical item payload."})}return`${serialized}
|
|
8
8
|
`}function parseItemDocument(content,options={}){const conflictMarker=findFirstMergeConflictMarker(content);if(conflictMarker)throw new PmCliError(`Merge conflict markers detected in item document at line ${conflictMarker.line} (${conflictMarker.marker}). Resolve <<<<<<< ======= >>>>>>> markers and retry.`,EXIT_CODE.GENERIC_FAILURE,{code:"merge_conflict_markers_detected",reason:"merge_conflict",required:"Resolve merge-conflict markers in the item file before parsing or mutation commands.",why:"Partially merged documents can corrupt item metadata and history integrity.",examples:["git status","git add <resolved-file> && git commit"],nextSteps:["Resolve conflicts, save the file, then rerun the pm command."]});const format=options.format??"toon",runtimeContext=resolveRuntimeSchemaValidationContext(options);return format==="toon"?parseToonItemDocument(content,runtimeContext,options):parseJsonMarkdownItemDocument(content,runtimeContext,options)}function serializeItemDocument(document,options={}){return(options.format??"toon")==="toon"?serializeToonItemDocument(document,options):serializeJsonMarkdownItemDocument(document,options)}function canonicalDocument(document,options={}){return{metadata:normalizeItemMetadata(document.metadata,options),body:normalizeBody(document.body??"")}}const _testOnlyItemFormat={buildKnownItemMetadataKeys,firstNonZeroComparison,normalizeBody,normalizePlanDecisions,normalizePlanDiscoveries,normalizePlanStepDocs,normalizePlanStepFiles,normalizePlanStepLinks,normalizePlanSteps,normalizePlanStepTests,normalizePlanValidation,normalizeTestRunSummaries,normalizeTypeOptions,runtimeFieldRequiredForType,sortTests};export{_testOnlyItemFormat,canonicalDocument,normalizeItemMetadata,normalizeLinkedTest,parseItemDocument,serializeItemDocument,splitFrontMatter};
|
|
9
9
|
//# sourceMappingURL=item-format.js.map
|