@unbrained/pm-cli 2026.9.13 → 2026.9.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +34 -0
- package/dist/cli/commander-usage.js +2 -2
- package/dist/cli/error-guidance.js +1 -1
- package/dist/cli/extension-command-help.d.ts +2 -2
- package/dist/cli/extension-command-help.js +2 -2
- package/dist/cli-bundle/bundle-manifest.json +144 -144
- package/dist/cli-bundle/chunks/{chunk-KM4XVZR7.js → chunk-3AHONKLL.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-ZZI7IHMM.js → chunk-3RB6Z7XE.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-GQQR6JAL.js → chunk-5P5PYCZX.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-XM7RWQLM.js → chunk-BOZ4HVYL.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-J4DRE3WN.js +237 -0
- package/dist/cli-bundle/chunks/{chunk-LA44JECQ.js → chunk-RKPUO75B.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-XEZOGC3P.js → chunk-RM2OGG65.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-YQTJACN5.js → chunk-UKLOSZV6.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-GBK5MV6N.js → chunk-WDF7PP4P.js} +26 -26
- package/dist/cli-bundle/chunks/chunk-WLJJ4MAU.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-YDSV4QIQ.js → chunk-Y2P3DSSO.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-3DWX3CKN.js → chunk-YMMLKKEP.js} +2 -2
- package/dist/cli-bundle/chunks/{register-list-query-WMJTBWNW.js → register-list-query-IWSPNFFD.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-EXGOXP3D.js → register-mutation-3DVF4R64.js} +2 -2
- package/dist/cli-bundle/chunks/{register-operations-2H4CDRGU.js → register-operations-LXP3MECQ.js} +2 -2
- package/dist/cli-bundle/chunks/{register-setup-NYBWGPOS.js → register-setup-KFQSNBDX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-4YTDKIPF.js +30 -0
- package/dist/cli-bundle/focused-chunks/{chunk-LQ67C7ZO.js → chunk-533DCWPY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-B6JAANOH.js → chunk-5SBU4QDC.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-SDQCJF4H.js → chunk-63YRRGKX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-KP3N6PVZ.js → chunk-6C3CUU2G.js} +3 -3
- package/dist/cli-bundle/focused-chunks/{chunk-TUHRUFID.js → chunk-AXDAIBT3.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-FBCLVOBE.js → chunk-BMATJLPT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-DSJYL4VP.js → chunk-JKJYXCT6.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-V7PSTKHD.js → chunk-MD7ADLME.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-OENAWWP4.js → chunk-OGGF2RBL.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-FPNI4U2B.js → chunk-PBJC2ZNA.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-SHF57M2H.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-F66QJWI4.js → chunk-UACMCSCC.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-XCCM7P7V.js → chunk-YBQTVE5S.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-ZAMG7HBB.js → chunk-ZHX3433X.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-ZOE2NSJB.js +20 -0
- package/dist/cli-bundle/main.js +19 -19
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +1 -1
- package/dist/cli-bundle/sdk-core.js +24 -24
- package/dist/cli-bundle/sdk-governance.js +1 -1
- package/dist/cli-bundle/sdk-graph.js +1 -1
- package/dist/cli-bundle/sdk-merge.js +40 -40
- 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 +8 -8
- package/dist/core/extensions/index.d.ts +7 -0
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/lock/lock.js +2 -2
- package/dist/core/output/output.js +3 -3
- package/dist/core/telemetry/policy.d.ts +2 -0
- package/dist/core/telemetry/policy.js +1 -1
- package/dist/core/telemetry/read-sampling.d.ts +8 -0
- package/dist/core/telemetry/read-sampling.js +3 -0
- package/dist/core/telemetry/runtime.d.ts +35 -8
- package/dist/core/telemetry/runtime.js +5 -4
- package/dist/sdk/agent/command-suggestions.d.ts +6 -0
- package/dist/sdk/agent/command-suggestions.js +1 -1
- package/dist/sdk/cli-contracts/command-aliases.js +1 -1
- package/dist/sdk/cli-contracts/grammar-contracts.d.ts +2 -2
- package/dist/sdk/cli-contracts/grammar-contracts.js +1 -1
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +7 -3
- package/dist/sdk/cli-contracts/runtime-contracts.js +1 -1
- package/dist/sdk/public-surface.json +1 -1
- package/dist/sdk/telemetry.js +1 -1
- package/docs/AGENT_UX_CONTRACTS.md +10 -2
- package/docs/CLI_GRAMMAR.md +28 -0
- package/docs/CONFIGURATION.md +41 -3
- package/docs/generated/AGENT_CAPABILITY_ROUTING.md +1 -1
- package/docs/generated/AGENT_COMMAND_SURFACE.md +1 -0
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +1 -0
- package/marketplace.json +2 -2
- package/package.json +5 -5
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/dist/cli-bundle/chunks/chunk-6KHYW3FH.js +0 -235
- package/dist/cli-bundle/chunks/chunk-AKTBOX6U.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-7JR6M2JR.js +0 -30
- package/dist/cli-bundle/focused-chunks/chunk-YUXBHIUV.js +0 -20
- package/dist/cli-bundle/focused-chunks/chunk-ZF5PXK6A.js +0 -2
|
@@ -38,6 +38,13 @@ export declare function resetActiveExtensionRuntimeState(): void;
|
|
|
38
38
|
export declare function setActiveCommandContext(context: Omit<CommandOverrideContext, "result"> | null): void;
|
|
39
39
|
/** Return a defensive snapshot of the current invocation's command context. */
|
|
40
40
|
export declare function getActiveCommandContext(): Omit<CommandOverrideContext, "result"> | null;
|
|
41
|
+
/**
|
|
42
|
+
* Prove that the active command has no extension execution surface. Unrelated
|
|
43
|
+
* command registrations are harmless; hooks, services, renderers, migrations,
|
|
44
|
+
* and matching handlers/parsers make ownership uncertain and fail closed.
|
|
45
|
+
* Snapshot this predicate before entering an isolated infrastructure context.
|
|
46
|
+
*/
|
|
47
|
+
export declare function isActiveCommandUnextended(command: string): boolean;
|
|
41
48
|
/** Implements set active command result for the public runtime surface of this module. */
|
|
42
49
|
export declare function setActiveCommandResult(result: unknown): void;
|
|
43
50
|
/** Implements get active command result for the public runtime surface of this module. */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="0989270e-6969-5059-b3df-06411211f701")}catch(e2){}})();import{existsSync}from"node:fs";import{AsyncLocalStorage}from"node:async_hooks";import path from"node:path";import{runCommandHandler,runBeforeMutationHooks,runCommandOverride,runOnIndexHooks,runParserOverride,runPreflightOverride,runOnReadHooks,runRendererOverride,runServiceOverride,runServiceOverrideSync,runOnWriteHooks}from"./loader.js";let activeExtensionHooks=null;let activeExtensionCommands=null;let activeExtensionParsers=null;let activeExtensionPreflight=null;let activeExtensionServices=null;let activeExtensionRenderers=null;let activeExtensionRegistrations=null;let activeCommandContext=null;let activeCommandResult=void 0;let activeAfterCommandAffectedItems=[];const isolatedExtensionRuntime=new AsyncLocalStorage;function runtimeState(){return isolatedExtensionRuntime.getStore()}function runWithIsolatedExtensionRuntime(run){return isolatedExtensionRuntime.run({hooks:null,commands:null,parsers:null,preflight:null,services:null,renderers:null,registrations:null,commandContext:null,commandResult:void 0,affectedItems:[]},run)}const AFTER_COMMAND_SNAPSHOT_OMITTED_FIELDS=new Set(["body","comments","dependencies","docs","events","files","learnings","notes","reminders","test_runs","tests"]);function findSourceRepositoryRoot(candidate){let cursor=path.resolve(candidate);while(true){if(existsSync(path.join(cursor,".git"))){return cursor}const parent=path.dirname(cursor);if(parent===cursor){return void 0}cursor=parent}}function resolvePortableWorkspaceContext(pmRoot){const sourceCandidate=process.env.PM_SOURCE_WORKSPACE_ROOT?.trim()||process.cwd();const sourceWorkspaceRoot=findSourceRepositoryRoot(sourceCandidate)??path.resolve(sourceCandidate);const repoRoot=findSourceRepositoryRoot(sourceWorkspaceRoot);if(!pmRoot){return{source_workspace_root:sourceWorkspaceRoot,...repoRoot?{repo_root:repoRoot}:{}}}const relativePmRoot=path.relative(sourceWorkspaceRoot,path.resolve(pmRoot));const contained=relativePmRoot.length>0&&!relativePmRoot.startsWith(`..${path.sep}`)&&relativePmRoot!==".."&&!path.isAbsolute(relativePmRoot);return{source_workspace_root:sourceWorkspaceRoot,...repoRoot?{repo_root:repoRoot}:{},...contained?{pm_root_rel:relativePmRoot.split(path.sep).join("/")}:{}}}function setActiveExtensionHooks(hooks){const state=runtimeState();if(state){state.hooks=hooks;return}activeExtensionHooks=hooks}function setActiveExtensionCommands(commands){const state=runtimeState();if(state){state.commands=commands;return}activeExtensionCommands=commands}function setActiveExtensionParsers(parsers){const state=runtimeState();if(state){state.parsers=parsers;return}activeExtensionParsers=parsers}function setActiveExtensionPreflight(preflight){const state=runtimeState();if(state){state.preflight=preflight;return}activeExtensionPreflight=preflight}function setActiveExtensionServices(services){const state=runtimeState();if(state){state.services=services;return}activeExtensionServices=services}function setActiveExtensionRenderers(renderers){const state=runtimeState();if(state){state.renderers=renderers;return}activeExtensionRenderers=renderers}function setActiveExtensionRegistrations(registrations){const state=runtimeState();if(state){state.registrations=registrations;return}activeExtensionRegistrations=registrations}function getActiveExtensionRegistrations(){const state=runtimeState();return state?state.registrations:activeExtensionRegistrations}function resetActiveExtensionRuntimeState(){const state=runtimeState();if(state){state.hooks=null;state.commands=null;state.parsers=null;state.preflight=null;state.services=null;state.renderers=null;state.registrations=null;state.commandContext=null;state.commandResult=null;state.affectedItems=[];return}activeExtensionHooks=null;activeExtensionCommands=null;activeExtensionParsers=null;activeExtensionPreflight=null;activeExtensionServices=null;activeExtensionRenderers=null;activeExtensionRegistrations=null;activeCommandContext=null;activeCommandResult=null}function setActiveCommandContext(context){const resolved=context?{...context,...resolvePortableWorkspaceContext(context.pm_root)}:null;const state=runtimeState();if(state){state.commandContext=resolved;return}activeCommandContext=resolved}function getActiveCommandContext(){const state=runtimeState();const context=state?state.commandContext:activeCommandContext;return context?{...context,args:[...context.args],options:context.options?{...context.options}:{},global:context.global?{...context.global}:void 0}:null}function setActiveCommandResult(result){const state=runtimeState();if(state){state.commandResult=result;return}activeCommandResult=result}function getActiveCommandResult(){const state=runtimeState();return state?state.commandResult:activeCommandResult}function recordAfterCommandAffectedItem(item){if(!item){return}const state=runtimeState();if(state){state.affectedItems.push(item)}else{activeAfterCommandAffectedItems.push(item)}}function projectAfterCommandItemSnapshot(metadata,changedFields){if(!metadata||!metadata.id){return{}}const snapshot={id:metadata.id,type:metadata.type,status:metadata.status};if(!Array.isArray(changedFields)){return snapshot}const source=metadata;for(const field of changedFields){if(typeof field!=="string"){continue}const actualField=field.startsWith("unset:")?field.slice("unset:".length):field;if(actualField==="id"||actualField==="type"||actualField==="status"||AFTER_COMMAND_SNAPSHOT_OMITTED_FIELDS.has(actualField)){continue}if(Object.hasOwn(source,actualField)&&source[actualField]!==void 0){snapshot[actualField]=source[actualField]}}return snapshot}function consumeAfterCommandAffectedItems(){const state=runtimeState();const affectedItems=state?.affectedItems??activeAfterCommandAffectedItems;if(affectedItems.length===0){return void 0}const affected=affectedItems;if(state){state.affectedItems=[]}else{activeAfterCommandAffectedItems=[]}return affected}function clearActiveExtensionHooks(){const state=runtimeState();if(state){state.hooks=null;state.commands=null;state.parsers=null;state.preflight=null;state.services=null;state.renderers=null;state.registrations=null;state.commandContext=null;state.commandResult=void 0;state.affectedItems=[];return}activeExtensionHooks=null;activeExtensionCommands=null;activeExtensionParsers=null;activeExtensionPreflight=null;activeExtensionServices=null;activeExtensionRenderers=null;activeExtensionRegistrations=null;activeCommandContext=null;activeCommandResult=void 0;activeAfterCommandAffectedItems=[]}async function runActiveOnWriteHooks(context){const state=runtimeState();const hooks=state?state.hooks:activeExtensionHooks;if(!hooks){return[]}return runOnWriteHooks(hooks,context)}async function runActiveBeforeMutationHooks(context){const state=runtimeState();const hooks=state?state.hooks:activeExtensionHooks;if(!hooks)return;await runBeforeMutationHooks(hooks,context)}async function runActiveOnReadHooks(context){const state=runtimeState();const hooks=state?state.hooks:activeExtensionHooks;if(!hooks){return[]}return runOnReadHooks(hooks,context)}function hasActiveOnReadHooks(){const state=runtimeState();const hooks=state?state.hooks:activeExtensionHooks;return(hooks?.onRead?.length??0)>0}async function runActiveOnIndexHooks(context){const state=runtimeState();const hooks=state?state.hooks:activeExtensionHooks;if(!hooks){return[]}return runOnIndexHooks(hooks,context)}function runActiveCommandOverride(result){const state=runtimeState();const commands=state?state.commands:activeExtensionCommands;const commandContext=state?state.commandContext:activeCommandContext;if(!commands||!commandContext){return{overridden:false,result,warnings:[]}}return runCommandOverride(commands,{command:commandContext.command,args:[...commandContext.args],options:commandContext.options?{...commandContext.options}:{},global:commandContext.global?{...commandContext.global}:void 0,pm_root:commandContext.pm_root,source_workspace_root:commandContext.source_workspace_root,repo_root:commandContext.repo_root,pm_root_rel:commandContext.pm_root_rel,result})}async function runActiveCommandHandler(context){const state=runtimeState();const commands=state?state.commands:activeExtensionCommands;if(!commands){return{handled:false,result:null,warnings:[]}}return runCommandHandler(commands,{...context,...resolvePortableWorkspaceContext(context.pm_root)})}async function runActiveParserOverride(context){const state=runtimeState();const parsers=state?state.parsers:activeExtensionParsers;if(!parsers){return{overridden:false,context:{command:context.command,args:[...context.args],options:{...context.options},global:{...context.global},pm_root:context.pm_root},warnings:[]}}return runParserOverride(parsers,{...context,...resolvePortableWorkspaceContext(context.pm_root)})}async function runActivePreflightOverride(context){const state=runtimeState();const preflight=state?state.preflight:activeExtensionPreflight;if(!preflight){return{overridden:false,context:{command:context.command,args:[...context.args],options:{...context.options},global:{...context.global},pm_root:context.pm_root},decision:{...context.decision},warnings:[]}}return runPreflightOverride(preflight,{...context,...resolvePortableWorkspaceContext(context.pm_root)})}function runActiveRendererOverride(format,result){const state=runtimeState();const renderers=state?state.renderers:activeExtensionRenderers;const commandContext=state?state.commandContext:activeCommandContext;if(!renderers){return{overridden:false,rendered:null,warnings:[]}}return runRendererOverride(renderers,{format,command:commandContext?.command,args:commandContext?[...commandContext.args]:[],options:commandContext?.options?{...commandContext.options}:{},global:commandContext?.global?{...commandContext.global}:void 0,pm_root:commandContext?.pm_root,source_workspace_root:commandContext?.source_workspace_root,repo_root:commandContext?.repo_root,pm_root_rel:commandContext?.pm_root_rel,result})}function buildServiceContext(service,payload){const state=runtimeState();const commandContext=state?state.commandContext:activeCommandContext;return{service,command:commandContext?.command,args:commandContext?[...commandContext.args]:[],options:commandContext?.options?{...commandContext.options}:{},global:commandContext?.global?{...commandContext.global}:void 0,pm_root:commandContext?.pm_root,source_workspace_root:commandContext?.source_workspace_root,repo_root:commandContext?.repo_root,pm_root_rel:commandContext?.pm_root_rel,payload}}async function runActiveServiceOverride(service,payload){const state=runtimeState();const services=state?state.services:activeExtensionServices;if(!services){return{handled:false,result:payload,warnings:[]}}return runServiceOverride(services,buildServiceContext(service,payload))}function runActiveServiceOverrideSync(service,payload){const state=runtimeState();const services=state?state.services:activeExtensionServices;if(!services){return{handled:false,result:payload,warnings:[]}}return runServiceOverrideSync(services,buildServiceContext(service,payload))}export*from"./loader.js";export*from"./command-hook-context.js";import{createSerialQueue}from"../shared/serial-queue.js";import{EXTENSION_CAPABILITY_REGISTRATION_SURFACES,collectUsedExtensionCapabilities,reconcileExtensionCapabilityUsage}from"./capability-usage.js";export{EXTENSION_CAPABILITY_REGISTRATION_SURFACES,clearActiveExtensionHooks,collectUsedExtensionCapabilities,consumeAfterCommandAffectedItems,createSerialQueue,getActiveCommandContext,getActiveCommandResult,getActiveExtensionRegistrations,hasActiveOnReadHooks,projectAfterCommandItemSnapshot,reconcileExtensionCapabilityUsage,recordAfterCommandAffectedItem,resetActiveExtensionRuntimeState,resolvePortableWorkspaceContext,runActiveBeforeMutationHooks,runActiveCommandHandler,runActiveCommandOverride,runActiveOnIndexHooks,runActiveOnReadHooks,runActiveOnWriteHooks,runActiveParserOverride,runActivePreflightOverride,runActiveRendererOverride,runActiveServiceOverride,runActiveServiceOverrideSync,runWithIsolatedExtensionRuntime,setActiveCommandContext,setActiveCommandResult,setActiveExtensionCommands,setActiveExtensionHooks,setActiveExtensionParsers,setActiveExtensionPreflight,setActiveExtensionRegistrations,setActiveExtensionRenderers,setActiveExtensionServices};
|
|
1
|
+
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="40b169fc-3c5f-5b2a-8fed-a9388b07d9f7")}catch(e2){}})();import{existsSync}from"node:fs";import{AsyncLocalStorage}from"node:async_hooks";import path from"node:path";import{runCommandHandler,runBeforeMutationHooks,runCommandOverride,runOnIndexHooks,runParserOverride,runPreflightOverride,runOnReadHooks,runRendererOverride,runServiceOverride,runServiceOverrideSync,runOnWriteHooks}from"./loader.js";let activeExtensionHooks=null;let activeExtensionCommands=null;let activeExtensionParsers=null;let activeExtensionPreflight=null;let activeExtensionServices=null;let activeExtensionRenderers=null;let activeExtensionRegistrations=null;let activeCommandContext=null;let activeCommandResult=void 0;let activeAfterCommandAffectedItems=[];const isolatedExtensionRuntime=new AsyncLocalStorage;function runtimeState(){return isolatedExtensionRuntime.getStore()}function runWithIsolatedExtensionRuntime(run){return isolatedExtensionRuntime.run({hooks:null,commands:null,parsers:null,preflight:null,services:null,renderers:null,registrations:null,commandContext:null,commandResult:void 0,affectedItems:[]},run)}const AFTER_COMMAND_SNAPSHOT_OMITTED_FIELDS=new Set(["body","comments","dependencies","docs","events","files","learnings","notes","reminders","test_runs","tests"]);function findSourceRepositoryRoot(candidate){let cursor=path.resolve(candidate);while(true){if(existsSync(path.join(cursor,".git"))){return cursor}const parent=path.dirname(cursor);if(parent===cursor){return void 0}cursor=parent}}function resolvePortableWorkspaceContext(pmRoot){const sourceCandidate=process.env.PM_SOURCE_WORKSPACE_ROOT?.trim()||process.cwd();const sourceWorkspaceRoot=findSourceRepositoryRoot(sourceCandidate)??path.resolve(sourceCandidate);const repoRoot=findSourceRepositoryRoot(sourceWorkspaceRoot);if(!pmRoot){return{source_workspace_root:sourceWorkspaceRoot,...repoRoot?{repo_root:repoRoot}:{}}}const relativePmRoot=path.relative(sourceWorkspaceRoot,path.resolve(pmRoot));const contained=relativePmRoot.length>0&&!relativePmRoot.startsWith(`..${path.sep}`)&&relativePmRoot!==".."&&!path.isAbsolute(relativePmRoot);return{source_workspace_root:sourceWorkspaceRoot,...repoRoot?{repo_root:repoRoot}:{},...contained?{pm_root_rel:relativePmRoot.split(path.sep).join("/")}:{}}}function setActiveExtensionHooks(hooks){const state=runtimeState();if(state){state.hooks=hooks;return}activeExtensionHooks=hooks}function setActiveExtensionCommands(commands){const state=runtimeState();if(state){state.commands=commands;return}activeExtensionCommands=commands}function setActiveExtensionParsers(parsers){const state=runtimeState();if(state){state.parsers=parsers;return}activeExtensionParsers=parsers}function setActiveExtensionPreflight(preflight){const state=runtimeState();if(state){state.preflight=preflight;return}activeExtensionPreflight=preflight}function setActiveExtensionServices(services){const state=runtimeState();if(state){state.services=services;return}activeExtensionServices=services}function setActiveExtensionRenderers(renderers){const state=runtimeState();if(state){state.renderers=renderers;return}activeExtensionRenderers=renderers}function setActiveExtensionRegistrations(registrations){const state=runtimeState();if(state){state.registrations=registrations;return}activeExtensionRegistrations=registrations}function getActiveExtensionRegistrations(){const state=runtimeState();return state?state.registrations:activeExtensionRegistrations}function resetActiveExtensionRuntimeState(){const state=runtimeState();if(state){state.hooks=null;state.commands=null;state.parsers=null;state.preflight=null;state.services=null;state.renderers=null;state.registrations=null;state.commandContext=null;state.commandResult=null;state.affectedItems=[];return}activeExtensionHooks=null;activeExtensionCommands=null;activeExtensionParsers=null;activeExtensionPreflight=null;activeExtensionServices=null;activeExtensionRenderers=null;activeExtensionRegistrations=null;activeCommandContext=null;activeCommandResult=null}function setActiveCommandContext(context){const resolved=context?{...context,...resolvePortableWorkspaceContext(context.pm_root)}:null;const state=runtimeState();if(state){state.commandContext=resolved;return}activeCommandContext=resolved}function getActiveCommandContext(){const state=runtimeState();const context=state?state.commandContext:activeCommandContext;return context?{...context,args:[...context.args],options:context.options?{...context.options}:{},global:context.global?{...context.global}:void 0}:null}function isActiveCommandUnextended(command){const state=runtimeState()??{commandContext:activeCommandContext,hooks:activeExtensionHooks,commands:activeExtensionCommands,parsers:activeExtensionParsers,preflight:activeExtensionPreflight,services:activeExtensionServices,renderers:activeExtensionRenderers,registrations:activeExtensionRegistrations};if(state.commandContext?.command!==command)return false;const broadInterceptors=[state.hooks,state.preflight,state.services,state.renderers];if(broadInterceptors.some(registry=>Object.values(registry??{}).some(entries=>entries.length>0)))return false;const commandInterceptors=[state.commands,state.parsers];if(commandInterceptors.some(registry=>Object.values(registry??{}).some(entries=>entries.some(entry=>entry.command===command))))return false;return!Object.entries(state.registrations??{}).some(([key,entries])=>["migrations","search_providers","vector_store_adapters","assurance_providers"].includes(key)&&entries.length>0)}function setActiveCommandResult(result){const state=runtimeState();if(state){state.commandResult=result;return}activeCommandResult=result}function getActiveCommandResult(){const state=runtimeState();return state?state.commandResult:activeCommandResult}function recordAfterCommandAffectedItem(item){if(!item){return}const state=runtimeState();if(state){state.affectedItems.push(item)}else{activeAfterCommandAffectedItems.push(item)}}function projectAfterCommandItemSnapshot(metadata,changedFields){if(!metadata||!metadata.id){return{}}const snapshot={id:metadata.id,type:metadata.type,status:metadata.status};if(!Array.isArray(changedFields)){return snapshot}const source=metadata;for(const field of changedFields){if(typeof field!=="string"){continue}const actualField=field.startsWith("unset:")?field.slice("unset:".length):field;if(actualField==="id"||actualField==="type"||actualField==="status"||AFTER_COMMAND_SNAPSHOT_OMITTED_FIELDS.has(actualField)){continue}if(Object.hasOwn(source,actualField)&&source[actualField]!==void 0){snapshot[actualField]=source[actualField]}}return snapshot}function consumeAfterCommandAffectedItems(){const state=runtimeState();const affectedItems=state?.affectedItems??activeAfterCommandAffectedItems;if(affectedItems.length===0){return void 0}const affected=affectedItems;if(state){state.affectedItems=[]}else{activeAfterCommandAffectedItems=[]}return affected}function clearActiveExtensionHooks(){const state=runtimeState();if(state){state.hooks=null;state.commands=null;state.parsers=null;state.preflight=null;state.services=null;state.renderers=null;state.registrations=null;state.commandContext=null;state.commandResult=void 0;state.affectedItems=[];return}activeExtensionHooks=null;activeExtensionCommands=null;activeExtensionParsers=null;activeExtensionPreflight=null;activeExtensionServices=null;activeExtensionRenderers=null;activeExtensionRegistrations=null;activeCommandContext=null;activeCommandResult=void 0;activeAfterCommandAffectedItems=[]}async function runActiveOnWriteHooks(context){const state=runtimeState();const hooks=state?state.hooks:activeExtensionHooks;if(!hooks){return[]}return runOnWriteHooks(hooks,context)}async function runActiveBeforeMutationHooks(context){const state=runtimeState();const hooks=state?state.hooks:activeExtensionHooks;if(!hooks)return;await runBeforeMutationHooks(hooks,context)}async function runActiveOnReadHooks(context){const state=runtimeState();const hooks=state?state.hooks:activeExtensionHooks;if(!hooks){return[]}return runOnReadHooks(hooks,context)}function hasActiveOnReadHooks(){const state=runtimeState();const hooks=state?state.hooks:activeExtensionHooks;return(hooks?.onRead?.length??0)>0}async function runActiveOnIndexHooks(context){const state=runtimeState();const hooks=state?state.hooks:activeExtensionHooks;if(!hooks){return[]}return runOnIndexHooks(hooks,context)}function runActiveCommandOverride(result){const state=runtimeState();const commands=state?state.commands:activeExtensionCommands;const commandContext=state?state.commandContext:activeCommandContext;if(!commands||!commandContext){return{overridden:false,result,warnings:[]}}return runCommandOverride(commands,{command:commandContext.command,args:[...commandContext.args],options:commandContext.options?{...commandContext.options}:{},global:commandContext.global?{...commandContext.global}:void 0,pm_root:commandContext.pm_root,source_workspace_root:commandContext.source_workspace_root,repo_root:commandContext.repo_root,pm_root_rel:commandContext.pm_root_rel,result})}async function runActiveCommandHandler(context){const state=runtimeState();const commands=state?state.commands:activeExtensionCommands;if(!commands){return{handled:false,result:null,warnings:[]}}return runCommandHandler(commands,{...context,...resolvePortableWorkspaceContext(context.pm_root)})}async function runActiveParserOverride(context){const state=runtimeState();const parsers=state?state.parsers:activeExtensionParsers;if(!parsers){return{overridden:false,context:{command:context.command,args:[...context.args],options:{...context.options},global:{...context.global},pm_root:context.pm_root},warnings:[]}}return runParserOverride(parsers,{...context,...resolvePortableWorkspaceContext(context.pm_root)})}async function runActivePreflightOverride(context){const state=runtimeState();const preflight=state?state.preflight:activeExtensionPreflight;if(!preflight){return{overridden:false,context:{command:context.command,args:[...context.args],options:{...context.options},global:{...context.global},pm_root:context.pm_root},decision:{...context.decision},warnings:[]}}return runPreflightOverride(preflight,{...context,...resolvePortableWorkspaceContext(context.pm_root)})}function runActiveRendererOverride(format,result){const state=runtimeState();const renderers=state?state.renderers:activeExtensionRenderers;const commandContext=state?state.commandContext:activeCommandContext;if(!renderers){return{overridden:false,rendered:null,warnings:[]}}return runRendererOverride(renderers,{format,command:commandContext?.command,args:commandContext?[...commandContext.args]:[],options:commandContext?.options?{...commandContext.options}:{},global:commandContext?.global?{...commandContext.global}:void 0,pm_root:commandContext?.pm_root,source_workspace_root:commandContext?.source_workspace_root,repo_root:commandContext?.repo_root,pm_root_rel:commandContext?.pm_root_rel,result})}function buildServiceContext(service,payload){const state=runtimeState();const commandContext=state?state.commandContext:activeCommandContext;return{service,command:commandContext?.command,args:commandContext?[...commandContext.args]:[],options:commandContext?.options?{...commandContext.options}:{},global:commandContext?.global?{...commandContext.global}:void 0,pm_root:commandContext?.pm_root,source_workspace_root:commandContext?.source_workspace_root,repo_root:commandContext?.repo_root,pm_root_rel:commandContext?.pm_root_rel,payload}}async function runActiveServiceOverride(service,payload){const state=runtimeState();const services=state?state.services:activeExtensionServices;if(!services){return{handled:false,result:payload,warnings:[]}}return runServiceOverride(services,buildServiceContext(service,payload))}function runActiveServiceOverrideSync(service,payload){const state=runtimeState();const services=state?state.services:activeExtensionServices;if(!services){return{handled:false,result:payload,warnings:[]}}return runServiceOverrideSync(services,buildServiceContext(service,payload))}export*from"./loader.js";export*from"./command-hook-context.js";import{createSerialQueue}from"../shared/serial-queue.js";import{EXTENSION_CAPABILITY_REGISTRATION_SURFACES,collectUsedExtensionCapabilities,reconcileExtensionCapabilityUsage}from"./capability-usage.js";export{EXTENSION_CAPABILITY_REGISTRATION_SURFACES,clearActiveExtensionHooks,collectUsedExtensionCapabilities,consumeAfterCommandAffectedItems,createSerialQueue,getActiveCommandContext,getActiveCommandResult,getActiveExtensionRegistrations,hasActiveOnReadHooks,isActiveCommandUnextended,projectAfterCommandItemSnapshot,reconcileExtensionCapabilityUsage,recordAfterCommandAffectedItem,resetActiveExtensionRuntimeState,resolvePortableWorkspaceContext,runActiveBeforeMutationHooks,runActiveCommandHandler,runActiveCommandOverride,runActiveOnIndexHooks,runActiveOnReadHooks,runActiveOnWriteHooks,runActiveParserOverride,runActivePreflightOverride,runActiveRendererOverride,runActiveServiceOverride,runActiveServiceOverrideSync,runWithIsolatedExtensionRuntime,setActiveCommandContext,setActiveCommandResult,setActiveExtensionCommands,setActiveExtensionHooks,setActiveExtensionParsers,setActiveExtensionPreflight,setActiveExtensionRegistrations,setActiveExtensionRenderers,setActiveExtensionServices};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/core/lock/lock.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
-
`,"utf8")}finally{await handle.close()}await emitLockWriteHook(lockPath,"lock:create")}async function unlinkLockWithHook(lockPath,op){try{await fs.unlink(lockPath);await emitLockWriteHook(lockPath,op);return true}catch{return false}}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,false);if(isOwnedLock(current2.info,id,owner,token)){await unlinkLockWithHook(lockPath,"lock:release")}}finally{await releaseCleanupGate()}return}const current=await readLockInfo(lockPath,false);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;const ageMs=Number.isFinite(createdAtMs)?Date.now()-createdAtMs:Number.POSITIVE_INFINITY;return ageMs>ttlSeconds*1e3}function lockOwnerSuffix(info){return info?.owner?` (owner ${info.owner})`:""}const LOCK_WAIT_INITIAL_DELAY_MS=25;const LOCK_WAIT_MAX_DELAY_MS=200;const LOCK_CONFLICT_RETRY_HINT_MS=250;const MAX_STALE_LOCK_REMOVALS=3;const STALE_CLEANUP_GATE_SUFFIX=".stale-cleanup";const STALE_CLEANUP_GATE_OWNER_FILE="owner.json";const STALE_CLEANUP_GATE_STALE_MS=1e4;const LOCK_RELEASE_GATE_WAIT_MS=STALE_CLEANUP_GATE_STALE_MS+LOCK_WAIT_MAX_DELAY_MS;const STALE_CLEANUP_GATE_MAX_UNVERIFIED_MS=60*6e4;function parseNonNegativeIntegerWaitMs(value){if(typeof value==="string"){const trimmed=value.trim();if(!/^\d+$/.test(trimmed)){return void 0}const parsed=Number(trimmed);return Number.isSafeInteger(parsed)?parsed:void 0}if(typeof value==="number"&&Number.isFinite(value)&&value>=0){return Math.trunc(value)}return void 0}function resolveLockWaitMs(waitMs){const envRaw=process.env.PM_LOCK_WAIT_MS;const envParsed=parseNonNegativeIntegerWaitMs(envRaw);if(envParsed!==void 0){return envParsed}const callerParsed=parseNonNegativeIntegerWaitMs(waitMs);if(callerParsed!==void 0){return callerParsed}return 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;const pid=candidate.pid;const token=candidate.token;const processStartIdentity=candidate.process_start_identity;if(typeof pid!=="number"||!Number.isInteger(pid)||pid<=0||typeof token!=="string"||token.length===0||processStartIdentity!==void 0&&(typeof processStartIdentity!=="string"||!/^\d+$/u.test(processStartIdentity))){return null}return{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 false;try{process.kill(pid,0);return true}catch(error){if(isErrno(error,"ESRCH")){return false}return true}}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 false;const currentStartIdentity=await readProcessStartIdentity(identity.pid);if(identity.process_start_identity!==void 0&¤tStartIdentity!==null){return currentStartIdentity===identity.process_start_identity}return unverifiedAgeMs<=maxUnverifiedAgeMs}async function removeStaleCleanupGateDirectory(gatePath){try{await fs.rm(gatePath,{recursive:true,force:true});return true}catch{return false}}async function releaseStaleCleanupGate(gatePath,token){const owner=await readStaleCleanupGateOwner(gatePath);if(owner===null||owner.token!==token){return}await removeStaleCleanupGateDirectory(gatePath)}async function tryCreateStaleCleanupGate(gatePath){try{await fs.mkdir(gatePath)}catch(error){if(isErrno(error,"EEXIST")){return null}return null}const owner={...await captureProcessIdentity(),token:randomUUID()};try{await fs.writeFile(path.join(gatePath,STALE_CLEANUP_GATE_OWNER_FILE),`${JSON.stringify(owner)}
|
|
1
|
+
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="f0484213-41f9-583e-bd0f-f85e507682b2")}catch(e2){}})();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;const id=candidate.id;const pid=candidate.pid;const owner=candidate.owner;const token=candidate.token;const createdAt=candidate.created_at;const ttlSeconds=candidate.ttl_seconds;if(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)){return{info:null,warnings:["lock_info_invalid_shape"]}}return{info:{id,pid,owner,...typeof token==="string"?{token}:{},created_at:createdAt,ttl_seconds:ttlSeconds},warnings:[]}}async function readLockInfo(lockPath,emitReadHook=true){try{const raw=await fs.readFile(lockPath,"utf8");if(emitReadHook){await runActiveOnReadHooks({path:lockPath,scope:"project"})}return parseLockInfo(raw)}catch(error){if(isFileMissingError(error)){return{info:null,warnings:[]}}return{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 true;if(!isErrno(error,"EPERM")&&!isErrno(error,"EACCES")&&!isErrno(error,"EBUSY")){return false}try{await fs.lstat(lockPath);return true}catch(probeError){if(platform!=="win32"||!isFileMissingError(probeError)&&!isErrno(probeError,"EPERM")&&!isErrno(probeError,"EACCES")&&!isErrno(probeError,"EBUSY")){return false}}try{await fs.access(path.dirname(lockPath),fsConstants.W_OK);return true}catch{return false}}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){await fs.mkdir(path.dirname(lockPath),{recursive:true});const releaseCleanupGate=await acquireStaleCleanupGate(lockPath,id);if(releaseCleanupGate===null){throw 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){await unlinkLockWithHook(lockPath,"lock:release");throw error}}finally{await releaseCleanupGate()}await emitLockWriteHook(lockPath,"lock:create")}async function unlinkLockWithHook(lockPath,op){try{await fs.unlink(lockPath);await emitLockWriteHook(lockPath,op);return true}catch{return false}}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,false);if(isOwnedLock(current2.info,id,owner,token)){await unlinkLockWithHook(lockPath,"lock:release")}}finally{await releaseCleanupGate()}return}const current=await readLockInfo(lockPath,false);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;const ageMs=Number.isFinite(createdAtMs)?Date.now()-createdAtMs:Number.POSITIVE_INFINITY;return ageMs>ttlSeconds*1e3}function lockOwnerSuffix(info){return info?.owner?` (owner ${info.owner})`:""}const LOCK_WAIT_INITIAL_DELAY_MS=25;const LOCK_WAIT_MAX_DELAY_MS=200;const LOCK_CONFLICT_RETRY_HINT_MS=250;const MAX_STALE_LOCK_REMOVALS=3;const STALE_CLEANUP_GATE_SUFFIX=".stale-cleanup";const STALE_CLEANUP_GATE_OWNER_FILE="owner.json";const STALE_CLEANUP_GATE_STALE_MS=1e4;const LOCK_RELEASE_GATE_WAIT_MS=STALE_CLEANUP_GATE_STALE_MS+LOCK_WAIT_MAX_DELAY_MS;const STALE_CLEANUP_GATE_MAX_UNVERIFIED_MS=60*6e4;function parseNonNegativeIntegerWaitMs(value){if(typeof value==="string"){const trimmed=value.trim();if(!/^\d+$/.test(trimmed)){return void 0}const parsed=Number(trimmed);return Number.isSafeInteger(parsed)?parsed:void 0}if(typeof value==="number"&&Number.isFinite(value)&&value>=0){return Math.trunc(value)}return void 0}function resolveLockWaitMs(waitMs){const envRaw=process.env.PM_LOCK_WAIT_MS;const envParsed=parseNonNegativeIntegerWaitMs(envRaw);if(envParsed!==void 0){return envParsed}const callerParsed=parseNonNegativeIntegerWaitMs(waitMs);if(callerParsed!==void 0){return callerParsed}return 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;const pid=candidate.pid;const token=candidate.token;const processStartIdentity=candidate.process_start_identity;if(typeof pid!=="number"||!Number.isInteger(pid)||pid<=0||typeof token!=="string"||token.length===0||processStartIdentity!==void 0&&(typeof processStartIdentity!=="string"||!/^\d+$/u.test(processStartIdentity))){return null}return{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 false;try{process.kill(pid,0);return true}catch(error){if(isErrno(error,"ESRCH")){return false}return true}}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 false;const currentStartIdentity=await readProcessStartIdentity(identity.pid);if(identity.process_start_identity!==void 0&¤tStartIdentity!==null){return currentStartIdentity===identity.process_start_identity}return unverifiedAgeMs<=maxUnverifiedAgeMs}async function removeStaleCleanupGateDirectory(gatePath){try{await fs.rm(gatePath,{recursive:true,force:true});return true}catch{return false}}async function releaseStaleCleanupGate(gatePath,token){const owner=await readStaleCleanupGateOwner(gatePath);if(owner===null||owner.token!==token){return}await removeStaleCleanupGateDirectory(gatePath)}async function tryCreateStaleCleanupGate(gatePath){try{await fs.mkdir(gatePath)}catch(error){if(isErrno(error,"EEXIST")){return null}return null}const owner={...await captureProcessIdentity(),token:randomUUID()};try{await fs.writeFile(path.join(gatePath,STALE_CLEANUP_GATE_OWNER_FILE),`${JSON.stringify(owner)}
|
|
3
3
|
`,"utf8")}catch{await removeStaleCleanupGateDirectory(gatePath);return null}return owner}async function removeExpiredStaleCleanupGate(gatePath){let gateAgeMs;try{const stats=await fs.stat(gatePath);gateAgeMs=Date.now()-stats.mtimeMs;if(gateAgeMs<=STALE_CLEANUP_GATE_STALE_MS){return false}}catch(error){return isFileMissingError(error)}const owner=await readStaleCleanupGateOwner(gatePath);if(owner!==null&&await isProcessIdentityAlive(owner,gateAgeMs,STALE_CLEANUP_GATE_MAX_UNVERIFIED_MS)){return false}return removeStaleCleanupGateDirectory(gatePath)}async function acquireStaleCleanupGate(lockPath,_id){const gatePath=`${lockPath}${STALE_CLEANUP_GATE_SUFFIX}`;const owner=await tryCreateStaleCleanupGate(gatePath);if(owner!==null){return async()=>releaseStaleCleanupGate(gatePath,owner.token)}if(!await removeExpiredStaleCleanupGate(gatePath)){return null}const recoveredOwner=await tryCreateStaleCleanupGate(gatePath);if(recoveredOwner===null){return null}return 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:false,staleRemovalCounted:false}}try{const currentLockInfo=await readLockInfo(params.lockPath);if(currentLockInfo.info===null&¤tLockInfo.warnings.length===0){return{lockInfo:currentLockInfo,shouldRetryCreate:true,staleRemovalCounted:false}}if(!isStaleLock(currentLockInfo.info,params.ttlSeconds)){return{lockInfo:currentLockInfo,shouldRetryCreate:false,staleRemovalCounted:false}}throwIfStaleLockNeedsForce(params.id,currentLockInfo,params.force,params.forceRequiredForStaleLock);if(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:true}}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=false,forceRequiredForStaleLock=true,waitMs){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);const waitBudgetMs=resolveLockWaitMs(waitMs);const startedAtMs=Date.now();let staleRemovals=0;let backoffMs=LOCK_WAIT_INITIAL_DELAY_MS;const token=randomUUID();for(;;){try{await createLockFile(lockPath,id,owner,ttlSeconds,token);return 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});lockInfo=staleRemoval.lockInfo;if(staleRemoval.staleRemovalCounted){staleRemovals+=1}if(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,isProcessIdentityAlive,readProcessStartIdentity};
|
|
4
4
|
//# sourceMappingURL=lock.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="2ca9480d-0ae4-50e8-887e-c4183501d92c")}catch(e2){}})();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";const DECLARED_PROCESS_EXIT_CODES=new Set(Object.values(EXIT_CODE));const NATIVE_OUTPUT_MARKER="__pm_native_output";let streamErrorHandlersInstalled=false;function isPlainObject(value){return typeof value==="object"&&value!==null&&!Array.isArray(value)}function setActiveCommandResultOmitted(source){const omitted={read_output:{result_omitted:true}};propagateContextUsageServingReceipt(source,omitted);setActiveCommandResult(omitted)}function setActiveCommandDeliveryResult(result,receiptSource,structuredDeliveryPreserved){if(structuredDeliveryPreserved){setActiveCommandResult(result);return}setActiveCommandResultOmitted(receiptSource)}function shouldUseNativeOutput(result){return isPlainObject(result)&&result[NATIVE_OUTPUT_MARKER]===true}function stripNativeOutputMarker(result){if(!isPlainObject(result)||result[NATIVE_OUTPUT_MARKER]!==true){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(){if(process.exitCode===void 0||process.exitCode===EXIT_CODE.SUCCESS){process.exitCode=EXIT_CODE.SUCCESS}}function markStderrBrokenPipeExitCode(){if(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(){if(streamErrorHandlersInstalled){return}streamErrorHandlersInstalled=true;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{if(target==="stdout"){process.stdout.write(text)}else{process.stderr.write(text)}return true}catch(error){if(isBrokenPipeError(error)){markBrokenPipeExitCode(target);return false}throw error}}function writeStdout(text){return writeToStream("stdout",text)}function writeStderr(text){return writeToStream("stderr",text)}function renderScalar(value){if(typeof value==="string")return JSON.stringify(value);if(typeof value==="number"||typeof value==="boolean")return String(value);if(value===null)return"null";return JSON.stringify(value)}function isToonPrimitive(value){return value===null||typeof value==="string"||typeof value==="number"||typeof value==="boolean"}function tabularObjectArray(value){if(value.length===0||!value.every(isPlainObject))return false;const keys=Object.keys(value[0]);return keys.length>0&&value.every(entry=>Object.keys(entry).length===keys.length&&keys.every(key=>Object.hasOwn(entry,key)&&isToonPrimitive(entry[key])))}function indentToon(encoded,depth){const indent=" ".repeat(depth);return encoded.split("\n").map(line=>`${indent}${line}`).join("\n")}function renderToonObjectEntry(key,entry,depth){const indent=" ".repeat(depth);if(!isPlainObject(entry)&&!Array.isArray(entry)){return`${indent}${key}: ${renderScalar(entry)}`}if(Array.isArray(entry)&&entry.length===0){return`${indent}${key}: []`}if(Array.isArray(entry)&&tabularObjectArray(entry)){return indentToon(encodeToon({[key]:entry}),depth)}if(isPlainObject(entry)&&Object.keys(entry).length===0){return`${indent}${key}: {}`}return`${indent}${key}:
|
|
2
2
|
${renderToonValue(entry,depth+1)}`}function compactToonValue(value){if(value===null||value===void 0){return void 0}if(Array.isArray(value)){const compactedEntries=value.map(entry=>compactToonValue(entry)).filter(entry=>entry!==void 0);return compactedEntries.length>0?compactedEntries:void 0}if(isPlainObject(value)){const compacted={};for(const[key,entry]of Object.entries(value)){if(key==="omitted_field_groups"&&Array.isArray(entry)&&entry.length===0){compacted[key]=[];continue}const compactedEntry=compactToonValue(entry);if(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)){if(value.length===0)return"[]";if(tabularObjectArray(value)){return indentToon(encodeToon(value),depth)}return value.map(entry=>{if(!isPlainObject(entry)&&!Array.isArray(entry)){return`${indent}- ${renderScalar(entry)}`}const rendered=renderToonValue(entry,depth+1);const lines=rendered.split("\n");const[firstLine,...rest]=lines;if(rest.length===0){return`${indent}- ${firstLine.trimStart()}`}return`${indent}- ${firstLine.trimStart()}
|
|
3
3
|
${rest.join("\n")}`}).join("\n")}if(isPlainObject(value)){const entries=Object.entries(value);if(entries.length===0)return"{}";return entries.map(([key,entry])=>renderToonObjectEntry(key,entry,depth)).join("\n")}return`${indent}${renderScalar(value)}`}function renderDefaultMarkdownResult(value){if(!isPlainObject(value)||value.output_default!=="markdown"){return null}if(typeof value.view!=="string"||!Array.isArray(value.events)||!Array.isArray(value.days)){return null}const lines=[`# pm calendar (${value.view})`,""];const summary=isPlainObject(value.summary)?value.summary:{};lines.push(`- events: ${String(summary.events??0)}`);lines.push("");if(value.events.length===0){lines.push("No calendar events matched the selected filters.");return`${lines.join("\n")}
|
|
4
4
|
`}for(const event of value.events){if(!isPlainObject(event)){continue}const kind=typeof event.kind==="string"?event.kind:"event";const title=typeof event.item_title==="string"?event.item_title:"";const itemId=typeof event.item_id==="string"?event.item_id:"";const reminderText=typeof event.reminder_text==="string"&&event.reminder_text.length>0?` ${event.reminder_text}`:"";lines.push(`- [${kind}] ${itemId} ${title}${reminderText}`.trim())}return`${lines.join("\n")}
|
|
5
|
-
`}function resolveOutputFormat(options){return options.json===true||options.json===void 0&&options.defaultOutputFormat==="json"?"json":"toon"}const LEAN_READ_ENVELOPE_ECHO_KEYS=new Set(["filters","now","projection","sorting"]);function projectLeanJsonValue(value){const compacted=compactToonValue(value);if(!isPlainObject(compacted)||!Array.isArray(compacted.items)){return compacted??null}const projected=Object.fromEntries(Object.entries(compacted).filter(([key])=>!LEAN_READ_ENVELOPE_ECHO_KEYS.has(key)));if(projected.has_more!==true){delete projected.next_cursor}return projected}function projectLinkedTestEvidence(value,lean){if(!isPlainObject(value)||!Array.isArray(value.run_results)){return value}if(!value.run_results.every(isPlainObject)){return value}const rows=value.run_results;const contexts=rows.map(row=>row.execution_context).filter(context=>context!==void 0);const sharedContext=contexts.length===rows.length&&contexts.length>0&&contexts.every(context=>JSON.stringify(context)===JSON.stringify(contexts[0]))?contexts[0]:void 0;const runResults=rows.map(row=>{const{execution_context:_executionContext,stdout,stderr,...rest}=row;if(sharedContext===void 0){return row}if(!lean||row.status!=="passed"){return{...rest,stdout,stderr}}return rest});return{...value,...sharedContext===void 0?{}:{execution_context:sharedContext},run_results:runResults}}function formatBuiltInOutput(result,format){if(format==="json"){return`${JSON.stringify(result,null,2)}
|
|
6
|
-
`}const compactedToon=compactToonValue(result);return compactedToon===void 0?"{}\n":`${renderToonValue(compactedToon,0)}
|
|
5
|
+
`}function resolveOutputFormat(options){return options.json===true||options.json===void 0&&options.defaultOutputFormat==="json"?"json":"toon"}const LEAN_READ_ENVELOPE_ECHO_KEYS=new Set(["filters","now","projection","sorting"]);function projectLeanJsonValue(value){const compacted=compactToonValue(value);if(!isPlainObject(compacted)||!Array.isArray(compacted.items)){return compacted??null}const projected=Object.fromEntries(Object.entries(compacted).filter(([key])=>!LEAN_READ_ENVELOPE_ECHO_KEYS.has(key)));if(projected.has_more!==true){delete projected.next_cursor}return projected}function projectLinkedTestEvidence(value,lean){if(!isPlainObject(value)||!Array.isArray(value.run_results)){return value}if(!value.run_results.every(isPlainObject)){return value}const rows=value.run_results;const contexts=rows.map(row=>row.execution_context).filter(context=>context!==void 0);const sharedContext=contexts.length===rows.length&&contexts.length>0&&contexts.every(context=>JSON.stringify(context)===JSON.stringify(contexts[0]))?contexts[0]:void 0;const runResults=rows.map(row=>{const{execution_context:_executionContext,stdout,stderr,...rest}=row;if(sharedContext===void 0){return row}if(!lean||row.status!=="passed"){return{...rest,stdout,stderr}}return rest});return{...value,...sharedContext===void 0?{}:{execution_context:sharedContext},run_results:runResults}}function projectCompleteBriefList(value){if(!isPlainObject(value)||!Array.isArray(value.items)||Object.hasOwn(value,"details")||!isPlainObject(value.projection)||value.projection.mode!=="brief"||!isPlainObject(value.completeness)||value.completeness.status!=="complete"||[value.completeness.unreadable_item_count,value.completeness.unreadable_directory_count].some(count=>count!==0)||[value.has_more,value.truncated].some(flag=>flag!==false)||value.count!==value.items.length||value.total!==value.count||!isPlainObject(value.omission_receipt)||JSON.stringify(value.omission_receipt.omitted_field_groups)!==JSON.stringify([{name:"full_item_fields",restore_with:"--full"}])){return value}const{total:_total,has_more:_hasMore,truncated:_truncated,next_cursor:_nextCursor,completeness:_completeness,projection:_projection,now:_now,omission_receipt:_omissions,sorting,...rest}=value;return{...rest,...isPlainObject(sorting)&&sorting.sort==="default"?{}:{sorting},details:"--full"}}function formatBuiltInOutput(result,format){if(format==="json"){return`${JSON.stringify(result,null,2)}
|
|
6
|
+
`}const compactedToon=compactToonValue(projectCompleteBriefList(result));return compactedToon===void 0?"{}\n":`${renderToonValue(compactedToon,0)}
|
|
7
7
|
`}function resolveOutputService(effectiveResult,nativeOutput,options,format){const serviceOverride=nativeOutput?{handled:false,result:effectiveResult,warnings:[]}:runActiveServiceOverrideSync("output_format",{command:options.command,args:options.commandArgs,command_options:options.commandOptions,global:{...options},pm_root:options.pmRoot,format,options:{...options},result:effectiveResult});const legacyPayloadEchoWarning=serviceOverride.warnings.find(warning=>warning.startsWith("extension_output_format_payload_echo_deprecated:"));if(legacyPayloadEchoWarning!==void 0){writeStderr(`Warning: ${legacyPayloadEchoWarning}. Returning context.payload now declines safely for compatibility; migrate the override to declineServiceOverride() or { handled: false }.
|
|
8
8
|
`)}if(serviceOverride.handled&&typeof serviceOverride.result==="string"){return{result:serviceOverride.result,rendered:serviceOverride.result.endsWith("\n")?serviceOverride.result:`${serviceOverride.result}
|
|
9
9
|
`,structuredDeliveryPreserved:false}}return{result:serviceOverride.handled?serviceOverride.result:effectiveResult,rendered:null,structuredDeliveryPreserved:!serviceOverride.handled||isPlainObject(serviceOverride.result)}}function formatEffectiveOutput(effectiveResult,nativeOutput,options){const activeCommandContext=getActiveCommandContext();const command=options.command??activeCommandContext?.command;const commandOptions={...activeCommandContext?.options,...options.commandOptions,...Object.fromEntries([["outputInclude",options.outputInclude],["outputLimit",options.outputLimit],["outputBudget",options.outputBudget],["outputFormat",options.outputFormat],["outputSession",options.outputSession],["outputCursor",options.outputCursor],["outputRowContract",options.outputRowContract]].filter(entry=>entry[1]!==void 0))};const format=resolveReadOutputEncoding(command??"",commandOptions)??resolveOutputFormat(options);const resolvedCommandOptions={...commandOptions,resolvedOutputFormat:format};const effectiveOptions={...options,command,commandOptions:resolvedCommandOptions};const service=resolveOutputService(effectiveResult,nativeOutput,effectiveOptions,format);if(service.rendered!==null){setActiveCommandResultOmitted(effectiveResult);return service.rendered}const outputResult=service.result;propagateContextUsageServingReceipt(effectiveResult,outputResult);const projectedOutputResult=command==="test"?projectLinkedTestEvidence(outputResult,options.lean===true):outputResult;const intentOutputResult=attachReadOutputContracts(command,resolvedCommandOptions,projectedOutputResult);if(isReadOutputBudgetExceeded(intentOutputResult)){process.exitCode||=EXIT_CODE.USAGE}let{structuredDeliveryPreserved}=service;const renderResolvedOutput=value=>{if(format==="toon"){const markdownDefault=renderDefaultMarkdownResult(value);if(markdownDefault!==null)return markdownDefault}const rendererOverride=nativeOutput?{rendered:null}:runActiveRendererOverride(format,value);if(rendererOverride.rendered!==null){structuredDeliveryPreserved=false;return rendererOverride.rendered.endsWith("\n")?rendererOverride.rendered:`${rendererOverride.rendered}
|
|
@@ -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
|
+
/** Fixed core reads eligible only after runtime ownership has been established. */
|
|
4
|
+
export declare const TELEMETRY_SAMPLEABLE_READS: ReadonlySet<string>;
|
|
3
5
|
/** Resolve explicit read sampling only for core-only invocations with no write-capable extensions. */
|
|
4
6
|
export declare function resolveTelemetryReadSampleRate(command: string, noExtensions: boolean, env?: Readonly<Record<string, string | undefined>>): number;
|
|
5
7
|
/** Explain process opt-outs without reading settings or creating installation identity. */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="c4fba032-7cda-53a2-b518-fa13a60a76d5")}catch(e2){}})();const TRUE_VALUES=new Set(["1","true","yes","on"]);const PM_TELEMETRY_SOURCE_CONTEXT_VALUES=["user","automation","test","dogfood"];const SOURCE_CONTEXTS=new Set(PM_TELEMETRY_SOURCE_CONTEXT_VALUES);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);const override=(env.PM_TELEMETRY_SOURCE_CONTEXT??"").trim().toLowerCase();const inferredTest=typeof env.VITEST==="string"||typeof env.VITEST_WORKER_ID==="string"||(env.NODE_ENV??"").trim().toLowerCase()==="test";const testSuppressed=inferredTest&&!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,resolveTelemetryEnvironmentPolicy,resolveTelemetryReadSampleRate};
|
|
2
2
|
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retain the first ten reads of each command per UTC minute, then sample the
|
|
3
|
+
* nth read at (10/n)^2. Expected retained successes stay below twenty per
|
|
4
|
+
* command per minute; this is a statistical bound, not a hard delivery cap.
|
|
5
|
+
* Explicit rates bypass automatic state. Corrupt or inaccessible state retains
|
|
6
|
+
* the invocation. Failures must override the returned probability at finish.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveAutomaticReadSampleRate(globalPmRoot: string, command: string, coreReadOwned: boolean, env?: Readonly<Record<string, string | undefined>>, now?: number): Promise<number>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
!(function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="9d949852-abfe-5fbd-88c5-5da0cfbaf7de")}catch(e2){}})();import path from"node:path";import{readFileIfExists,writeFileAtomic}from"../fs/fs-utils.js";import{resolveTelemetryReadSampleRate,TELEMETRY_SAMPLEABLE_READS}from"./policy.js";async function resolveAutomaticReadSampleRate(globalPmRoot,command,coreReadOwned,env=process.env,now=Date.now()){if(!coreReadOwned||!TELEMETRY_SAMPLEABLE_READS.has(command))return 1;if(env.PM_TELEMETRY_READ_SAMPLE_RATE!==void 0){return resolveTelemetryReadSampleRate(command,true,env)}try{const statePath=path.join(globalPmRoot,"runtime","telemetry","read-sampling.json");const minute=Math.floor(now/6e4);const counts=parseReadCounts(await readFileIfExists(statePath),minute);const ordinal=Math.min(Number.MAX_SAFE_INTEGER,(counts[command]??0)+1);counts[command]=ordinal;await writeFileAtomic(statePath,`${JSON.stringify({minute,counts})}
|
|
2
|
+
`);return Math.min(1,(10/ordinal)**2)}catch{return 1}}function parseReadCounts(raw,minute){const counts={};let previous;try{previous=JSON.parse(raw??"null")}catch{return counts}if(typeof previous!=="object"||previous===null||!("minute"in previous)||previous.minute!==minute||!("counts"in previous)||typeof previous.counts!=="object"||previous.counts===null)return counts;for(const[key,value]of Object.entries(previous.counts)){if(TELEMETRY_SAMPLEABLE_READS.has(key)&&typeof value==="number"&&Number.isSafeInteger(value)&&value>=0)counts[key]=value}return counts}export{resolveAutomaticReadSampleRate};
|
|
3
|
+
//# sourceMappingURL=read-sampling.js.map
|
|
@@ -51,7 +51,7 @@ interface PendingOtelSpan {
|
|
|
51
51
|
}
|
|
52
52
|
type TelemetryCaptureLevel = "minimal" | "redacted" | "max";
|
|
53
53
|
type TelemetrySourceContext = (typeof PM_TELEMETRY_SOURCE_CONTEXT_VALUES)[number];
|
|
54
|
-
type TelemetrySourceContextSource = "inferred" | "env_override";
|
|
54
|
+
type TelemetrySourceContextSource = "inferred" | "env_override" | "env_override_rejected";
|
|
55
55
|
interface ResolvedTelemetrySourceContext {
|
|
56
56
|
source_context: TelemetrySourceContext;
|
|
57
57
|
source_context_source: TelemetrySourceContextSource;
|
|
@@ -72,7 +72,7 @@ export interface ActiveTelemetryCommand {
|
|
|
72
72
|
pm_version: string;
|
|
73
73
|
/** Value that configures or reports source context for this contract. */
|
|
74
74
|
source_context: TelemetrySourceContext;
|
|
75
|
-
/**
|
|
75
|
+
/** Whether attribution was inferred, explicitly accepted, or inferred after rejecting an override without retaining its value. */
|
|
76
76
|
source_context_source: TelemetrySourceContextSource;
|
|
77
77
|
/** Value that configures or reports installation id for this contract. */
|
|
78
78
|
installation_id: string;
|
|
@@ -177,14 +177,19 @@ declare function parseBooleanTrueLike(value: string | undefined): boolean;
|
|
|
177
177
|
declare function resolveTelemetryHttpTimeoutMs(): number;
|
|
178
178
|
/** POST a JSON payload with one total timeout that covers DNS, connection, TLS, and response completion. */
|
|
179
179
|
declare function postTelemetryJson(endpoint: string, headers: Record<string, string>, body: string): Promise<number>;
|
|
180
|
+
/** Use a trimmed package version when provided, falling back to 0.0.0 for an unknown producer version. */
|
|
180
181
|
declare function normalizePmVersion(value: string | undefined): string;
|
|
182
|
+
/** Trim a supplied diagnostic code and omit missing or whitespace-only codes from event payloads. */
|
|
181
183
|
declare function normalizeTelemetryErrorCode(value: string | undefined): string | undefined;
|
|
184
|
+
/** Preserve finite non-negative integer exit codes; otherwise derive zero for success and one for failure. */
|
|
182
185
|
declare function normalizeTelemetryExitCode(exitCode: number | undefined, ok: boolean): number;
|
|
186
|
+
/** Omit categories for successful outcomes; preserve explicit failure categories or derive them from a stable error code. */
|
|
183
187
|
declare function normalizeTelemetryErrorCategory(params: {
|
|
184
188
|
ok: boolean;
|
|
185
189
|
errorCode?: string;
|
|
186
190
|
errorCategory?: TelemetryErrorCategory;
|
|
187
191
|
}): TelemetryErrorCategory | undefined;
|
|
192
|
+
/** Resolve explicit attribution and explain rejected input without retaining its value. */
|
|
188
193
|
declare function resolveTelemetrySourceContext(globalOptions: GlobalOptions): ResolvedTelemetrySourceContext;
|
|
189
194
|
/**
|
|
190
195
|
* Builds privacy-bounded author and agent dimensions for a telemetry payload.
|
|
@@ -225,6 +230,7 @@ declare function buildOtelSpanRequest(activeCommand: ActiveTelemetryCommand, out
|
|
|
225
230
|
} | null;
|
|
226
231
|
/** Build a bounded, capture-level-sanitized result preview. Omit undefined object values as JSON does so optional fields cannot prevent completion telemetry. */
|
|
227
232
|
declare function summarizeResult(result: unknown, captureLevel?: Exclude<TelemetryCaptureLevel, "minimal">): Record<string, unknown>;
|
|
233
|
+
/** Build invocation metadata for the selected capture level; minimal capture retains digests while richer levels include sanitized inputs and hashed runtime context. */
|
|
228
234
|
declare function buildCommandStartPayload(params: {
|
|
229
235
|
captureLevel: TelemetryCaptureLevel;
|
|
230
236
|
context: TelemetryCommandContext;
|
|
@@ -234,6 +240,7 @@ declare function buildCommandStartPayload(params: {
|
|
|
234
240
|
cwdHash: string;
|
|
235
241
|
installationId: string;
|
|
236
242
|
}): Record<string, unknown>;
|
|
243
|
+
/** Build completion diagnostics with sanitized errors and failure fingerprints; minimal capture omits start timestamps and result previews. */
|
|
237
244
|
declare function buildCommandFinishPayload(params: {
|
|
238
245
|
captureLevel: TelemetryCaptureLevel;
|
|
239
246
|
pmVersion: string;
|
|
@@ -250,6 +257,7 @@ declare function buildCommandFinishPayload(params: {
|
|
|
250
257
|
commandResolution: TelemetryCommandResolution;
|
|
251
258
|
resolutionStage: TelemetryResolutionStage;
|
|
252
259
|
}): Record<string, unknown>;
|
|
260
|
+
/** Build error diagnostics at the selected capture level, hashing attempted inputs and redacting error text even in minimal mode. */
|
|
253
261
|
declare function buildCommandErrorPayload(params: {
|
|
254
262
|
captureLevel: TelemetryCaptureLevel;
|
|
255
263
|
pmVersion: string;
|
|
@@ -268,43 +276,62 @@ declare function buildCommandErrorPayload(params: {
|
|
|
268
276
|
errorCategory: TelemetryErrorCategory;
|
|
269
277
|
exitCode: number;
|
|
270
278
|
}): Record<string, unknown>;
|
|
279
|
+
/** Append an event as an independent queue transaction; compound capture transactions use the private writer while already holding the mutex. */
|
|
271
280
|
declare function enqueueTelemetryEvent(globalPmRoot: string, event: TelemetryEvent): Promise<void>;
|
|
281
|
+
/** Recover well-shaped event envelopes from JSONL while discarding malformed lines so one corrupt record cannot strand delivery. */
|
|
272
282
|
declare function parseQueueLines(raw: string): QueuedTelemetryEvent[];
|
|
283
|
+
/** Allow immediate retry when scheduling metadata is absent or malformed; otherwise compare its timestamp with the current time. */
|
|
273
284
|
declare function isDueForRetryAt(nextAttemptAfter: string | undefined): boolean;
|
|
285
|
+
/** Apply the shared due-time policy to an event envelope without altering its retry metadata. */
|
|
274
286
|
declare function isDueForRetry(entry: QueuedTelemetryEvent): boolean;
|
|
287
|
+
/** Convert a finite retention duration to a cutoff using at least one whole day; invalid durations fall back to one day. */
|
|
275
288
|
declare function retentionCutoffMs(retentionDays: number): number;
|
|
289
|
+
/** Expire only events with a valid occurrence timestamp before the cutoff; unknown dates do not establish expiration. */
|
|
276
290
|
declare function isExpiredQueueEntry(entry: QueuedTelemetryEvent, cutoffMs: number): boolean;
|
|
291
|
+
/** Preserve event order while removing oversized, expired, and attempt-exhausted envelopes; return the retained snapshot and removal count. */
|
|
277
292
|
declare function pruneExpiredQueueEntries(entries: QueuedTelemetryEvent[], retentionDays: number): {
|
|
278
293
|
entries: QueuedTelemetryEvent[];
|
|
279
294
|
prunedCount: number;
|
|
280
295
|
};
|
|
296
|
+
/** Atomically replace the event snapshot with bounded retries for transient filesystem failures; mutation callers must hold the queue mutex. */
|
|
281
297
|
declare function rewriteQueue(globalPmRoot: string, entries: QueuedTelemetryEvent[]): Promise<void>;
|
|
298
|
+
/** Recognize only access, busy, and permission filesystem codes as transient atomic-rewrite failures. */
|
|
282
299
|
declare function isRetryableQueueRewriteError(error: unknown): boolean;
|
|
300
|
+
/** Yield for the requested retry delay without synchronously blocking the process. */
|
|
283
301
|
declare function sleep(milliseconds: number): Promise<void>;
|
|
284
|
-
/**
|
|
302
|
+
/** Serialize an independent pending-span append; compound completion capture calls the private writer under its existing queue transaction. */
|
|
285
303
|
declare function enqueuePendingOtelSpan(globalPmRoot: string, request: {
|
|
286
304
|
endpoint: string;
|
|
287
305
|
payload: unknown;
|
|
288
306
|
}): Promise<void>;
|
|
307
|
+
/** Recover valid pending span envelopes from JSONL, skip malformed rows, and assign stable content-derived IDs to legacy entries for reconciliation. */
|
|
289
308
|
declare function parsePendingOtelSpanLines(raw: string): PendingOtelSpan[];
|
|
309
|
+
/** Compare valid enqueue timestamps with the retention cutoff; retain unknown or malformed dates rather than inventing an age. */
|
|
290
310
|
declare function isExpiredPendingOtelSpan(entry: PendingOtelSpan, cutoffMs: number): boolean;
|
|
311
|
+
/** Drop oversized, expired, and attempt-exhausted spans, then keep the newest entries within the pending-span cap and report every removal. */
|
|
291
312
|
declare function prunePendingOtelSpans(entries: PendingOtelSpan[], retentionDays: number): {
|
|
292
313
|
entries: PendingOtelSpan[];
|
|
293
314
|
prunedCount: number;
|
|
294
315
|
};
|
|
316
|
+
/** Atomically replace the span snapshot, retrying transient filesystem contention; callers coordinate mutations with the queue mutex. */
|
|
295
317
|
declare function rewritePendingOtelSpans(globalPmRoot: string, entries: PendingOtelSpan[]): Promise<void>;
|
|
296
|
-
/** Drain the pending OTLP span queue and POST due spans to their traces endpoint. Runs only inside the flush worker (detached child) or the inline test path, so the foreground command never makes OTLP network calls. Failures increment per-span attempts with backoff and are retried by a later flush; runtime state records OTLP export diagnostics for `pm health` (GH-205). */
|
|
297
318
|
/** Re-read the spans queue under the mutation serializer and rewrite it with the processed spans removed/updated by id, preserving any spans a concurrent foreground process appended during the (network) flush window. `succeededIds` are dropped; `failedUpdates` patch attempts/next_attempt_after by id; all other (incl. newly-appended) entries are retained, then pruned. Returns the count of spans left in the queue. Mirrors removeFlushedEntriesFromCurrentQueue. */
|
|
298
319
|
declare function reconcilePendingOtelSpansAfterFlush(globalPmRoot: string, retentionDays: number, succeededIds: ReadonlySet<string>, failedUpdates: ReadonlyMap<string, {
|
|
299
320
|
attempts: number;
|
|
300
321
|
next_attempt_after: string;
|
|
301
322
|
}>): Promise<number>;
|
|
323
|
+
/** POST due spans outside the mutation mutex, then reconcile successes and retry metadata against the current queue; publish export diagnostics for health inspection. */
|
|
302
324
|
declare function flushPendingOtelSpans(globalPmRoot: string, retentionDays: number): Promise<void>;
|
|
303
325
|
/** Flush both telemetry artifacts under the same worker invocation: the event ingest queue and the pending OTLP span queue. Used by the detached flush worker and the inline (test) path so OTLP export always happens off the foreground command's critical path. */
|
|
304
326
|
declare function flushTelemetryArtifacts(globalPmRoot: string, endpoint: string, retentionDays: number): Promise<void>;
|
|
305
|
-
|
|
327
|
+
export { withQueueMutation as withTelemetryQueueMutation };
|
|
328
|
+
/** 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. */
|
|
329
|
+
declare function withQueueMutation<T>(operation: () => Promise<T>, globalPmRoot?: string, waitMs?: number): Promise<T>;
|
|
330
|
+
/** Read the current event snapshot, treating a missing or blank queue as empty and dropping malformed records through the shared parser. */
|
|
306
331
|
declare function readCurrentQueueEntries(globalPmRoot: string): Promise<QueuedTelemetryEvent[]>;
|
|
332
|
+
/** Remove acknowledged event IDs and expired entries from a fresh locked snapshot, returning the retained queue including intervening appends. */
|
|
307
333
|
declare function removeFlushedEntriesFromCurrentQueue(globalPmRoot: string, flushedIds: ReadonlySet<string>, retentionDays: number): Promise<QueuedTelemetryEvent[]>;
|
|
334
|
+
/** Send one due event batch without holding the mutation mutex, then reconcile its result against the current queue and record delivery diagnostics. */
|
|
308
335
|
declare function flushQueue(globalPmRoot: string, endpoint: string, retentionDays: number): Promise<void>;
|
|
309
336
|
declare function acquireTelemetryFlushLock(globalPmRoot: string): Promise<boolean>;
|
|
310
337
|
declare function isFreshDirectoryLock(lockPath: string, staleMs: number): boolean;
|
|
@@ -385,9 +412,9 @@ declare function flushQueueWithProcessLock(globalPmRoot: string, endpoint: strin
|
|
|
385
412
|
declare function scheduleTelemetryFlush(globalPmRoot: string, endpoint: string, retentionDays: number): void;
|
|
386
413
|
/** Best-effort drain of event and span queues when both process consent and persisted settings permit delivery. */
|
|
387
414
|
export declare function flushTelemetryQueueNow(globalPmRoot?: string): Promise<void>;
|
|
388
|
-
/**
|
|
415
|
+
/** 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. */
|
|
389
416
|
export declare function startTelemetryCommand(context: TelemetryCommandContext): Promise<ActiveTelemetryCommand | null>;
|
|
390
|
-
/** Complete an invocation
|
|
417
|
+
/** Complete an invocation only while process consent, saved consent, and its installation identity still agree; retain failed reads and weight selected successful pairs. */
|
|
391
418
|
export declare function finishTelemetryCommand(activeCommand: ActiveTelemetryCommand | null, outcome: TelemetryCommandOutcome): Promise<void>;
|
|
392
|
-
/**
|
|
419
|
+
/** Atomically validate consent and append a sanitized command error with its installation identity; schedule delivery only after releasing the queue mutex. */
|
|
393
420
|
export declare function emitTelemetryErrorEvent(context: TelemetryErrorEventContext): Promise<void>;
|