@unbrained/pm-cli 2026.11.3 → 2026.11.5
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/HARNESS_COMPATIBILITY.md +1 -1
- package/.agents/skills/README.md +14 -14
- package/.agents/skills/pm-developer/SKILL.md +16 -16
- package/.agents/skills/pm-developer/references/GRAPH_AND_RELATIONSHIPS.md +14 -14
- package/.agents/skills/pm-developer/references/SCRIPTING_COMPOSITION.md +10 -10
- package/.agents/skills/pm-extensions/SKILL.md +13 -13
- package/.agents/skills/pm-extensions/references/AUTHORING.md +12 -12
- package/.agents/skills/pm-sdk/SKILL.md +27 -27
- package/.agents/skills/pm-sdk/references/SURFACE_MAP.md +32 -32
- package/.agents/skills/pm-test-audit/references/AUDIT.md +1 -1
- package/.agents/skills/pm-user/SKILL.md +35 -35
- package/.claude-plugin/marketplace.json +1 -1
- package/AGENTS.md +9 -9
- package/CHANGELOG.md +19 -0
- package/README.md +13 -13
- package/dist/cli/error-guidance.d.ts +14 -35
- package/dist/cli/error-guidance.js +2 -2
- package/dist/cli/expected-revisions.d.ts +55 -0
- package/dist/cli/expected-revisions.js +2 -0
- package/dist/cli/main.js +2 -2
- package/dist/cli/register-setup.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-2RPORE7M.js +31 -0
- package/dist/cli-bundle/chunks/{chunk-Y7H55PCY.js → chunk-335BZ75D.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-5GWEY4P6.js +122 -0
- package/dist/cli-bundle/chunks/chunk-6VRX2CM7.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-5JZMF4M5.js → chunk-7DEKAXVA.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-32BCU6HN.js → chunk-7ZRCYESH.js} +47 -46
- package/dist/cli-bundle/chunks/chunk-AUEKTX7V.js +6 -0
- package/dist/cli-bundle/chunks/chunk-D7KYPRK4.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-2CBHQXYJ.js → chunk-DAX3AOFI.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-JPKIUWLG.js → chunk-F6NDMKZ4.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-FRNMQM45.js +2 -0
- package/dist/cli-bundle/chunks/chunk-HNGLDMSZ.js +9 -0
- package/dist/cli-bundle/chunks/{chunk-DEJHTFEF.js → chunk-HRCMORE7.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-HRFGFIYU.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-5IPXDZKU.js → chunk-JI2GDE4I.js} +66 -66
- package/dist/cli-bundle/chunks/{chunk-MQJXZX3Q.js → chunk-LS3GI3H4.js} +53 -53
- package/dist/cli-bundle/chunks/chunk-OH6WQ7VT.js +3 -0
- package/dist/cli-bundle/chunks/{chunk-TZ3D3DPQ.js → chunk-OJDMJT7Y.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-S4LPZ4TN.js +20 -0
- package/dist/cli-bundle/chunks/chunk-UEGXWXUZ.js +2 -0
- package/dist/cli-bundle/chunks/chunk-XLSHFYXZ.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-UYNMKUGA.js → chunk-YKXATU2G.js} +2 -2
- package/dist/cli-bundle/chunks/item-revision-OJJVPQY7.js +2 -0
- package/dist/cli-bundle/chunks/item-transaction-QEPBUCMY.js +2 -0
- package/dist/cli-bundle/chunks/mutation-admission-INMM3HHG.js +2 -0
- package/dist/cli-bundle/chunks/{register-list-query-I6AZA3IX.js → register-list-query-5Y5JKWU5.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-3DAXCLXR.js → register-mutation-WC7OSQID.js} +2 -2
- package/dist/cli-bundle/chunks/register-operations-PO63DBZH.js +2 -0
- package/dist/cli-bundle/chunks/register-setup-RRFOS7IT.js +2 -0
- package/dist/cli-bundle/chunks/{stage-7H36OTDJ.js → stage-E3MMV4TV.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-5PMJOJCZ.js +44 -0
- package/dist/cli-bundle/focused-chunks/chunk-7KK66ISG.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-D4XQOMG4.js → chunk-AHWJPZSJ.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-C3O6JJPO.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-LKN2WGGB.js → chunk-C6P6HPCX.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-CPMSL4HS.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-CZM75DE3.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-TYHDZUL4.js → chunk-D2TBEBNW.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-E56OXRYH.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-I5FODKYB.js → chunk-F62XGAAY.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-G4QP365K.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-G5PJCR7R.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-GS3JC5UU.js +23 -0
- package/dist/cli-bundle/focused-chunks/chunk-I5LGPUWH.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-LW64TINU.js +3 -0
- package/dist/cli-bundle/focused-chunks/chunk-M6V7UMWL.js +26 -0
- package/dist/cli-bundle/focused-chunks/chunk-MC7IE7D7.js +8 -0
- package/dist/cli-bundle/focused-chunks/chunk-MG7C3JUY.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-F3X6UWMI.js → chunk-MK4HV4JO.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-ZQRCVRGS.js → chunk-NQ7GYFOX.js} +54 -54
- package/dist/cli-bundle/focused-chunks/chunk-O7EI33NP.js +91 -0
- package/dist/cli-bundle/focused-chunks/{chunk-RY4QEMAE.js → chunk-RFTJZ5VB.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-SNOXXRSJ.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-UPJUTP2V.js +12 -0
- package/dist/cli-bundle/focused-chunks/{chunk-HJ27QLZV.js → chunk-VWWTIX5L.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-HOXIIZEO.js → chunk-XHOBYCVE.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-YMGB2O4E.js +81 -0
- package/dist/cli-bundle/focused-chunks/item-revision-CTDO4H3I.js +2 -0
- package/dist/cli-bundle/focused-chunks/item-transaction-AEAYVVHA.js +2 -0
- package/dist/cli-bundle/focused-chunks/mutation-admission-4WM7TNHZ.js +2 -0
- package/dist/cli-bundle/focused-chunks/{stage-4SQHVI3O.js → stage-WV7QXR4C.js} +2 -2
- package/dist/cli-bundle/main.js +25 -25
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +5 -5
- package/dist/cli-bundle/sdk-core.js +1 -1
- 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 +57 -57
- package/dist/cli-bundle/sdk-query.js +1 -1
- package/dist/cli-bundle/sdk-runtime.js +1 -1
- package/dist/cli-bundle/sdk-testing.js +1 -1
- package/dist/cli-bundle/sdk.js +11 -11
- package/dist/core/config/positional-value.d.ts +7 -1
- package/dist/core/config/positional-value.js +1 -1
- package/dist/core/extensions/reserved-host-flags.js +1 -1
- package/dist/core/history/history-rewrite.js +1 -1
- package/dist/core/item/literal-mutation-input.d.ts +17 -0
- package/dist/core/item/literal-mutation-input.js +1 -1
- package/dist/core/item/parent-reference-policy.d.ts +8 -4
- package/dist/core/item/parent-reference-policy.js +1 -1
- package/dist/core/item/sprint-release-format.d.ts +2 -1
- package/dist/core/item/sprint-release-format.js +1 -1
- package/dist/core/output/mutation-projection.js +1 -1
- package/dist/core/shared/command-types.d.ts +7 -0
- package/dist/core/store/item-mutation-precondition.d.ts +72 -6
- package/dist/core/store/item-mutation-precondition.js +1 -1
- package/dist/core/store/item-store.js +1 -1
- package/dist/core/store/settings-validator.js +1 -1
- package/dist/core/store/settings.d.ts +14 -0
- package/dist/core/store/settings.js +5 -4
- package/dist/core/telemetry/policy.d.ts +27 -1
- package/dist/core/telemetry/policy.js +1 -1
- package/dist/core/telemetry/runtime.d.ts +18 -7
- package/dist/core/telemetry/runtime.js +4 -4
- package/dist/sdk/cli-contracts/bootstrap-command-scanner.js +1 -1
- package/dist/sdk/cli-contracts/completeness.js +1 -1
- package/dist/sdk/cli-contracts/enum-contracts.d.ts +11 -0
- package/dist/sdk/cli-contracts/enum-contracts.js +1 -1
- package/dist/sdk/cli-contracts/flag-lexicon-contracts.js +1 -1
- package/dist/sdk/cli-contracts/registration-helpers.js +1 -1
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +1 -1
- package/dist/sdk/cli-contracts/tool-schema.js +1 -1
- package/dist/sdk/cli-contracts/typed-action-inputs.d.ts +8 -5
- package/dist/sdk/cli-contracts.d.ts +1 -1
- package/dist/sdk/cli-contracts.js +1 -1
- package/dist/sdk/cli-program.js +1 -1
- package/dist/sdk/config.d.ts +3 -3
- package/dist/sdk/config.js +1 -1
- package/dist/sdk/environment/project-runtime-compatibility.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.d.ts +2 -2
- package/dist/sdk/governance/health.js +2 -2
- package/dist/sdk/governance/validate.js +1 -1
- package/dist/sdk/history/salvage.js +3 -3
- package/dist/sdk/history-compact.d.ts +7 -1
- package/dist/sdk/history-compact.js +1 -1
- package/dist/sdk/history-repair.d.ts +2 -1
- package/dist/sdk/history-repair.js +1 -1
- package/dist/sdk/index.d.ts +6 -1
- package/dist/sdk/index.js +1 -1
- package/dist/sdk/init.d.ts +4 -4
- package/dist/sdk/init.js +8 -8
- package/dist/sdk/lifecycle/checkpoint-rollback.d.ts +10 -2
- package/dist/sdk/lifecycle/checkpoint-rollback.js +1 -1
- package/dist/sdk/lifecycle/claim.d.ts +4 -0
- package/dist/sdk/lifecycle/claim.js +1 -1
- package/dist/sdk/lifecycle/close-many.d.ts +11 -2
- package/dist/sdk/lifecycle/close-many.js +1 -1
- package/dist/sdk/lifecycle/close.d.ts +25 -0
- package/dist/sdk/lifecycle/close.js +1 -1
- package/dist/sdk/lifecycle/create.d.ts +7 -5
- package/dist/sdk/lifecycle/create.js +1 -1
- package/dist/sdk/lifecycle/item-revision.d.ts +162 -0
- package/dist/sdk/lifecycle/item-revision.js +2 -0
- package/dist/sdk/lifecycle/restore.js +1 -1
- package/dist/sdk/lifecycle/shared-unset-fields.d.ts +628 -4
- package/dist/sdk/lifecycle/shared-unset-fields.js +1 -1
- package/dist/sdk/lifecycle/start-blockers.d.ts +52 -0
- package/dist/sdk/lifecycle/start-blockers.js +2 -0
- package/dist/sdk/lifecycle/task-composition.d.ts +11 -0
- package/dist/sdk/lifecycle/task-composition.js +1 -1
- package/dist/sdk/lifecycle/update-many.d.ts +11 -2
- package/dist/sdk/lifecycle/update-many.js +1 -1
- package/dist/sdk/lifecycle/update.d.ts +5 -4
- package/dist/sdk/lifecycle/update.js +2 -2
- package/dist/sdk/public-surface.json +1 -1
- package/dist/sdk/query/declared-blockers.d.ts +16 -0
- package/dist/sdk/query/declared-blockers.js +2 -0
- package/dist/sdk/query/get.d.ts +7 -0
- package/dist/sdk/query/get.js +1 -1
- package/dist/sdk/query/projection-contracts.js +1 -1
- package/dist/sdk/runtime/actions.js +1 -1
- package/dist/sdk/runtime/mutation-value-validation.js +1 -1
- package/dist/sdk/runtime-input.d.ts +12 -0
- package/dist/sdk/runtime-input.js +1 -1
- package/dist/sdk/runtime-primitives.d.ts +1 -0
- package/dist/sdk/runtime-primitives.js +1 -1
- package/dist/sdk/runtime.d.ts +10 -0
- package/dist/sdk/runtime.js +1 -1
- package/dist/sdk/structured-mutations.js +1 -1
- package/dist/sdk/telemetry.d.ts +1 -1
- package/dist/sdk/telemetry.js +2 -2
- package/dist/sdk/test/batch.js +2 -2
- package/dist/sdk/test/execution.js +2 -2
- package/dist/sdk/test/linked-command-detection.js +1 -1
- package/dist/sdk/workspace-transaction.d.ts +17 -6
- package/dist/sdk/workspace-transaction.js +1 -1
- package/dist/types.d.ts +6 -0
- package/dist/types.js +1 -1
- package/docs/AGENT_GUIDE.md +48 -48
- package/docs/AGENT_OUTPUT_ENCODINGS.md +20 -20
- package/docs/ASSURANCE.md +10 -10
- package/docs/BOUNDED_CONTEXT_READS.md +3 -3
- package/docs/CLAUDE_CODE_PLUGIN.md +1 -1
- package/docs/CLI_GRAMMAR.md +2 -2
- package/docs/COMMANDS.md +144 -32
- package/docs/COMMAND_NAMESPACES.md +1 -1
- package/docs/CONFIGURATION.md +82 -70
- package/docs/CONTEXT_ALGORITHM_PORTFOLIO.md +2 -2
- package/docs/CONTEXT_INTEGRITY_CONTRACTS.md +5 -5
- package/docs/CORPUS_SHAPES.md +1 -1
- package/docs/DEPENDENCY_KIND_CONTRACT.md +6 -6
- package/docs/DIAGNOSTIC_OUTPUT_CONTRACTS.md +5 -5
- package/docs/ECOSYSTEM_PLANNING_REVIEW.md +3 -3
- package/docs/EXTENSION_AUTHOR_CONTRACTS.md +4 -4
- package/docs/HISTORY_ATTESTATION.md +1 -1
- package/docs/HISTORY_MAINTENANCE.md +1 -1
- package/docs/LIFECYCLE_COMMANDS.md +1 -1
- package/docs/MCP_2026_07_28.md +16 -16
- package/docs/MCP_2026_07_28_CONFORMANCE.md +19 -19
- package/docs/MCP_REMOTE_TRANSPORT_SECURITY.md +22 -22
- package/docs/MCP_SKILLS_AND_APPS.md +1 -1
- package/docs/MERGE_SAFETY.md +6 -6
- package/docs/MUTATION_INTEGRITY.md +5 -5
- package/docs/OUTPUT_PROJECTION_CONTRACTS.md +14 -14
- package/docs/PACKED_FIRST_RUN.md +1 -1
- package/docs/QUICKSTART.md +10 -10
- package/docs/README.md +21 -21
- package/docs/READ_OUTPUT_CONTRACTS.md +9 -9
- package/docs/RECURRENCE_RECOVERY_CONTRACTS.md +1 -1
- package/docs/RELEASING.md +19 -10
- package/docs/SCRIPTING.md +10 -10
- package/docs/SDK.md +183 -38
- package/docs/SDK_ARTIFACT_OUTPUT.md +1 -1
- package/docs/SDK_PRIMITIVE_INVENTORY.md +2 -2
- package/docs/SELF_DESCRIBING_CONTEXT_CONTRACTS.md +7 -7
- package/docs/TESTING.md +1 -1
- package/docs/WORKFLOW_POLICIES.md +2 -2
- package/docs/WORKSPACE_POSITION_AND_LIFECYCLE.md +8 -8
- package/docs/agent-task-token-baseline.json +1 -1
- package/docs/generated/AGENT_CAPABILITY_ROUTING.md +1 -1
- package/docs/generated/AGENT_COMMAND_SURFACE.md +1 -1
- package/docs/generated/FLAG_LEXICON_BUDGETS.md +112 -112
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +13 -4
- package/docs/performance/cli-transport-overhead.md +7 -7
- package/marketplace.json +1 -1
- package/package.json +1 -1
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/README.md +5 -5
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/GAP_REPORT.md +16 -16
- 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/README.md +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/GAP_REPORT.md +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-claude/README.md +6 -6
- 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-7ZEFHFAU.js +0 -2
- package/dist/cli-bundle/chunks/chunk-B6UTLYLM.js +0 -3
- package/dist/cli-bundle/chunks/chunk-HBKD5HZB.js +0 -2
- package/dist/cli-bundle/chunks/chunk-L6LCLC37.js +0 -2
- package/dist/cli-bundle/chunks/chunk-NR4KABHC.js +0 -31
- package/dist/cli-bundle/chunks/chunk-PWD5RY2D.js +0 -2
- package/dist/cli-bundle/chunks/chunk-XRMYA4R7.js +0 -20
- package/dist/cli-bundle/chunks/chunk-YWS4XV4I.js +0 -6
- package/dist/cli-bundle/chunks/chunk-ZOAJNPBL.js +0 -129
- package/dist/cli-bundle/chunks/item-transaction-ZHLJTBD7.js +0 -2
- package/dist/cli-bundle/chunks/mutation-admission-ZQMRMGIB.js +0 -2
- package/dist/cli-bundle/chunks/register-operations-G3QGGQ5Z.js +0 -2
- package/dist/cli-bundle/chunks/register-setup-LDXHMNOT.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-3XGKBVJ3.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-4HY6EGPB.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-AK2CI2GI.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-HUXZCPWT.js +0 -26
- package/dist/cli-bundle/focused-chunks/chunk-IKXJ57XA.js +0 -8
- package/dist/cli-bundle/focused-chunks/chunk-MOY6KZGJ.js +0 -44
- package/dist/cli-bundle/focused-chunks/chunk-PWUTFKSI.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-PZRB7IXH.js +0 -91
- package/dist/cli-bundle/focused-chunks/chunk-WSYPVBKS.js +0 -80
- package/dist/cli-bundle/focused-chunks/chunk-WXLG7HZ5.js +0 -3
- package/dist/cli-bundle/focused-chunks/chunk-WZDFCVLX.js +0 -12
- package/dist/cli-bundle/focused-chunks/chunk-YGO3FWA2.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-YVLAP3BL.js +0 -23
- package/dist/cli-bundle/focused-chunks/chunk-ZYXQACPB.js +0 -2
- package/dist/cli-bundle/focused-chunks/item-transaction-PZ2FQ6B2.js +0 -2
- package/dist/cli-bundle/focused-chunks/mutation-admission-XOOK6XFH.js +0 -2
|
@@ -38,6 +38,8 @@ available:true;
|
|
|
38
38
|
recommendation:NextRecommendation;
|
|
39
39
|
/** Value that configures or reports attempts for this contract. */
|
|
40
40
|
attempts:number;
|
|
41
|
+
/** Earlier candidates skipped because a declared blocker refused their start; nothing was written to them. */
|
|
42
|
+
start_refused?:string[];
|
|
41
43
|
}
|
|
42
44
|
/** Non-error empty result returned when an if-available candidate walk is exhausted. */
|
|
43
45
|
export interface ClaimNextUnavailableResult {
|
|
@@ -57,6 +59,8 @@ skipped:true;
|
|
|
57
59
|
recommendation:null;
|
|
58
60
|
/** Number of ranked candidates attempted. */
|
|
59
61
|
attempts:number;
|
|
62
|
+
/** Candidates skipped because a declared blocker refused their start; nothing was written to them. */
|
|
63
|
+
start_refused?:string[];
|
|
60
64
|
/** Stable machine-readable exhaustion warning. */
|
|
61
65
|
warnings:[typeof NO_AVAILABLE_NEXT_ITEM_CODE];
|
|
62
66
|
}
|
|
@@ -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]="f5335488-184f-5938-a61a-b3fd26fbf3e3")}catch{}})();import{assertInitializedTracker}from"../environment/tracker-preflight.js";import{resolveRuntimeStatusRegistry,statusIsTerminal,EXIT_CODE,PmCliError,toItemRecord,mutateItem,resolvePmRoot,readSettings,resolveAuthor,resolveClaimPrincipal,normalizeStatusForRegistry}from"../runtime-primitives.js";import{wrapOwnershipConflict}from"../annotations.js";import{resolveItemOwnershipConflict}from"../ownership-source.js";import{applyReleaseHandoff,resolveReleaseHandoff}from"./release-handoff.js";import{enforceTypeWorkflowTransition}from"./workflow-transition.js";import{resolveTypeWorkflows}from"../../core/schema/type-workflows.js";import{resolveStartTaskInProgressStatus}from"../start-task-status.js";import{runNext}from"../query/next.js";import{recordClaimSemanticAttribution,recordReleaseSemanticAttribution}from"../context/semantic-session-attribution.js";const NO_AVAILABLE_NEXT_ITEM_CODE="no_available_next_item";function isAlreadyClaimedError(error){if(!(error instanceof Error)||error.name!=="PmCliError")return!1;const context=error.context;return typeof context=="object"&&context!==null&&"code"in context&&context.code==="already_claimed_by"}async function runClaim(id,force,global2,options={}){const pmRoot=resolvePmRoot(process.cwd(),global2.path);await assertInitializedTracker(pmRoot);const settings=await readSettings(pmRoot),statusRegistry=resolveRuntimeStatusRegistry(settings.schema),author=resolveAuthor(options.author,settings.author_default),claimPrincipal=resolveClaimPrincipal(author);let previousAssignee=null,skipped=!1,startEvidence={};const mutationWarnings=[],result=await mutateItem({pmRoot,settings,id,op:"claim",author,message:options.message,force,skipNoop:!0,async mutate(document){const currentAssigneeText=document.metadata.assignee??"",currentClaimPrincipal=document.metadata.claim_principal?.trim()||currentAssigneeText;if(previousAssignee=currentAssigneeText.trim().length>0?currentAssigneeText:null,statusIsTerminal(document.metadata.status,statusRegistry)&&!force)throw new PmCliError(`Cannot claim terminal item ${document.metadata.id} without --force`,EXIT_CODE.CONFLICT);if(previousAssignee!==null&¤tClaimPrincipal!==claimPrincipal){if(options.ifAvailable===!0)return skipped=!0,mutationWarnings.push(`claim_skipped_held_by:${previousAssignee}`),{changedFields:[]};if(!force){const ownership2=await resolveItemOwnershipConflict(pmRoot,document.metadata.id,currentAssigneeText);throw new PmCliError(`Item ${document.metadata.id} is already ${ownership2.phrase}. Use --force to take over, or --if-available to skip without failing.`,EXIT_CODE.CONFLICT,{code:"already_claimed_by",item_id:document.metadata.id,claimed_by:ownership2.holder,claimed_at:ownership2.since,claim_source:ownership2.source,why:"Claim is an atomic test-and-set so parallel agents never proceed believing they own the same item.",nextSteps:["Run pm next to pick a different unclaimed item.","Re-run with --if-available to treat a held item as a no-op skip.","Re-run with --force only when taking over the item is coordinated."]})}mutationWarnings.push(`claim_takeover:${previousAssignee}->${author}`)}const ownership={assignee:author,claim_principal:claimPrincipal},changedFields=["assignee","claim_principal"].filter(field=>document.metadata[field]!==ownership[field]);Object.assign(document.metadata,ownership);const{changedFields:startedFields,warnings:startWarnings,...started}=applyClaimStart(document.metadata,options.start===!0,settings,statusRegistry);return startEvidence=started,mutationWarnings.push(...startWarnings),{changedFields:[...changedFields,...startedFields],warnings:mutationWarnings}}});return skipped||mutationWarnings.push(...await recordClaimAttributionAfterCommit({pmRoot,settings,principal:claimPrincipal,itemId:result.item.id})),{item:toItemRecord(result.item),changed_fields:result.changedFields,claimed_by:skipped&&previousAssignee!==null?previousAssignee:author,previous_assignee:previousAssignee,forced:force,...skipped?{skipped:!0}:{},...mutationWarnings.length>0?{warnings:mutationWarnings}:{},...startEvidence}}const CLAIM_ATTRIBUTION_UNRECORDED_WARNING="claim_semantic_attribution_unrecorded";async function recordClaimAttributionAfterCommit(params){try{return await recordClaimSemanticAttribution(params),[]}catch{return[CLAIM_ATTRIBUTION_UNRECORDED_WARNING]}}function requireClaimTarget(id,next,start=!1){const startSuffix=start?" --start":"";if(!next&&!id)throw new PmCliError(start?"pm claim --start needs an item id, or --next to start the next available item":"Specify an item id or pass --next",EXIT_CODE.USAGE,{code:"missing_required_argument",field:"id",required:"Pass an item id, or --next to select the next available item.",nextSteps:[`Retry as pm claim <id>${startSuffix}, or pm claim --next${startSuffix}.`]});if(next&&id)throw new PmCliError("Specify either an item id or --next, not both",EXIT_CODE.USAGE,{code:"ambiguous_option_combination",required:"Pass either an item id or --next.",nextSteps:[`Retry as pm claim ${id}${startSuffix} to claim that item, or drop the id to select with --next.`]})}function applyClaimStart(metadata,start,settings,registry){if(!start)return{changedFields:[],warnings:[]};if(statusIsTerminal(metadata.status,registry))throw new PmCliError(`Cannot start terminal item ${metadata.id}; reopen it with pm item reopen before starting it`,EXIT_CODE.CONFLICT,{code:"terminal_state_conflict",item_id:metadata.id,why:"Starting work moves an active item into progress; a terminal item must be reopened so its recurrence evidence is recorded.",nextSteps:[`Run pm item reopen ${metadata.id} "<reason>", then pm claim ${metadata.id} --start.`]});const startStatus=resolveStartTaskInProgressStatus(registry),enforcement=settings.governance.workflow_enforcement??"off",warning=enforceTypeWorkflowTransition({enforcement,typeWorkflows:enforcement==="off"?[]:resolveTypeWorkflows(settings.schema),statusRegistry:registry,typeName:metadata.type,fromStatus:metadata.status,toStatus:startStatus}),receipt={from_status:metadata.status,to_status:startStatus},changedFields=metadata.status===startStatus?[]:["status"];return metadata.status=startStatus,{start:receipt,changedFields,warnings:warning?[warning]:[]}}async function runClaimNext(force,global2,options={},nextOptions={}){const maxAttempts=parseClaimNextAttempts(options.maxAttempts),settings=await readSettings(resolvePmRoot(process.cwd(),global2.path)),claimOptions={...options,author:resolveAuthor(options.author,settings.author_default)},next=await runNext({...nextOptions,callerAuthor:claimOptions.author,limit:String(maxAttempts)},global2),recommendations=[next.recommended,...next.ready].filter(entry=>entry!==null).map(entry=>({...entry,reasons:"reasons"in entry?entry.reasons:["ranked ready candidate"]}));return claimNextFromRecommendations(recommendations.slice(0,maxAttempts),force,global2,claimOptions)}function parseClaimNextAttempts(raw){if(raw===void 0)return 10;const parsed=Number(raw);if(!Number.isSafeInteger(parsed)||parsed<1||parsed>100)throw new PmCliError("--max-attempts must be an integer from 1 to 100",EXIT_CODE.USAGE);return parsed}async function claimNextFromRecommendations(recommendations,force,global2,options={},claimRunner=runClaim){let attempts=0;for(const recommendation of recommendations){attempts+=1;try{const claimed=await claimRunner(recommendation.id,force,global2,options),result={...claimed,recommendation,attempts,available:!0};if(!claimed.skipped)return result}catch(error){if(!isAlreadyClaimedError(error))throw error}}if(options.ifAvailable===!0)return{available:!1,item:null,claimed_by:resolveAuthor(options.author,""),previous_assignee:null,forced:force,skipped:!0,recommendation:null,attempts,warnings:[NO_AVAILABLE_NEXT_ITEM_CODE]};const noCandidatesMatched=attempts===0;throw new PmCliError(noCandidatesMatched?"No actionable items matched the selection filters":"No actionable item remained available to claim",noCandidatesMatched?EXIT_CODE.NOT_FOUND:EXIT_CODE.CONFLICT,{code:NO_AVAILABLE_NEXT_ITEM_CODE,why:noCandidatesMatched?"No ready items matched the specified filters or selection criteria.":"Every ranked candidate was claimed by another agent before this atomic selection completed.",nextSteps:[noCandidatesMatched?"Verify the filters or run pm next to inspect all ready work.":"Run pm claim --next again to refresh the ranked candidate set."]})}async function runRelease(id,force,global2,options={}){const pmRoot=resolvePmRoot(process.cwd(),global2.path);await assertInitializedTracker(pmRoot);const settings=await readSettings(pmRoot),author=resolveAuthor(options.author,settings.author_default),claimPrincipal=resolveClaimPrincipal(author),ownershipReleaseBypass=options.ownershipReleaseBypass===!0;let previousAssignee=null;const statusRegistry=resolveRuntimeStatusRegistry(settings.schema),handoffStatus=resolveReleaseHandoff(options,statusRegistry);if(handoffStatus!==void 0&&ownershipReleaseBypass)throw new PmCliError("Ownership-release bypass only clears ownership; it cannot change a handoff status.",EXIT_CODE.USAGE);let handoff,result;try{result=await mutateItem({pmRoot,settings,id,op:"release",author,message:options.message,force,bypassAssigneeConflict:ownershipReleaseBypass,mutate(document){previousAssignee=document.metadata.assignee??null;const transition=handoffStatus===void 0?void 0:applyReleaseHandoff(document.metadata,handoffStatus,settings,statusRegistry,options.message);return handoff=transition?.receipt,!previousAssignee&&!document.metadata.claim_principal?{changedFields:[]}:(delete document.metadata.assignee,delete document.metadata.claim_principal,{changedFields:["assignee","claim_principal",...transition?.changedFields??[]],warnings:transition?.warnings})}})}catch(error){wrapOwnershipConflict(error,{required:"For approved non-owner handoffs, prefer the ownership-release bypass before considering --force.",examples:['pm release pm-a1b2 --author "reviewer" --force'],nextSteps:["Use the package-provided ownership-release bypass for handoffs that only clear assignee metadata.","Use --force only when an explicit override is approved for broader ownership conflicts."]})}await recordReleaseSemanticAttribution({pmRoot,principal:claimPrincipal,itemId:result.item.id});const stillInProgress=normalizeStatusForRegistry(result.item.status,statusRegistry)===normalizeStatusForRegistry(statusRegistry.in_progress_status,statusRegistry);return{item:toItemRecord(result.item),released_by:author,changed_fields:result.changedFields,previous_assignee:previousAssignee,forced:force,...handoff===void 0?{}:{handoff},...result.warnings.length>0||stillInProgress?{warnings:[...result.warnings,...stillInProgress?["released_unclaimed_in_progress"]:[]]}:{},...stillInProgress?{suggestions:[`${result.item.id} remains ${result.item.status} and unclaimed. If work is paused, run pm release ${result.item.id} --pause to move it to ${statusRegistry.open_status}.`]}:{}}}export{CLAIM_ATTRIBUTION_UNRECORDED_WARNING,NO_AVAILABLE_NEXT_ITEM_CODE,applyClaimStart,claimNextFromRecommendations,isAlreadyClaimedError,parseClaimNextAttempts,requireClaimTarget,runClaim,runClaimNext,runRelease};
|
|
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]="8893eba1-595b-5f31-9496-e8debc63a27c")}catch{}})();import{assertInitializedTracker}from"../environment/tracker-preflight.js";import{resolveRuntimeStatusRegistry,statusIsTerminal,EXIT_CODE,PmCliError,toItemRecord,mutateItem,resolvePmRoot,readSettings,resolveAuthor,resolveClaimPrincipal,normalizeStatusForRegistry}from"../runtime-primitives.js";import{wrapOwnershipConflict}from"../annotations.js";import{resolveItemOwnershipConflict}from"../ownership-source.js";import{applyReleaseHandoff,resolveReleaseHandoff}from"./release-handoff.js";import{enforceTypeWorkflowTransition}from"./workflow-transition.js";import{admitExplicitStartClaim,admitStartTransition,START_BLOCKED_REFUSAL_CODE}from"./start-blockers.js";import{resolveTypeWorkflows}from"../../core/schema/type-workflows.js";import{resolveStartTaskInProgressStatus}from"../start-task-status.js";import{runNext}from"../query/next.js";import{recordClaimSemanticAttribution,recordReleaseSemanticAttribution}from"../context/semantic-session-attribution.js";const NO_AVAILABLE_NEXT_ITEM_CODE="no_available_next_item";function hasRefusalCode(error,code){if(!(error instanceof Error)||error.name!=="PmCliError")return!1;const context=error.context;return typeof context=="object"&&context!==null&&"code"in context&&context.code===code}function isAlreadyClaimedError(error){return hasRefusalCode(error,"already_claimed_by")}async function runClaim(id,force,global2,options={}){const pmRoot=resolvePmRoot(process.cwd(),global2.path);await assertInitializedTracker(pmRoot);const settings=await readSettings(pmRoot),statusRegistry=resolveRuntimeStatusRegistry(settings.schema),author=resolveAuthor(options.author,settings.author_default),claimPrincipal=resolveClaimPrincipal(author);let previousAssignee=null,skipped=!1,startEvidence={};const mutationWarnings=[],result=await mutateItem({pmRoot,settings,id,op:"claim",author,message:options.message,force,skipNoop:!0,async mutate(document){const currentAssigneeText=document.metadata.assignee??"",currentClaimPrincipal=document.metadata.claim_principal?.trim()||currentAssigneeText;if(previousAssignee=currentAssigneeText.trim().length>0?currentAssigneeText:null,statusIsTerminal(document.metadata.status,statusRegistry)&&!force)throw new PmCliError(`Cannot claim terminal item ${document.metadata.id} without --force`,EXIT_CODE.CONFLICT);if(previousAssignee!==null&¤tClaimPrincipal!==claimPrincipal){if(options.ifAvailable===!0)return skipped=!0,mutationWarnings.push(`claim_skipped_held_by:${previousAssignee}`),{changedFields:[]};if(!force){const ownership2=await resolveItemOwnershipConflict(pmRoot,document.metadata.id,currentAssigneeText);throw new PmCliError(`Item ${document.metadata.id} is already ${ownership2.phrase}. Use --force to take over, or --if-available to skip without failing.`,EXIT_CODE.CONFLICT,{code:"already_claimed_by",item_id:document.metadata.id,claimed_by:ownership2.holder,claimed_at:ownership2.since,claim_source:ownership2.source,why:"Claim is an atomic test-and-set so parallel agents never proceed believing they own the same item.",nextSteps:["Run pm next to pick a different unclaimed item.","Re-run with --if-available to treat a held item as a no-op skip.","Re-run with --force only when taking over the item is coordinated."]})}mutationWarnings.push(`claim_takeover:${previousAssignee}->${author}`)}const ownership={assignee:author,claim_principal:claimPrincipal},changedFields=["assignee","claim_principal"].filter(field=>document.metadata[field]!==ownership[field]);Object.assign(document.metadata,ownership);const fromStatus=document.metadata.status,{changedFields:startedFields,warnings:startWarnings,...started}=applyClaimStart(document.metadata,options.start===!0,settings,statusRegistry);return startWarnings.push(...await claimStartWarnings({pmRoot,settings,metadata:document.metadata,fromStatus,registry:statusRegistry,force,start:options.start===!0})),startEvidence=started,mutationWarnings.push(...startWarnings),{changedFields:[...changedFields,...startedFields],warnings:mutationWarnings}}});return skipped||mutationWarnings.push(...await recordClaimAttributionAfterCommit({pmRoot,settings,principal:claimPrincipal,itemId:result.item.id})),{item:toItemRecord(result.item),changed_fields:result.changedFields,claimed_by:skipped&&previousAssignee!==null?previousAssignee:author,previous_assignee:previousAssignee,forced:force,...skipped?{skipped:!0}:{},...mutationWarnings.length>0?{warnings:mutationWarnings}:{},...startEvidence}}const CLAIM_ATTRIBUTION_UNRECORDED_WARNING="claim_semantic_attribution_unrecorded";async function recordClaimAttributionAfterCommit(params){try{return await recordClaimSemanticAttribution(params),[]}catch{return[CLAIM_ATTRIBUTION_UNRECORDED_WARNING]}}function requireClaimTarget(id,next,start=!1){const startSuffix=start?" --start":"";if(!next&&!id)throw new PmCliError(start?"pm claim --start needs an item id, or --next to start the next available item":"Specify an item id or pass --next",EXIT_CODE.USAGE,{code:"missing_required_argument",field:"id",required:"Pass an item id, or --next to select the next available item.",nextSteps:[`Retry as pm claim <id>${startSuffix}, or pm claim --next${startSuffix}.`]});if(next&&id)throw new PmCliError("Specify either an item id or --next, not both",EXIT_CODE.USAGE,{code:"ambiguous_option_combination",required:"Pass either an item id or --next.",nextSteps:[`Retry as pm claim ${id}${startSuffix} to claim that item, or drop the id to select with --next.`]})}async function claimStartWarnings(params){return params.start?admitStartTransition(params):admitExplicitStartClaim(params)}function applyClaimStart(metadata,start,settings,registry){if(!start)return{changedFields:[],warnings:[]};if(statusIsTerminal(metadata.status,registry))throw new PmCliError(`Cannot start terminal item ${metadata.id}; reopen it with pm item reopen before starting it`,EXIT_CODE.CONFLICT,{code:"terminal_state_conflict",item_id:metadata.id,why:"Starting work moves an active item into progress; a terminal item must be reopened so its recurrence evidence is recorded.",nextSteps:[`Run pm item reopen ${metadata.id} "<reason>", then pm claim ${metadata.id} --start.`]});const startStatus=resolveStartTaskInProgressStatus(registry),enforcement=settings.governance.workflow_enforcement??"off",warning=enforceTypeWorkflowTransition({enforcement,typeWorkflows:enforcement==="off"?[]:resolveTypeWorkflows(settings.schema),statusRegistry:registry,typeName:metadata.type,fromStatus:metadata.status,toStatus:startStatus}),receipt={from_status:metadata.status,to_status:startStatus},changedFields=metadata.status===startStatus?[]:["status"];return metadata.status=startStatus,{start:receipt,changedFields,warnings:warning?[warning]:[]}}async function runClaimNext(force,global2,options={},nextOptions={}){const maxAttempts=parseClaimNextAttempts(options.maxAttempts),settings=await readSettings(resolvePmRoot(process.cwd(),global2.path)),claimOptions={...options,author:resolveAuthor(options.author,settings.author_default)},next=await runNext({...nextOptions,callerAuthor:claimOptions.author,limit:String(maxAttempts)},global2),recommendations=[next.recommended,...next.ready].filter(entry=>entry!==null).map(entry=>({...entry,reasons:"reasons"in entry?entry.reasons:["ranked ready candidate"]}));return claimNextFromRecommendations(recommendations.slice(0,maxAttempts),force,global2,claimOptions)}function parseClaimNextAttempts(raw){if(raw===void 0)return 10;const parsed=Number(raw);if(!Number.isSafeInteger(parsed)||parsed<1||parsed>100)throw new PmCliError("--max-attempts must be an integer from 1 to 100",EXIT_CODE.USAGE);return parsed}async function claimNextFromRecommendations(recommendations,force,global2,options={},claimRunner=runClaim){let attempts=0;const startRefused=[],refusals=()=>startRefused.length>0?{start_refused:[...startRefused]}:{};for(const recommendation of recommendations){attempts+=1;try{const claimed=await claimRunner(recommendation.id,force,global2,options),result={...claimed,recommendation,attempts,available:!0,...refusals()};if(!claimed.skipped)return result}catch(error){if(hasRefusalCode(error,START_BLOCKED_REFUSAL_CODE)){startRefused.push(recommendation.id);continue}if(!isAlreadyClaimedError(error))throw error}}if(options.ifAvailable===!0)return{available:!1,item:null,claimed_by:resolveAuthor(options.author,""),previous_assignee:null,forced:force,skipped:!0,recommendation:null,attempts,...refusals(),warnings:[NO_AVAILABLE_NEXT_ITEM_CODE]};throw noAvailableNextItemError(attempts,startRefused,options.start===!0)}function noAvailableNextItemError(attempts,startRefused,start){const noCandidatesMatched=attempts===0;let why="Every ranked candidate was claimed by another agent before this atomic selection completed.";return noCandidatesMatched?why="No ready items matched the specified filters or selection criteria.":startRefused.length>0&&(why=`${startRefused.length} of ${attempts} attempted candidates refused their start because a declared blocker is open (${startRefused.join(", ")}), and nothing was written to them; ${startRefused.length===attempts?"no other candidate was attempted":"every other attempted candidate was claimed by another agent"}.`),new PmCliError(noCandidatesMatched?"No actionable items matched the selection filters":"No actionable item remained available to claim",noCandidatesMatched?EXIT_CODE.NOT_FOUND:EXIT_CODE.CONFLICT,{code:NO_AVAILABLE_NEXT_ITEM_CODE,why,nextSteps:[noCandidatesMatched?"Verify the filters or run pm next to inspect all ready work.":`Run pm claim --next${start?" --start":""} again, with the same filters, to refresh the ranked candidate set.`],...startRefused.length>0?{details:{start_refused:[...startRefused]}}:{}})}async function runRelease(id,force,global2,options={}){const pmRoot=resolvePmRoot(process.cwd(),global2.path);await assertInitializedTracker(pmRoot);const settings=await readSettings(pmRoot),author=resolveAuthor(options.author,settings.author_default),claimPrincipal=resolveClaimPrincipal(author),ownershipReleaseBypass=options.ownershipReleaseBypass===!0;let previousAssignee=null;const statusRegistry=resolveRuntimeStatusRegistry(settings.schema),handoffStatus=resolveReleaseHandoff(options,statusRegistry);if(handoffStatus!==void 0&&ownershipReleaseBypass)throw new PmCliError("Ownership-release bypass only clears ownership; it cannot change a handoff status.",EXIT_CODE.USAGE);let handoff,result;try{result=await mutateItem({pmRoot,settings,id,op:"release",author,message:options.message,force,bypassAssigneeConflict:ownershipReleaseBypass,mutate(document){previousAssignee=document.metadata.assignee??null;const transition=handoffStatus===void 0?void 0:applyReleaseHandoff(document.metadata,handoffStatus,settings,statusRegistry,options.message);return handoff=transition?.receipt,!previousAssignee&&!document.metadata.claim_principal?{changedFields:[]}:(delete document.metadata.assignee,delete document.metadata.claim_principal,{changedFields:["assignee","claim_principal",...transition?.changedFields??[]],warnings:transition?.warnings})}})}catch(error){wrapOwnershipConflict(error,{required:"For approved non-owner handoffs, prefer the ownership-release bypass before considering --force.",examples:['pm release pm-a1b2 --author "reviewer" --force'],nextSteps:["Use the package-provided ownership-release bypass for handoffs that only clear assignee metadata.","Use --force only when an explicit override is approved for broader ownership conflicts."]})}await recordReleaseSemanticAttribution({pmRoot,principal:claimPrincipal,itemId:result.item.id});const stillInProgress=normalizeStatusForRegistry(result.item.status,statusRegistry)===normalizeStatusForRegistry(statusRegistry.in_progress_status,statusRegistry);return{item:toItemRecord(result.item),released_by:author,changed_fields:result.changedFields,previous_assignee:previousAssignee,forced:force,...handoff===void 0?{}:{handoff},...result.warnings.length>0||stillInProgress?{warnings:[...result.warnings,...stillInProgress?["released_unclaimed_in_progress"]:[]]}:{},...stillInProgress?{suggestions:[`${result.item.id} remains ${result.item.status} and unclaimed. If work is paused, run pm release ${result.item.id} --pause to move it to ${statusRegistry.open_status}.`]}:{}}}export{CLAIM_ATTRIBUTION_UNRECORDED_WARNING,NO_AVAILABLE_NEXT_ITEM_CODE,applyClaimStart,claimNextFromRecommendations,isAlreadyClaimedError,parseClaimNextAttempts,requireClaimTarget,runClaim,runClaimNext,runRelease};
|
|
2
2
|
//# sourceMappingURL=claim.js.map
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module cli/commands/close-many
|
|
3
|
+
*
|
|
4
|
+
* Implements the pm close many command surface and its agent-facing runtime behavior.
|
|
5
|
+
*/
|
|
6
|
+
import { type ItemRevisionConflictRowFields } from "./item-revision.js";
|
|
1
7
|
import { type GlobalOptions,readSettings } from "../runtime-primitives.js";
|
|
8
|
+
import { type DependentRevisionConflict } from "./close.js";
|
|
2
9
|
import type { CloseCompletionReceipt } from "../lifecycle-policy.js";
|
|
3
10
|
import { type ListOptions } from "../query/list.js";
|
|
4
11
|
import { type PmCommandEffectReceipt } from "../cli-contracts/command-exit-contracts.js";
|
|
@@ -43,7 +50,7 @@ action:"close" | "skip";
|
|
|
43
50
|
skip_reason?:string;
|
|
44
51
|
active_child_ids?:string[];
|
|
45
52
|
}
|
|
46
|
-
interface CloseManyApplyRow {
|
|
53
|
+
interface CloseManyApplyRow extends ItemRevisionConflictRowFields {
|
|
47
54
|
/** Completion provenance for a successfully closed target. */
|
|
48
55
|
completion?:CloseCompletionReceipt;
|
|
49
56
|
id:string;
|
|
@@ -52,6 +59,8 @@ skip_reason?:string;
|
|
|
52
59
|
changed_fields?:string[];
|
|
53
60
|
warnings?:string[];
|
|
54
61
|
error?:string;
|
|
62
|
+
/** A guarded dependent whose auto-unblock refused after this row's close committed. */
|
|
63
|
+
dependent_revision_conflict?:DependentRevisionConflict;
|
|
55
64
|
}
|
|
56
65
|
/** Documents the close many result payload exchanged by command, SDK, and package integrations. */
|
|
57
66
|
export interface CloseManyResult extends PmCommandEffectReceipt {
|
|
@@ -87,7 +96,7 @@ restored_count?:number;
|
|
|
87
96
|
/** Value that configures or reports rollback checkpoint id for this contract. */
|
|
88
97
|
rollback_checkpoint_id?:string;
|
|
89
98
|
/** Value that configures or reports rows for this contract. */
|
|
90
|
-
rows?:CloseManyApplyRow[] | Array<{
|
|
99
|
+
rows?:CloseManyApplyRow[] | Array<ItemRevisionConflictRowFields & {
|
|
91
100
|
id:string;
|
|
92
101
|
status:"restored" | "failed" | "skipped";
|
|
93
102
|
changed_fields?:string[];
|
|
@@ -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]="da095c39-4e7a-5c52-9b33-aa85d6e12e2d")}catch{}})();import{assertInitializedTracker}from"../environment/tracker-preflight.js";import{withCheckpointMutation}from"../../core/checkpoint/mutation-context.js";import{resolveCheckpointRollbackId}from"../../core/checkpoint/mutation-checkpoint.js";import{rollbackMutationCheckpoint}from"./checkpoint-rollback.js";import{createCheckpointId,loadMutationCheckpoint,writeMutationCheckpoint,getActiveExtensionRegistrations,isTerminalStatus,resolveItemTypeRegistry,resolveRuntimeStatusRegistry,EXIT_CODE,PmCliError,toErrorMessage,resolveAuthor,nowIso,listAllItemMetadataLight,resolvePmRoot,readSettings}from"../runtime-primitives.js";import{runClose}from"./close.js";import{hasListFilters}from"../query/list-filter-shared.js";import{runList}from"../query/list.js";import{derivePmBulkMutationEffect}from"../cli-contracts/command-exit-contracts.js";const CLOSE_MANY_CHECKPOINT_SCHEMA_VERSION=2,CLOSE_MANY_CHECKPOINT_SUBDIR="close-many",CLOSE_MANY_FILTER_GUIDANCE=["--filter-status","--filter-type","--filter-tag","--filter-priority","--filter-sprint","--filter-release","--filter-parent","--filter-assignee","--filter-updated-before","--ids"].join(", ");function hasCloseManyFilters(list,status){return hasListFilters(list,status,{includePagination:!1})}function hasCloseManyRollbackConflicts(list,status){return hasListFilters(list,status)}function rejectBlankIdsFilter(list){if(list?.ids!=null&&String(list.ids).trim().length===0)throw new PmCliError("--ids requires at least one non-empty item ID",EXIT_CODE.USAGE)}function activeListOptions(list){const active={};if(!list)return active;for(const[key,value]of Object.entries(list))value==null||typeof value=="string"&&!value.split(",").some(entry=>entry.trim().length>0)||(active[key]=value);return active}function resolveReason(reason,required){const trimmed=String(reason??"").trim();if(trimmed.length>0)return trimmed;if(required)throw new PmCliError("pm close-many requires a shared close reason via --reason because governance.require_close_reason is enabled.",EXIT_CODE.USAGE,{code:"close_reason_required",required:"Provide a shared closing summary via --reason for the whole batch.",why:"governance.require_close_reason is enabled, so every close must record why the items are done.",examples:['pm close-many --filter-sprint S-12 --reason "Sprint S-12 acceptance criteria met"','pm close-many --ids pm-a,pm-b --reason "Superseded by redesign"'],nextSteps:["Re-run with --reason describing the shared outcome.","To stop requiring reasons, run: pm config set governance-require-close-reason --policy disabled"]})}async function buildActiveChildrenByParent(pmRoot,settings){const statusRegistry=resolveRuntimeStatusRegistry(settings.schema),typeRegistry=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations()),items=await listAllItemMetadataLight(pmRoot,settings.item_format,typeRegistry.type_to_folder,void 0,settings.schema),childrenByParent=new Map,parentByChild=new Map;for(const item of items){if(typeof item.parent!="string"||item.parent.length===0||(parentByChild.set(item.id,item.parent),isTerminalStatus(item.status,statusRegistry)))continue;const existing=childrenByParent.get(item.parent);existing?existing.push(item.id):childrenByParent.set(item.parent,[item.id])}for(const ids of childrenByParent.values())ids.sort((left,right)=>left.localeCompare(right));return{childrenByParent,parentByChild}}function hierarchyDepth(id,parentByChild,cache){const cached=cache?.get(id);if(cached!==void 0)return cached;let depth=0,current=parentByChild.get(id);const path=[],visited=new Set;let hasCycle=!1;for(;current!==void 0&&!visited.has(current);){const cachedCurrent=cache?.get(current);if(cachedCurrent!==void 0){depth+=cachedCurrent+1;break}visited.add(current),path.push(current),depth+=1,current=parentByChild.get(current)}if(current!==void 0&&visited.has(current)&&(hasCycle=!0),!hasCycle){cache?.set(id,depth);for(const[index,ancestorId]of path.entries())cache?.set(ancestorId,depth-index-1)}return depth}async function runCloseManyRollback(params){const checkpoint=await loadMutationCheckpoint(params.pmRoot,CLOSE_MANY_CHECKPOINT_SUBDIR,params.rollbackId,CLOSE_MANY_CHECKPOINT_SCHEMA_VERSION),restoreMessage=params.options.message??`Rollback close-many checkpoint ${checkpoint.id}`,rollback=await rollbackMutationCheckpoint(params.pmRoot,checkpoint,{author:params.options.author,message:restoreMessage,force:params.options.force}),skipped=rollback.rows.filter(row=>row.status==="skipped").length;return{...derivePmBulkMutationEffect({applied:rollback.restored_ids.length,skipped,failed:rollback.failed_count,unmatched:0}),mode:"rollback",matched_count:checkpoint.items.length,dry_run:!1,rollback_checkpoint_id:checkpoint.id,checkpoint:{id:checkpoint.id,created_at:checkpoint.created_at,path:checkpoint.path,rollback_command:`pm close-many --rollback ${checkpoint.id}`},restored_count:rollback.restored_ids.length,skipped_count:skipped,failed_count:rollback.failed_count,rows:rollback.rows,ids:rollback.restored_ids}}function planCloseManyRows(matched,childrenByParent,closePlannedIds,statusRegistry,force){return matched.map(item=>{const activeChildIds=(childrenByParent.get(item.id)??[]).filter(childId=>!closePlannedIds.has(childId)),willSkip=!canCloseManyItem(item,statusRegistry,force);return{id:item.id,title:typeof item.title=="string"?item.title:"",status:item.status,action:willSkip?"skip":"close",...willSkip?{skip_reason:"already_terminal"}:{},...activeChildIds.length>0?{active_child_ids:activeChildIds}:{}}})}async function writeCloseManyCheckpoint(params){const checkpointPath=await writeMutationCheckpoint(params.pmRoot,CLOSE_MANY_CHECKPOINT_SUBDIR,params.checkpointId,{schema_version:CLOSE_MANY_CHECKPOINT_SCHEMA_VERSION,rollback_strategy:"guarded_inverse",id:params.checkpointId,created_at:params.nowValue,author:resolveAuthor(params.options.author,"unknown"),...params.reason!==void 0?{reason:params.reason}:{},filters:params.filters,items:params.checkpointItems});return{id:params.checkpointId,created_at:params.nowValue,path:checkpointPath,rollback_command:`pm close-many --rollback ${params.checkpointId}`}}async function applyCloseManyRows(params){const rows=[],closedIds=[];for(const item of params.matched){if(!params.closableIds.has(item.id)){rows.push({id:item.id,status:"skipped",skip_reason:"already_terminal"});continue}try{const result=await withCheckpointMutation({pmRoot:params.pmRoot,itemId:item.id,checkpointId:params.checkpointId},()=>runClose(item.id,params.reason,params.closeOptions,params.global));rows.push({id:item.id,status:"closed",completion:result.completion,changed_fields:result.changed_fields,...result.warnings&&result.warnings.length>0?{warnings:result.warnings}:{}}),closedIds.push(item.id)}catch(error){rows.push({id:item.id,status:"failed",error:toErrorMessage(error)})}}return{rows,closedIds}}function resolveCloseManyRollbackId(options){return resolveCheckpointRollbackId(options.rollback)}function validateCloseManyRollbackOptions(options){if(options.dryRun===!0)throw new PmCliError("--dry-run cannot be combined with --rollback",EXIT_CODE.USAGE);if(hasCloseManyRollbackConflicts(options.list,options.status))throw new PmCliError("Rollback mode does not accept filter options",EXIT_CODE.USAGE)}function assertCloseManyHasFilters(options){if(!hasCloseManyFilters(options.list,options.status))throw new PmCliError(`close-many requires at least one filter to scope the close (for example: ${CLOSE_MANY_FILTER_GUIDANCE}). Refusing to match every item.`,EXIT_CODE.USAGE)}function sortCloseManyMatchedItems(matched,parentByChild){const depthCache=new Map;return[...matched].sort((left,right)=>{const depthDelta=hierarchyDepth(right.id,parentByChild,depthCache)-hierarchyDepth(left.id,parentByChild,depthCache);return depthDelta!==0?depthDelta:left.id.localeCompare(right.id)})}function canCloseManyItem(item,statusRegistry,force){return force||!isTerminalStatus(item.status,statusRegistry)}function resolveCloseManyPlannedIds(matched,statusRegistry,force){return new Set(matched.filter(item=>canCloseManyItem(item,statusRegistry,force)).map(item=>item.id))}async function buildCloseManyPlanContext(params){assertCloseManyHasFilters(params.options);const statusRegistry=resolveRuntimeStatusRegistry(params.settings.schema),reason=resolveReason(params.options.reason,params.settings.governance.require_close_reason),force=params.options.force===!0,listed=await runList(params.options.status,activeListOptions(params.options.list),params.global),{childrenByParent,parentByChild}=await buildActiveChildrenByParent(params.pmRoot,params.settings),matched=sortCloseManyMatchedItems(listed.items,parentByChild),requestedIds=[...new Set(String(params.options.list?.ids??"").split(",").map(entry=>entry.trim()).filter(entry=>entry.length>0))],existenceItems=requestedIds.length===0?[]:(await runList(void 0,{ids:requestedIds.join(","),noTruncate:!0,full:!0},params.global)).items,existingIds=new Set(existenceItems.map(item=>item.id)),closePlannedIds=resolveCloseManyPlannedIds(matched,statusRegistry,force);return{pmRoot:params.pmRoot,settings:params.settings,statusRegistry,reason,validateCloseMode:params.options.validateClose,force,listed,matched,unmatchedIds:requestedIds.length===0?void 0:requestedIds.filter(id=>!existingIds.has(id)),planRows:planCloseManyRows(matched,childrenByParent,closePlannedIds,statusRegistry,force)}}function buildCloseManyDryRunResult(context){return{outcome:"effect",exit_code:EXIT_CODE.SUCCESS,mode:"dry_run",matched_count:context.matched.length,dry_run:!0,...context.reason!==void 0?{reason:context.reason}:{},filters:context.listed.filters,...context.validateCloseMode?{validate_close:context.validateCloseMode}:{},item_plans:context.planRows,ids:[],...context.unmatchedIds!==void 0?{unmatched_ids:context.unmatchedIds,unmatched_count:context.unmatchedIds.length}:{}}}async function resolveCloseManyCheckpointInfo(params){if(params.options.checkpoint===!1||params.closableIds.size===0)return;const checkpointItems=params.context.matched.filter(item=>params.closableIds.has(item.id)).map(item=>({id:item.id,target_updated_at:item.updated_at}));return writeCloseManyCheckpoint({pmRoot:params.context.pmRoot,checkpointId:params.checkpointId,nowValue:params.nowValue,options:params.options,reason:params.context.reason,filters:params.context.listed.filters,checkpointItems})}async function runCloseMany(options,global2){const rollbackId=resolveCloseManyRollbackId(options),pmRoot=resolvePmRoot(process.cwd(),global2.path);await assertInitializedTracker(pmRoot);const settings=await readSettings(pmRoot),dryRun=options.dryRun===!0;if(rejectBlankIdsFilter(options.list),rollbackId!==void 0)return validateCloseManyRollbackOptions(options),runCloseManyRollback({pmRoot,rollbackId,options,global:global2});const context=await buildCloseManyPlanContext({pmRoot,settings,options,global:global2});if(dryRun)return buildCloseManyDryRunResult(context);const closableIds=new Set(context.planRows.filter(row=>row.action==="close").map(row=>row.id)),nowValue=nowIso(),checkpointId=createCheckpointId(CLOSE_MANY_CHECKPOINT_SUBDIR,nowValue),checkpointInfo=await resolveCloseManyCheckpointInfo({context,options,closableIds,checkpointId,nowValue}),closeOptions={author:options.author,message:options.message??`close-many apply ${checkpointId}`,completedAt:options.completedAt,validateClose:context.validateCloseMode,force:context.force,resolution:options.resolution,expectedResult:options.expectedResult,actualResult:options.actualResult},{rows,closedIds}=await applyCloseManyRows({pmRoot,checkpointId,matched:context.matched,closableIds,reason:context.reason,closeOptions,global:global2}),closedCount=rows.filter(row=>row.status==="closed").length,skippedCount=rows.filter(row=>row.status==="skipped").length,failedCount=rows.filter(row=>row.status==="failed").length;return{...derivePmBulkMutationEffect({applied:closedCount,skipped:skippedCount,failed:failedCount,unmatched:context.unmatchedIds?.length??0}),mode:"apply",matched_count:context.matched.length,dry_run:!1,...context.reason!==void 0?{reason:context.reason}:{},filters:context.listed.filters,...context.validateCloseMode?{validate_close:context.validateCloseMode}:{},...checkpointInfo?{checkpoint:checkpointInfo}:{},closed_count:closedCount,skipped_count:skippedCount,failed_count:failedCount,rows,ids:closedIds,...context.unmatchedIds!==void 0?{unmatched_ids:context.unmatchedIds,unmatched_count:context.unmatchedIds.length}:{}}}const _testOnly={activeListOptions,buildActiveChildrenByParent,hasCloseManyFilters,hasCloseManyRollbackConflicts,hierarchyDepth,rejectBlankIdsFilter,resolveReason};export{_testOnly,runCloseMany};
|
|
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]="90dbc790-401a-5b74-90e2-143f65d32b9f")}catch{}})();import{itemRevisionConflictRowFields}from"./item-revision.js";import{assertInitializedTracker}from"../environment/tracker-preflight.js";import{withCheckpointMutation}from"../../core/checkpoint/mutation-context.js";import{resolveCheckpointRollbackId}from"../../core/checkpoint/mutation-checkpoint.js";import{rollbackMutationCheckpoint}from"./checkpoint-rollback.js";import{createCheckpointId,loadMutationCheckpoint,writeMutationCheckpoint,getActiveExtensionRegistrations,isTerminalStatus,resolveItemTypeRegistry,resolveRuntimeStatusRegistry,EXIT_CODE,PmCliError,toErrorMessage,resolveAuthor,nowIso,listAllItemMetadataLight,resolvePmRoot,readSettings}from"../runtime-primitives.js";import{committedCloseDependentConflict,runClose}from"./close.js";import{hasListFilters}from"../query/list-filter-shared.js";import{runList}from"../query/list.js";import{derivePmBulkMutationEffect}from"../cli-contracts/command-exit-contracts.js";const CLOSE_MANY_CHECKPOINT_SCHEMA_VERSION=2,CLOSE_MANY_CHECKPOINT_SUBDIR="close-many",CLOSE_MANY_FILTER_GUIDANCE=["--filter-status","--filter-type","--filter-tag","--filter-priority","--filter-sprint","--filter-release","--filter-parent","--filter-assignee","--filter-updated-before","--ids"].join(", ");function hasCloseManyFilters(list,status){return hasListFilters(list,status,{includePagination:!1})}function hasCloseManyRollbackConflicts(list,status){return hasListFilters(list,status)}function rejectBlankIdsFilter(list){if(list?.ids!=null&&String(list.ids).trim().length===0)throw new PmCliError("--ids requires at least one non-empty item ID",EXIT_CODE.USAGE)}function activeListOptions(list){const active={};if(!list)return active;for(const[key,value]of Object.entries(list))value==null||typeof value=="string"&&!value.split(",").some(entry=>entry.trim().length>0)||(active[key]=value);return active}function resolveReason(reason,required){const trimmed=String(reason??"").trim();if(trimmed.length>0)return trimmed;if(required)throw new PmCliError("pm close-many requires a shared close reason via --reason because governance.require_close_reason is enabled.",EXIT_CODE.USAGE,{code:"close_reason_required",required:"Provide a shared closing summary via --reason for the whole batch.",why:"governance.require_close_reason is enabled, so every close must record why the items are done.",examples:['pm close-many --filter-sprint S-12 --reason "Sprint S-12 acceptance criteria met"','pm close-many --ids pm-a,pm-b --reason "Superseded by redesign"'],nextSteps:["Re-run with --reason describing the shared outcome.","To stop requiring reasons, run: pm config set governance-require-close-reason --policy disabled"]})}async function buildActiveChildrenByParent(pmRoot,settings){const statusRegistry=resolveRuntimeStatusRegistry(settings.schema),typeRegistry=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations()),items=await listAllItemMetadataLight(pmRoot,settings.item_format,typeRegistry.type_to_folder,void 0,settings.schema),childrenByParent=new Map,parentByChild=new Map;for(const item of items){if(typeof item.parent!="string"||item.parent.length===0||(parentByChild.set(item.id,item.parent),isTerminalStatus(item.status,statusRegistry)))continue;const existing=childrenByParent.get(item.parent);existing?existing.push(item.id):childrenByParent.set(item.parent,[item.id])}for(const ids of childrenByParent.values())ids.sort((left,right)=>left.localeCompare(right));return{childrenByParent,parentByChild}}function hierarchyDepth(id,parentByChild,cache){const cached=cache?.get(id);if(cached!==void 0)return cached;let depth=0,current=parentByChild.get(id);const path=[],visited=new Set;let hasCycle=!1;for(;current!==void 0&&!visited.has(current);){const cachedCurrent=cache?.get(current);if(cachedCurrent!==void 0){depth+=cachedCurrent+1;break}visited.add(current),path.push(current),depth+=1,current=parentByChild.get(current)}if(current!==void 0&&visited.has(current)&&(hasCycle=!0),!hasCycle){cache?.set(id,depth);for(const[index,ancestorId]of path.entries())cache?.set(ancestorId,depth-index-1)}return depth}async function runCloseManyRollback(params){const checkpoint=await loadMutationCheckpoint(params.pmRoot,CLOSE_MANY_CHECKPOINT_SUBDIR,params.rollbackId,CLOSE_MANY_CHECKPOINT_SCHEMA_VERSION),restoreMessage=params.options.message??`Rollback close-many checkpoint ${checkpoint.id}`,rollback=await rollbackMutationCheckpoint(params.pmRoot,checkpoint,{author:params.options.author,message:restoreMessage,force:params.options.force}),skipped=rollback.rows.filter(row=>row.status==="skipped").length;return{...derivePmBulkMutationEffect({applied:rollback.restored_ids.length,skipped,failed:rollback.failed_count,unmatched:0}),mode:"rollback",matched_count:checkpoint.items.length,dry_run:!1,rollback_checkpoint_id:checkpoint.id,checkpoint:{id:checkpoint.id,created_at:checkpoint.created_at,path:checkpoint.path,rollback_command:`pm close-many --rollback ${checkpoint.id}`},restored_count:rollback.restored_ids.length,skipped_count:skipped,failed_count:rollback.failed_count,rows:rollback.rows,ids:rollback.restored_ids}}function planCloseManyRows(matched,childrenByParent,closePlannedIds,statusRegistry,force){return matched.map(item=>{const activeChildIds=(childrenByParent.get(item.id)??[]).filter(childId=>!closePlannedIds.has(childId)),willSkip=!canCloseManyItem(item,statusRegistry,force);return{id:item.id,title:typeof item.title=="string"?item.title:"",status:item.status,action:willSkip?"skip":"close",...willSkip?{skip_reason:"already_terminal"}:{},...activeChildIds.length>0?{active_child_ids:activeChildIds}:{}}})}async function writeCloseManyCheckpoint(params){const checkpointPath=await writeMutationCheckpoint(params.pmRoot,CLOSE_MANY_CHECKPOINT_SUBDIR,params.checkpointId,{schema_version:CLOSE_MANY_CHECKPOINT_SCHEMA_VERSION,rollback_strategy:"guarded_inverse",id:params.checkpointId,created_at:params.nowValue,author:resolveAuthor(params.options.author,"unknown"),...params.reason!==void 0?{reason:params.reason}:{},filters:params.filters,items:params.checkpointItems});return{id:params.checkpointId,created_at:params.nowValue,path:checkpointPath,rollback_command:`pm close-many --rollback ${params.checkpointId}`}}async function applyCloseManyRows(params){const rows=[],closedIds=[];for(const item of params.matched){if(!params.closableIds.has(item.id)){rows.push({id:item.id,status:"skipped",skip_reason:"already_terminal"});continue}try{const result=await withCheckpointMutation({pmRoot:params.pmRoot,itemId:item.id,checkpointId:params.checkpointId},()=>runClose(item.id,params.reason,params.closeOptions,params.global));rows.push({id:item.id,status:"closed",completion:result.completion,changed_fields:result.changed_fields,...result.warnings&&result.warnings.length>0?{warnings:result.warnings}:{}}),closedIds.push(item.id)}catch(error){const committed=await committedCloseDependentConflict(error,item.id,params.pmRoot);if(committed!==void 0){rows.push({id:item.id,status:"closed",...committed}),closedIds.push(item.id);continue}rows.push({id:item.id,status:"failed",error:toErrorMessage(error),...await itemRevisionConflictRowFields(error,params.pmRoot)})}}return{rows,closedIds}}function resolveCloseManyRollbackId(options){return resolveCheckpointRollbackId(options.rollback)}function validateCloseManyRollbackOptions(options){if(options.dryRun===!0)throw new PmCliError("--dry-run cannot be combined with --rollback",EXIT_CODE.USAGE);if(hasCloseManyRollbackConflicts(options.list,options.status))throw new PmCliError("Rollback mode does not accept filter options",EXIT_CODE.USAGE)}function assertCloseManyHasFilters(options){if(!hasCloseManyFilters(options.list,options.status))throw new PmCliError(`close-many requires at least one filter to scope the close (for example: ${CLOSE_MANY_FILTER_GUIDANCE}). Refusing to match every item.`,EXIT_CODE.USAGE)}function sortCloseManyMatchedItems(matched,parentByChild){const depthCache=new Map;return[...matched].sort((left,right)=>{const depthDelta=hierarchyDepth(right.id,parentByChild,depthCache)-hierarchyDepth(left.id,parentByChild,depthCache);return depthDelta!==0?depthDelta:left.id.localeCompare(right.id)})}function canCloseManyItem(item,statusRegistry,force){return force||!isTerminalStatus(item.status,statusRegistry)}function resolveCloseManyPlannedIds(matched,statusRegistry,force){return new Set(matched.filter(item=>canCloseManyItem(item,statusRegistry,force)).map(item=>item.id))}async function buildCloseManyPlanContext(params){assertCloseManyHasFilters(params.options);const statusRegistry=resolveRuntimeStatusRegistry(params.settings.schema),reason=resolveReason(params.options.reason,params.settings.governance.require_close_reason),force=params.options.force===!0,listed=await runList(params.options.status,activeListOptions(params.options.list),params.global),{childrenByParent,parentByChild}=await buildActiveChildrenByParent(params.pmRoot,params.settings),matched=sortCloseManyMatchedItems(listed.items,parentByChild),requestedIds=[...new Set(String(params.options.list?.ids??"").split(",").map(entry=>entry.trim()).filter(entry=>entry.length>0))],existenceItems=requestedIds.length===0?[]:(await runList(void 0,{ids:requestedIds.join(","),noTruncate:!0,full:!0},params.global)).items,existingIds=new Set(existenceItems.map(item=>item.id)),closePlannedIds=resolveCloseManyPlannedIds(matched,statusRegistry,force);return{pmRoot:params.pmRoot,settings:params.settings,statusRegistry,reason,validateCloseMode:params.options.validateClose,force,listed,matched,unmatchedIds:requestedIds.length===0?void 0:requestedIds.filter(id=>!existingIds.has(id)),planRows:planCloseManyRows(matched,childrenByParent,closePlannedIds,statusRegistry,force)}}function buildCloseManyDryRunResult(context){return{outcome:"effect",exit_code:EXIT_CODE.SUCCESS,mode:"dry_run",matched_count:context.matched.length,dry_run:!0,...context.reason!==void 0?{reason:context.reason}:{},filters:context.listed.filters,...context.validateCloseMode?{validate_close:context.validateCloseMode}:{},item_plans:context.planRows,ids:[],...context.unmatchedIds!==void 0?{unmatched_ids:context.unmatchedIds,unmatched_count:context.unmatchedIds.length}:{}}}async function resolveCloseManyCheckpointInfo(params){if(params.options.checkpoint===!1||params.closableIds.size===0)return;const checkpointItems=params.context.matched.filter(item=>params.closableIds.has(item.id)).map(item=>({id:item.id,target_updated_at:item.updated_at}));return writeCloseManyCheckpoint({pmRoot:params.context.pmRoot,checkpointId:params.checkpointId,nowValue:params.nowValue,options:params.options,reason:params.context.reason,filters:params.context.listed.filters,checkpointItems})}async function runCloseMany(options,global2){const rollbackId=resolveCloseManyRollbackId(options),pmRoot=resolvePmRoot(process.cwd(),global2.path);await assertInitializedTracker(pmRoot);const settings=await readSettings(pmRoot),dryRun=options.dryRun===!0;if(rejectBlankIdsFilter(options.list),rollbackId!==void 0)return validateCloseManyRollbackOptions(options),runCloseManyRollback({pmRoot,rollbackId,options,global:global2});const context=await buildCloseManyPlanContext({pmRoot,settings,options,global:global2});if(dryRun)return buildCloseManyDryRunResult(context);const closableIds=new Set(context.planRows.filter(row=>row.action==="close").map(row=>row.id)),nowValue=nowIso(),checkpointId=createCheckpointId(CLOSE_MANY_CHECKPOINT_SUBDIR,nowValue),checkpointInfo=await resolveCloseManyCheckpointInfo({context,options,closableIds,checkpointId,nowValue}),closeOptions={author:options.author,message:options.message??`close-many apply ${checkpointId}`,completedAt:options.completedAt,validateClose:context.validateCloseMode,force:context.force,resolution:options.resolution,expectedResult:options.expectedResult,actualResult:options.actualResult},{rows,closedIds}=await applyCloseManyRows({pmRoot,checkpointId,matched:context.matched,closableIds,reason:context.reason,closeOptions,global:global2}),closedCount=rows.filter(row=>row.status==="closed").length,skippedCount=rows.filter(row=>row.status==="skipped").length,failedCount=rows.filter(row=>row.status==="failed").length;return{...derivePmBulkMutationEffect({applied:closedCount,skipped:skippedCount,failed:failedCount,unmatched:context.unmatchedIds?.length??0}),mode:"apply",matched_count:context.matched.length,dry_run:!1,...context.reason!==void 0?{reason:context.reason}:{},filters:context.listed.filters,...context.validateCloseMode?{validate_close:context.validateCloseMode}:{},...checkpointInfo?{checkpoint:checkpointInfo}:{},closed_count:closedCount,skipped_count:skippedCount,failed_count:failedCount,rows,ids:closedIds,...context.unmatchedIds!==void 0?{unmatched_ids:context.unmatchedIds,unmatched_count:context.unmatchedIds.length}:{}}}const _testOnly={activeListOptions,buildActiveChildrenByParent,hasCloseManyFilters,hasCloseManyRollbackConflicts,hierarchyDepth,rejectBlankIdsFilter,resolveReason};export{_testOnly,runCloseMany};
|
|
2
2
|
//# sourceMappingURL=close-many.js.map
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { type ItemRevisionConflictRowFields } from "./item-revision.js";
|
|
1
2
|
import { type GlobalOptions } from "../runtime-primitives.js";
|
|
2
3
|
import { collectBlockedByIds } from "../actionability.js";
|
|
3
4
|
import { type CloseOperationOptions,type CloseOperationResult,type CloseEvidenceFollowUp,type CloseCompletionReceipt } from "../lifecycle-policy.js";
|
|
5
|
+
import type { PmCliErrorDetails,PmCliErrorDetailValue } from "../../core/shared/errors.js";
|
|
4
6
|
/** Compatibility options for command-shaped close consumers. */
|
|
5
7
|
export interface CloseCommandOptions {
|
|
6
8
|
/** Mutation author. */
|
|
@@ -35,11 +37,34 @@ follow_up?:CloseEvidenceFollowUp;
|
|
|
35
37
|
/** Validation and lifecycle receipts. */
|
|
36
38
|
warnings:string[];
|
|
37
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* Trim the merged post-close details until the error host renders them whole:
|
|
42
|
+
* other failures first, then the revision change evidence, then pending ids
|
|
43
|
+
* (one always stays). Each dropped entry is counted in its list's omitted
|
|
44
|
+
* field, so a reader knows the list is partial.
|
|
45
|
+
*/
|
|
46
|
+
declare function fitPostCloseDetails(details:Record<string,PmCliErrorDetailValue>):PmCliErrorDetails;
|
|
47
|
+
/** A guarded dependent whose auto-unblock refused after a bulk row's close committed. */
|
|
48
|
+
export type DependentRevisionConflict = ItemRevisionConflictRowFields & {
|
|
49
|
+
item_id:string;
|
|
50
|
+
error:string;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Bulk-row fields for a row whose close committed before a guarded dependent's
|
|
54
|
+
* auto-unblock refused (the refusal discloses the close in `side_effects`), or
|
|
55
|
+
* undefined for any other failure (pm-gh1576).
|
|
56
|
+
*/
|
|
57
|
+
export declare function committedCloseDependentConflict(error:unknown,id:string,pmRoot:string):Promise<{
|
|
58
|
+
warnings:string[];
|
|
59
|
+
dependent_revision_conflict:DependentRevisionConflict;
|
|
60
|
+
} | undefined>;
|
|
38
61
|
/** Public contract for test only close command, shared by SDK and presentation-layer consumers. */
|
|
39
62
|
export declare const _testOnlyCloseCommand:{
|
|
40
63
|
blockedByIds:typeof collectBlockedByIds;
|
|
64
|
+
fitPostCloseDetails:typeof fitPostCloseDetails;
|
|
41
65
|
};
|
|
42
66
|
/** Close one item through the SDK-owned lifecycle transaction and policy. */
|
|
43
67
|
export declare function closeItem(id:string,closeReasonText:string | undefined,options:CloseOperationOptions,global:GlobalOptions):Promise<CloseOperationResult>;
|
|
44
68
|
/** Compatibility command-shaped wrapper over the SDK-owned close operation. */
|
|
45
69
|
export declare function runClose(id:string,closeReasonText:string | undefined,options:CloseCommandOptions,global:GlobalOptions):Promise<CloseResult>;
|
|
70
|
+
export {};
|
|
@@ -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]="3445f237-469f-5713-bcd1-826fda836efd")}catch{}})();import{assertInitializedTracker}from"../environment/tracker-preflight.js";import{toItemRecord,isTerminalStatus,resolveItemTypeRegistry,resolveRuntimeStatusRegistry,EXIT_CODE,PmCliError,buildItemNotFoundError,listAllItemMetadataLight,locateItem,readLocatedItem,mutateItem,resolvePmRoot,readSettings,resolveAuthor,resolveIsoOrRelative,shouldCompletePlanOnClose,getActiveExtensionRegistrations}from"../runtime-primitives.js";import{collectBlockedByIds,indexBlockedByIds}from"../actionability.js";import{applyTerminalOrderingPolicy,requireTerminalReason}from"../lifecycle-policy.js";import{nowIso}from"../../core/shared/time.js";import{renderPmCommand,resolvePmCommandScopeArgs}from"../command-line.js";import{mutateItemWithHistoryContextResolver}from"../../core/store/item-store.js";const CLOSE_VALIDATION_FIELDS=[{key:"resolution",label:"resolution (--resolution)"},{key:"expected_result",label:"expected_result (--expected-result)"},{key:"actual_result",label:"actual_result (--actual-result)"}];function parseValidateCloseMode(raw){if(raw===void 0)return;const normalized=raw.trim().toLowerCase();if(normalized.length===0||normalized==="warn")return"warn";if(normalized==="off"||normalized==="none"||normalized==="disabled")return"off";if(normalized==="strict")return"strict";throw new PmCliError(`Invalid --validate-close mode "${raw}" (expected "off", "warn", or "strict")`,EXIT_CODE.USAGE)}function findMissingCloseValidationFields(itemMetadata){const missing=[];for(const field of CLOSE_VALIDATION_FIELDS){const rawValue=itemMetadata[field.key];(typeof rawValue!="string"||rawValue.trim().length===0)&&missing.push(field)}return missing}function closeEvidenceRecovery(metadata,commandScope,options={}){const missing=findMissingCloseValidationFields(metadata);if(missing.length===0)return;const values={resolution:options.resolution,expected_result:options.expectedResult,actual_result:options.actualResult},missingFlags=missing.map(field=>`--${field.key.replaceAll("_","-")}`),args=[...commandScope,"update",metadata.id,...missing.flatMap((field,index)=>[missingFlags[index],values[field.key]?.trim()||"<value>"])];return{missing:missingFlags,suggested_retry:renderPmCommand(args),suggested_retry_args:args}}async function duplicateChainReferencesClosingItem(loadItemById,initialDuplicateOf,closingId){const visited=new Set;let current=initialDuplicateOf;for(;typeof current=="string"&¤t.trim().length>0;){const currentId=current.trim();if(currentId===closingId)return!0;if(visited.has(currentId))return!1;visited.add(currentId),current=(await loadItemById(currentId))?.duplicate_of}return!1}function shouldApplyDuplicateFallback(value){return typeof value!="string"||value.trim().length===0}async function assertDuplicateTargetExists(pmRoot,settings,duplicateOf,closingId){const rawTarget=duplicateOf?.trim();if(!rawTarget)return;if(rawTarget===closingId)throw new PmCliError("An item cannot be closed as a duplicate of itself.",EXIT_CODE.USAGE,{code:"duplicate_target_self",why:"--duplicate-of must identify the canonical item that should remain open or already represent the work."});const typeRegistry=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations()),itemCache=new Map,loadItemById=async id=>{if(itemCache.has(id))return itemCache.get(id)??null;const located=await locateItem(pmRoot,id,settings.id_prefix,settings.item_format,typeRegistry.type_to_folder);if(!located)return itemCache.set(id,null),null;const{document}=await readLocatedItem(located,{schema:settings.schema});return itemCache.set(id,document.metadata),document.metadata},target=await loadItemById(rawTarget);if(!target)throw new PmCliError(`Duplicate target "${rawTarget}" was not found. Create or locate the canonical item first.`,EXIT_CODE.USAGE,{code:"duplicate_target_missing",why:"Duplicate closure should point at a real canonical pm item so future dedupe and changelog tooling can trace the relationship.",examples:[`pm close ${closingId} "Duplicate of ${rawTarget}" --duplicate-of ${rawTarget}`],nextSteps:["Run pm search/list to find the canonical item, then retry with --duplicate-of <id>."]});if(await duplicateChainReferencesClosingItem(loadItemById,target.duplicate_of,closingId))throw new PmCliError(`Circular duplicate reference detected. Target "${rawTarget}" points back to "${closingId}".`,EXIT_CODE.USAGE,{code:"duplicate_target_circular",why:"Circular duplicate relationships create loops for dedupe and status propagation tooling.",nextSteps:["Choose the existing canonical item, or clear the target duplicate_of metadata before closing this item as a duplicate."]});if(typeof target.duplicate_of=="string"&&target.duplicate_of.trim().length>0)throw new PmCliError(`Duplicate target "${rawTarget}" is already marked as a duplicate of "${target.duplicate_of.trim()}".`,EXIT_CODE.USAGE,{code:"duplicate_target_is_duplicate",why:"Duplicate closure should point directly at the canonical item, not another duplicate.",examples:[`pm close ${closingId} "Duplicate of ${target.duplicate_of.trim()}" --duplicate-of ${target.duplicate_of.trim()}`],nextSteps:["Use the canonical item referenced by duplicate_of as the --duplicate-of target."]});return target.id}function findActiveChildIds(items,parentId,statusRegistry){return items.filter(item=>item.parent===parentId&&!isTerminalStatus(item.status,statusRegistry)).map(item=>item.id).sort((left,right)=>left.localeCompare(right))}function findAutoUnblockCandidates(items,closedId,statusRegistry){const itemsById=new Map(items.map(item=>[item.id.trim().toLowerCase(),item])),blockerIdsByItem=indexBlockedByIds(items),normalizedClosedId=closedId.trim().toLowerCase(),blockedStatuses=statusRegistry.blocked_statuses;return items.filter(item=>blockedStatuses.has(item.status)).map(item=>({item,blockerIds:blockerIdsByItem.get(item.id.trim().toLowerCase())})).filter(({blockerIds})=>blockerIds.includes(normalizedClosedId)).filter(({blockerIds})=>blockerIds.every(blockerId=>{if(blockerId===normalizedClosedId)return!0;const blocker=itemsById.get(blockerId);return blocker!==void 0&&isTerminalStatus(blocker.status,statusRegistry)})).map(({item,blockerIds})=>({id:item.id,blocker_ids:blockerIds})).sort((left,right)=>left.id.localeCompare(right.id))}async function autoUnblockResolvedDependents(pmRoot,settings,items,closedId,author,statusRegistry){const candidates=findAutoUnblockCandidates(items,closedId,statusRegistry),warnings=[];for(const candidate of candidates)try{const unblocked=await mutateItem({pmRoot,settings,id:candidate.id,op:"update",author,message:`Auto-unblocked after blocker ${closedId} closed`,mutate(document){const dependencies=document.metadata.dependencies??[],remainingDependencies=dependencies.filter(dependency=>{const dependencyId=dependency.id.trim().toLowerCase();return dependency.kind!=="blocked_by"||!candidate.blocker_ids.includes(dependencyId)});document.metadata.status=statusRegistry.open_status,delete document.metadata.blocked_by,delete document.metadata.blocked_reason,document.metadata.unblock_note=`Auto-unblocked after blocker ${closedId} closed; all blockers resolved (${candidate.blocker_ids.join(", ")}).`,remainingDependencies.length>0?document.metadata.dependencies=remainingDependencies:delete document.metadata.dependencies;const changedFields=["status","blocked_by","blocked_reason","unblock_note"];return remainingDependencies.length!==dependencies.length&&changedFields.push("dependencies"),{changedFields}}});warnings.push(`auto_unblocked:${unblocked.item.id}:resolved_blockers=${candidate.blocker_ids.join(",")}`)}catch(error){const reason=error instanceof Error?error.message.replace(/\s+/g," ").trim():"unknown";warnings.push(`auto_unblock_failed:${candidate.id}:${reason}`)}return warnings}function applyInlineCloseFields(metadata,options){const changedFields=[],inlineCloseFields=[{option:options.resolution,key:"resolution"},{option:options.expectedResult,key:"expected_result"},{option:options.actualResult,key:"actual_result"}];for(const{option,key}of inlineCloseFields){if(typeof option!="string")continue;const trimmed=option.trim();trimmed.length!==0&&(metadata[key]=trimmed,changedFields.push(key))}return changedFields}function applyDuplicateCloseMetadata(metadata,duplicateOf){if(duplicateOf===void 0)return[];metadata.duplicate_of=duplicateOf;const duplicateFallbackFields=[],fallbackValues=[{key:"resolution",value:`Duplicate of ${duplicateOf}`},{key:"expected_result",value:`Canonical item ${duplicateOf} tracks the work.`},{key:"actual_result",value:`Closed as duplicate of ${duplicateOf}.`}];for(const{key,value}of fallbackValues)shouldApplyDuplicateFallback(metadata[key])&&(metadata[key]=value,duplicateFallbackFields.push(key));return duplicateFallbackFields}function collectCloseValidationWarnings(metadata,validateCloseMode,activeChildIds,commandScope){const warnings=[];if(validateCloseMode!=="off"){const missingFields=findMissingCloseValidationFields(metadata);if(missingFields.length>0){const missingLabels=missingFields.map(field=>field.label);if(validateCloseMode==="strict"){const missingFlags=missingFields.map(field=>`--${field.key.replaceAll("_","-")}`),updateTokens=[...commandScope,"update",metadata.id,...missingFlags.flatMap(flag=>[flag,"<value>"])];throw new PmCliError(`Cannot close item ${metadata.id}: missing ${missingLabels.join(", ")}. Populate fields or use --validate-close warn.`,EXIT_CODE.USAGE,{code:"close_validation_missing_fields",recovery:{missing:missingFlags,suggested_retry:renderPmCommand(updateTokens),suggested_retry_args:updateTokens},nextSteps:["Run the suggested pm update, then retry the original pm close invocation.","Use --validate-close warn only when governance permits an evidenced exception."]})}warnings.push(`close_validation_missing_fields:${metadata.id}:${missingLabels.join(",")}`)}if(activeChildIds.length>0){if(validateCloseMode==="strict")throw new PmCliError(`Cannot close item ${metadata.id}: active child items remain open (${activeChildIds.join(", ")}). Close, cancel, or re-parent them first, or use --validate-close warn.`,EXIT_CODE.USAGE);warnings.push(`close_validation_active_children:${metadata.id}:${activeChildIds.join(",")}`)}return warnings}return activeChildIds.length>0&&warnings.push(`closed_with_active_children:${metadata.id}:${activeChildIds.join(",")}`),warnings}function applyCloseReason(metadata,closeReason){return closeReason!==void 0?(metadata.close_reason=closeReason,["close_reason"]):[]}function clearCloseAssignee(metadata){const cleared=["assignee","claim_principal"].filter(key=>metadata[key]!==void 0);for(const key of cleared)delete metadata[key];return[...cleared]}function mutateCloseMetadata(metadata,context){if(isTerminalStatus(metadata.status,context.statusRegistry)&&!context.force)throw new PmCliError(`Item ${metadata.id} is already terminal; use pm update to append acceptance evidence, or --force only for an intentional repeat closure.`,EXIT_CODE.CONFLICT,{recovery:closeEvidenceRecovery(metadata,context.commandScope,context.options)});const inlineChangedFields=applyInlineCloseFields(metadata,context.options),duplicateFallbackFields=applyDuplicateCloseMetadata(metadata,context.duplicateOf),mutationWarnings=collectCloseValidationWarnings(metadata,context.validateCloseMode,context.activeChildIds,context.commandScope);metadata.status=context.statusRegistry.close_status,metadata.closed_at=context.closedAt;const shouldWriteCompletedAt=context.options.completedAt!==void 0||metadata.completed_at===void 0;shouldWriteCompletedAt&&(metadata.completed_at=context.completedAt);const changedFields=["status","closed_at",...shouldWriteCompletedAt?["completed_at"]:[],...applyCloseReason(metadata,context.closeReason),...inlineChangedFields];if(shouldCompletePlanOnClose(metadata)&&(metadata.plan_mode="completed",changedFields.push("plan_mode")),context.duplicateOf!==void 0){changedFields.push("duplicate_of");for(const key of duplicateFallbackFields)changedFields.includes(key)||changedFields.push(key)}changedFields.push(...clearCloseAssignee(metadata));const blockerCleanup=applyTerminalOrderingPolicy(metadata,context.lifecyclePolicy);return changedFields.push(...blockerCleanup.changedFields),mutationWarnings.push(...blockerCleanup.warnings),{changedFields,...mutationWarnings.length>0?{warnings:mutationWarnings}:{}}}const _testOnlyCloseCommand={blockedByIds:collectBlockedByIds};async function closeItem(id,closeReasonText,options,global2){const pmRoot=resolvePmRoot(process.cwd(),global2.path),commandScope=resolvePmCommandScopeArgs(global2);await assertInitializedTracker(pmRoot);const settings=await readSettings(pmRoot),statusRegistry=resolveRuntimeStatusRegistry(settings.schema),author=resolveAuthor(options.author,settings.author_default),typeToFolder=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations()).type_to_folder,located=await locateItem(pmRoot,id,settings.id_prefix,settings.item_format,typeToFolder);if(!located)throw await buildItemNotFoundError(pmRoot,id,settings.id_prefix,typeToFolder);const duplicateOf=await assertDuplicateTargetExists(pmRoot,settings,options.duplicateOf,located.id),lifecyclePolicy={requireCloseReason:options.lifecyclePolicy?.requireCloseReason??settings.governance.require_close_reason,orderingEdges:options.lifecyclePolicy?.orderingEdges??"preserve"},closeReason=requireTerminalReason({explicit:closeReasonText,duplicateOf,resolution:options.resolution,message:options.message},lifecyclePolicy.requireCloseReason).closeReason,validateCloseMode=parseValidateCloseMode(options.validateClose)??settings.governance.close_validation_default,trackerItems=await listAllItemMetadataLight(pmRoot,settings.item_format,typeToFolder,void 0,settings.schema),activeChildIds=findActiveChildIds(trackerItems,located.id,statusRegistry),closedAt=nowIso(),completedAt=options.completedAt===void 0?closedAt:resolveIsoOrRelative(options.completedAt,new Date(closedAt),"completed-at");let completion={timestamp:completedAt,source:options.completedAt===void 0?"close_time":"asserted",...options.completedAt===void 0?{hint:`completed_at defaults to the close time. If work finished earlier, correct it with ${renderPmCommand([...commandScope,"update",located.id,"--completed-at","<ISO>"])}.`}:{}};const result=await mutateItemWithHistoryContextResolver({pmRoot,settings,id:located.id,op:"close",author,message:options.message,force:options.force,resolveHistoryContext:()=>({completion:{timestamp:completion.timestamp,source:completion.source}}),mutate(document){return options.completedAt===void 0&&document.metadata.completed_at!==void 0&&(completion={timestamp:document.metadata.completed_at,source:"existing"}),mutateCloseMetadata(document.metadata,{pmRoot,commandScope,statusRegistry,force:options.force,options,duplicateOf,validateCloseMode,activeChildIds,closeReason,closedAt,completedAt,lifecyclePolicy})}}),evidence=validateCloseMode==="warn"?closeEvidenceRecovery(result.item,commandScope):void 0;return{item:toItemRecord(result.item),changed_fields:result.changedFields,...evidence?{follow_up:{kind:"complete_close_evidence",missing:evidence.missing,suggested_command:evidence.suggested_retry,suggested_command_args:evidence.suggested_retry_args}}:{},warnings:[...result.warnings,...await autoUnblockResolvedDependents(pmRoot,settings,trackerItems,located.id,author,statusRegistry)],completion}}function runClose(id,closeReasonText,options,global2){return closeItem(id,closeReasonText,options,global2)}export{_testOnlyCloseCommand,closeItem,runClose};
|
|
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]="1ae551f9-53e5-5f63-a6a2-231a40c61c62")}catch{}})();import{assertInitializedTracker}from"../environment/tracker-preflight.js";import{enrichItemRevisionConflict,isItemRevisionConflict,itemRevisionConflictRowFields}from"./item-revision.js";import{toErrorMessage}from"../runtime-primitives.js";import{toItemRecord,isTerminalStatus,resolveItemTypeRegistry,resolveRuntimeStatusRegistry,EXIT_CODE,PmCliError,buildItemNotFoundError,listAllItemMetadataLight,locateItem,readLocatedItem,mutateItem,resolvePmRoot,readSettings,resolveAuthor,resolveIsoOrRelative,shouldCompletePlanOnClose,getActiveExtensionRegistrations}from"../runtime-primitives.js";import{collectBlockedByIds,indexBlockedByIds}from"../actionability.js";import{applyTerminalOrderingPolicy,requireTerminalReason}from"../lifecycle-policy.js";import{nowIso}from"../../core/shared/time.js";import{isPmCliErrorDetails}from"../../core/shared/error-details.js";import{unicodeSafePrefix}from"../../core/shared/text-normalization.js";import{renderPmCommand,resolvePmCommandScopeArgs}from"../command-line.js";import{mutateItemWithHistoryContextResolver}from"../../core/store/item-store.js";const CLOSE_VALIDATION_FIELDS=[{key:"resolution",label:"resolution (--resolution)"},{key:"expected_result",label:"expected_result (--expected-result)"},{key:"actual_result",label:"actual_result (--actual-result)"}];function parseValidateCloseMode(raw){if(raw===void 0)return;const normalized=raw.trim().toLowerCase();if(normalized.length===0||normalized==="warn")return"warn";if(normalized==="off"||normalized==="none"||normalized==="disabled")return"off";if(normalized==="strict")return"strict";throw new PmCliError(`Invalid --validate-close mode "${raw}" (expected "off", "warn", or "strict")`,EXIT_CODE.USAGE)}function findMissingCloseValidationFields(itemMetadata){const missing=[];for(const field of CLOSE_VALIDATION_FIELDS){const rawValue=itemMetadata[field.key];(typeof rawValue!="string"||rawValue.trim().length===0)&&missing.push(field)}return missing}function closeEvidenceRecovery(metadata,commandScope,options={}){const missing=findMissingCloseValidationFields(metadata);if(missing.length===0)return;const values={resolution:options.resolution,expected_result:options.expectedResult,actual_result:options.actualResult},missingFlags=missing.map(field=>`--${field.key.replaceAll("_","-")}`),args=[...commandScope,"update",metadata.id,...missing.flatMap((field,index)=>[missingFlags[index],values[field.key]?.trim()||"<value>"])];return{missing:missingFlags,suggested_retry:renderPmCommand(args),suggested_retry_args:args}}async function duplicateChainReferencesClosingItem(loadItemById,initialDuplicateOf,closingId){const visited=new Set;let current=initialDuplicateOf;for(;typeof current=="string"&¤t.trim().length>0;){const currentId=current.trim();if(currentId===closingId)return!0;if(visited.has(currentId))return!1;visited.add(currentId),current=(await loadItemById(currentId))?.duplicate_of}return!1}function shouldApplyDuplicateFallback(value){return typeof value!="string"||value.trim().length===0}async function assertDuplicateTargetExists(pmRoot,settings,duplicateOf,closingId){const rawTarget=duplicateOf?.trim();if(!rawTarget)return;if(rawTarget===closingId)throw new PmCliError("An item cannot be closed as a duplicate of itself.",EXIT_CODE.USAGE,{code:"duplicate_target_self",why:"--duplicate-of must identify the canonical item that should remain open or already represent the work."});const typeRegistry=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations()),itemCache=new Map,loadItemById=async id=>{if(itemCache.has(id))return itemCache.get(id)??null;const located=await locateItem(pmRoot,id,settings.id_prefix,settings.item_format,typeRegistry.type_to_folder);if(!located)return itemCache.set(id,null),null;const{document}=await readLocatedItem(located,{schema:settings.schema});return itemCache.set(id,document.metadata),document.metadata},target=await loadItemById(rawTarget);if(!target)throw new PmCliError(`Duplicate target "${rawTarget}" was not found. Create or locate the canonical item first.`,EXIT_CODE.USAGE,{code:"duplicate_target_missing",why:"Duplicate closure should point at a real canonical pm item so future dedupe and changelog tooling can trace the relationship.",examples:[`pm close ${closingId} "Duplicate of ${rawTarget}" --duplicate-of ${rawTarget}`],nextSteps:["Run pm search/list to find the canonical item, then retry with --duplicate-of <id>."]});if(await duplicateChainReferencesClosingItem(loadItemById,target.duplicate_of,closingId))throw new PmCliError(`Circular duplicate reference detected. Target "${rawTarget}" points back to "${closingId}".`,EXIT_CODE.USAGE,{code:"duplicate_target_circular",why:"Circular duplicate relationships create loops for dedupe and status propagation tooling.",nextSteps:["Choose the existing canonical item, or clear the target duplicate_of metadata before closing this item as a duplicate."]});if(typeof target.duplicate_of=="string"&&target.duplicate_of.trim().length>0)throw new PmCliError(`Duplicate target "${rawTarget}" is already marked as a duplicate of "${target.duplicate_of.trim()}".`,EXIT_CODE.USAGE,{code:"duplicate_target_is_duplicate",why:"Duplicate closure should point directly at the canonical item, not another duplicate.",examples:[`pm close ${closingId} "Duplicate of ${target.duplicate_of.trim()}" --duplicate-of ${target.duplicate_of.trim()}`],nextSteps:["Use the canonical item referenced by duplicate_of as the --duplicate-of target."]});return target.id}function findActiveChildIds(items,parentId,statusRegistry){return items.filter(item=>item.parent===parentId&&!isTerminalStatus(item.status,statusRegistry)).map(item=>item.id).sort((left,right)=>left.localeCompare(right))}function findAutoUnblockCandidates(items,closedId,statusRegistry){const itemsById=new Map(items.map(item=>[item.id.trim().toLowerCase(),item])),blockerIdsByItem=indexBlockedByIds(items),normalizedClosedId=closedId.trim().toLowerCase(),blockedStatuses=statusRegistry.blocked_statuses;return items.filter(item=>blockedStatuses.has(item.status)).map(item=>({item,blockerIds:blockerIdsByItem.get(item.id.trim().toLowerCase())})).filter(({blockerIds})=>blockerIds.includes(normalizedClosedId)).filter(({blockerIds})=>blockerIds.every(blockerId=>{if(blockerId===normalizedClosedId)return!0;const blocker=itemsById.get(blockerId);return blocker!==void 0&&isTerminalStatus(blocker.status,statusRegistry)})).map(({item,blockerIds})=>({id:item.id,blocker_ids:blockerIds})).sort((left,right)=>left.id.localeCompare(right.id))}async function autoUnblockResolvedDependents(pmRoot,settings,items,closedId,author,statusRegistry,commandScope){const candidates=findAutoUnblockCandidates(items,closedId,statusRegistry),warnings=[],unblockedIds=[],conflictIds=[],failed=[];let conflict;for(const candidate of candidates)try{const unblocked=await mutateItem({pmRoot,settings,id:candidate.id,op:"update",author,message:`Auto-unblocked after blocker ${closedId} closed`,mutate(document){const dependencies=document.metadata.dependencies??[],remainingDependencies=dependencies.filter(dependency=>{const dependencyId=dependency.id.trim().toLowerCase();return dependency.kind!=="blocked_by"||!candidate.blocker_ids.includes(dependencyId)});document.metadata.status=statusRegistry.open_status,delete document.metadata.blocked_by,delete document.metadata.blocked_reason,document.metadata.unblock_note=`Auto-unblocked after blocker ${closedId} closed; all blockers resolved (${candidate.blocker_ids.join(", ")}).`,remainingDependencies.length>0?document.metadata.dependencies=remainingDependencies:delete document.metadata.dependencies;const changedFields=["status","blocked_by","blocked_reason","unblock_note"];return remainingDependencies.length!==dependencies.length&&changedFields.push("dependencies"),{changedFields}}});warnings.push(`auto_unblocked:${unblocked.item.id}:resolved_blockers=${candidate.blocker_ids.join(",")}`),unblockedIds.push(unblocked.item.id)}catch(error){const reason=error instanceof Error?error.message.replace(/\s+/g," ").trim():"unknown";isItemRevisionConflict(error)?(conflict??=error,conflictIds.push(candidate.id)):failed.push({id:candidate.id,reason}),warnings.push(`auto_unblock_failed:${candidate.id}:${reason}`)}if(conflict!==void 0){const enriched=await enrichItemRevisionConflict(conflict,pmRoot),blockedStatuses=[...statusRegistry.blocked_statuses].sort().join(",");throw postCloseDependentConflict(enriched,{closedId,unblockedIds,conflictIds,failed,openStatus:statusRegistry.open_status,blockedStatuses,commandScope})}return warnings}const POST_CLOSE_REPORT_LIMIT=10,POST_CLOSE_STEP_LIMIT=20,POST_CLOSE_DETAIL_TRIMS=[{list:"auto_unblock_failed",omitted:"auto_unblock_failed_omitted",floor:0},{list:"changes_since",omitted:"changes_since_omitted",floor:0},{list:"pending_unblock",omitted:"pending_unblock_omitted",floor:1}];function fitPostCloseDetails(details){for(const trim of POST_CLOSE_DETAIL_TRIMS){const list=details[trim.list];if(Array.isArray(list))for(;list.length>trim.floor&&!isPmCliErrorDetails(details);)list.pop(),Reflect.set(details,trim.omitted,Number(details[trim.omitted])+1)}return details}function boundedIdList(ids){const omitted=ids.length-POST_CLOSE_REPORT_LIMIT;return`${ids.slice(0,POST_CLOSE_REPORT_LIMIT).join(", ")}${omitted>0?`, and ${omitted} more`:""}`}function postCloseDependentConflict(conflict,fanOut){const{closedId,conflictIds,failed,commandScope}=fanOut,dependent=String(conflict.context.item_id),unblock=id=>renderPmCommand([...commandScope,"update",id,"--status",fanOut.openStatus,"--unset","blocked_by","--unset","blocked_reason","--expect-hash",`${id}=<item_hash>`]),reported=failed.slice(0,POST_CLOSE_REPORT_LIMIT).map(entry=>({id:entry.id,reason:unicodeSafePrefix(entry.reason,160)})),otherFailures=failed.length===0?"":` Auto-unblocking also failed for ${boundedIdList(failed.map(entry=>entry.id))}; details.auto_unblock_failed gives the reasons it kept (auto_unblock_failed_omitted counts the rest; their get step shows the item). Fix that cause before unblocking it.`,discovery=renderPmCommand([...commandScope,"list","--status",fanOut.blockedStatuses,"--fields","id,title,blocked_by,dependencies","--limit","200"]),allSteps=[...conflictIds.slice(0,POST_CLOSE_REPORT_LIMIT).flatMap(id=>[renderPmCommand([...commandScope,"get",id,"--json"]),unblock(id)]),...reported.map(entry=>renderPmCommand([...commandScope,"get",entry.id,"--json"]))],truncated=conflictIds.length>POST_CLOSE_REPORT_LIMIT||failed.length>POST_CLOSE_REPORT_LIMIT||allSteps.length>POST_CLOSE_STEP_LIMIT,steps=allSteps.slice(0,truncated?POST_CLOSE_STEP_LIMIT-1:POST_CLOSE_STEP_LIMIT);return new PmCliError(`${closedId} was closed, but auto-unblocking ${dependent} was refused. ${conflict.message}`,conflict.exitCode,{...conflict.context,required:`The close of ${closedId} is complete; do not retry it. Only unblocking ${conflictIds.length===1?dependent:`the guarded dependents it refused (${boundedIdList(conflictIds)})`} remains: re-read each one (pm get <id> --json reports item_hash), check that every blocker it declares is resolved, then unblock it with ${unblock(dependent)}${conflictIds.length===1?"":" for each id"}.${otherFailures}${truncated?` This refusal does not list a step for every dependent left blocked; list them with ${discovery}, and while it reports has_more, continue with --after <next_cursor>.`:""}`,nextSteps:truncated?[...steps,discovery]:steps,details:fitPostCloseDetails({...structuredClone(conflict.context.details),pending_unblock:conflictIds.slice(0,POST_CLOSE_REPORT_LIMIT),pending_unblock_omitted:Math.max(0,conflictIds.length-POST_CLOSE_REPORT_LIMIT),auto_unblock_failed:reported,auto_unblock_failed_omitted:Math.max(0,failed.length-POST_CLOSE_REPORT_LIMIT)}),side_effects:[{path:`history/${closedId}.jsonl`,op:"close"},...fanOut.unblockedIds.map(id=>({path:`history/${id}.jsonl`,op:"update"}))]})}async function committedCloseDependentConflict(error,id,pmRoot){if(!isItemRevisionConflict(error)||!error.context.side_effects?.some(effect=>`${effect.op}:${effect.path}`==`close:history/${id}.jsonl`))return;const dependent=String(error.context.item_id);return{warnings:[...error.context.side_effects.filter(effect=>effect.op==="update").map(effect=>effect.path.slice(8,-6)).map(unblockedId=>`auto_unblocked:${unblockedId}`),`auto_unblock_refused:${dependent}:item_revision_conflict`],dependent_revision_conflict:{item_id:dependent,error:toErrorMessage(error),...await itemRevisionConflictRowFields(error,pmRoot)}}}function applyInlineCloseFields(metadata,options){const changedFields=[],inlineCloseFields=[{option:options.resolution,key:"resolution"},{option:options.expectedResult,key:"expected_result"},{option:options.actualResult,key:"actual_result"}];for(const{option,key}of inlineCloseFields){if(typeof option!="string")continue;const trimmed=option.trim();trimmed.length!==0&&(metadata[key]=trimmed,changedFields.push(key))}return changedFields}function applyDuplicateCloseMetadata(metadata,duplicateOf){if(duplicateOf===void 0)return[];metadata.duplicate_of=duplicateOf;const duplicateFallbackFields=[],fallbackValues=[{key:"resolution",value:`Duplicate of ${duplicateOf}`},{key:"expected_result",value:`Canonical item ${duplicateOf} tracks the work.`},{key:"actual_result",value:`Closed as duplicate of ${duplicateOf}.`}];for(const{key,value}of fallbackValues)shouldApplyDuplicateFallback(metadata[key])&&(metadata[key]=value,duplicateFallbackFields.push(key));return duplicateFallbackFields}function collectCloseValidationWarnings(metadata,validateCloseMode,activeChildIds,commandScope){const warnings=[];if(validateCloseMode!=="off"){const missingFields=findMissingCloseValidationFields(metadata);if(missingFields.length>0){const missingLabels=missingFields.map(field=>field.label);if(validateCloseMode==="strict"){const missingFlags=missingFields.map(field=>`--${field.key.replaceAll("_","-")}`),updateTokens=[...commandScope,"update",metadata.id,...missingFlags.flatMap(flag=>[flag,"<value>"])];throw new PmCliError(`Cannot close item ${metadata.id}: missing ${missingLabels.join(", ")}. Populate fields or use --validate-close warn.`,EXIT_CODE.USAGE,{code:"close_validation_missing_fields",recovery:{missing:missingFlags,suggested_retry:renderPmCommand(updateTokens),suggested_retry_args:updateTokens},nextSteps:["Run the suggested pm update, then retry the original pm close invocation.","Use --validate-close warn only when governance permits an evidenced exception."]})}warnings.push(`close_validation_missing_fields:${metadata.id}:${missingLabels.join(",")}`)}if(activeChildIds.length>0){if(validateCloseMode==="strict")throw new PmCliError(`Cannot close item ${metadata.id}: active child items remain open (${activeChildIds.join(", ")}). Close, cancel, or re-parent them first, or use --validate-close warn.`,EXIT_CODE.USAGE);warnings.push(`close_validation_active_children:${metadata.id}:${activeChildIds.join(",")}`)}return warnings}return activeChildIds.length>0&&warnings.push(`closed_with_active_children:${metadata.id}:${activeChildIds.join(",")}`),warnings}function applyCloseReason(metadata,closeReason){return closeReason!==void 0?(metadata.close_reason=closeReason,["close_reason"]):[]}function clearCloseAssignee(metadata){const cleared=["assignee","claim_principal"].filter(key=>metadata[key]!==void 0);for(const key of cleared)delete metadata[key];return[...cleared]}function mutateCloseMetadata(metadata,context){if(isTerminalStatus(metadata.status,context.statusRegistry)&&!context.force)throw new PmCliError(`Item ${metadata.id} is already terminal; use pm update to append acceptance evidence, or --force only for an intentional repeat closure.`,EXIT_CODE.CONFLICT,{recovery:closeEvidenceRecovery(metadata,context.commandScope,context.options)});const inlineChangedFields=applyInlineCloseFields(metadata,context.options),duplicateFallbackFields=applyDuplicateCloseMetadata(metadata,context.duplicateOf),mutationWarnings=collectCloseValidationWarnings(metadata,context.validateCloseMode,context.activeChildIds,context.commandScope);metadata.status=context.statusRegistry.close_status,metadata.closed_at=context.closedAt;const shouldWriteCompletedAt=context.options.completedAt!==void 0||metadata.completed_at===void 0;shouldWriteCompletedAt&&(metadata.completed_at=context.completedAt);const changedFields=["status","closed_at",...shouldWriteCompletedAt?["completed_at"]:[],...applyCloseReason(metadata,context.closeReason),...inlineChangedFields];if(shouldCompletePlanOnClose(metadata)&&(metadata.plan_mode="completed",changedFields.push("plan_mode")),context.duplicateOf!==void 0){changedFields.push("duplicate_of");for(const key of duplicateFallbackFields)changedFields.includes(key)||changedFields.push(key)}changedFields.push(...clearCloseAssignee(metadata));const blockerCleanup=applyTerminalOrderingPolicy(metadata,context.lifecyclePolicy);return changedFields.push(...blockerCleanup.changedFields),mutationWarnings.push(...blockerCleanup.warnings),{changedFields,...mutationWarnings.length>0?{warnings:mutationWarnings}:{}}}const _testOnlyCloseCommand={blockedByIds:collectBlockedByIds,fitPostCloseDetails};async function closeItem(id,closeReasonText,options,global2){const pmRoot=resolvePmRoot(process.cwd(),global2.path),commandScope=resolvePmCommandScopeArgs(global2);await assertInitializedTracker(pmRoot);const settings=await readSettings(pmRoot),statusRegistry=resolveRuntimeStatusRegistry(settings.schema),author=resolveAuthor(options.author,settings.author_default),typeToFolder=resolveItemTypeRegistry(settings,getActiveExtensionRegistrations()).type_to_folder,located=await locateItem(pmRoot,id,settings.id_prefix,settings.item_format,typeToFolder);if(!located)throw await buildItemNotFoundError(pmRoot,id,settings.id_prefix,typeToFolder);const duplicateOf=await assertDuplicateTargetExists(pmRoot,settings,options.duplicateOf,located.id),lifecyclePolicy={requireCloseReason:options.lifecyclePolicy?.requireCloseReason??settings.governance.require_close_reason,orderingEdges:options.lifecyclePolicy?.orderingEdges??"preserve"},closeReason=requireTerminalReason({explicit:closeReasonText,duplicateOf,resolution:options.resolution,message:options.message},lifecyclePolicy.requireCloseReason).closeReason,validateCloseMode=parseValidateCloseMode(options.validateClose)??settings.governance.close_validation_default,trackerItems=await listAllItemMetadataLight(pmRoot,settings.item_format,typeToFolder,void 0,settings.schema),activeChildIds=findActiveChildIds(trackerItems,located.id,statusRegistry),closedAt=nowIso(),completedAt=options.completedAt===void 0?closedAt:resolveIsoOrRelative(options.completedAt,new Date(closedAt),"completed-at");let completion={timestamp:completedAt,source:options.completedAt===void 0?"close_time":"asserted",...options.completedAt===void 0?{hint:`completed_at defaults to the close time. If work finished earlier, correct it with ${renderPmCommand([...commandScope,"update",located.id,"--completed-at","<ISO>"])}.`}:{}};const result=await mutateItemWithHistoryContextResolver({pmRoot,settings,id:located.id,op:"close",author,message:options.message,force:options.force,resolveHistoryContext:()=>({completion:{timestamp:completion.timestamp,source:completion.source}}),mutate(document){return options.completedAt===void 0&&document.metadata.completed_at!==void 0&&(completion={timestamp:document.metadata.completed_at,source:"existing"}),mutateCloseMetadata(document.metadata,{pmRoot,commandScope,statusRegistry,force:options.force,options,duplicateOf,validateCloseMode,activeChildIds,closeReason,closedAt,completedAt,lifecyclePolicy})}}),evidence=validateCloseMode==="warn"?closeEvidenceRecovery(result.item,commandScope):void 0;return{item:toItemRecord(result.item),changed_fields:result.changedFields,...evidence?{follow_up:{kind:"complete_close_evidence",missing:evidence.missing,suggested_command:evidence.suggested_retry,suggested_command_args:evidence.suggested_retry_args}}:{},warnings:[...result.warnings,...await autoUnblockResolvedDependents(pmRoot,settings,trackerItems,located.id,author,statusRegistry,commandScope)],completion}}function runClose(id,closeReasonText,options,global2){return closeItem(id,closeReasonText,options,global2)}export{_testOnlyCloseCommand,closeItem,committedCloseDependentConflict,runClose};
|
|
2
2
|
//# sourceMappingURL=close.js.map
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { type MutationInputAudience } from "../../core/item/literal-mutation-input.js";
|
|
1
2
|
import { type ResolvedItemTypeDefinition,type RuntimeFieldRegistry,type GlobalOptions } from "../runtime-primitives.js";
|
|
2
3
|
import { type SimilarityAdvisory } from "../similarity.js";
|
|
3
4
|
import { type LifecycleTransitionSuggestion } from "./lifecycle-transitions.js";
|
|
5
|
+
import { type CreateNullClearableOptionKey,type WithNullClears } from "./shared-unset-fields.js";
|
|
4
6
|
import type { MutationMetadataCommandOptions,SharedLinkedResourceClearOptions,SharedLinkedResourceOptions } from "./mutation-command-options.js";
|
|
5
7
|
import type { Comment,Dependency,ItemMetadata,LinkedDoc,LinkedFile,LinkedTest,LogNote } from "../../types/index.js";
|
|
6
8
|
/** Documents the create command options payload exchanged by command, SDK, and package integrations. */
|
|
@@ -43,8 +45,8 @@ allowDuplicate?:boolean;
|
|
|
43
45
|
inheritFocus?:boolean;
|
|
44
46
|
[key:string]:unknown;
|
|
45
47
|
}
|
|
46
|
-
/** Presentation-neutral input accepted by the SDK-owned create operation
|
|
47
|
-
export type CreateOperationOptions = CreateCommandOptions
|
|
48
|
+
/** Presentation-neutral input accepted by the SDK-owned create operation; clearable fields also accept `null`. */
|
|
49
|
+
export type CreateOperationOptions = WithNullClears<CreateCommandOptions,CreateNullClearableOptionKey>;
|
|
48
50
|
/** Documents the create result payload exchanged by command, SDK, and package integrations. */
|
|
49
51
|
export interface CreateResult {
|
|
50
52
|
/** Value that configures or reports item for this contract. */
|
|
@@ -107,14 +109,14 @@ declare function createExampleTokensForFlag(flag:string,typeName:string,openStat
|
|
|
107
109
|
/** Build a runnable option shape for one configured type, expressing empty required collections with explicit clear flags. */
|
|
108
110
|
declare function buildTypeSpecificCreateExample(typeDefinition:ResolvedItemTypeDefinition,missingCreateFlags:string[],missingTypeOptionKeys:string[],openStatus:string):string;
|
|
109
111
|
/** Require a trimmed option value while preserving title-specific recovery guidance. */
|
|
110
|
-
export declare function requireStringOption(value:string | undefined,flag:string):string;
|
|
111
|
-
declare function mergeCreateOptionsWithTemplate(templateOptions:Record<string,unknown>,explicitOptions:CreateCommandOptions):CreateCommandOptions;
|
|
112
|
+
export declare function requireStringOption(value:string | undefined,flag:string,audience?:MutationInputAudience):string;
|
|
113
|
+
declare function mergeCreateOptionsWithTemplate(templateOptions:Record<string,unknown>,explicitOptions:CreateCommandOptions,runtimeFieldRegistry?:RuntimeFieldRegistry):CreateCommandOptions;
|
|
112
114
|
declare function normalizeExtensionCommandPath(command:string):string;
|
|
113
115
|
declare function hasTemplatesShowHandler():boolean;
|
|
114
116
|
declare function readTemplateOptionsFromRuntimeResult(result:unknown,templateName:string):Record<string,string | string[] | number | boolean>;
|
|
115
117
|
declare function loadCreateTemplateOptionsFromRuntime(templateName:string,global:GlobalOptions,pmRoot:string):Promise<Record<string,string | string[] | number | boolean>>;
|
|
116
118
|
/** Implements run create for the public runtime surface of this module. */
|
|
117
|
-
export declare function runCreate(
|
|
119
|
+
export declare function runCreate(input:CreateOperationOptions,global:GlobalOptions):Promise<CreateResult>;
|
|
118
120
|
/** Public contract for test only create command, shared by SDK and presentation-layer consumers. */
|
|
119
121
|
export declare const _testOnlyCreateCommand:{
|
|
120
122
|
buildHistoryMessage:typeof buildHistoryMessage;
|