@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
package/dist/core/lock/lock.d.ts
CHANGED
|
@@ -36,6 +36,8 @@ declare function isErrno(error:unknown,code:string):boolean;
|
|
|
36
36
|
declare function isLockCreateContention(error:unknown,lockPath:string,platform?:NodeJS.Platform):Promise<boolean>;
|
|
37
37
|
declare function buildLockPayload(id:string,owner:string,ttlSeconds:number,token?:string):LockInfo;
|
|
38
38
|
declare function isStaleLock(info:LockInfo | null,ttlSeconds:number):boolean;
|
|
39
|
+
/** Observe a built-in lock's owner lease without acquiring it or changing storage. */
|
|
40
|
+
export declare function hasUnexpiredLockOwner(pmRoot:string,id:string,ownerPrefix:string):Promise<boolean>;
|
|
39
41
|
declare function lockOwnerSuffix(info:LockInfo | null):string;
|
|
40
42
|
/** Resolves the effective bounded wait budget for a contended lock: the PM_LOCK_WAIT_MS environment override wins when it parses as a non-negative integer, then the caller-provided budget (settings `locks.wait_ms`), then 0 (fail-fast, the pre-wait behavior). */
|
|
41
43
|
declare function resolveLockWaitMs(waitMs:number | undefined):number;
|
|
@@ -80,9 +82,14 @@ removeConfirmedStaleLock:typeof removeConfirmedStaleLock;
|
|
|
80
82
|
* Acquire a token-owned tracker lock with bounded contention waiting and
|
|
81
83
|
* explicit stale-owner policy. Background consumers may disable creation of
|
|
82
84
|
* parent directories so acquiring or retrying a lock cannot revive removed
|
|
83
|
-
* storage.
|
|
85
|
+
* storage. An explicit maxWaitMs caps contention retries even when the process
|
|
86
|
+
* environment requests a longer wait. Extension overrides receive that ceiling
|
|
87
|
+
* and retain responsibility for their own lifecycle.
|
|
84
88
|
*/
|
|
85
89
|
export declare function acquireLock(pmRoot:string,id:string,ttlSeconds:number,owner:string,force?:boolean,forceRequiredForStaleLock?:boolean,waitMs?:number,options?:{
|
|
90
|
+
/** Allow lock acquisition to initialize missing lock directories. */
|
|
86
91
|
createParentDirectories?:boolean;
|
|
92
|
+
/** Ceiling on the effective retry budget, including PM_LOCK_WAIT_MS. */
|
|
93
|
+
maxWaitMs?:number;
|
|
87
94
|
}):Promise<() => Promise<void>>;
|
|
88
95
|
export {};
|
package/dist/core/lock/lock.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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
|
-
`,"utf8")}finally{await handle.close()}}catch(error){throw await unlinkLockWithHook(lockPath,"lock:release"),error}}finally{await releaseCleanupGate()}await emitLockWriteHook(lockPath,"lock:create")}async function unlinkLockWithHook(lockPath,op){try{return await fs.unlink(lockPath),await emitLockWriteHook(lockPath,op),!0}catch{return!1}}async function releaseOwnedLock(lockPath,id,owner,token){const startedAtMs=Date.now();let backoffMs=LOCK_WAIT_INITIAL_DELAY_MS;for(;;){const releaseCleanupGate=await acquireStaleCleanupGate(lockPath,id);if(releaseCleanupGate!==null){try{const current2=await readLockInfo(lockPath,!1);isOwnedLock(current2.info,id,owner,token)&&await unlinkLockWithHook(lockPath,"lock:release")}finally{await releaseCleanupGate()}return}const current=await readLockInfo(lockPath,!1);if(!isOwnedLock(current.info,id,owner,token))return;const elapsedMs=Date.now()-startedAtMs;if(elapsedMs>=LOCK_RELEASE_GATE_WAIT_MS)return;await sleepWithJitter(Math.min(backoffMs,LOCK_RELEASE_GATE_WAIT_MS-elapsedMs)),backoffMs=Math.min(backoffMs*2,LOCK_WAIT_MAX_DELAY_MS)}}function isOwnedLock(info,id,owner,token){return info?.id===id&&info.pid===process.pid&&info.owner===owner&&info.token===token}function isStaleLock(info,ttlSeconds){const createdAtMs=info?.created_at?Date.parse(info.created_at):Number.NaN;return(Number.isFinite(createdAtMs)?Date.now()-createdAtMs:Number.POSITIVE_INFINITY)>ttlSeconds*1e3}function lockOwnerSuffix(info){return info?.owner?` (owner ${info.owner})`:""}const LOCK_WAIT_INITIAL_DELAY_MS=25,LOCK_WAIT_MAX_DELAY_MS=200,LOCK_CONFLICT_RETRY_HINT_MS=250,MAX_STALE_LOCK_REMOVALS=3,STALE_CLEANUP_GATE_SUFFIX=".stale-cleanup",STALE_CLEANUP_GATE_OWNER_FILE="owner.json",STALE_CLEANUP_GATE_STALE_MS=1e4,LOCK_RELEASE_GATE_WAIT_MS=STALE_CLEANUP_GATE_STALE_MS+LOCK_WAIT_MAX_DELAY_MS,STALE_CLEANUP_GATE_MAX_UNVERIFIED_MS=60*6e4;function parseNonNegativeIntegerWaitMs(value){if(typeof value=="string"){const trimmed=value.trim();if(!/^\d+$/.test(trimmed))return;const parsed=Number(trimmed);return Number.isSafeInteger(parsed)?parsed:void 0}if(typeof value=="number"&&Number.isFinite(value)&&value>=0)return Math.trunc(value)}function resolveLockWaitMs(waitMs){const envRaw=process.env.PM_LOCK_WAIT_MS,envParsed=parseNonNegativeIntegerWaitMs(envRaw);if(envParsed!==void 0)return envParsed;const callerParsed=parseNonNegativeIntegerWaitMs(waitMs);return callerParsed!==void 0?callerParsed:0}function sleepWithJitter(baseDelayMs){const jitteredMs=Math.max(1,Math.round(baseDelayMs*(.5+Math.random())));return new Promise(resolve=>setTimeout(resolve,jitteredMs))}function buildLockConflictError(id,info,waitedMs){const waitedSuffix=waitedMs>0?` after waiting ${waitedMs}ms`:"";return new PmCliError(`Item ${id} is locked${lockOwnerSuffix(info)}${waitedSuffix}`,EXIT_CODE.CONFLICT,{code:"lock_conflict",recovery:{retry_after_ms:LOCK_CONFLICT_RETRY_HINT_MS}})}function resolveLockOverrideRelease(result){if(typeof result=="function")return result;if(typeof result=="object"&&result!==null&&"release"in result){const release=result.release;return typeof release=="function"?release:null}return null}function throwIfStaleLockNeedsForce(id,lockInfo,force,forceRequired){if(!force&&forceRequired){const warningSuffix=lockInfo.warnings.length>0?` (${lockInfo.warnings.join(",")})`:"";throw new PmCliError(`Item ${id} lock is stale${warningSuffix}; rerun with --force when supported for this command`,EXIT_CODE.CONFLICT)}}function parseStaleCleanupGateOwner(raw){let parsed;try{parsed=JSON.parse(raw)}catch{return null}if(typeof parsed!="object"||parsed===null||Array.isArray(parsed))return null;const candidate=parsed,pid=candidate.pid,token=candidate.token,processStartIdentity=candidate.process_start_identity;return typeof pid!="number"||!Number.isInteger(pid)||pid<=0||typeof token!="string"||token.length===0||processStartIdentity!==void 0&&(typeof processStartIdentity!="string"||!/^\d+$/u.test(processStartIdentity))?null:{pid,token,...typeof processStartIdentity=="string"?{process_start_identity:processStartIdentity}:{}}}async function readStaleCleanupGateOwner(gatePath){try{return parseStaleCleanupGateOwner(await fs.readFile(path.join(gatePath,STALE_CLEANUP_GATE_OWNER_FILE),"utf8"))}catch{return null}}function isProcessAlive(pid){if(!Number.isSafeInteger(pid)||pid<=0)return!1;try{return process.kill(pid,0),!0}catch(error){return!isErrno(error,"ESRCH")}}function parseLinuxProcessStartIdentity(raw){const closeParenIndex=raw.lastIndexOf(")");if(closeParenIndex<0)return null;const startTime=raw.slice(closeParenIndex+2).trim().split(/\s+/u)[19];return startTime!==void 0&&/^\d+$/u.test(startTime)?startTime:null}async function readProcessStartIdentity(pid){try{return parseLinuxProcessStartIdentity(await fs.readFile(`/proc/${pid}/stat`,"utf8"))}catch{return null}}async function captureProcessIdentity(pid=process.pid){const processStartIdentity=await readProcessStartIdentity(pid);return{pid,...processStartIdentity===null?{}:{process_start_identity:processStartIdentity}}}async function isProcessIdentityAlive(identity,unverifiedAgeMs,maxUnverifiedAgeMs){if(!isProcessAlive(identity.pid))return!1;const currentStartIdentity=await readProcessStartIdentity(identity.pid);return identity.process_start_identity!==void 0&¤tStartIdentity!==null?currentStartIdentity===identity.process_start_identity:unverifiedAgeMs<=maxUnverifiedAgeMs}async function removeStaleCleanupGateDirectory(gatePath){try{return await fs.rm(gatePath,{recursive:!0,force:!0}),!0}catch{return!1}}async function releaseStaleCleanupGate(gatePath,token){const owner=await readStaleCleanupGateOwner(gatePath);owner===null||owner.token!==token||await removeStaleCleanupGateDirectory(gatePath)}async function tryCreateStaleCleanupGate(gatePath){try{await fs.mkdir(gatePath)}catch(error){return isErrno(error,"EEXIST"),null}const owner={...await captureProcessIdentity(),token:randomUUID()};try{await fs.writeFile(path.join(gatePath,STALE_CLEANUP_GATE_OWNER_FILE),`${JSON.stringify(owner)}
|
|
3
|
-
`,"utf8")}catch{return await removeStaleCleanupGateDirectory(gatePath),null}return owner}async function removeExpiredStaleCleanupGate(gatePath){let gateAgeMs;try{const stats=await fs.stat(gatePath);if(gateAgeMs=Date.now()-stats.mtimeMs,gateAgeMs<=STALE_CLEANUP_GATE_STALE_MS)return!1}catch(error){return isFileMissingError(error)}const owner=await readStaleCleanupGateOwner(gatePath);return owner!==null&&await isProcessIdentityAlive(owner,gateAgeMs,STALE_CLEANUP_GATE_MAX_UNVERIFIED_MS)?!1:removeStaleCleanupGateDirectory(gatePath)}async function acquireStaleCleanupGate(lockPath,_id){const gatePath=`${lockPath}${STALE_CLEANUP_GATE_SUFFIX}`,owner=await tryCreateStaleCleanupGate(gatePath);if(owner!==null)return async()=>releaseStaleCleanupGate(gatePath,owner.token);if(!await removeExpiredStaleCleanupGate(gatePath))return null;const recoveredOwner=await tryCreateStaleCleanupGate(gatePath);return recoveredOwner===null?null:async()=>releaseStaleCleanupGate(gatePath,recoveredOwner.token)}async function removeConfirmedStaleLock(params){const releaseCleanupGate=await acquireStaleCleanupGate(params.lockPath,params.id);if(releaseCleanupGate===null)return{lockInfo:params.fallbackLockInfo,shouldRetryCreate:!1,staleRemovalCounted:!1};try{const currentLockInfo=await readLockInfo(params.lockPath);if(currentLockInfo.info===null&¤tLockInfo.warnings.length===0)return{lockInfo:currentLockInfo,shouldRetryCreate:!0,staleRemovalCounted:!1};if(!isStaleLock(currentLockInfo.info,params.ttlSeconds))return{lockInfo:currentLockInfo,shouldRetryCreate:!1,staleRemovalCounted:!1};if(throwIfStaleLockNeedsForce(params.id,currentLockInfo,params.force,params.forceRequiredForStaleLock),params.staleRemovals>=MAX_STALE_LOCK_REMOVALS)throw buildLockConflictError(params.id,currentLockInfo.info,Date.now()-params.startedAtMs);return{lockInfo:currentLockInfo,shouldRetryCreate:await unlinkLockWithHook(params.lockPath,"lock:stale_remove"),staleRemovalCounted:!0}}finally{await releaseCleanupGate()}}const _testOnly={parseLockInfo,readLockInfo,isErrno,isLockCreateContention,buildLockPayload,isStaleLock,lockOwnerSuffix,resolveLockWaitMs,parseLinuxProcessStartIdentity,readProcessStartIdentity,acquireStaleCleanupGate,removeConfirmedStaleLock};async function acquireLock(pmRoot,id,ttlSeconds,owner,force=!1,forceRequiredForStaleLock=!0,waitMs,options={}){const lockOverride=await runActiveServiceOverride("lock_acquire",{pm_root:pmRoot,id,ttl_seconds:ttlSeconds,owner,force,force_required_for_stale_lock:forceRequiredForStaleLock});if(lockOverride.handled){const release=resolveLockOverrideRelease(lockOverride.result);if(release)return async()=>{await Promise.resolve(release()),await runActiveServiceOverride("lock_release",{pm_root:pmRoot,id,owner})}}const lockPath=getLockPath(pmRoot,id),waitBudgetMs=
|
|
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]="4a6fa947-cc6f-5e48-8722-3db9a1af36f1")}catch{}})();import{isFileMissingError}from"../fs/fs-utils.js";import{constants as fsConstants}from"node:fs";import fs from"node:fs/promises";import path from"node:path";import{randomUUID}from"node:crypto";import{runActiveOnReadHooks,runActiveOnWriteHooks,runActiveServiceOverride}from"../extensions/index.js";import{EXIT_CODE}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{toErrorMessage}from"../shared/primitives.js";import{getLockPath}from"../store/paths.js";import{nowIso}from"../shared/time.js";function parseLockInfo(raw){let parsed;try{parsed=JSON.parse(raw)}catch{return{info:null,warnings:["lock_info_invalid_json"]}}if(typeof parsed!="object"||parsed===null||Array.isArray(parsed))return{info:null,warnings:["lock_info_invalid_shape"]};const candidate=parsed,id=candidate.id,pid=candidate.pid,owner=candidate.owner,token=candidate.token,createdAt=candidate.created_at,ttlSeconds=candidate.ttl_seconds;return typeof id!="string"||typeof pid!="number"||!Number.isFinite(pid)||typeof owner!="string"||token!==void 0&&(typeof token!="string"||token.trim().length===0)||typeof createdAt!="string"||typeof ttlSeconds!="number"||!Number.isFinite(ttlSeconds)?{info:null,warnings:["lock_info_invalid_shape"]}:{info:{id,pid,owner,...typeof token=="string"?{token}:{},created_at:createdAt,ttl_seconds:ttlSeconds},warnings:[]}}async function readLockInfo(lockPath,emitReadHook=!0){try{const raw=await fs.readFile(lockPath,"utf8");return emitReadHook&&await runActiveOnReadHooks({path:lockPath,scope:"project"}),parseLockInfo(raw)}catch(error){return isFileMissingError(error)?{info:null,warnings:[]}:{info:null,warnings:["lock_info_read_failed"]}}}function isErrno(error,code){return typeof error=="object"&&error!==null&&"code"in error&&error.code===code}async function isLockCreateContention(error,lockPath,platform=process.platform){if(isErrno(error,"EEXIST"))return!0;if(!isErrno(error,"EPERM")&&!isErrno(error,"EACCES")&&!isErrno(error,"EBUSY"))return!1;try{return await fs.lstat(lockPath),!0}catch(probeError){if(platform!=="win32"||!isFileMissingError(probeError)&&!isErrno(probeError,"EPERM")&&!isErrno(probeError,"EACCES")&&!isErrno(probeError,"EBUSY"))return!1}try{return await fs.access(path.dirname(lockPath),fsConstants.W_OK),!0}catch{return!1}}async function emitLockWriteHook(lockPath,op){await runActiveOnWriteHooks({path:lockPath,scope:"project",op})}function buildLockPayload(id,owner,ttlSeconds,token=randomUUID()){return{id,pid:process.pid,owner,token,created_at:nowIso(),ttl_seconds:ttlSeconds}}async function createLockFile(lockPath,id,owner,ttlSeconds,token,createParentDirectories){createParentDirectories&&await fs.mkdir(path.dirname(lockPath),{recursive:!0});const releaseCleanupGate=await acquireStaleCleanupGate(lockPath,id);if(releaseCleanupGate===null)throw await fs.access(path.dirname(lockPath)),Object.assign(new Error("Lock initialization is contended"),{code:"EEXIST"});try{const handle=await fs.open(lockPath,"wx");try{try{await handle.writeFile(`${JSON.stringify(buildLockPayload(id,owner,ttlSeconds,token),null,2)}
|
|
2
|
+
`,"utf8")}finally{await handle.close()}}catch(error){throw await unlinkLockWithHook(lockPath,"lock:release"),error}}finally{await releaseCleanupGate()}await emitLockWriteHook(lockPath,"lock:create")}async function unlinkLockWithHook(lockPath,op){try{return await fs.unlink(lockPath),await emitLockWriteHook(lockPath,op),!0}catch{return!1}}async function releaseOwnedLock(lockPath,id,owner,token){const startedAtMs=Date.now();let backoffMs=LOCK_WAIT_INITIAL_DELAY_MS;for(;;){const releaseCleanupGate=await acquireStaleCleanupGate(lockPath,id);if(releaseCleanupGate!==null){try{const current2=await readLockInfo(lockPath,!1);isOwnedLock(current2.info,id,owner,token)&&await unlinkLockWithHook(lockPath,"lock:release")}finally{await releaseCleanupGate()}return}const current=await readLockInfo(lockPath,!1);if(!isOwnedLock(current.info,id,owner,token))return;const elapsedMs=Date.now()-startedAtMs;if(elapsedMs>=LOCK_RELEASE_GATE_WAIT_MS)return;await sleepWithJitter(Math.min(backoffMs,LOCK_RELEASE_GATE_WAIT_MS-elapsedMs)),backoffMs=Math.min(backoffMs*2,LOCK_WAIT_MAX_DELAY_MS)}}function isOwnedLock(info,id,owner,token){return info?.id===id&&info.pid===process.pid&&info.owner===owner&&info.token===token}function isStaleLock(info,ttlSeconds){const createdAtMs=info?.created_at?Date.parse(info.created_at):Number.NaN;return(Number.isFinite(createdAtMs)?Date.now()-createdAtMs:Number.POSITIVE_INFINITY)>ttlSeconds*1e3}async function hasUnexpiredLockOwner(pmRoot,id,ownerPrefix){const{info}=await readLockInfo(getLockPath(pmRoot,id),!1);return info!==null&&info.owner.startsWith(ownerPrefix)&&!isStaleLock(info,info.ttl_seconds)}function lockOwnerSuffix(info){return info?.owner?` (owner ${info.owner})`:""}const LOCK_WAIT_INITIAL_DELAY_MS=25,LOCK_WAIT_MAX_DELAY_MS=200,LOCK_CONFLICT_RETRY_HINT_MS=250,MAX_STALE_LOCK_REMOVALS=3,STALE_CLEANUP_GATE_SUFFIX=".stale-cleanup",STALE_CLEANUP_GATE_OWNER_FILE="owner.json",STALE_CLEANUP_GATE_STALE_MS=1e4,LOCK_RELEASE_GATE_WAIT_MS=STALE_CLEANUP_GATE_STALE_MS+LOCK_WAIT_MAX_DELAY_MS,STALE_CLEANUP_GATE_MAX_UNVERIFIED_MS=60*6e4;function parseNonNegativeIntegerWaitMs(value){if(typeof value=="string"){const trimmed=value.trim();if(!/^\d+$/.test(trimmed))return;const parsed=Number(trimmed);return Number.isSafeInteger(parsed)?parsed:void 0}if(typeof value=="number"&&Number.isFinite(value)&&value>=0)return Math.trunc(value)}function resolveLockWaitMs(waitMs){const envRaw=process.env.PM_LOCK_WAIT_MS,envParsed=parseNonNegativeIntegerWaitMs(envRaw);if(envParsed!==void 0)return envParsed;const callerParsed=parseNonNegativeIntegerWaitMs(waitMs);return callerParsed!==void 0?callerParsed:0}function cappedLockWaitMs(waitMs,maxWaitMs){return Math.min(resolveLockWaitMs(waitMs),maxWaitMs??1/0)}function sleepWithJitter(baseDelayMs){const jitteredMs=Math.max(1,Math.round(baseDelayMs*(.5+Math.random())));return new Promise(resolve=>setTimeout(resolve,jitteredMs))}function buildLockConflictError(id,info,waitedMs){const waitedSuffix=waitedMs>0?` after waiting ${waitedMs}ms`:"";return new PmCliError(`Item ${id} is locked${lockOwnerSuffix(info)}${waitedSuffix}`,EXIT_CODE.CONFLICT,{code:"lock_conflict",recovery:{retry_after_ms:LOCK_CONFLICT_RETRY_HINT_MS}})}function resolveLockOverrideRelease(result){if(typeof result=="function")return result;if(typeof result=="object"&&result!==null&&"release"in result){const release=result.release;return typeof release=="function"?release:null}return null}function throwIfStaleLockNeedsForce(id,lockInfo,force,forceRequired){if(!force&&forceRequired){const warningSuffix=lockInfo.warnings.length>0?` (${lockInfo.warnings.join(",")})`:"";throw new PmCliError(`Item ${id} lock is stale${warningSuffix}; rerun with --force when supported for this command`,EXIT_CODE.CONFLICT)}}function parseStaleCleanupGateOwner(raw){let parsed;try{parsed=JSON.parse(raw)}catch{return null}if(typeof parsed!="object"||parsed===null||Array.isArray(parsed))return null;const candidate=parsed,pid=candidate.pid,token=candidate.token,processStartIdentity=candidate.process_start_identity;return typeof pid!="number"||!Number.isInteger(pid)||pid<=0||typeof token!="string"||token.length===0||processStartIdentity!==void 0&&(typeof processStartIdentity!="string"||!/^\d+$/u.test(processStartIdentity))?null:{pid,token,...typeof processStartIdentity=="string"?{process_start_identity:processStartIdentity}:{}}}async function readStaleCleanupGateOwner(gatePath){try{return parseStaleCleanupGateOwner(await fs.readFile(path.join(gatePath,STALE_CLEANUP_GATE_OWNER_FILE),"utf8"))}catch{return null}}function isProcessAlive(pid){if(!Number.isSafeInteger(pid)||pid<=0)return!1;try{return process.kill(pid,0),!0}catch(error){return!isErrno(error,"ESRCH")}}function parseLinuxProcessStartIdentity(raw){const closeParenIndex=raw.lastIndexOf(")");if(closeParenIndex<0)return null;const startTime=raw.slice(closeParenIndex+2).trim().split(/\s+/u)[19];return startTime!==void 0&&/^\d+$/u.test(startTime)?startTime:null}async function readProcessStartIdentity(pid){try{return parseLinuxProcessStartIdentity(await fs.readFile(`/proc/${pid}/stat`,"utf8"))}catch{return null}}async function captureProcessIdentity(pid=process.pid){const processStartIdentity=await readProcessStartIdentity(pid);return{pid,...processStartIdentity===null?{}:{process_start_identity:processStartIdentity}}}async function isProcessIdentityAlive(identity,unverifiedAgeMs,maxUnverifiedAgeMs){if(!isProcessAlive(identity.pid))return!1;const currentStartIdentity=await readProcessStartIdentity(identity.pid);return identity.process_start_identity!==void 0&¤tStartIdentity!==null?currentStartIdentity===identity.process_start_identity:unverifiedAgeMs<=maxUnverifiedAgeMs}async function removeStaleCleanupGateDirectory(gatePath){try{return await fs.rm(gatePath,{recursive:!0,force:!0}),!0}catch{return!1}}async function releaseStaleCleanupGate(gatePath,token){const owner=await readStaleCleanupGateOwner(gatePath);owner===null||owner.token!==token||await removeStaleCleanupGateDirectory(gatePath)}async function tryCreateStaleCleanupGate(gatePath){try{await fs.mkdir(gatePath)}catch(error){return isErrno(error,"EEXIST"),null}const owner={...await captureProcessIdentity(),token:randomUUID()};try{await fs.writeFile(path.join(gatePath,STALE_CLEANUP_GATE_OWNER_FILE),`${JSON.stringify(owner)}
|
|
3
|
+
`,"utf8")}catch{return await removeStaleCleanupGateDirectory(gatePath),null}return owner}async function removeExpiredStaleCleanupGate(gatePath){let gateAgeMs;try{const stats=await fs.stat(gatePath);if(gateAgeMs=Date.now()-stats.mtimeMs,gateAgeMs<=STALE_CLEANUP_GATE_STALE_MS)return!1}catch(error){return isFileMissingError(error)}const owner=await readStaleCleanupGateOwner(gatePath);return owner!==null&&await isProcessIdentityAlive(owner,gateAgeMs,STALE_CLEANUP_GATE_MAX_UNVERIFIED_MS)?!1:removeStaleCleanupGateDirectory(gatePath)}async function acquireStaleCleanupGate(lockPath,_id){const gatePath=`${lockPath}${STALE_CLEANUP_GATE_SUFFIX}`,owner=await tryCreateStaleCleanupGate(gatePath);if(owner!==null)return async()=>releaseStaleCleanupGate(gatePath,owner.token);if(!await removeExpiredStaleCleanupGate(gatePath))return null;const recoveredOwner=await tryCreateStaleCleanupGate(gatePath);return recoveredOwner===null?null:async()=>releaseStaleCleanupGate(gatePath,recoveredOwner.token)}async function removeConfirmedStaleLock(params){const releaseCleanupGate=await acquireStaleCleanupGate(params.lockPath,params.id);if(releaseCleanupGate===null)return{lockInfo:params.fallbackLockInfo,shouldRetryCreate:!1,staleRemovalCounted:!1};try{const currentLockInfo=await readLockInfo(params.lockPath);if(currentLockInfo.info===null&¤tLockInfo.warnings.length===0)return{lockInfo:currentLockInfo,shouldRetryCreate:!0,staleRemovalCounted:!1};if(!isStaleLock(currentLockInfo.info,params.ttlSeconds))return{lockInfo:currentLockInfo,shouldRetryCreate:!1,staleRemovalCounted:!1};if(throwIfStaleLockNeedsForce(params.id,currentLockInfo,params.force,params.forceRequiredForStaleLock),params.staleRemovals>=MAX_STALE_LOCK_REMOVALS)throw buildLockConflictError(params.id,currentLockInfo.info,Date.now()-params.startedAtMs);return{lockInfo:currentLockInfo,shouldRetryCreate:await unlinkLockWithHook(params.lockPath,"lock:stale_remove"),staleRemovalCounted:!0}}finally{await releaseCleanupGate()}}const _testOnly={parseLockInfo,readLockInfo,isErrno,isLockCreateContention,buildLockPayload,isStaleLock,lockOwnerSuffix,resolveLockWaitMs,parseLinuxProcessStartIdentity,readProcessStartIdentity,acquireStaleCleanupGate,removeConfirmedStaleLock};async function acquireLock(pmRoot,id,ttlSeconds,owner,force=!1,forceRequiredForStaleLock=!0,waitMs,options={}){const maxWaitMs=parseNonNegativeIntegerWaitMs(options.maxWaitMs),lockOverride=await runActiveServiceOverride("lock_acquire",{pm_root:pmRoot,id,ttl_seconds:ttlSeconds,owner,force,force_required_for_stale_lock:forceRequiredForStaleLock,...maxWaitMs===void 0?{}:{max_wait_ms:maxWaitMs}});if(lockOverride.handled){const release=resolveLockOverrideRelease(lockOverride.result);if(release)return async()=>{await Promise.resolve(release()),await runActiveServiceOverride("lock_release",{pm_root:pmRoot,id,owner})}}const lockPath=getLockPath(pmRoot,id),waitBudgetMs=cappedLockWaitMs(waitMs,maxWaitMs),startedAtMs=Date.now();let staleRemovals=0,backoffMs=LOCK_WAIT_INITIAL_DELAY_MS;const token=randomUUID();for(;;)try{return await createLockFile(lockPath,id,owner,ttlSeconds,token,options.createParentDirectories!==!1),async()=>{await releaseOwnedLock(lockPath,id,owner,token),await runActiveServiceOverride("lock_release",{pm_root:pmRoot,id,owner})}}catch(error){if(!await isLockCreateContention(error,lockPath))throw new PmCliError(`Failed to acquire lock for ${id}: ${toErrorMessage(error)}`,EXIT_CODE.GENERIC_FAILURE);let lockInfo=await readLockInfo(lockPath);if(isStaleLock(lockInfo.info,ttlSeconds)){const staleRemoval=await removeConfirmedStaleLock({lockPath,id,ttlSeconds,force,forceRequiredForStaleLock,staleRemovals,waitBudgetMs,startedAtMs,fallbackLockInfo:lockInfo});if(lockInfo=staleRemoval.lockInfo,staleRemoval.staleRemovalCounted&&(staleRemovals+=1),staleRemoval.shouldRetryCreate)continue}const elapsedMs=Date.now()-startedAtMs;if(waitBudgetMs===0||elapsedMs>=waitBudgetMs)throw buildLockConflictError(id,lockInfo.info,waitBudgetMs===0?0:elapsedMs);await sleepWithJitter(Math.min(backoffMs,waitBudgetMs-elapsedMs)),backoffMs=Math.min(backoffMs*2,LOCK_WAIT_MAX_DELAY_MS)}}export{_testOnly,acquireLock,captureProcessIdentity,hasUnexpiredLockOwner,isProcessIdentityAlive,readProcessStartIdentity};
|
|
4
4
|
//# sourceMappingURL=lock.js.map
|
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared projection helper for mutation command results.
|
|
3
|
-
*
|
|
4
|
-
* Mutation commands (create/update/close/append/update-many) return a result
|
|
5
|
-
* envelope that carries a `changed_fields` string array. On create this array simply
|
|
6
|
-
* re-lists every field the command just set, which the item echo above it already
|
|
7
|
-
* shows, so for high-volume agent loops it is ~50% redundant payload. This helper
|
|
8
|
-
* lets the CLI (`--no-changed-fields`) and the MCP agent path trim that array down
|
|
9
|
-
* to a deterministic `changed_field_count` without losing mutation evidence.
|
|
10
|
-
*
|
|
11
|
-
* Compaction is deliberately scoped to the mutation envelope only:
|
|
12
|
-
* - the envelope's own top-level `changed_fields` (create/update/close/append), and
|
|
13
|
-
* - `rows[*].changed_fields` (update-many reports its delta per row).
|
|
14
|
-
* - recognized start/pause/close composition steps sharing the root item id.
|
|
15
|
-
* It does NOT recurse into arbitrary nested objects, so unrelated payloads that
|
|
16
|
-
* legitimately carry `changed_fields` (for example `pm history --diff` entries, or a
|
|
17
|
-
* custom runtime metadata field) are left untouched.
|
|
18
|
-
*
|
|
19
|
-
* The helper is pure and side-effect free, reused by both the output layer and the
|
|
20
|
-
* MCP server, and returns the original reference unchanged when nothing is compacted.
|
|
21
|
-
*/
|
|
22
1
|
/** Controls whether mutation output keeps full changed fields or compact counts. */
|
|
23
2
|
export type ChangedFieldsMode = "full" | "compact";
|
|
24
3
|
/** Documents the mutation projection options payload exchanged by command, SDK, and package integrations. */
|
|
@@ -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]="9bdf8ad1-8d1e-5e3e-a23a-ba1d4293402b")}catch{}})();import{unicodeSafePrefix}from"../shared/text-normalization.js";const CHANGED_FIELDS_KEY="changed_fields",CHANGED_FIELD_COUNT_KEY="changed_field_count",ROWS_KEY="rows",UPDATE_MANY_MUTATION_MODES=new Set(["apply","rollback"]),DELETE_OUTCOMES=new Set(["deleted","would_delete"]),COMPACT_RECURRENCE_TEXT_LIMIT=256,COMPOUND_MUTATION_STEPS={start_task:["claim","update"],pause_task:["update","release"],close_task:["close","release"]};function projectCompoundMutation(result,options){if(!isPlainObject(result)||typeof result.action!="string"||typeof result.id!="string"||result.id.length===0)return null;const steps=Object.hasOwn(COMPOUND_MUTATION_STEPS,result.action)?COMPOUND_MUTATION_STEPS[result.action]:void 0;if(!steps||!steps.every(step=>{const value=result[step];return isPlainObject(value)&&isPlainObject(value.item)&&value.item.id===result.id&&Array.isArray(value.changed_fields)&&value.changed_fields.every(field=>typeof field=="string")}))return null;const final=result[steps.at(-1)],identity=projectIdOnlyResult(final);return options.idOnly?identity:!options.compactEnvelope&&options.changedFields!=="compact"?null:{...result,...options.compactEnvelope?{...identity,changed_field_count:new Set(steps.flatMap(step=>result[step].changed_fields)).size}:{},...Object.fromEntries(steps.map(step=>[step,projectMutationResult(result[step],options)]))}}function truncateCompactRecurrenceText(value){return typeof value!="string"||value.length<=COMPACT_RECURRENCE_TEXT_LIMIT?value:`${unicodeSafePrefix(value,COMPACT_RECURRENCE_TEXT_LIMIT-1)}\u2026`}function projectCompactRecurrence(value){if(!isPlainObject(value))return null;const recurrence={...value};return recurrence.reason=truncateCompactRecurrenceText(recurrence.reason),isPlainObject(recurrence.previous_terminal)&&(recurrence.previous_terminal=Object.fromEntries(Object.entries(recurrence.previous_terminal).map(([key,entry])=>[key,truncateCompactRecurrenceText(entry)]))),recurrence}function isPlainObject(value){if(typeof value!="object"||value===null||Array.isArray(value))return!1;const proto=Object.getPrototypeOf(value);return proto===null||proto===Object.prototype}function compactOwnChangedFields(envelope){const changedFields=envelope[CHANGED_FIELDS_KEY];if(!Array.isArray(changedFields))return null;const projected=Object.getPrototypeOf(envelope)===null?Object.create(null):{};for(const[key,value]of Object.entries(envelope))key!==CHANGED_FIELDS_KEY&&(projected[key]=value);return projected[CHANGED_FIELD_COUNT_KEY]=changedFields.length,projected}function isMutationEnvelope(value){return"item"in value&&Array.isArray(value[CHANGED_FIELDS_KEY])}function isUpdateManyMutationEnvelope(value){return typeof value.mode=="string"&&UPDATE_MANY_MUTATION_MODES.has(value.mode)&&Array.isArray(value[ROWS_KEY])}function replaceRows(envelope,rows){const projected=Object.getPrototypeOf(envelope)===null?Object.create(null):{};return Object.assign(projected,envelope),projected[ROWS_KEY]=rows,projected}function projectIdOnlyResult(result){if(!isPlainObject(result))return null;const subject=isPlainObject(result.item)?result.item:isPlainObject(result.plan)?result.plan:null;if(subject===null)return null;const id=typeof subject.id=="string"?subject.id:void 0,status=typeof result.outcome=="string"&&DELETE_OUTCOMES.has(result.outcome)?result.outcome:typeof subject.status=="string"?subject.status:void 0;return id?status?{id,status,...typeof result.deleted=="boolean"?{deleted:result.deleted}:{}}:{id}:null}function projectCompactMutationEnvelope(result,includeItem){if(!isPlainObject(result))return null;if(isPlainObject(result.plan)&&isPlainObject(result.mutation_receipt)&&result.mutation_receipt.kind==="plan_mutation"&&result.mutation_receipt.id===result.plan.id&&result.mutation_receipt.action===result.action)return result.mutation_receipt;if(!includeItem||!isPlainObject(result.item)||typeof result.item.id!="string")return null;const changedFields=result[CHANGED_FIELDS_KEY];if(!Array.isArray(changedFields))return null;const compact={id:result.item.id,...typeof result.outcome=="string"&&DELETE_OUTCOMES.has(result.outcome)?{status:result.outcome}:typeof result.item.status=="string"?{status:result.item.status}:{},...typeof result.deleted=="boolean"?{deleted:result.deleted}:{},...typeof result.previous_status=="string"?{previous_status:result.previous_status}:{},changed_field_count:changedFields.length};return appendCompactMutationEvidence(result,result.item,compact),compact}function appendCompactMutationEvidence(result,item,compact){const closeReason=typeof result.close_reason=="string"?result.close_reason:typeof item.close_reason=="string"?item.close_reason:void 0;closeReason!==void 0&&(compact.close_reason=closeReason);const recurrence=projectCompactRecurrence(result.recurrence);recurrence!==null&&(compact.recurrence=recurrence),Array.isArray(result.warnings)&&result.warnings.length>0&&(compact.warnings=result.warnings);for(const key of["recovery","follow_up","handoff"])isPlainObject(result[key])&&(compact[key]=result[key]);if(typeof result.claimed_by=="string"||typeof result.released_by=="string")for(const key of["claimed_by","released_by","previous_assignee","forced","skipped","available","attempts","suggestions"])Object.hasOwn(result,key)&&(compact[key]=result[key])}function compactUpdateManyRows(envelope){const rows=isUpdateManyMutationEnvelope(envelope)?envelope[ROWS_KEY]:void 0;if(!Array.isArray(rows))return{projected:envelope,changed:!1};let rowsChanged=!1;const nextRows=rows.map(row=>{if(!isPlainObject(row))return row;const compactedRow=compactOwnChangedFields(row);return compactedRow?(rowsChanged=!0,compactedRow):row});return rowsChanged?{projected:replaceRows(envelope,nextRows),changed:!0}:{projected:envelope,changed:!1}}function projectMutationResult(result,options={}){const compound=projectCompoundMutation(result,options);if(compound!==null)return compound;if(options.idOnly===!0){const idOnly=projectIdOnlyResult(result);if(idOnly!==null)return idOnly}if(options.compactEnvelope===!0||options.changedFields==="compact"){const compact=projectCompactMutationEnvelope(result,options.compactEnvelope===!0);if(compact!==null)return compact}if((options.changedFields??"full")==="full"||!isPlainObject(result))return result;let changed=!1,projected=result;const compactedTop=isMutationEnvelope(result)?compactOwnChangedFields(result):null;compactedTop!==null&&(projected=compactedTop,changed=!0);const rowProjection=compactUpdateManyRows(projected);return rowProjection.changed&&(projected=rowProjection.projected,changed=!0),changed?projected:result}export{projectMutationResult};
|
|
2
2
|
//# sourceMappingURL=mutation-projection.js.map
|
|
@@ -1,7 +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]="
|
|
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]="ee7a4cf5-ca04-5ee7-affe-3cc1184e04a0")}catch{}})();import{getActiveCommandContext,runActiveCommandOverride,runActiveRendererOverride,runActiveServiceOverrideSync,setActiveCommandResult}from"../extensions/index.js";import{EXIT_CODE}from"../shared/constants.js";import{isHostOutputSuppressed}from"./output-control.js";import{projectMutationResult}from"./mutation-projection.js";import{attachReadOutputContracts}from"../../sdk/context-intent-contracts.js";import{attachOutputTokenAccounting}from"../../sdk/output-token-accounting.js";import{propagateContextUsageServingReceipt}from"../../sdk/context-usage.js";import{isReadOutputBudgetExceeded,resolveReadOutputEncoding}from"../../sdk/read-output-contracts.js";import{encode as encodeToon}from"@toon-format/toon";import{encodePmTableRows}from"../../sdk/output/table-rows.js";const DECLARED_PROCESS_EXIT_CODES=new Set(Object.values(EXIT_CODE)),COLLECTION_COUNT_ALIASES=new Map([["notes_count","notes"],["tests_count","tests"]]),NATIVE_OUTPUT_MARKER="__pm_native_output";let streamErrorHandlersInstalled=!1;function isPlainObject(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function setActiveCommandResultOmitted(source){const omitted={read_output:{result_omitted:!0}};propagateContextUsageServingReceipt(source,omitted),setActiveCommandResult(omitted)}function setActiveCommandDeliveryResult(result,receiptSource,structuredDeliveryPreserved){if(structuredDeliveryPreserved){setActiveCommandResult(result);return}setActiveCommandResultOmitted(receiptSource)}function stripNativeOutputMarker(result){if(!isPlainObject(result)||result[NATIVE_OUTPUT_MARKER]!==!0)return result;const{[NATIVE_OUTPUT_MARKER]:_marker,...rest}=result;return rest}function isBrokenPipeError(error){return typeof error=="object"&&error!==null&&error.code==="EPIPE"}function markStdoutBrokenPipeExitCode(){(process.exitCode===void 0||process.exitCode===EXIT_CODE.SUCCESS)&&(process.exitCode=EXIT_CODE.SUCCESS)}function markStderrBrokenPipeExitCode(){(process.exitCode===void 0||process.exitCode===EXIT_CODE.SUCCESS)&&(process.exitCode=EXIT_CODE.GENERIC_FAILURE)}function markBrokenPipeExitCode(target){if(target==="stdout"){markStdoutBrokenPipeExitCode();return}markStderrBrokenPipeExitCode()}function handleUnhandledStreamError(error){const unhandled=error instanceof Error?error:new Error(String(error));setImmediate(()=>{throw unhandled})}function installStreamErrorHandlers(){streamErrorHandlersInstalled||(streamErrorHandlersInstalled=!0,process.stdout.on("error",error=>{if(isBrokenPipeError(error)){markBrokenPipeExitCode("stdout");return}handleUnhandledStreamError(error)}),process.stderr.on("error",error=>{if(isBrokenPipeError(error)){markBrokenPipeExitCode("stderr");return}handleUnhandledStreamError(error)}))}function writeToStream(target,text){installStreamErrorHandlers();try{return target==="stdout"?process.stdout.write(text):process.stderr.write(text),!0}catch(error){if(isBrokenPipeError(error))return markBrokenPipeExitCode(target),!1;throw error}}function writeStdout(text){return writeToStream("stdout",text)}function writeStderr(text){return writeToStream("stderr",text)}function renderScalar(value){return typeof value=="string"?JSON.stringify(value):typeof value=="number"||typeof value=="boolean"?String(value):value===null?"null":JSON.stringify(value)}function tabularObjectArray(value){const keys=Object.keys(value[0]);return keys.length>0&&value.every(entry=>Object.keys(entry).length===keys.length&&keys.every(key=>{if(!Object.hasOwn(entry,key))return!1;const cell=entry[key];return cell===null||typeof cell=="string"||typeof cell=="number"||typeof cell=="boolean"}))}function indentToon(encoded,depth){const indent=" ".repeat(depth);return encoded.split(`
|
|
2
2
|
`).map(line=>`${indent}${line}`).join(`
|
|
3
3
|
`)}function isNestedTableCandidateBounded(rows){const columns=new Set;let presentCells=0;for(const row of rows){const keys=Object.keys(row);presentCells+=keys.length;for(const key of keys)columns.add(key)}return rows.length*columns.size<=presentCells*2}function renderToonObjectEntry(key,entry,depth,allowNestedTable){const indent=" ".repeat(depth);if(!isPlainObject(entry)&&!Array.isArray(entry))return`${indent}${key}: ${renderScalar(entry)}`;if(Array.isArray(entry)){if(entry.length===0)return`${indent}${key}: []`;const expanded=indentToon(encodeToon({[key]:entry}),depth);if(allowNestedTable&&entry.length>=2&&entry.every(isPlainObject)&&!tabularObjectArray(entry)&&isNestedTableCandidateBounded(entry)){const table=encodePmTableRows(entry),tabular=indentToon(encodeToon({[key]:table.rows,[`${key}_encoding`]:table.encoding}),depth);if(Buffer.byteLength(tabular)<Buffer.byteLength(expanded))return tabular}return expanded}return isPlainObject(entry)&&Object.keys(entry).length===0?`${indent}${key}: {}`:`${indent}${key}:
|
|
4
|
-
${renderToonValue(entry,depth+1)}`}function compactToonValue(value,omitDuplicateCountAliases=!0){if(value!=null){if(Array.isArray(value)){const compactedEntries=value.map(entry=>compactToonValue(entry,omitDuplicateCountAliases)).filter(entry=>entry!==void 0);return compactedEntries.length>0?compactedEntries:void 0}if(isPlainObject(value)){const compacted={},entries=Object.entries(value).filter(([key,entry])=>{const canonicalCount=COLLECTION_COUNT_ALIASES.get(key);return!omitDuplicateCountAliases||canonicalCount===void 0||!isPlainObject(value.collection_counts)||entry!==value.collection_counts[canonicalCount]});for(const[key,entry]of entries){if(key==="omitted_field_groups"&&Array.isArray(entry)&&entry.length===0){compacted[key]=[];continue}const compactedEntry=compactToonValue(entry,omitDuplicateCountAliases);compactedEntry!==void 0&&(compacted[key]=compactedEntry)}return Object.keys(compacted).length>0?compacted:void 0}return value}}function renderToonValue(value,depth){const indent=" ".repeat(depth);if(Array.isArray(value))return value.length===0?"[]":indentToon(encodeToon(value),depth);if(isPlainObject(value)){const entries=Object.entries(value);return entries.length===0?"{}":entries.map(([key,entry])=>renderToonObjectEntry(key,entry,depth,!Object.hasOwn(value,`${key}_encoding`))).join(`
|
|
4
|
+
${renderToonValue(entry,depth+1)}`}function compactToonValue(value,omitDuplicateCountAliases=!0){if(value!=null){if(Array.isArray(value)){const compactedEntries=value.map(entry=>compactToonValue(entry,omitDuplicateCountAliases)).filter(entry=>entry!==void 0);return compactedEntries.length>0?compactedEntries:void 0}if(isPlainObject(value)){const compacted={},entries=Object.entries(value).filter(([key,entry])=>{const canonicalCount=COLLECTION_COUNT_ALIASES.get(key);return!omitDuplicateCountAliases||canonicalCount===void 0||!isPlainObject(value.collection_counts)||entry!==value.collection_counts[canonicalCount]});for(const[key,entry]of entries){if(key==="omitted_field_groups"&&Array.isArray(entry)&&entry.length===0){compacted[key]=[];continue}const compactedEntry=compactToonValue(entry,omitDuplicateCountAliases);compactedEntry!==void 0&&(compacted[key]=compactedEntry)}return Object.keys(compacted).length>0?compacted:void 0}return value}}function renderToonValue(value,depth){const indent=" ".repeat(depth);if(Array.isArray(value))return value.length===0?"[]":indentToon(encodeToon(value),depth);if(isPlainObject(value)){const entries=Object.entries(value);return entries.length===0?"{}":entries.map(([key,entry])=>renderToonObjectEntry(key,entry,depth,!Object.hasOwn(value,`${key}_encoding`)&&!(key==="checks"&&isPlainObject(value.verdict)&&value.verdict.authority==="ok"))).join(`
|
|
5
5
|
`)}return`${indent}${renderScalar(value)}`}function renderDefaultMarkdownResult(value){if(!isPlainObject(value)||value.output_default!=="markdown"||typeof value.view!="string"||!Array.isArray(value.events)||!Array.isArray(value.days))return null;const lines=[`# pm calendar (${value.view})`,""],summary=isPlainObject(value.summary)?value.summary:{};if(lines.push(`- events: ${String(summary.events??0)}`),lines.push(""),value.events.length===0)return lines.push("No calendar events matched the selected filters."),`${lines.join(`
|
|
6
6
|
`)}
|
|
7
7
|
`;for(const event of value.events){if(!isPlainObject(event))continue;const kind=typeof event.kind=="string"?event.kind:"event",title=typeof event.item_title=="string"?event.item_title:"",itemId=typeof event.item_id=="string"?event.item_id:"",reminderText=typeof event.reminder_text=="string"&&event.reminder_text.length>0?` ${event.reminder_text}`:"";lines.push(`- [${kind}] ${itemId} ${title}${reminderText}`.trim())}return`${lines.join(`
|
|
@@ -17,7 +17,7 @@ export { normalizeStatusToken } from "./status-token.js";
|
|
|
17
17
|
* - A same-status no-op (from === to) is ALWAYS allowed.
|
|
18
18
|
*
|
|
19
19
|
* This module is intentionally dependency-light and fully unit-testable; the
|
|
20
|
-
*
|
|
20
|
+
* SDK lifecycle writers share enforcement through lifecycle/workflow-transition.
|
|
21
21
|
*/
|
|
22
22
|
export interface NormalizedTypeWorkflow {
|
|
23
23
|
/** Lower-cased type name used for case-insensitive matching. */
|
|
@@ -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]="77a7b77a-907c-541d-ac55-e06174dbbf11")}catch{}})();import{normalizeStatusToken}from"./status-token.js";import{normalizeStatusToken as normalizeStatusToken2}from"./status-token.js";function normalizeTypeName(value){return typeof value=="string"?value.trim().toLowerCase():""}function resolveStatusId(value,statusRegistry){const token=normalizeStatusToken(value);return token.length===0?"":statusRegistry?.alias_to_id?.get(token)??token}function resolveTypeWorkflows(schema){const rawWorkflows=Array.isArray(schema?.type_workflows)?schema.type_workflows:[],byType=new Map;for(const entry of rawWorkflows){const type=normalizeTypeName(entry?.type);if(type.length===0||!Array.isArray(entry?.allowed_transitions))continue;const pairs=entry.allowed_transitions,record=byType.get(type)??{pairs:[],denyAll:!1};pairs.length===0&&(record.denyAll=!0);for(const pair of pairs){if(!Array.isArray(pair)||pair.length!==2)continue;const from=normalizeStatusToken(pair[0]),to=normalizeStatusToken(pair[1]);from.length===0||to.length===0||record.pairs.some(candidate=>candidate[0]===from&&candidate[1]===to)||record.pairs.push([from,to])}byType.set(type,record)}return[...byType.entries()].filter(([,record])=>record.pairs.length>0||record.denyAll).map(([type,record])=>({type,allowed_transitions:record.pairs})).sort((left,right)=>left.type.localeCompare(right.type))}function evaluateTransition(input){const typeName=normalizeTypeName(input.typeName),matched=input.typeWorkflows.find(workflow=>workflow.type===typeName);if(!matched)return{allowed:!0,hasRule:!1,allowedTransitions:[]};const from=resolveStatusId(input.fromStatus,input.statusRegistry),to=resolveStatusId(input.toStatus,input.statusRegistry);return from.length>0&&from===to?{allowed:!0,hasRule:!0,allowedTransitions:matched.allowed_transitions}:{allowed:matched.allowed_transitions.some(pair=>{const ruleFrom=resolveStatusId(pair[0],input.statusRegistry),ruleTo=resolveStatusId(pair[1],input.statusRegistry);return ruleFrom===from&&ruleTo===to}),hasRule:!0,allowedTransitions:matched.allowed_transitions}}function describeAllowedTransitions(allowedTransitions){return allowedTransitions.length===0?"(no transitions allowed)":allowedTransitions.map(pair=>`${pair[0]} -> ${pair[1]}`).join(", ")}export{describeAllowedTransitions,evaluateTransition,normalizeStatusToken2 as normalizeStatusToken,resolveTypeWorkflows};
|
|
2
2
|
//# sourceMappingURL=type-workflows.js.map
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
/** Normalizes text to lowercase whitespace-collapsed form for stable matching and comparison. */
|
|
7
7
|
export declare function normalizeLowercaseWhitespace(value:string):string;
|
|
8
|
+
/** Return a UTF-16 prefix without splitting a valid surrogate pair at its boundary. */
|
|
9
|
+
export declare function unicodeSafePrefix(value:string,end:number):string;
|
|
8
10
|
/** Implements tokenize alpha numeric for the public runtime surface of this module. */
|
|
9
11
|
export declare function tokenizeAlphaNumeric(value:string):string[];
|
|
10
12
|
/** Implements jaccard similarity for the public runtime surface of this module. */
|
|
@@ -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]="4a7b042c-7fb8-57a5-8f94-de44f82d7589")}catch{}})();function normalizeLowercaseWhitespace(value){return value.trim().toLowerCase().replace(/\s+/g," ")}function unicodeSafePrefix(value,end){const prefix=value.slice(0,end),last=prefix.charCodeAt(prefix.length-1),next=value.charCodeAt(prefix.length);return last>=55296&&last<=56319&&next>=56320&&next<=57343?prefix.slice(0,-1):prefix}function tokenizeAlphaNumeric(value){return normalizeLowercaseWhitespace(value).split(/[^a-z0-9]+/).filter(token=>token.length>0)}function jaccardSimilarity(leftTokens,rightTokens){if(leftTokens.length===0&&rightTokens.length===0)return 1;if(leftTokens.length===0||rightTokens.length===0)return 0;const leftSet=new Set(leftTokens),rightSet=new Set(rightTokens);let intersection=0;for(const token of leftSet)rightSet.has(token)&&(intersection+=1);const union=new Set([...leftSet,...rightSet]).size;return intersection/union}export{jaccardSimilarity,normalizeLowercaseWhitespace,tokenizeAlphaNumeric,unicodeSafePrefix};
|
|
2
2
|
//# sourceMappingURL=text-normalization.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ItemDocument } from "../../types/index.js";
|
|
2
|
+
interface ItemMutationPrecondition {
|
|
3
|
+
pmRoot:string;
|
|
4
|
+
id:string;
|
|
5
|
+
validate:(document:ItemDocument) => void;
|
|
6
|
+
}
|
|
7
|
+
/** Scope a target-specific precondition to an awaited mutation without affecting concurrent callers. */
|
|
8
|
+
export declare function runWithItemMutationPrecondition<T>(condition:ItemMutationPrecondition,operation:() => Promise<T>):Promise<T>;
|
|
9
|
+
/** Evaluate matching preconditions only after the item lock has been acquired and its document read. */
|
|
10
|
+
export declare function assertItemMutationPreconditions(pmRoot:string,document:ItemDocument):void;
|
|
11
|
+
export {};
|
|
@@ -0,0 +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]="53df109f-bd64-5879-96a6-39f70334910e")}catch{}})();import{AsyncLocalStorage}from"node:async_hooks";import path from"node:path";const preconditions=new AsyncLocalStorage;function runWithItemMutationPrecondition(condition,operation){return preconditions.run([...preconditions.getStore()??[],{...condition,pmRoot:path.resolve(condition.pmRoot)}],operation)}function assertItemMutationPreconditions(pmRoot,document){for(const condition of preconditions.getStore()??[])condition.pmRoot===path.resolve(pmRoot)&&condition.id===document.metadata.id&&condition.validate(document)}export{assertItemMutationPreconditions,runWithItemMutationPrecondition};
|
|
2
|
+
//# sourceMappingURL=item-mutation-precondition.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]="75d742ab-22c4-5a3f-8f63-74c68afa6b3f")}catch{}})();import fs from"node:fs/promises";import{buildDeletedItemError}from"../history/tombstone.js";import{normalizeHistoryOperationForWrite}from"../history/operation-contract.js";import{enforceWorkflowMutation}from"../policy/workflow-policy-store.js";import{recordItemMetadataEnumeration}from"./item-metadata-read-work.js";import path from"node:path";import{getActiveExtensionRegistrations,projectAfterCommandItemSnapshot,recordAfterCommandAffectedItem,runActiveOnReadHooks,runActiveBeforeMutationHooks,runActiveOnWriteHooks,runActiveServiceOverride}from"../extensions/index.js";import{collectRegisteredItemFieldNames}from"../extensions/item-fields.js";import{EMPTY_CANONICAL_DOCUMENT,EXIT_CODE,TYPE_TO_FOLDER}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{levenshteinDistanceWithinLimit}from"../shared/levenshtein.js";import{appendHistoryEntry,createHistoryEntry}from"../history/history.js";import{enforceHistoryStreamPolicyForItem}from"../history/history-stream-policy.js";import{canonicalDocument,parseItemDocument,serializeItemDocument}from"../item/item-format.js";import{resolveItemTypeRegistry}from"../item/type-registry.js";import{effectiveItemFormatVersion,requiredItemFormatVersion}from"../item/item-format-version.js";import{assertProjectRuntimeFormatGuard}from"../../sdk/environment/project-runtime-compatibility.js";import{acquireLock}from"../lock/lock.js";import{writeFileAtomic}from"../fs/fs-utils.js";import{isUtf8}from"node:buffer";import{normalizeItemId,normalizeRawItemId}from"../item/id.js";import{acquireItemMetadataDerivedIndexLock,listAllDocumentCandidatesCached,listAllDocumentsCached,listAllDocumentsCachedLight,refreshItemMetadataDerivedIndex}from"./item-metadata-cache.js";import{getHistoryPath,getItemPath,ITEM_FILE_EXTENSIONS,resolveWorkspaceRoot}from"./paths.js";import{resolveGovernanceKnobs}from"./settings.js";import{assertReadableTrackerRoot}from"./tracker-preflight.js";import{resolveClaimPrincipal}from"../shared/author.js";import{nowIso}from"../shared/time.js";async function fileExists(targetPath){try{return await fs.access(targetPath),!0}catch{return!1}}function isErrno(error,code){return typeof error=="object"&&error!==null&&"code"in error&&error.code===code}function appendWarning(warnings,warning){warnings&&(warnings.includes(warning)||warnings.push(warning))}function resolveActiveExtensionFieldNames(explicit){return explicit??collectRegisteredItemFieldNames(getActiveExtensionRegistrations())}function resolveItemFormatSearchOrder(preferredFormat){return preferredFormat==="toon"?["toon","json_markdown"]:preferredFormat==="json_markdown"?["json_markdown","toon"]:["toon","json_markdown"]}async function locateItem(pmRoot,rawId,idPrefix="pm-",preferredFormat,typeToFolder=TYPE_TO_FOLDER){const trimmedRawId=rawId.trim(),exactRawId=trimmedRawId.startsWith("#")?trimmedRawId.slice(1):trimmedRawId;if(exactRawId.length===0)return null;const normalizedId=normalizeItemId(rawId,idPrefix),rawNormalizedId=normalizeRawItemId(rawId),candidateIds=[...new Set([exactRawId,normalizedId,rawNormalizedId])].filter(candidateId=>candidateId.length>0),entries=Object.entries(typeToFolder),searchOrder=resolveItemFormatSearchOrder(preferredFormat);for(const candidateId of candidateIds){const matches=new Map;for(const[type]of entries)for(const itemFormat of searchOrder){const itemPath=getItemPath(pmRoot,type,candidateId,itemFormat,typeToFolder);await fileExists(itemPath)&&matches.set(itemPath,matches.get(itemPath)??{id:candidateId,type,itemPath,item_format:itemFormat})}if(matches.size>1){const paths=[...matches.keys()].map(itemPath=>path.relative(pmRoot,itemPath).split(path.sep).join("/")).sort();throw new PmCliError(`Item ${candidateId} has ambiguous identity across ${paths.join(", ")}. Preserve both documents and inspect pm ops validate --check-storage-integrity before resolving the collision.`,EXIT_CODE.CONFLICT,{code:"item_identity_ambiguous",item_id:candidateId,paths})}for(const match of matches.values())return match}return null}async function readLocatedItem(item,options={}){const snapshot=await readLocatedItemSnapshot(item,options);if(snapshot.error!==null)throw snapshot.error;return{raw:snapshot.raw,document:snapshot.document}}async function readLocatedItemSnapshot(item,options={}){const bytes=await fs.readFile(item.itemPath);if(!isUtf8(bytes))throw new PmCliError("Item contains invalid UTF-8; preserve a binary backup before recovering it.",EXIT_CODE.CONFLICT,{code:"item_document_encoding_invalid",item_id:item.id,item_path:item.itemPath,byte_length:bytes.length,empty:!1});const raw=bytes.toString("utf8");await runActiveOnReadHooks({path:item.itemPath,scope:"project"});let document;try{document=parseItemDocument(raw,{format:item.item_format,requireSupportedFormat:!0,schema:options.schema,extensionFieldNames:resolveActiveExtensionFieldNames(options.extensionFieldNames),onWarning:warning=>appendWarning(options.warnings,warning)})}catch(error){if(error instanceof PmCliError&&error.code==="item_format_version_unsupported")throw new PmCliError(`Item ${item.id}: ${error.message}`,error.exitCode,{...error.context,item_id:item.id,item_path:item.itemPath});if(error instanceof PmCliError&&error.code==="item_document_invalid")return{raw,document:null,error:new PmCliError(`Cannot read ${item.id} at ${item.itemPath}${bytes.length===0?" (zero-length file)":""}: ${error.message}`,error.exitCode,{...error.context,item_id:item.id,item_path:item.itemPath,byte_length:bytes.length,empty:bytes.length===0,nextSteps:[`Run pm history ${item.id} --full, then pm restore ${item.id} <version> to recover a recorded state.`]})};throw error}return{raw,document,error:null}}async function listAllItemMetadata(pmRoot,preferredFormat,typeToFolder=TYPE_TO_FOLDER,warnings,schema){await assertReadableTrackerRoot(pmRoot);const documents=await listAllDocumentsCached(pmRoot,preferredFormat,typeToFolder,warnings,schema);return recordItemMetadataEnumeration(documents.length),documents.map(document=>document.metadata)}async function listAllItemMetadataLight(pmRoot,preferredFormat,typeToFolder=TYPE_TO_FOLDER,warnings,schema){await assertReadableTrackerRoot(pmRoot);const documents=await listAllDocumentsCachedLight(pmRoot,preferredFormat,typeToFolder,warnings,schema);return recordItemMetadataEnumeration(documents.length),documents.map(document=>document.metadata)}async function listAllItemMetadataWithBody(pmRoot,preferredFormat,typeToFolder=TYPE_TO_FOLDER,warnings,schema,options={}){await assertReadableTrackerRoot(pmRoot);const candidates=await listAllDocumentCandidatesCached(pmRoot,preferredFormat,typeToFolder,warnings,schema,{includeBody:!0,forceSourceScan:options.forceSourceScan});return recordItemMetadataEnumeration(candidates.length),candidates.map(candidate=>({...candidate.metadata,body:candidate.body}))}function createMutationGuardSdk(params){return{async get(id){const located=await locateItem(params.pmRoot,id,params.settings.id_prefix,params.settings.item_format,params.typeToFolder);if(!located)return null;const{document}=await readLocatedItem(located,{schema:params.settings.schema});return{item:document.metadata,body:document.body}},list:()=>listAllItemMetadata(params.pmRoot,params.settings.item_format,params.typeToFolder,void 0,params.settings.schema)}}async function listKnownItemIds(pmRoot,typeToFolder){const folders=new Set(Object.values(typeToFolder)),allIds=[];return await Promise.all([...folders].map(async folder=>{try{const entries=await fs.readdir(path.join(pmRoot,folder));for(const entry of entries)for(const ext of ITEM_FILE_EXTENSIONS)if(entry.toLowerCase().endsWith(ext)){allIds.push(entry.slice(0,-ext.length));break}}catch{}})),allIds}async function buildDidYouMeanSuggestions(pmRoot,badId,idPrefix,typeToFolder){const normalized=normalizeItemId(badId,idPrefix),ids=await listKnownItemIds(pmRoot,typeToFolder);if(ids.length===0)return[];const limit=Math.max(3,Math.floor(normalized.length/2));return ids.map(id=>({id,distance:levenshteinDistanceWithinLimit(id,normalized,limit)})).filter(entry=>entry.distance!==null).sort((left,right)=>left.distance-right.distance).slice(0,3).map(entry=>entry.id)}async function buildItemNotFoundError(pmRoot,badId,idPrefix,typeToFolder){const deleted=await buildDeletedItemError(pmRoot,badId,idPrefix);if(deleted)return deleted;const suggestions=await buildDidYouMeanSuggestions(pmRoot,badId,idPrefix,typeToFolder),nextSteps=["Confirm the active --path/PM_PATH scope, then retry with a valid id."];return suggestions.length>0&&nextSteps.unshift(`Did you mean one of: ${suggestions.join(", ")}?`),new PmCliError(`Item ${badId} not found`,EXIT_CODE.NOT_FOUND,{nextSteps})}function bypassesAssigneeConflict(op,bypassAssigneeConflict){return op==="claim"||bypassAssigneeConflict===!0&&(op==="comment_add"||op==="comment_edit"||op==="comment_delete"||op==="note_add"||op==="learning_add"||op==="release"||op==="update"||op==="update_ownership_bypass"||op==="update_audit")}async function prepareLockedItem(params){const typeToFolder=params.typeToFolder??resolveItemTypeRegistry(params.settings,getActiveExtensionRegistrations()).type_to_folder,located=await locateItem(params.pmRoot,params.id,params.settings.id_prefix,params.settings.item_format,typeToFolder);if(!located)throw await buildItemNotFoundError(params.pmRoot,params.id,params.settings.id_prefix,typeToFolder);const releaseLock=await acquireLock(params.pmRoot,located.id,params.settings.locks.ttl_seconds,params.author,!!params.force,params.settings.governance.force_required_for_stale_lock,params.settings.locks.wait_ms);try{const warnings=[],{raw:originalRaw,document}=await readLocatedItem(located,{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames,warnings}),assigned=document.metadata.assignee?.trim(),assignedPrincipal=document.metadata.claim_principal?.trim()||assigned,callerPrincipal=resolveClaimPrincipal(params.author),governance=resolveGovernanceKnobs(params.settings);if(assigned&&assignedPrincipal!==callerPrincipal&&!params.force&&!bypassesAssigneeConflict(params.op,params.bypassAssigneeConflict)){if(governance.ownership_enforcement==="strict")throw new PmCliError(`Item ${located.id} is assigned to ${assigned}. Use --force to override.`,EXIT_CODE.CONFLICT);governance.ownership_enforcement==="warn"&&warnings.push(`ownership_warning:assignee_conflict:${located.id}:${assigned}`)}return{typeToFolder,located,originalRaw,document,warnings,releaseLock}}catch(error){throw await releaseLock(),error}}function resolveItemStoreWriteOverride(serviceWriteOverride,targetItemPath,serializedAfter){if(!serviceWriteOverride.handled||typeof serviceWriteOverride.result!="object"||serviceWriteOverride.result===null)return{effectiveTargetItemPath:targetItemPath,effectiveSerializedAfter:serializedAfter,skipItemWrite:!1};const overrideRecord=serviceWriteOverride.result;return{effectiveTargetItemPath:typeof overrideRecord.target_item_path=="string"&&overrideRecord.target_item_path.trim().length>0?overrideRecord.target_item_path:targetItemPath,effectiveSerializedAfter:typeof overrideRecord.contents=="string"?overrideRecord.contents:serializedAfter,skipItemWrite:overrideRecord.skip_write===!0}}async function rollbackMutatedItemWrite(params){if(!params.skipItemWrite){if(params.effectiveTargetItemPath!==params.originalItemPath){await writeFileAtomic(params.originalItemPath,params.originalRaw),await fs.rm(params.effectiveTargetItemPath,{force:!0});return}await writeFileAtomic(params.originalItemPath,params.originalRaw)}}async function mutateItemWithDeferredHistoryContext(params){normalizeHistoryOperationForWrite(params.op);const prepared=await prepareLockedItem({pmRoot:params.pmRoot,settings:params.settings,id:params.id,op:params.op,author:params.author,force:params.force,bypassAssigneeConflict:params.bypassAssigneeConflict,extensionFieldNames:params.extensionFieldNames,typeToFolder:params.typeToFolder}),{typeToFolder,located,originalRaw,document,warnings:parseWarnings,releaseLock}=prepared;try{const beforeDocument=canonicalDocument(document,{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),mutableDocument=canonicalDocument(structuredClone(document),{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),mutation=await params.mutate(mutableDocument);if(params.skipNoop===!0&&mutation.changedFields.length===0)return{item:beforeDocument.metadata,body:beforeDocument.body,changedFields:[],warnings:[...parseWarnings,...mutation.warnings??[]]};const historyContext=params.resolveHistoryContext?.(),requiredFormat=Math.max(requiredItemFormatVersion(beforeDocument.metadata),requiredItemFormatVersion(mutableDocument.metadata));assertProjectRuntimeFormatGuard(resolveWorkspaceRoot(params.pmRoot),requiredFormat),requiredFormat>effectiveItemFormatVersion(mutableDocument.metadata)&&(mutableDocument.metadata.pm_format_version=requiredFormat,mutation.changedFields.push("pm_format_version")),mutableDocument.metadata.updated_at=nowIso();const afterDocument=canonicalDocument(mutableDocument,{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),workflowPolicy=await enforceWorkflowMutation({pmRoot:params.pmRoot,settings:params.settings,operation:params.op,author:params.author,before:beforeDocument,after:afterDocument});await runActiveBeforeMutationHooks({pm_root:params.pmRoot,operation:params.op,before:beforeDocument,after:afterDocument,changed_fields:mutation.changedFields,sdk:createMutationGuardSdk({pmRoot:params.pmRoot,settings:params.settings,typeToFolder})});const historyPolicy=await enforceHistoryStreamPolicyForItem({pmRoot:params.pmRoot,settings:params.settings,itemId:located.id,commandLabel:params.op}),targetItemFormat="toon",serializedAfter=serializeItemDocument(afterDocument,{format:targetItemFormat,schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),targetItemPath=getItemPath(params.pmRoot,afterDocument.metadata.type,located.id,targetItemFormat,typeToFolder),historyPath=getHistoryPath(params.pmRoot,located.id),serviceWriteOverride=await runActiveServiceOverride("item_store_write",{op:params.op,pm_root:params.pmRoot,item_id:located.id,source_item_path:located.itemPath,target_item_path:targetItemPath,history_path:historyPath,item_format:targetItemFormat,before:beforeDocument,after:afterDocument,contents:serializedAfter}),{effectiveTargetItemPath,effectiveSerializedAfter,skipItemWrite}=resolveItemStoreWriteOverride(serviceWriteOverride,targetItemPath,serializedAfter),releaseDerivedIndexLock=await acquireItemMetadataDerivedIndexLock(params.pmRoot,params.author);let derivedIndexWarnings=[];try{skipItemWrite||await writeFileAtomic(effectiveTargetItemPath,effectiveSerializedAfter),!skipItemWrite&&effectiveTargetItemPath!==located.itemPath&&await fs.rm(located.itemPath);const entry=createHistoryEntry({nowIso:afterDocument.metadata.updated_at,author:params.author,op:params.op,before:beforeDocument,after:afterDocument,message:params.message,context:workflowPolicy.decisions.length===0?historyContext:{...historyContext,workflow_policies:workflowPolicy.decisions}});try{await appendHistoryEntry(historyPath,entry)}catch(error){throw await rollbackMutatedItemWrite({skipItemWrite,effectiveTargetItemPath,originalItemPath:located.itemPath,originalRaw}),error}skipItemWrite||(derivedIndexWarnings=await refreshItemMetadataDerivedIndex({pmRoot:params.pmRoot,preferredFormat:params.settings.item_format,typeToFolder,schema:params.settings.schema,itemPath:effectiveTargetItemPath,previousItemPath:located.itemPath,document:afterDocument}))}finally{await releaseDerivedIndexLock()}const hookWarnings=[...await runActiveOnWriteHooks({path:effectiveTargetItemPath,scope:"project",op:params.op,item_id:afterDocument.metadata.id,item_type:afterDocument.metadata.type,before:beforeDocument,after:afterDocument,changed_fields:mutation.changedFields}),...await runActiveOnWriteHooks({path:historyPath,scope:"project",op:`${params.op}:history`,item_id:afterDocument.metadata.id,item_type:afterDocument.metadata.type,before:beforeDocument,after:afterDocument,changed_fields:mutation.changedFields})];return recordAfterCommandAffectedItem({id:afterDocument.metadata.id,op:params.op,item_type:afterDocument.metadata.type,previous_status:beforeDocument.metadata.status,status:afterDocument.metadata.status,previous:projectAfterCommandItemSnapshot(beforeDocument.metadata,mutation.changedFields),current:projectAfterCommandItemSnapshot(afterDocument.metadata,mutation.changedFields),changed_fields:mutation.changedFields}),{item:afterDocument.metadata,body:afterDocument.body,changedFields:mutation.changedFields,warnings:[...parseWarnings,...mutation.warnings??[],...workflowPolicy.warnings,...historyPolicy.warnings,...serviceWriteOverride.warnings,...derivedIndexWarnings,...hookWarnings]}}finally{await releaseLock()}}async function mutateItemWithHistoryContext(params){const{historyContext,...mutationParams}=params;return mutateItemWithDeferredHistoryContext({...mutationParams,resolveHistoryContext:()=>historyContext})}async function mutateItemWithHistoryContextResolver(params){return mutateItemWithDeferredHistoryContext(params)}async function mutateItem(params){return mutateItemWithDeferredHistoryContext(params)}const itemStoreTestOnly={appendWarning,bypassesAssigneeConflict,buildDidYouMeanSuggestions,isErrno};async function deleteItem(params){const prepared=await prepareLockedItem({pmRoot:params.pmRoot,settings:params.settings,id:params.id,op:"delete",author:params.author,force:params.force}),{located,originalRaw,document,warnings:parseWarnings,releaseLock}=prepared;try{const extensionFieldNames=resolveActiveExtensionFieldNames(void 0),beforeDocument=canonicalDocument(document,{schema:params.settings.schema,extensionFieldNames}),workflowPolicy=await enforceWorkflowMutation({pmRoot:params.pmRoot,settings:params.settings,operation:"delete",author:params.author,before:beforeDocument,after:null,dryRun:params.dryRun});await runActiveBeforeMutationHooks({pm_root:params.pmRoot,operation:"delete",before:beforeDocument,after:null,changed_fields:["deleted"],sdk:createMutationGuardSdk({pmRoot:params.pmRoot,settings:params.settings,typeToFolder:prepared.typeToFolder})});const historyPolicy=await enforceHistoryStreamPolicyForItem({pmRoot:params.pmRoot,settings:params.settings,itemId:located.id,commandLabel:"delete"}),deletionTimestamp=nowIso(),tombstoneDocument=EMPTY_CANONICAL_DOCUMENT,historyEntry=createHistoryEntry({nowIso:deletionTimestamp,author:params.author,op:"delete",before:beforeDocument,after:tombstoneDocument,message:params.message,context:workflowPolicy.decisions.length===0?void 0:{workflow_policies:workflowPolicy.decisions}}),historyPath=getHistoryPath(params.pmRoot,located.id),serviceDeleteOverride=await runActiveServiceOverride("item_store_delete",{op:"delete",pm_root:params.pmRoot,item_id:located.id,item_path:located.itemPath,history_path:historyPath,before:beforeDocument});let effectiveItemPath=located.itemPath,skipDelete=!1;if(serviceDeleteOverride.handled&&typeof serviceDeleteOverride.result=="object"&&serviceDeleteOverride.result!==null){const overrideRecord=serviceDeleteOverride.result;typeof overrideRecord.item_path=="string"&&overrideRecord.item_path.trim().length>0&&(effectiveItemPath=overrideRecord.item_path),overrideRecord.skip_delete===!0&&(skipDelete=!0)}if(params.dryRun===!0)return{item:beforeDocument.metadata,changedFields:["deleted"],targetPath:effectiveItemPath,warnings:[...parseWarnings,...workflowPolicy.warnings,...historyPolicy.warnings,...serviceDeleteOverride.warnings]};const releaseDerivedIndexLock=await acquireItemMetadataDerivedIndexLock(params.pmRoot,params.author);let derivedIndexWarnings=[];try{skipDelete||await fs.rm(effectiveItemPath);try{await appendHistoryEntry(historyPath,historyEntry)}catch(error){throw skipDelete||await writeFileAtomic(effectiveItemPath,originalRaw),error}skipDelete||(derivedIndexWarnings=await refreshItemMetadataDerivedIndex({pmRoot:params.pmRoot,preferredFormat:params.settings.item_format,typeToFolder:prepared.typeToFolder,schema:params.settings.schema,itemPath:effectiveItemPath,document:null}))}finally{await releaseDerivedIndexLock()}const hookWarnings=[...await runActiveOnWriteHooks({path:effectiveItemPath,scope:"project",op:"delete",item_id:beforeDocument.metadata.id,item_type:beforeDocument.metadata.type,before:beforeDocument,after:tombstoneDocument,changed_fields:["deleted"]}),...await runActiveOnWriteHooks({path:historyPath,scope:"project",op:"delete:history",item_id:beforeDocument.metadata.id,item_type:beforeDocument.metadata.type,before:beforeDocument,after:tombstoneDocument,changed_fields:["deleted"]})];return recordAfterCommandAffectedItem({id:beforeDocument.metadata.id,op:"delete",item_type:beforeDocument.metadata.type,previous_status:beforeDocument.metadata.status,previous:projectAfterCommandItemSnapshot(beforeDocument.metadata,Object.keys(beforeDocument.metadata)),changed_fields:["deleted"]}),{item:beforeDocument.metadata,changedFields:["deleted"],warnings:[...parseWarnings,...workflowPolicy.warnings,...historyPolicy.warnings,...serviceDeleteOverride.warnings,...derivedIndexWarnings,...hookWarnings]}}finally{await releaseLock()}}export{buildItemNotFoundError,createMutationGuardSdk,deleteItem,itemStoreTestOnly,listAllItemMetadata,listAllItemMetadataLight,listAllItemMetadataWithBody,locateItem,mutateItem,mutateItemWithHistoryContext,mutateItemWithHistoryContextResolver,readLocatedItem,readLocatedItemSnapshot};
|
|
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]="018adb6c-4e3c-58d5-b636-04dbf4307d7a")}catch{}})();import fs from"node:fs/promises";import{buildDeletedItemError}from"../history/tombstone.js";import{normalizeHistoryOperationForWrite}from"../history/operation-contract.js";import{enforceWorkflowMutation}from"../policy/workflow-policy-store.js";import{recordItemMetadataEnumeration}from"./item-metadata-read-work.js";import{assertItemMutationPreconditions}from"./item-mutation-precondition.js";import path from"node:path";import{getActiveExtensionRegistrations,projectAfterCommandItemSnapshot,recordAfterCommandAffectedItem,runActiveOnReadHooks,runActiveBeforeMutationHooks,runActiveOnWriteHooks,runActiveServiceOverride}from"../extensions/index.js";import{collectRegisteredItemFieldNames}from"../extensions/item-fields.js";import{EMPTY_CANONICAL_DOCUMENT,EXIT_CODE,TYPE_TO_FOLDER}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{levenshteinDistanceWithinLimit}from"../shared/levenshtein.js";import{appendHistoryEntry,createHistoryEntry}from"../history/history.js";import{enforceHistoryStreamPolicyForItem}from"../history/history-stream-policy.js";import{canonicalDocument,parseItemDocument,serializeItemDocument}from"../item/item-format.js";import{resolveItemTypeRegistry}from"../item/type-registry.js";import{effectiveItemFormatVersion,requiredItemFormatVersion}from"../item/item-format-version.js";import{assertProjectRuntimeFormatGuard}from"../../sdk/environment/project-runtime-compatibility.js";import{acquireLock}from"../lock/lock.js";import{writeFileAtomic}from"../fs/fs-utils.js";import{isUtf8}from"node:buffer";import{normalizeItemId,normalizeRawItemId}from"../item/id.js";import{acquireItemMetadataDerivedIndexLock,listAllDocumentCandidatesCached,listAllDocumentsCached,listAllDocumentsCachedLight,refreshItemMetadataDerivedIndex}from"./item-metadata-cache.js";import{getHistoryPath,getItemPath,ITEM_FILE_EXTENSIONS,resolveWorkspaceRoot}from"./paths.js";import{resolveGovernanceKnobs}from"./settings.js";import{assertReadableTrackerRoot}from"./tracker-preflight.js";import{resolveClaimPrincipal}from"../shared/author.js";import{nowIso}from"../shared/time.js";async function fileExists(targetPath){try{return await fs.access(targetPath),!0}catch{return!1}}function isErrno(error,code){return typeof error=="object"&&error!==null&&"code"in error&&error.code===code}function appendWarning(warnings,warning){warnings&&(warnings.includes(warning)||warnings.push(warning))}function resolveActiveExtensionFieldNames(explicit){return explicit??collectRegisteredItemFieldNames(getActiveExtensionRegistrations())}function resolveItemFormatSearchOrder(preferredFormat){return preferredFormat==="toon"?["toon","json_markdown"]:preferredFormat==="json_markdown"?["json_markdown","toon"]:["toon","json_markdown"]}async function locateItem(pmRoot,rawId,idPrefix="pm-",preferredFormat,typeToFolder=TYPE_TO_FOLDER){const trimmedRawId=rawId.trim(),exactRawId=trimmedRawId.startsWith("#")?trimmedRawId.slice(1):trimmedRawId;if(exactRawId.length===0)return null;const normalizedId=normalizeItemId(rawId,idPrefix),rawNormalizedId=normalizeRawItemId(rawId),candidateIds=[...new Set([exactRawId,normalizedId,rawNormalizedId])].filter(candidateId=>candidateId.length>0),entries=Object.entries(typeToFolder),searchOrder=resolveItemFormatSearchOrder(preferredFormat);for(const candidateId of candidateIds){const matches=new Map;for(const[type]of entries)for(const itemFormat of searchOrder){const itemPath=getItemPath(pmRoot,type,candidateId,itemFormat,typeToFolder);await fileExists(itemPath)&&matches.set(itemPath,matches.get(itemPath)??{id:candidateId,type,itemPath,item_format:itemFormat})}if(matches.size>1){const paths=[...matches.keys()].map(itemPath=>path.relative(pmRoot,itemPath).split(path.sep).join("/")).sort();throw new PmCliError(`Item ${candidateId} has ambiguous identity across ${paths.join(", ")}. Preserve both documents and inspect pm ops validate --check-storage-integrity before resolving the collision.`,EXIT_CODE.CONFLICT,{code:"item_identity_ambiguous",item_id:candidateId,paths})}for(const match of matches.values())return match}return null}async function readLocatedItem(item,options={}){const snapshot=await readLocatedItemSnapshot(item,options);if(snapshot.error!==null)throw snapshot.error;return{raw:snapshot.raw,document:snapshot.document}}async function readLocatedItemSnapshot(item,options={}){const bytes=await fs.readFile(item.itemPath);if(!isUtf8(bytes))throw new PmCliError("Item contains invalid UTF-8; preserve a binary backup before recovering it.",EXIT_CODE.CONFLICT,{code:"item_document_encoding_invalid",item_id:item.id,item_path:item.itemPath,byte_length:bytes.length,empty:!1});const raw=bytes.toString("utf8");await runActiveOnReadHooks({path:item.itemPath,scope:"project"});let document;try{document=parseItemDocument(raw,{format:item.item_format,requireSupportedFormat:!0,schema:options.schema,extensionFieldNames:resolveActiveExtensionFieldNames(options.extensionFieldNames),onWarning:warning=>appendWarning(options.warnings,warning)})}catch(error){if(error instanceof PmCliError&&error.code==="item_format_version_unsupported")throw new PmCliError(`Item ${item.id}: ${error.message}`,error.exitCode,{...error.context,item_id:item.id,item_path:item.itemPath});if(error instanceof PmCliError&&error.code==="item_document_invalid")return{raw,document:null,error:new PmCliError(`Cannot read ${item.id} at ${item.itemPath}${bytes.length===0?" (zero-length file)":""}: ${error.message}`,error.exitCode,{...error.context,item_id:item.id,item_path:item.itemPath,byte_length:bytes.length,empty:bytes.length===0,nextSteps:[`Run pm history ${item.id} --full, then pm restore ${item.id} <version> to recover a recorded state.`]})};throw error}return{raw,document,error:null}}async function listAllItemMetadata(pmRoot,preferredFormat,typeToFolder=TYPE_TO_FOLDER,warnings,schema){await assertReadableTrackerRoot(pmRoot);const documents=await listAllDocumentsCached(pmRoot,preferredFormat,typeToFolder,warnings,schema);return recordItemMetadataEnumeration(documents.length),documents.map(document=>document.metadata)}async function listAllItemMetadataLight(pmRoot,preferredFormat,typeToFolder=TYPE_TO_FOLDER,warnings,schema){await assertReadableTrackerRoot(pmRoot);const documents=await listAllDocumentsCachedLight(pmRoot,preferredFormat,typeToFolder,warnings,schema);return recordItemMetadataEnumeration(documents.length),documents.map(document=>document.metadata)}async function listAllItemMetadataWithBody(pmRoot,preferredFormat,typeToFolder=TYPE_TO_FOLDER,warnings,schema,options={}){await assertReadableTrackerRoot(pmRoot);const candidates=await listAllDocumentCandidatesCached(pmRoot,preferredFormat,typeToFolder,warnings,schema,{includeBody:!0,forceSourceScan:options.forceSourceScan});return recordItemMetadataEnumeration(candidates.length),candidates.map(candidate=>({...candidate.metadata,body:candidate.body}))}function createMutationGuardSdk(params){return{async get(id){const located=await locateItem(params.pmRoot,id,params.settings.id_prefix,params.settings.item_format,params.typeToFolder);if(!located)return null;const{document}=await readLocatedItem(located,{schema:params.settings.schema});return{item:document.metadata,body:document.body}},list:()=>listAllItemMetadata(params.pmRoot,params.settings.item_format,params.typeToFolder,void 0,params.settings.schema)}}async function listKnownItemIds(pmRoot,typeToFolder){const folders=new Set(Object.values(typeToFolder)),allIds=[];return await Promise.all([...folders].map(async folder=>{try{const entries=await fs.readdir(path.join(pmRoot,folder));for(const entry of entries)for(const ext of ITEM_FILE_EXTENSIONS)if(entry.toLowerCase().endsWith(ext)){allIds.push(entry.slice(0,-ext.length));break}}catch{}})),allIds}async function buildDidYouMeanSuggestions(pmRoot,badId,idPrefix,typeToFolder){const normalized=normalizeItemId(badId,idPrefix),ids=await listKnownItemIds(pmRoot,typeToFolder);if(ids.length===0)return[];const limit=Math.max(3,Math.floor(normalized.length/2));return ids.map(id=>({id,distance:levenshteinDistanceWithinLimit(id,normalized,limit)})).filter(entry=>entry.distance!==null).sort((left,right)=>left.distance-right.distance).slice(0,3).map(entry=>entry.id)}async function buildItemNotFoundError(pmRoot,badId,idPrefix,typeToFolder){const deleted=await buildDeletedItemError(pmRoot,badId,idPrefix);if(deleted)return deleted;const suggestions=await buildDidYouMeanSuggestions(pmRoot,badId,idPrefix,typeToFolder),nextSteps=["Confirm the active --path/PM_PATH scope, then retry with a valid id."];return suggestions.length>0&&nextSteps.unshift(`Did you mean one of: ${suggestions.join(", ")}?`),new PmCliError(`Item ${badId} not found`,EXIT_CODE.NOT_FOUND,{nextSteps})}function bypassesAssigneeConflict(op,bypassAssigneeConflict){return op==="claim"||bypassAssigneeConflict===!0&&(op==="comment_add"||op==="comment_edit"||op==="comment_delete"||op==="note_add"||op==="learning_add"||op==="release"||op==="update"||op==="update_ownership_bypass"||op==="update_audit")}async function prepareLockedItem(params){const typeToFolder=params.typeToFolder??resolveItemTypeRegistry(params.settings,getActiveExtensionRegistrations()).type_to_folder,located=await locateItem(params.pmRoot,params.id,params.settings.id_prefix,params.settings.item_format,typeToFolder);if(!located)throw await buildItemNotFoundError(params.pmRoot,params.id,params.settings.id_prefix,typeToFolder);const releaseLock=await acquireLock(params.pmRoot,located.id,params.settings.locks.ttl_seconds,params.author,!!params.force,params.settings.governance.force_required_for_stale_lock,params.settings.locks.wait_ms);try{const warnings=[],{raw:originalRaw,document}=await readLocatedItem(located,{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames,warnings}),assigned=document.metadata.assignee?.trim(),assignedPrincipal=document.metadata.claim_principal?.trim()||assigned,callerPrincipal=resolveClaimPrincipal(params.author),governance=resolveGovernanceKnobs(params.settings);if(assigned&&assignedPrincipal!==callerPrincipal&&!params.force&&!bypassesAssigneeConflict(params.op,params.bypassAssigneeConflict)){if(governance.ownership_enforcement==="strict")throw new PmCliError(`Item ${located.id} is assigned to ${assigned}. Use --force to override.`,EXIT_CODE.CONFLICT);governance.ownership_enforcement==="warn"&&warnings.push(`ownership_warning:assignee_conflict:${located.id}:${assigned}`)}return{typeToFolder,located,originalRaw,document,warnings,releaseLock}}catch(error){throw await releaseLock(),error}}function resolveItemStoreWriteOverride(serviceWriteOverride,targetItemPath,serializedAfter){if(!serviceWriteOverride.handled||typeof serviceWriteOverride.result!="object"||serviceWriteOverride.result===null)return{effectiveTargetItemPath:targetItemPath,effectiveSerializedAfter:serializedAfter,skipItemWrite:!1};const overrideRecord=serviceWriteOverride.result;return{effectiveTargetItemPath:typeof overrideRecord.target_item_path=="string"&&overrideRecord.target_item_path.trim().length>0?overrideRecord.target_item_path:targetItemPath,effectiveSerializedAfter:typeof overrideRecord.contents=="string"?overrideRecord.contents:serializedAfter,skipItemWrite:overrideRecord.skip_write===!0}}async function rollbackMutatedItemWrite(params){if(!params.skipItemWrite){if(params.effectiveTargetItemPath!==params.originalItemPath){await writeFileAtomic(params.originalItemPath,params.originalRaw),await fs.rm(params.effectiveTargetItemPath,{force:!0});return}await writeFileAtomic(params.originalItemPath,params.originalRaw)}}async function mutateItemWithDeferredHistoryContext(params){normalizeHistoryOperationForWrite(params.op);const prepared=await prepareLockedItem({pmRoot:params.pmRoot,settings:params.settings,id:params.id,op:params.op,author:params.author,force:params.force,bypassAssigneeConflict:params.bypassAssigneeConflict,extensionFieldNames:params.extensionFieldNames,typeToFolder:params.typeToFolder}),{typeToFolder,located,originalRaw,document,warnings:parseWarnings,releaseLock}=prepared;try{assertItemMutationPreconditions(params.pmRoot,document);const beforeDocument=canonicalDocument(document,{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),mutableDocument=canonicalDocument(structuredClone(document),{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),mutation=await params.mutate(mutableDocument);if(params.skipNoop===!0&&mutation.changedFields.length===0)return{item:beforeDocument.metadata,body:beforeDocument.body,changedFields:[],warnings:[...parseWarnings,...mutation.warnings??[]]};const historyContext=params.resolveHistoryContext?.(),requiredFormat=Math.max(requiredItemFormatVersion(beforeDocument.metadata),requiredItemFormatVersion(mutableDocument.metadata));assertProjectRuntimeFormatGuard(resolveWorkspaceRoot(params.pmRoot),requiredFormat),requiredFormat>effectiveItemFormatVersion(mutableDocument.metadata)&&(mutableDocument.metadata.pm_format_version=requiredFormat,mutation.changedFields.push("pm_format_version")),mutableDocument.metadata.updated_at=nowIso();const afterDocument=canonicalDocument(mutableDocument,{schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),workflowPolicy=await enforceWorkflowMutation({pmRoot:params.pmRoot,settings:params.settings,operation:params.op,author:params.author,before:beforeDocument,after:afterDocument});await runActiveBeforeMutationHooks({pm_root:params.pmRoot,operation:params.op,before:beforeDocument,after:afterDocument,changed_fields:mutation.changedFields,sdk:createMutationGuardSdk({pmRoot:params.pmRoot,settings:params.settings,typeToFolder})});const historyPolicy=await enforceHistoryStreamPolicyForItem({pmRoot:params.pmRoot,settings:params.settings,itemId:located.id,commandLabel:params.op}),targetItemFormat="toon",serializedAfter=serializeItemDocument(afterDocument,{format:targetItemFormat,schema:params.settings.schema,extensionFieldNames:params.extensionFieldNames}),targetItemPath=getItemPath(params.pmRoot,afterDocument.metadata.type,located.id,targetItemFormat,typeToFolder),historyPath=getHistoryPath(params.pmRoot,located.id),serviceWriteOverride=await runActiveServiceOverride("item_store_write",{op:params.op,pm_root:params.pmRoot,item_id:located.id,source_item_path:located.itemPath,target_item_path:targetItemPath,history_path:historyPath,item_format:targetItemFormat,before:beforeDocument,after:afterDocument,contents:serializedAfter}),{effectiveTargetItemPath,effectiveSerializedAfter,skipItemWrite}=resolveItemStoreWriteOverride(serviceWriteOverride,targetItemPath,serializedAfter),releaseDerivedIndexLock=await acquireItemMetadataDerivedIndexLock(params.pmRoot,params.author);let derivedIndexWarnings=[];try{skipItemWrite||await writeFileAtomic(effectiveTargetItemPath,effectiveSerializedAfter),!skipItemWrite&&effectiveTargetItemPath!==located.itemPath&&await fs.rm(located.itemPath);const entry=createHistoryEntry({nowIso:afterDocument.metadata.updated_at,author:params.author,op:params.op,before:beforeDocument,after:afterDocument,message:params.message,context:workflowPolicy.decisions.length===0?historyContext:{...historyContext,workflow_policies:workflowPolicy.decisions}});try{await appendHistoryEntry(historyPath,entry)}catch(error){throw await rollbackMutatedItemWrite({skipItemWrite,effectiveTargetItemPath,originalItemPath:located.itemPath,originalRaw}),error}skipItemWrite||(derivedIndexWarnings=await refreshItemMetadataDerivedIndex({pmRoot:params.pmRoot,preferredFormat:params.settings.item_format,typeToFolder,schema:params.settings.schema,itemPath:effectiveTargetItemPath,previousItemPath:located.itemPath,document:afterDocument}))}finally{await releaseDerivedIndexLock()}const hookWarnings=[...await runActiveOnWriteHooks({path:effectiveTargetItemPath,scope:"project",op:params.op,item_id:afterDocument.metadata.id,item_type:afterDocument.metadata.type,before:beforeDocument,after:afterDocument,changed_fields:mutation.changedFields}),...await runActiveOnWriteHooks({path:historyPath,scope:"project",op:`${params.op}:history`,item_id:afterDocument.metadata.id,item_type:afterDocument.metadata.type,before:beforeDocument,after:afterDocument,changed_fields:mutation.changedFields})];return recordAfterCommandAffectedItem({id:afterDocument.metadata.id,op:params.op,item_type:afterDocument.metadata.type,previous_status:beforeDocument.metadata.status,status:afterDocument.metadata.status,previous:projectAfterCommandItemSnapshot(beforeDocument.metadata,mutation.changedFields),current:projectAfterCommandItemSnapshot(afterDocument.metadata,mutation.changedFields),changed_fields:mutation.changedFields}),{item:afterDocument.metadata,body:afterDocument.body,changedFields:mutation.changedFields,warnings:[...parseWarnings,...mutation.warnings??[],...workflowPolicy.warnings,...historyPolicy.warnings,...serviceWriteOverride.warnings,...derivedIndexWarnings,...hookWarnings]}}finally{await releaseLock()}}async function mutateItemWithHistoryContext(params){const{historyContext,...mutationParams}=params;return mutateItemWithDeferredHistoryContext({...mutationParams,resolveHistoryContext:()=>historyContext})}async function mutateItemWithHistoryContextResolver(params){return mutateItemWithDeferredHistoryContext(params)}async function mutateItem(params){return mutateItemWithDeferredHistoryContext(params)}const itemStoreTestOnly={appendWarning,bypassesAssigneeConflict,buildDidYouMeanSuggestions,isErrno};async function deleteItem(params){const prepared=await prepareLockedItem({pmRoot:params.pmRoot,settings:params.settings,id:params.id,op:"delete",author:params.author,force:params.force}),{located,originalRaw,document,warnings:parseWarnings,releaseLock}=prepared;try{const extensionFieldNames=resolveActiveExtensionFieldNames(void 0),beforeDocument=canonicalDocument(document,{schema:params.settings.schema,extensionFieldNames}),workflowPolicy=await enforceWorkflowMutation({pmRoot:params.pmRoot,settings:params.settings,operation:"delete",author:params.author,before:beforeDocument,after:null,dryRun:params.dryRun});await runActiveBeforeMutationHooks({pm_root:params.pmRoot,operation:"delete",before:beforeDocument,after:null,changed_fields:["deleted"],sdk:createMutationGuardSdk({pmRoot:params.pmRoot,settings:params.settings,typeToFolder:prepared.typeToFolder})});const historyPolicy=await enforceHistoryStreamPolicyForItem({pmRoot:params.pmRoot,settings:params.settings,itemId:located.id,commandLabel:"delete"}),deletionTimestamp=nowIso(),tombstoneDocument=EMPTY_CANONICAL_DOCUMENT,historyEntry=createHistoryEntry({nowIso:deletionTimestamp,author:params.author,op:"delete",before:beforeDocument,after:tombstoneDocument,message:params.message,context:workflowPolicy.decisions.length===0?void 0:{workflow_policies:workflowPolicy.decisions}}),historyPath=getHistoryPath(params.pmRoot,located.id),serviceDeleteOverride=await runActiveServiceOverride("item_store_delete",{op:"delete",pm_root:params.pmRoot,item_id:located.id,item_path:located.itemPath,history_path:historyPath,before:beforeDocument});let effectiveItemPath=located.itemPath,skipDelete=!1;if(serviceDeleteOverride.handled&&typeof serviceDeleteOverride.result=="object"&&serviceDeleteOverride.result!==null){const overrideRecord=serviceDeleteOverride.result;typeof overrideRecord.item_path=="string"&&overrideRecord.item_path.trim().length>0&&(effectiveItemPath=overrideRecord.item_path),overrideRecord.skip_delete===!0&&(skipDelete=!0)}if(params.dryRun===!0)return{item:beforeDocument.metadata,changedFields:["deleted"],targetPath:effectiveItemPath,warnings:[...parseWarnings,...workflowPolicy.warnings,...historyPolicy.warnings,...serviceDeleteOverride.warnings]};const releaseDerivedIndexLock=await acquireItemMetadataDerivedIndexLock(params.pmRoot,params.author);let derivedIndexWarnings=[];try{skipDelete||await fs.rm(effectiveItemPath);try{await appendHistoryEntry(historyPath,historyEntry)}catch(error){throw skipDelete||await writeFileAtomic(effectiveItemPath,originalRaw),error}skipDelete||(derivedIndexWarnings=await refreshItemMetadataDerivedIndex({pmRoot:params.pmRoot,preferredFormat:params.settings.item_format,typeToFolder:prepared.typeToFolder,schema:params.settings.schema,itemPath:effectiveItemPath,document:null}))}finally{await releaseDerivedIndexLock()}const hookWarnings=[...await runActiveOnWriteHooks({path:effectiveItemPath,scope:"project",op:"delete",item_id:beforeDocument.metadata.id,item_type:beforeDocument.metadata.type,before:beforeDocument,after:tombstoneDocument,changed_fields:["deleted"]}),...await runActiveOnWriteHooks({path:historyPath,scope:"project",op:"delete:history",item_id:beforeDocument.metadata.id,item_type:beforeDocument.metadata.type,before:beforeDocument,after:tombstoneDocument,changed_fields:["deleted"]})];return recordAfterCommandAffectedItem({id:beforeDocument.metadata.id,op:"delete",item_type:beforeDocument.metadata.type,previous_status:beforeDocument.metadata.status,previous:projectAfterCommandItemSnapshot(beforeDocument.metadata,Object.keys(beforeDocument.metadata)),changed_fields:["deleted"]}),{item:beforeDocument.metadata,changedFields:["deleted"],warnings:[...parseWarnings,...workflowPolicy.warnings,...historyPolicy.warnings,...serviceDeleteOverride.warnings,...derivedIndexWarnings,...hookWarnings]}}finally{await releaseLock()}}export{buildItemNotFoundError,createMutationGuardSdk,deleteItem,itemStoreTestOnly,listAllItemMetadata,listAllItemMetadataLight,listAllItemMetadataWithBody,locateItem,mutateItem,mutateItemWithHistoryContext,mutateItemWithHistoryContextResolver,readLocatedItem,readLocatedItemSnapshot};
|
|
2
2
|
//# sourceMappingURL=item-store.js.map
|
package/dist/core/store/paths.js
CHANGED
|
@@ -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]="7f4b8abe-997c-549c-9791-87c78506c8b5")}catch{}})();import{readFileSync,readdirSync,realpathSync,statSync}from"node:fs";import os from"node:os";import path from"node:path";import{PM_DIRNAME,EXIT_CODE,SETTINGS_FILENAME,TYPE_TO_FOLDER}from"../shared/constants.js";import{PmCliError}from"../shared/errors.js";import{isFileAbsentError}from"../fs/fs-utils.js";import{toDefaultFolder}from"../item/type-registry.js";const ITEM_FILE_EXTENSION_BY_FORMAT={json_markdown:".md",toon:".toon"},ITEM_FORMAT_BY_EXTENSION={".md":"json_markdown",".toon":"toon"},NEARBY_TRACKER_SCAN_IGNORED_DIRECTORIES=new Set([".git","coverage","dist","node_modules"]),ITEM_FILE_EXTENSIONS=[".md",".toon"];function pathExists(pathValue){try{return statSync(pathValue),!0}catch{return!1}}function physicalDiscoveryStart(cwd){let ancestor=path.resolve(cwd);const missing=[];for(;path.dirname(ancestor)!==ancestor;)try{return path.join(realpathSync(ancestor),...missing)}catch(error){if(!isFileAbsentError(error))throw error;missing.unshift(path.basename(ancestor)),ancestor=path.dirname(ancestor)}return path.join(realpathSync(ancestor),...missing)}function repositoryBoundaryExists(marker){try{return statSync(marker),!0}catch(error){if(isFileAbsentError(error))return!1;throw error}}function isPmSettingsFile(settingsPath){try{const parsed=JSON.parse(readFileSync(settingsPath,"utf8"));return typeof parsed!="object"||parsed===null||Array.isArray(parsed)?!1:"id_prefix"in parsed||"item_format"in parsed}catch{return!1}}function discoverPmRootFromAncestors(cwd){let current=physicalDiscoveryStart(cwd);for(;;){const candidateRoot=path.join(current,PM_DIRNAME),candidateSettingsPath=path.join(candidateRoot,SETTINGS_FILENAME);if(pathExists(candidateSettingsPath))return candidateRoot;const rootLayoutSettingsPath=path.join(current,SETTINGS_FILENAME);if(pathExists(rootLayoutSettingsPath)&&isPmSettingsFile(rootLayoutSettingsPath))return current;if(repositoryBoundaryExists(path.join(current,".git")))return candidateRoot;const parent=path.dirname(current);if(parent===current)return;current=parent}}function resolveImplicitPmRoot(cwd){return discoverPmRootFromAncestors(cwd)??path.resolve(cwd,PM_DIRNAME)}function discoverNearbyPmRoot(cwd,excludedRoot){const normalizedExcluded=excludedRoot?path.resolve(excludedRoot):void 0;try{return readdirSync(path.resolve(cwd),{withFileTypes:!0}).filter(entry=>entry.isDirectory()&&!NEARBY_TRACKER_SCAN_IGNORED_DIRECTORIES.has(entry.name)).map(entry=>path.join(path.resolve(cwd),entry.name)).filter(candidate=>candidate!==normalizedExcluded).filter(candidate=>pathExists(getSettingsPath(candidate))).filter(candidate=>isPmSettingsFile(getSettingsPath(candidate))).sort((left,right)=>left.localeCompare(right))[0]}catch{return}}function resolvePmRoot(cwd,cliPath){const envPath=process.env.PM_PATH,explicitPath=cliPath?.trim()||envPath?.trim();if(explicitPath){const resolved=path.resolve(cwd,explicitPath);if(!pathExists(getSettingsPath(resolved))){const nestedRoot=path.join(resolved,PM_DIRNAME);if(pathExists(getSettingsPath(nestedRoot)))return nestedRoot}return resolved}return resolveImplicitPmRoot(cwd)}function resolveWorkspaceRoot(pmRoot){const normalizedRoot=path.resolve(pmRoot),parent=path.dirname(normalizedRoot);return path.basename(normalizedRoot)==="pm"&&path.basename(parent)===".agents"?path.dirname(parent):normalizedRoot}function resolveGlobalPmRoot(cwd){const envPath=process.env.PM_GLOBAL_PATH?.trim(),selected=envPath&&envPath.length>0?envPath:path.join(os.homedir(),".pm-cli");return path.resolve(cwd,selected)}function getSettingsPath(pmRoot){return path.join(pmRoot,SETTINGS_FILENAME)}function getTypeDirPath(pmRoot,type,typeToFolder=TYPE_TO_FOLDER){const folder=typeToFolder[type]??toDefaultFolder(type);return path.join(pmRoot,folder)}function getItemPath(pmRoot,type,id,itemFormat="toon",typeToFolder=TYPE_TO_FOLDER){return path.join(getTypeDirPath(pmRoot,type,typeToFolder),`${id}${ITEM_FILE_EXTENSION_BY_FORMAT[itemFormat]}`)}function getItemFormatFromPath(itemPath){const normalizedItemPath=itemPath.replaceAll("\\","/"),extension=path.posix.extname(normalizedItemPath).toLowerCase();return ITEM_FORMAT_BY_EXTENSION[extension]??null}function getHistoryPath(pmRoot,id){if(!/^(?!\.{1,2}$)[^/\\:\0]+$/.test(id))throw new PmCliError("Invalid history item id: expected a single filename.",EXIT_CODE.USAGE);return path.join(pmRoot,"history",`${id}.jsonl`)}function getLockPath(pmRoot,id){return path.join(pmRoot,"locks",`${id}.lock`)}function getRuntimePath(pmRoot){return path.join(pmRoot,"runtime")}function getTestRunsPath(pmRoot){return path.join(getRuntimePath(pmRoot),"test-runs")}function getTestRunsRecordsPath(pmRoot){return path.join(getTestRunsPath(pmRoot),"runs")}function getTestRunRecordPath(pmRoot,runId){return path.join(getTestRunsRecordsPath(pmRoot),`${runId}.json`)}function getTestRunsStdoutPath(pmRoot){return path.join(getTestRunsPath(pmRoot),"stdout")}function getTestRunsStderrPath(pmRoot){return path.join(getTestRunsPath(pmRoot),"stderr")}function getTestRunStdoutPath(pmRoot,runId){return path.join(getTestRunsStdoutPath(pmRoot),`${runId}.log`)}function getTestRunStderrPath(pmRoot,runId){return path.join(getTestRunsStderrPath(pmRoot),`${runId}.log`)}function getTestRunsResultsPath(pmRoot){return path.join(getTestRunsPath(pmRoot),"results")}function getTestRunResultPath(pmRoot,runId){return path.join(getTestRunsResultsPath(pmRoot),`${runId}.json`)}export{ITEM_FILE_EXTENSIONS,ITEM_FILE_EXTENSION_BY_FORMAT,discoverNearbyPmRoot,getHistoryPath,getItemFormatFromPath,getItemPath,getLockPath,getRuntimePath,getSettingsPath,getTestRunRecordPath,getTestRunResultPath,getTestRunStderrPath,getTestRunStdoutPath,getTestRunsPath,getTestRunsRecordsPath,getTestRunsResultsPath,getTestRunsStderrPath,getTestRunsStdoutPath,getTypeDirPath,resolveGlobalPmRoot,resolveImplicitPmRoot,resolvePmRoot,resolveWorkspaceRoot};
|
|
2
2
|
//# sourceMappingURL=paths.js.map
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** Supported explicit classifications for intentional telemetry delivery. */
|
|
2
2
|
export declare const PM_TELEMETRY_SOURCE_CONTEXT_VALUES:readonly ["user","automation","test","dogfood"];
|
|
3
|
+
/** Share native and package test signals across consent, attribution and flush lifetime. */
|
|
4
|
+
export declare function isTelemetryTestEnvironment(env?:Readonly<Record<string,string | undefined>>):boolean;
|
|
3
5
|
/** Fixed core reads eligible only after runtime ownership has been established. */
|
|
4
6
|
export declare const TELEMETRY_SAMPLEABLE_READS:ReadonlySet<string>;
|
|
5
7
|
/** Resolve explicit read sampling only for core-only invocations with no write-capable extensions. */
|
|
@@ -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]="eae1b641-d6ed-5c32-899e-fe534a17aafd")}catch{}})();const TRUE_VALUES=new Set(["1","true","yes","on"]),PM_TELEMETRY_SOURCE_CONTEXT_VALUES=["user","automation","test","dogfood"],SOURCE_CONTEXTS=new Set(PM_TELEMETRY_SOURCE_CONTEXT_VALUES);function isTelemetryTestEnvironment(env=process.env){return typeof env.VITEST=="string"||typeof env.VITEST_WORKER_ID=="string"||typeof env.NODE_TEST_CONTEXT=="string"||(env.NODE_ENV??"").trim().toLowerCase()==="test"}const TELEMETRY_SAMPLEABLE_READS=new Set(["stats","ops stats","list","get","next","context","activity","aggregate"]);function resolveTelemetryReadSampleRate(command,noExtensions,env=process.env){const raw=env.PM_TELEMETRY_READ_SAMPLE_RATE?.trim();if(!raw||!noExtensions||!TELEMETRY_SAMPLEABLE_READS.has(command))return 1;const rate=Number(raw);return Number.isFinite(rate)&&rate>0&&rate<=1?rate:1}function telemetryEnvironmentFlag(key,env){return TRUE_VALUES.has((env[key]??"").trim().toLowerCase())}function resolveTelemetryEnvironmentPolicy(env=process.env){const doNotTrack=telemetryEnvironmentFlag("DO_NOT_TRACK",env),override=(env.PM_TELEMETRY_SOURCE_CONTEXT??"").trim().toLowerCase(),testSuppressed=isTelemetryTestEnvironment(env)&&!SOURCE_CONTEXTS.has(override)&&!telemetryEnvironmentFlag("PM_TELEMETRY_SEND_TEST_EVENTS",env);return{telemetry_disabled:doNotTrack||testSuppressed||telemetryEnvironmentFlag("PM_TELEMETRY_DISABLED",env)||telemetryEnvironmentFlag("PM_NO_TELEMETRY",env),do_not_track:doNotTrack,test_suppressed:testSuppressed}}export{PM_TELEMETRY_SOURCE_CONTEXT_VALUES,TELEMETRY_SAMPLEABLE_READS,isTelemetryTestEnvironment,resolveTelemetryEnvironmentPolicy,resolveTelemetryReadSampleRate};
|
|
2
2
|
//# sourceMappingURL=policy.js.map
|
|
@@ -161,6 +161,7 @@ declare function runtimeStatePath(globalPmRoot:string):string;
|
|
|
161
161
|
declare function flushLockPath(globalPmRoot:string):string;
|
|
162
162
|
declare function flushSpawnLockPath(globalPmRoot:string):string;
|
|
163
163
|
declare function telemetryFlushRunnerPath():string;
|
|
164
|
+
/** Select foreground lifetime from explicit worker flags or a recognized test environment. */
|
|
164
165
|
declare function shouldFlushInline():boolean;
|
|
165
166
|
declare function readRuntimeState(globalPmRoot:string):Promise<TelemetryRuntimeState>;
|
|
166
167
|
declare function writeRuntimeState(globalPmRoot:string,patch:TelemetryRuntimeState):Promise<void>;
|
|
@@ -322,7 +323,7 @@ next_attempt_after:string;
|
|
|
322
323
|
}>):Promise<number>;
|
|
323
324
|
/** POST due spans outside the mutation mutex, then reconcile successes and retry metadata against the current queue; publish export diagnostics for health inspection. */
|
|
324
325
|
declare function flushPendingOtelSpans(globalPmRoot:string,retentionDays:number):Promise<void>;
|
|
325
|
-
/** Flush
|
|
326
|
+
/** Flush event and OTLP queues together for a detached worker or inline test delivery, isolating each artifact's failures for a later retry. */
|
|
326
327
|
declare function flushTelemetryArtifacts(globalPmRoot:string,endpoint:string,retentionDays:number):Promise<void>;
|
|
327
328
|
export { withQueueMutation as withTelemetryQueueMutation };
|
|
328
329
|
/** Serialize complete queue transactions across processes. The per-acquisition wait defaults to five seconds for maintenance; foreground capture supplies a shorter budget. PM_LOCK_WAIT_MS remains an explicit override. Never hold the lock during network I/O. */
|
|
@@ -409,12 +410,13 @@ runtimeStatePath:typeof runtimeStatePath;
|
|
|
409
410
|
writeRuntimeState:typeof writeRuntimeState;
|
|
410
411
|
};
|
|
411
412
|
declare function flushQueueWithProcessLock(globalPmRoot:string,endpoint:string,retentionDays:number):Promise<boolean>;
|
|
412
|
-
|
|
413
|
+
/** Serialize foreground snapshots or dispatch one detached worker for queued production delivery. */
|
|
414
|
+
declare function scheduleTelemetryFlush(globalPmRoot:string,endpoint:string,retentionDays:number):Promise<void> | undefined;
|
|
413
415
|
/** Drain consented event and span queues without reviving removed storage in detached workers. Foreground SDK callers retain identity initialization; workers only read existing base settings and never scaffold directories, schemas or identities. */
|
|
414
416
|
export declare function flushTelemetryQueueNow(globalPmRoot?:string):Promise<void>;
|
|
415
417
|
/** Atomically validate consent, initialize identity, and capture an invocation; defer sampled reads until their outcome determines pair retention and schedule delivery after releasing the mutex. */
|
|
416
418
|
export declare function startTelemetryCommand(context:TelemetryCommandContext):Promise<ActiveTelemetryCommand | null>;
|
|
417
|
-
/** Complete an invocation only while
|
|
419
|
+
/** Complete an invocation only while consent and installation identity agree; retain failed reads, weight selected pairs and await delivery in inline mode. */
|
|
418
420
|
export declare function finishTelemetryCommand(activeCommand:ActiveTelemetryCommand | null,outcome:TelemetryCommandOutcome):Promise<void>;
|
|
419
421
|
/** Atomically validate consent and append a sanitized command error with its installation identity; schedule delivery only after releasing the queue mutex. */
|
|
420
422
|
export declare function emitTelemetryErrorEvent(context:TelemetryErrorEventContext):Promise<void>;
|