@unbrained/pm-cli 2026.8.8 → 2026.8.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/CHANGELOG.md +59 -0
- package/dist/cli/commander-usage.js +17 -12
- package/dist/cli/help-json-payload.js +51 -16
- package/dist/cli/main.js +7 -6
- package/dist/cli-bundle/bundle-manifest.json +162 -162
- package/dist/cli-bundle/chunks/chunk-2QYH4QMI.js +30 -0
- package/dist/cli-bundle/chunks/{chunk-2ZMXX3Q6.js → chunk-EBO7OUUE.js} +70 -70
- package/dist/cli-bundle/chunks/{chunk-NUXRRNAB.js → chunk-ETML5C6H.js} +48 -48
- package/dist/cli-bundle/chunks/chunk-JUDU4RO4.js +194 -0
- package/dist/cli-bundle/chunks/chunk-JZSNADRR.js +5 -0
- package/dist/cli-bundle/chunks/chunk-MENWVGJW.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-ALDHXLPS.js → chunk-S4EITGLA.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-TIGKWVLA.js +13 -0
- package/dist/cli-bundle/chunks/{chunk-CBLA33YK.js → chunk-TRWXF476.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-TSLDTJLQ.js +2 -0
- package/dist/cli-bundle/chunks/{register-list-query-WFZAMJHZ.js → register-list-query-OJ6ZXKV4.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-SOKKOTHQ.js → register-mutation-DKI7QC7O.js} +2 -2
- package/dist/cli-bundle/chunks/register-operations-P5OGMT6I.js +2 -0
- package/dist/cli-bundle/chunks/{register-setup-2HL5ZHMK.js → register-setup-S3KT2LTH.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-ANTMGYLI.js → chunk-2COZ67XT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-2EXI2DKR.js +4 -0
- package/dist/cli-bundle/focused-chunks/{chunk-YSAHYUXX.js → chunk-34SX654S.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-36FTZ2NT.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-3CQECMKR.js +16 -0
- package/dist/cli-bundle/focused-chunks/chunk-75774JWP.js +6 -0
- package/dist/cli-bundle/focused-chunks/chunk-7UN6BHHO.js +2 -0
- package/dist/cli-bundle/focused-chunks/{chunk-TCSAPH33.js → chunk-CHIBMEZR.js} +6 -6
- package/dist/cli-bundle/focused-chunks/chunk-DZGAHZZV.js +3 -0
- package/dist/cli-bundle/focused-chunks/chunk-FF4MNAYB.js +153 -0
- package/dist/cli-bundle/focused-chunks/chunk-GHTN2ILR.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-I4YM2I7S.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-IMDTEN7K.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-IW43E4XL.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-JMVA4HKR.js +5 -0
- package/dist/cli-bundle/focused-chunks/{chunk-PL2EYDJK.js → chunk-KR5RVXLQ.js} +31 -29
- package/dist/cli-bundle/focused-chunks/chunk-KSNJG4KI.js +16 -0
- package/dist/cli-bundle/focused-chunks/chunk-M6RPIXKC.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-MXYSIQ56.js +18 -0
- package/dist/cli-bundle/focused-chunks/chunk-RIIN5V4N.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-RKWSCYYN.js +2 -0
- package/dist/cli-bundle/main.js +13 -13
- package/dist/cli-bundle/sdk-authoring.js +1 -1
- package/dist/cli-bundle/sdk-contracts.js +1 -1
- package/dist/cli-bundle/sdk-core.js +38 -38
- 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 +1 -1
- 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 +2 -2
- package/dist/core/diagnostics/remediation.js +19 -9
- package/dist/core/fs/fs-utils.d.ts +10 -0
- package/dist/core/fs/fs-utils.js +16 -4
- package/dist/core/history/history.js +13 -4
- package/dist/core/item/actionability.d.ts +7 -1
- package/dist/core/item/actionability.js +71 -15
- package/dist/core/item/item-format.js +3 -32
- package/dist/core/schema/fields-file.d.ts +1 -2
- package/dist/core/schema/fields-file.js +4 -11
- package/dist/core/schema/runtime-schema.js +3 -10
- package/dist/core/schema/status-defs-file.d.ts +1 -2
- package/dist/core/schema/status-defs-file.js +4 -32
- package/dist/core/schema/status-token.d.ts +2 -0
- package/dist/core/schema/status-token.js +32 -0
- package/dist/core/schema/type-workflows.d.ts +1 -2
- package/dist/core/schema/type-workflows.js +4 -11
- package/dist/core/shared/author.d.ts +25 -0
- package/dist/core/shared/author.js +128 -10
- package/dist/core/shared/errors.d.ts +4 -0
- package/dist/core/shared/errors.js +2 -2
- package/dist/core/shared/text-normalization.d.ts +1 -1
- package/dist/core/shared/text-normalization.js +2 -2
- package/dist/sdk/actionability.d.ts +1 -1
- package/dist/sdk/actionability.js +3 -3
- package/dist/sdk/agent/command-recovery.d.ts +4 -0
- package/dist/sdk/agent/command-recovery.js +52 -0
- package/dist/sdk/agent/command-suggestions.d.ts +4 -0
- package/dist/sdk/agent/command-suggestions.js +67 -0
- package/dist/sdk/agent/create-option-policy.d.ts +12 -0
- package/dist/sdk/agent/create-option-policy.js +32 -0
- package/dist/sdk/agent/item-addressing.d.ts +19 -0
- package/dist/sdk/agent/item-addressing.js +208 -0
- package/dist/sdk/cli-bootstrap.d.ts +1 -1
- package/dist/sdk/cli-bootstrap.js +20 -5
- package/dist/sdk/cli-contracts/commander-mutation-options.js +16 -4
- package/dist/sdk/cli-contracts/flag-contracts.js +62 -21
- package/dist/sdk/cli-contracts/registration-helpers.js +10 -2
- package/dist/sdk/cli-contracts/runtime-contracts.d.ts +8 -0
- package/dist/sdk/cli-contracts/runtime-contracts.js +20 -3
- package/dist/sdk/cli-contracts/tool-option-contracts.d.ts +6 -0
- package/dist/sdk/cli-contracts/tool-option-contracts.js +4 -2
- package/dist/sdk/cli-contracts/tool-parameter-tables.js +19 -4
- package/dist/sdk/cli-contracts/tool-schema.js +17 -4
- package/dist/sdk/context-intent-runtime.js +8 -5
- package/dist/sdk/context-signal-store.d.ts +34 -0
- package/dist/sdk/context-signal-store.js +24 -2
- package/dist/sdk/core-governance.d.ts +1 -1
- package/dist/sdk/core-governance.js +3 -3
- package/dist/sdk/dependencies.d.ts +2 -0
- package/dist/sdk/dependencies.js +7 -6
- package/dist/sdk/dependency-flag-validation.d.ts +15 -1
- package/dist/sdk/dependency-flag-validation.js +54 -2
- package/dist/sdk/extension/bundled-catalog.js +19 -6
- package/dist/sdk/generated-error-code-catalog.js +110 -2
- package/dist/sdk/governance/health.js +38 -12
- package/dist/sdk/governance/provenance-health.d.ts +39 -0
- package/dist/sdk/governance/provenance-health.js +185 -0
- package/dist/sdk/governance/validate-item-reader.d.ts +13 -0
- package/dist/sdk/governance/validate-item-reader.js +18 -0
- package/dist/sdk/governance/validate.d.ts +2 -2
- package/dist/sdk/governance/validate.js +25 -11
- package/dist/sdk/governance.d.ts +1 -0
- package/dist/sdk/governance.js +3 -2
- package/dist/sdk/graph/assembly.d.ts +4 -0
- package/dist/sdk/graph/assembly.js +22 -2
- package/dist/sdk/graph/run.d.ts +2 -0
- package/dist/sdk/graph/run.js +3 -2
- package/dist/sdk/index.d.ts +4 -0
- package/dist/sdk/index.js +6 -2
- package/dist/sdk/lifecycle/close.js +27 -19
- package/dist/sdk/lifecycle/create.d.ts +2 -0
- package/dist/sdk/lifecycle/create.js +66 -19
- package/dist/sdk/lifecycle/plan.js +6 -3
- package/dist/sdk/lifecycle/update-many.js +39 -27
- package/dist/sdk/lifecycle/update.d.ts +6 -1
- package/dist/sdk/lifecycle/update.js +51 -28
- package/dist/sdk/merge/driver.d.ts +2 -1
- package/dist/sdk/merge/driver.js +7 -4
- package/dist/sdk/merge/index.d.ts +1 -1
- package/dist/sdk/merge/index.js +3 -3
- package/dist/sdk/merge/install.d.ts +4 -0
- package/dist/sdk/merge/install.js +29 -17
- package/dist/sdk/merge/receipts.d.ts +17 -1
- package/dist/sdk/merge/receipts.js +112 -20
- package/dist/sdk/merge/reconcile.js +21 -4
- package/dist/sdk/merge/three-way.d.ts +6 -2
- package/dist/sdk/merge/three-way.js +24 -10
- package/dist/sdk/output-projection.js +24 -4
- package/dist/sdk/query/context.d.ts +2 -0
- package/dist/sdk/query/context.js +7 -4
- package/dist/sdk/query/get.d.ts +11 -0
- package/dist/sdk/query/get.js +37 -3
- package/dist/sdk/query/light-metadata.d.ts +3 -0
- package/dist/sdk/query/light-metadata.js +19 -0
- package/dist/sdk/read-output-contracts.d.ts +1 -1
- package/dist/sdk/read-output-contracts.js +23 -4
- package/dist/sdk/relationship-kinds/contract.d.ts +48 -0
- package/dist/sdk/relationship-kinds/contract.js +22 -0
- package/dist/sdk/relationships.d.ts +6 -41
- package/dist/sdk/relationships.js +12 -126
- package/dist/sdk/runtime-primitives.d.ts +1 -1
- package/dist/sdk/runtime-primitives.js +3 -3
- package/dist/sdk/runtime.d.ts +4 -1
- package/dist/sdk/runtime.js +8 -3
- package/dist/sdk/schema-migration.js +7 -9
- package/dist/sdk/similarity-scoring.d.ts +1 -2
- package/dist/sdk/similarity-scoring.js +4 -16
- package/dist/sdk/similarity.d.ts +5 -0
- package/dist/sdk/similarity.js +40 -10
- package/dist/sdk/structured-mutations.js +5 -2
- package/dist/sdk/test/linked-command-detection.d.ts +2 -7
- package/dist/sdk/test/linked-command-detection.js +22 -9
- package/dist/sdk/workspace-snapshot.d.ts +4 -0
- package/dist/sdk/workspace-snapshot.js +24 -11
- package/docs/AGENT_GUIDE.md +5 -2
- package/docs/COMMANDS.md +27 -6
- package/docs/DEPENDENCY_KIND_CONTRACT.md +29 -0
- package/docs/ITEM_READ_PROJECTIONS.md +26 -0
- package/docs/MERGE_SAFETY.md +17 -8
- package/docs/README.md +2 -5
- package/docs/READ_OUTPUT_CONTRACTS.md +2 -2
- package/docs/RELATIONSHIP_GRAPH.md +1 -1
- package/docs/SDK.md +33 -8
- package/docs/SDK_AGENT_SESSION_CONTEXT.md +36 -2
- package/docs/SDK_CONTEXT.md +97 -0
- package/docs/SDK_CONTEXT_INTEGRITY.md +33 -3
- package/docs/SENTRY_CONTRACT_EPOCHS.md +20 -0
- package/docs/agent-task-token-baseline.json +2 -2
- package/marketplace.json +2 -2
- package/package.json +5 -4
- package/packages/pm-beads/package.json +1 -1
- package/packages/pm-calendar/package.json +1 -1
- package/packages/pm-command-kit/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/sdk/public-surface.json +415 -43
- package/dist/cli-bundle/chunks/chunk-GKA54IJM.js +0 -5
- package/dist/cli-bundle/chunks/chunk-KRY7SRUO.js +0 -2
- package/dist/cli-bundle/chunks/chunk-MNJ4NNSY.js +0 -26
- package/dist/cli-bundle/chunks/chunk-OJPCFDDY.js +0 -13
- package/dist/cli-bundle/chunks/chunk-PFSD3DAN.js +0 -194
- package/dist/cli-bundle/chunks/chunk-SQ7QZFQ6.js +0 -2
- package/dist/cli-bundle/chunks/register-operations-5XQETS6E.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-54EU2UVO.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-5FLBTZJQ.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-5GJ57YKN.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-CMDS3KYT.js +0 -14
- package/dist/cli-bundle/focused-chunks/chunk-DMKOMTTY.js +0 -6
- package/dist/cli-bundle/focused-chunks/chunk-F5B3HBEZ.js +0 -5
- package/dist/cli-bundle/focused-chunks/chunk-FI6DWU2M.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-FNOKJG6N.js +0 -16
- package/dist/cli-bundle/focused-chunks/chunk-FPDYXZBK.js +0 -4
- package/dist/cli-bundle/focused-chunks/chunk-GWI6YIKJ.js +0 -3
- package/dist/cli-bundle/focused-chunks/chunk-HCUC62AB.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-HGNKPSCB.js +0 -153
- package/dist/cli-bundle/focused-chunks/chunk-IAS7PMLG.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-SM2PJGP3.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-U646T7Z6.js +0 -18
- package/dist/cli-bundle/focused-chunks/chunk-YKPE4PPY.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-ZOLDTUU7.js +0 -2
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
* Implements the pm update many command surface and its agent-facing runtime behavior.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="0f91de58-2cbc-52ba-97ea-42482d0c6ce1")}catch(e){}}();
|
|
8
8
|
import { pathExists, createCheckpointId, loadMutationCheckpoint, restoreCheckpointItems, writeMutationCheckpoint, toItemRecord, applyAcceptanceCriteriaMutations, applyTagRemovals, mergeAdditiveTags, parseOptionalNonNegativeInteger, parseTags, splitAcceptanceCriteria, resolvePriority, normalizeStatusInput, resolveItemTypeRegistry, resolveTypeName, collectRuntimeUpdateFieldValues, buildInvalidTypeError, resolveItemTypesFilePath, resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, EXIT_CODE, PmCliError, toErrorMessage, stableValueEquals, nowIso, resolveIsoOrRelative, getActiveExtensionRegistrations, getSettingsPath, resolvePmRoot, readSettings, resolveAuthor, } from "../runtime-primitives.js";
|
|
9
|
+
import { assertDependencyTargetsResolvable } from "../dependency-flag-validation.js";
|
|
9
10
|
import { parseStatusFilterCsv } from "../../core/item/status-filter.js";
|
|
10
11
|
import { hasListFilters } from "../query/list-filter-shared.js";
|
|
11
12
|
import { runList, } from "../query/list.js";
|
|
12
13
|
import { runRestore } from "./restore.js";
|
|
13
|
-
import { runUpdate } from "./update.js";
|
|
14
|
+
import { assertUpdateMutationOptionCombinations, parseDependencyAdditions, runUpdate, } from "./update.js";
|
|
14
15
|
import { derivePmBulkMutationEffect, } from "../cli-contracts/command-exit-contracts.js";
|
|
15
16
|
const UPDATE_MANY_CHECKPOINT_SCHEMA_VERSION = 1;
|
|
16
17
|
const UPDATE_MANY_CHECKPOINT_SUBDIR = "update-many";
|
|
@@ -20,6 +21,7 @@ const NON_MUTATION_UPDATE_OPTION_KEYS = new Set([
|
|
|
20
21
|
"force",
|
|
21
22
|
"ownershipMetadataBypass",
|
|
22
23
|
"ownershipDependencyBypass",
|
|
24
|
+
"allowUnresolvedDeps",
|
|
23
25
|
]);
|
|
24
26
|
const UPDATE_MANY_MUTATION_FLAG_GUIDANCE = [
|
|
25
27
|
"--status",
|
|
@@ -379,19 +381,20 @@ const buildTagMutationPlan = (row, update) => {
|
|
|
379
381
|
// --add-ac-only bulk update must NOT be treated as a no-op skip).
|
|
380
382
|
const buildAcceptanceCriteriaMutationPlan = (row, update) => {
|
|
381
383
|
const before = row.acceptance_criteria;
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
:
|
|
385
|
-
|
|
386
|
-
|
|
384
|
+
const mutation = applyAcceptanceCriteriaMutations(splitAcceptanceCriteria(before), update.addAc, update.removeAc);
|
|
385
|
+
if (mutation.unmatchedRemovals.length > 0) {
|
|
386
|
+
throw new PmCliError(`Acceptance criteria removal did not match: ${mutation.unmatchedRemovals.join(", ")}`, EXIT_CODE.NOT_FOUND, {
|
|
387
|
+
code: "acceptance_criteria_remove_unmatched",
|
|
388
|
+
reason: "exact_match_not_found",
|
|
389
|
+
field: "acceptance_criteria",
|
|
390
|
+
unmatched: mutation.unmatchedRemovals,
|
|
391
|
+
});
|
|
392
|
+
}
|
|
387
393
|
const after = mutation.criteria.join("; ");
|
|
388
|
-
if (areValuesEqual(
|
|
389
|
-
return
|
|
394
|
+
if (areValuesEqual(typeof before === "string" ? before : "", after)) {
|
|
395
|
+
return undefined;
|
|
390
396
|
}
|
|
391
|
-
return {
|
|
392
|
-
change: { field: "acceptance_criteria", before, after },
|
|
393
|
-
warnings,
|
|
394
|
-
};
|
|
397
|
+
return { field: "acceptance_criteria", before, after };
|
|
395
398
|
};
|
|
396
399
|
/** Adds changed scalar options to a planned item diff. */
|
|
397
400
|
const appendScalarMutationPlans = (changes, row, update) => {
|
|
@@ -431,7 +434,6 @@ const appendUnsetMutationPlans = (changes, row, unset) => {
|
|
|
431
434
|
const buildPlannedItemDiff = (item, runtimeFieldRegistry, update = {}) => {
|
|
432
435
|
const row = toItemRecord(item);
|
|
433
436
|
const changes = [];
|
|
434
|
-
const warnings = [];
|
|
435
437
|
const tagPlan = buildTagMutationPlan(row, update);
|
|
436
438
|
if (tagPlan) {
|
|
437
439
|
changes.push(tagPlan);
|
|
@@ -439,13 +441,10 @@ const buildPlannedItemDiff = (item, runtimeFieldRegistry, update = {}) => {
|
|
|
439
441
|
appendScalarMutationPlans(changes, row, update);
|
|
440
442
|
if (updateArrayValueCount(update.addAc) > 0 ||
|
|
441
443
|
updateArrayValueCount(update.removeAc) > 0) {
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
if (composed.change !== undefined) {
|
|
446
|
-
changes.push(composed.change);
|
|
444
|
+
const acceptanceCriteriaChange = buildAcceptanceCriteriaMutationPlan(row, update);
|
|
445
|
+
if (acceptanceCriteriaChange !== undefined) {
|
|
446
|
+
changes.push(acceptanceCriteriaChange);
|
|
447
447
|
}
|
|
448
|
-
warnings.push(...composed.warnings);
|
|
449
448
|
}
|
|
450
449
|
changes.push(...buildCollectionMutationPlans(row, update));
|
|
451
450
|
appendRuntimeFieldMutationPlans(changes, row, update, runtimeFieldRegistry);
|
|
@@ -453,7 +452,6 @@ const buildPlannedItemDiff = (item, runtimeFieldRegistry, update = {}) => {
|
|
|
453
452
|
return {
|
|
454
453
|
id: item.id,
|
|
455
454
|
changes,
|
|
456
|
-
...(warnings.length > 0 ? { warnings } : {}),
|
|
457
455
|
};
|
|
458
456
|
};
|
|
459
457
|
/** Normalizes an optional list status against the runtime schema. */
|
|
@@ -631,7 +629,15 @@ const buildUpdateManyPlan = async (params) => {
|
|
|
631
629
|
includeBody: true,
|
|
632
630
|
full: true,
|
|
633
631
|
}, params.global);
|
|
634
|
-
const planned = listed.items.map((item) =>
|
|
632
|
+
const planned = listed.items.map((item) => {
|
|
633
|
+
const diff = buildPlannedItemDiff(item, params.runtime.runtimeFieldRegistry, params.options.update);
|
|
634
|
+
return params.dependencyWarnings.length === 0
|
|
635
|
+
? diff
|
|
636
|
+
: {
|
|
637
|
+
...diff,
|
|
638
|
+
warnings: [...params.dependencyWarnings],
|
|
639
|
+
};
|
|
640
|
+
});
|
|
635
641
|
const existenceItems = params.options.list?.ids == null
|
|
636
642
|
? []
|
|
637
643
|
: (await runList(undefined, {
|
|
@@ -679,7 +685,6 @@ const buildUpdateManyNoopResult = (plan) => ({
|
|
|
679
685
|
rows: plan.planned.map((row) => ({
|
|
680
686
|
id: row.id,
|
|
681
687
|
status: "skipped",
|
|
682
|
-
...(row.warnings ? { warnings: row.warnings } : {}),
|
|
683
688
|
})),
|
|
684
689
|
ids: [],
|
|
685
690
|
...buildUnmatchedIdFields(plan),
|
|
@@ -689,15 +694,12 @@ const applyUpdateManyRows = async (params) => {
|
|
|
689
694
|
const rows = [];
|
|
690
695
|
const updatedIds = [];
|
|
691
696
|
const updateMessage = params.options.update.message ?? `update-many apply ${params.checkpointId}`;
|
|
692
|
-
const plannedById = new Map(params.plans.map((row) => [row.id, row]));
|
|
693
697
|
const actionableById = new Set(params.plans.filter((row) => row.changes.length > 0).map((row) => row.id));
|
|
694
698
|
for (const item of params.items) {
|
|
695
699
|
if (!actionableById.has(item.id)) {
|
|
696
|
-
const warnings = plannedById.get(item.id)?.warnings;
|
|
697
700
|
rows.push({
|
|
698
701
|
id: item.id,
|
|
699
702
|
status: "skipped",
|
|
700
|
-
...(warnings ? { warnings } : {}),
|
|
701
703
|
});
|
|
702
704
|
continue;
|
|
703
705
|
}
|
|
@@ -800,11 +802,21 @@ export const runUpdateMany = async (options, global) => {
|
|
|
800
802
|
throw new PmCliError(`No update-many mutation flags provided. Add at least one mutation flag (for example: ${UPDATE_MANY_MUTATION_FLAG_GUIDANCE}).`, EXIT_CODE.USAGE);
|
|
801
803
|
}
|
|
802
804
|
assertPlannedUpdateValuesValid(options.update, runtime.settings, runtime.statusRegistry, runtime.pmRoot);
|
|
805
|
+
assertUpdateMutationOptionCombinations(options.update);
|
|
806
|
+
const dependencyWarnings = await assertDependencyTargetsResolvable({
|
|
807
|
+
pmRoot: runtime.pmRoot,
|
|
808
|
+
dependencies: parseDependencyAdditions(options.update.dep, runtime.settings.id_prefix, nowIso(), resolveAuthor(options.update.author, runtime.settings.author_default)).additions,
|
|
809
|
+
idPrefix: runtime.settings.id_prefix,
|
|
810
|
+
itemFormat: runtime.settings.item_format,
|
|
811
|
+
typeToFolder: resolveItemTypeRegistry(runtime.settings, getActiveExtensionRegistrations()).type_to_folder,
|
|
812
|
+
allowUnresolved: options.update.allowUnresolvedDeps,
|
|
813
|
+
});
|
|
803
814
|
const plan = await buildUpdateManyPlan({
|
|
804
815
|
options,
|
|
805
816
|
global,
|
|
806
817
|
runtime,
|
|
807
818
|
updateSummary,
|
|
819
|
+
dependencyWarnings,
|
|
808
820
|
});
|
|
809
821
|
return options.dryRun === true
|
|
810
822
|
? buildUpdateManyDryRunResult(plan)
|
|
@@ -828,4 +840,4 @@ export const _testOnlyUpdateManyCommand = {
|
|
|
828
840
|
toComparablePreviewValue,
|
|
829
841
|
};
|
|
830
842
|
//# sourceMappingURL=update-many.js.map
|
|
831
|
-
//# debugId=
|
|
843
|
+
//# debugId=0f91de58-2cbc-52ba-97ea-42482d0c6ce1
|
|
@@ -40,6 +40,8 @@ export interface UpdateCommandOptions extends MutationMetadataCommandOptions, Sh
|
|
|
40
40
|
force?: boolean;
|
|
41
41
|
/** Permit an intentional unresolved parent reference under strict validation. */
|
|
42
42
|
allowMissingParent?: boolean;
|
|
43
|
+
/** Explicitly permit unresolved local dependency targets with warning receipts. */
|
|
44
|
+
allowUnresolvedDeps?: boolean;
|
|
43
45
|
/** Value that configures or reports dep remove for this contract. */
|
|
44
46
|
depRemove?: string[];
|
|
45
47
|
/** Value that configures or reports replace deps for this contract. */
|
|
@@ -96,7 +98,8 @@ interface DependencyRemovalSelector {
|
|
|
96
98
|
kind?: (typeof DEPENDENCY_KIND_VALUES)[number];
|
|
97
99
|
source_kind?: string;
|
|
98
100
|
}
|
|
99
|
-
|
|
101
|
+
/** Parse dependency additions into their canonical storage representation. */
|
|
102
|
+
export declare function parseDependencyAdditions(raw: string[] | undefined, prefix: string, nowIso: string, fallbackAuthor: string): ParsedDependencyUpdates;
|
|
100
103
|
declare function parseDependencyRemovals(raw: string[] | undefined, prefix: string): DependencyRemovalSelector[];
|
|
101
104
|
declare function reconcileBlockedByDependency(current: Dependency[] | undefined, nextBlockedById: string | undefined, nowIsoValue: string, author: string): {
|
|
102
105
|
dependencies: Dependency[] | undefined;
|
|
@@ -130,6 +133,8 @@ interface UpdateMutationContext {
|
|
|
130
133
|
author: string;
|
|
131
134
|
pmRoot: string;
|
|
132
135
|
}
|
|
136
|
+
/** Validate mutually exclusive and required update mutation option combinations. */
|
|
137
|
+
export declare function assertUpdateMutationOptionCombinations(options: UpdateCommandOptions): void;
|
|
133
138
|
type UpdateStatusMutationContext = Pick<UpdateMutationContext, "options" | "statusRegistry" | "clearItemMetadataKeys" | "nowIso">;
|
|
134
139
|
declare function applyStatusAndCloseReasonMutations(document: ItemDocument, context: UpdateStatusMutationContext, previousStatusNormalized: string, changedFields: string[]): void;
|
|
135
140
|
/** Implements run update for the public runtime surface of this module. */
|
|
@@ -4,15 +4,16 @@
|
|
|
4
4
|
* Implements the pm update command surface and its agent-facing runtime behavior.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
7
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="244583b8-2ffd-5da4-a4d3-46396fb354c0")}catch(e){}}();
|
|
8
8
|
import { pathExists, COMMON_MUTATION_COMMAND_OPTION_KEYS, canonicalizeCommandOptionKey, commandOptionFlagLabel, resolveItemTypeRegistry, resolveCommandOptionPolicyState, resolveTypeDefinition, resolveTypeName, validateTypeOptions, normalizeItemId, toItemRecord, buildInvalidTypeError, assertParentReferenceIsNotSelf, normalizeParentReferenceValue, validateMissingParentReference, validateSprintOrReleaseValue, applyAcceptanceCriteriaMutations, applyTagRemovals, assertNoUnknownCsvKeys, createStdinTokenResolver, looksLikeGenericKeyValueEntry, mergeAdditiveTags, parseCsvKv, parseOptionalNonNegativeInteger, parseOptionalNumber, parseTags, splitAcceptanceCriteria, resolvePriority, normalizeStatusInput, isTerminalStatus, collectRuntimeUpdateFieldValues, resolveItemTypesFilePath, resolveRuntimeFieldRegistry, resolveRuntimeStatusRegistry, describeAllowedTransitions, evaluateTransition, resolveTypeWorkflows, EXIT_CODE, PmCliError, stableValueEquals, resolveIsoOrRelative, getActiveExtensionRegistrations, collectRegisteredItemFieldNames, applyRegisteredItemFieldDefaultsAndValidation, parseRegisteredItemFieldAssignments, buildItemNotFoundError, listAllItemMetadataLight, locateItem, mutateItem, readLocatedItem, getSettingsPath, resolvePmRoot, readSettings, resolveAuthor, } from "../runtime-primitives.js";
|
|
9
9
|
import { runClose } from "./close.js";
|
|
10
10
|
import { normalizeRiskInput, normalizeSeverityInput, parseConfidenceInput, parseRegressionInput, } from "./metadata-normalizers.js";
|
|
11
11
|
import { applyLegacyNoneCollectionNormalizers, createLegacyNoneCollectionNormalizers, assertNoLegacyNoneToken, assertNoLegacyNoneTokens, isLegacyNoneToken, } from "./legacy-none-tokens.js";
|
|
12
12
|
import { ensureEnumValue as ensureEnum } from "./recurrence-parsers.js";
|
|
13
13
|
import { parseEventEntries, parseReminderEntries, parseTypeOptionEntries, } from "./repeatable-metadata-parsers.js";
|
|
14
|
-
import { assertDependencyEdgesAllowed, assertValidBareDependencyFlagValue, } from "../dependency-flag-validation.js";
|
|
14
|
+
import { assertDependencyEdgesAllowed, assertDependencyTargetsResolvable, assertValidBareDependencyFlagValue, } from "../dependency-flag-validation.js";
|
|
15
15
|
import { normalizeDependencySeedId, normalizeDependencySourceKind, } from "../dependency-provenance.js";
|
|
16
|
+
import { resolveCanonicalRelationshipKind } from "../relationships.js";
|
|
16
17
|
import { collectNewOrderingCycleWarnings } from "../graph/mutation-advisory.js";
|
|
17
18
|
import { DEPENDENCY_KIND_VALUES, ISSUE_SEVERITY_VALUES, RISK_VALUES, } from "../../types/index.js";
|
|
18
19
|
import { parseDocs, parseFiles, parseLogSeed, parseTests, requireStringOption, } from "./create.js";
|
|
@@ -386,27 +387,13 @@ function looksLikeStructuredDependencyEntry(raw) {
|
|
|
386
387
|
// key is rejected rather than swallowed as a bare item id (GH-258).
|
|
387
388
|
return looksLikeGenericKeyValueEntry(raw);
|
|
388
389
|
}
|
|
389
|
-
// pm-fl0c #4 (2026-05-28): `pm plan` accepts `depends_on` as a link kind
|
|
390
|
-
// (`PLAN_STEP_LINK_KIND_VALUES`) but `pm update --dep kind=depends_on` rejected
|
|
391
|
-
// it because `DEPENDENCY_KIND_VALUES` only lists `blocked_by`. The two terms
|
|
392
|
-
// are semantically identical from this side ("X depends on Y" === "X blocked
|
|
393
|
-
// by Y"), so we normalize input here rather than expanding the persisted enum
|
|
394
|
-
// — the stored kind stays canonical (`blocked_by`) and downstream consumers
|
|
395
|
-
// (closing logic, dependency graphs, blockers views) keep working unchanged.
|
|
396
|
-
const DEPENDENCY_KIND_INPUT_ALIASES = {
|
|
397
|
-
"blocked-by": "blocked_by",
|
|
398
|
-
depends_on: "blocked_by",
|
|
399
|
-
"depends-on": "blocked_by",
|
|
400
|
-
};
|
|
401
390
|
function normalizeDependencyKindInput(raw) {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
const trimmed = raw.trim();
|
|
406
|
-
const alias = DEPENDENCY_KIND_INPUT_ALIASES[trimmed.toLowerCase()];
|
|
407
|
-
return alias ?? trimmed;
|
|
391
|
+
return typeof raw === "string"
|
|
392
|
+
? (resolveCanonicalRelationshipKind(raw) ?? raw.trim())
|
|
393
|
+
: raw;
|
|
408
394
|
}
|
|
409
|
-
|
|
395
|
+
/** Parse dependency additions into their canonical storage representation. */
|
|
396
|
+
export function parseDependencyAdditions(raw, prefix, nowIso, fallbackAuthor) {
|
|
410
397
|
if (!raw) {
|
|
411
398
|
return { additions: [] };
|
|
412
399
|
}
|
|
@@ -931,7 +918,20 @@ function validateLinkedArtifactReplacement(params) {
|
|
|
931
918
|
throw new PmCliError(`${params.replaceFlag} cannot be combined with ${params.clearFlag}`, EXIT_CODE.USAGE);
|
|
932
919
|
}
|
|
933
920
|
}
|
|
934
|
-
|
|
921
|
+
/** Validate mutually exclusive and required update mutation option combinations. */
|
|
922
|
+
export function assertUpdateMutationOptionCombinations(options) {
|
|
923
|
+
const hasAdditiveAcceptanceCriteriaMutation = (options.addAc?.length ?? 0) > 0 || (options.removeAc?.length ?? 0) > 0;
|
|
924
|
+
if (options.acceptanceCriteria !== undefined &&
|
|
925
|
+
hasAdditiveAcceptanceCriteriaMutation) {
|
|
926
|
+
throw new PmCliError("Cannot combine --acceptance-criteria replacement with --add-ac or --remove-ac. Use --remove-ac and --add-ac together for an atomic one-entry repair.", EXIT_CODE.USAGE, {
|
|
927
|
+
code: "acceptance_criteria_mutation_conflict",
|
|
928
|
+
reason: "replacement_and_additive_mutation_combined",
|
|
929
|
+
nextSteps: [
|
|
930
|
+
"Use --acceptance-criteria alone to replace the complete list.",
|
|
931
|
+
"Use --remove-ac <old> --add-ac <new> to repair one criterion without replacing unrelated entries.",
|
|
932
|
+
],
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
935
|
if (options.replaceDeps === true &&
|
|
936
936
|
(options.dep === undefined || options.dep.length === 0)) {
|
|
937
937
|
throw new PmCliError("--replace-deps requires at least one --dep entry", EXIT_CODE.USAGE);
|
|
@@ -1458,7 +1458,7 @@ function applyTagsAndPlanningMutations(document, context, scalarMutationContext)
|
|
|
1458
1458
|
// concurrent branch edits with disjoint additions merge instead of clobbering
|
|
1459
1459
|
// the whole acceptance_criteria value (tag-API parity). Runs after the scalar
|
|
1460
1460
|
// mutations so composition with a `--ac` replace uses the replaced base.
|
|
1461
|
-
function applyAcceptanceCriteriaAdditiveMutation(document, context, scalarMutationContext
|
|
1461
|
+
function applyAcceptanceCriteriaAdditiveMutation(document, context, scalarMutationContext) {
|
|
1462
1462
|
const addValues = context.options.addAc;
|
|
1463
1463
|
const removeValues = context.options.removeAc;
|
|
1464
1464
|
if (!(Array.isArray(addValues) && addValues.length > 0) &&
|
|
@@ -1466,8 +1466,18 @@ function applyAcceptanceCriteriaAdditiveMutation(document, context, scalarMutati
|
|
|
1466
1466
|
return;
|
|
1467
1467
|
}
|
|
1468
1468
|
const mutation = applyAcceptanceCriteriaMutations(splitAcceptanceCriteria(document.metadata.acceptance_criteria), addValues, removeValues);
|
|
1469
|
-
|
|
1470
|
-
|
|
1469
|
+
if (mutation.unmatchedRemovals.length > 0) {
|
|
1470
|
+
throw new PmCliError(`Acceptance criteria removal did not match: ${mutation.unmatchedRemovals.join(", ")}`, EXIT_CODE.NOT_FOUND, {
|
|
1471
|
+
code: "acceptance_criteria_remove_unmatched",
|
|
1472
|
+
reason: "exact_match_not_found",
|
|
1473
|
+
field: "acceptance_criteria",
|
|
1474
|
+
unmatched: mutation.unmatchedRemovals,
|
|
1475
|
+
why: "Lossless removal fails instead of silently applying the remaining mutations when an exact selector is wrong.",
|
|
1476
|
+
nextSteps: [
|
|
1477
|
+
"Read the current acceptance_criteria value and retry with the exact criterion text.",
|
|
1478
|
+
"Use --acceptance-criteria alone only when replacing the complete list is intentional.",
|
|
1479
|
+
],
|
|
1480
|
+
});
|
|
1471
1481
|
}
|
|
1472
1482
|
const nextValue = mutation.criteria.join("; ");
|
|
1473
1483
|
if (document.metadata.acceptance_criteria === nextValue) {
|
|
@@ -1652,7 +1662,7 @@ function mutateUpdateDocument(document, context) {
|
|
|
1652
1662
|
applyLogCollectionMutations(document, context, changedFields);
|
|
1653
1663
|
applyEvidenceCollectionMutations(document, context, changedFields);
|
|
1654
1664
|
applyTagsAndPlanningMutations(document, context, scalarMutationContext);
|
|
1655
|
-
applyAcceptanceCriteriaAdditiveMutation(document, context, scalarMutationContext
|
|
1665
|
+
applyAcceptanceCriteriaAdditiveMutation(document, context, scalarMutationContext);
|
|
1656
1666
|
applyOwnershipAndIssueMutations(document, context, scalarMutationContext, warnings);
|
|
1657
1667
|
if (context.options.dep !== undefined ||
|
|
1658
1668
|
context.options.depRemove !== undefined ||
|
|
@@ -1683,6 +1693,10 @@ function mutateUpdateDocument(document, context) {
|
|
|
1683
1693
|
const actualChangedFields = [...new Set(changedFields)].filter((field) => field === "body"
|
|
1684
1694
|
? document.body !== beforeBody
|
|
1685
1695
|
: !stableValueEquals(beforeMetadata[field], afterMetadata[field]));
|
|
1696
|
+
if (context.options.acceptanceCriteria !== undefined &&
|
|
1697
|
+
actualChangedFields.includes("acceptance_criteria")) {
|
|
1698
|
+
warnings.push(`acceptance_criteria_replaced:${splitAcceptanceCriteria(beforeMetadata.acceptance_criteria).length}:${splitAcceptanceCriteria(afterMetadata.acceptance_criteria).length}`);
|
|
1699
|
+
}
|
|
1686
1700
|
return { changedFields: actualChangedFields, warnings };
|
|
1687
1701
|
}
|
|
1688
1702
|
/** Implements run update for the public runtime surface of this module. */
|
|
@@ -1715,7 +1729,7 @@ export async function runUpdate(id, options, global) {
|
|
|
1715
1729
|
const unsetTargets = parseUpdateUnsetTargets(options.unset, runtimeFieldRegistry, extensionFieldNames);
|
|
1716
1730
|
const clearOptionKeys = new Set(unsetTargets.optionKeys);
|
|
1717
1731
|
const clearItemMetadataKeys = new Set(unsetTargets.metadataKeys);
|
|
1718
|
-
|
|
1732
|
+
assertUpdateMutationOptionCombinations(options);
|
|
1719
1733
|
applyClearCollectionDefinitions({
|
|
1720
1734
|
definitions: buildClearCollectionDefinitions(options),
|
|
1721
1735
|
options,
|
|
@@ -1729,6 +1743,14 @@ export async function runUpdate(id, options, global) {
|
|
|
1729
1743
|
const nowValue = new Date();
|
|
1730
1744
|
const nowIso = nowValue.toISOString();
|
|
1731
1745
|
const dependencyUpdates = parseDependencyAdditions(options.dep, settings.id_prefix, nowIso, author);
|
|
1746
|
+
const dependencyTargetWarnings = await assertDependencyTargetsResolvable({
|
|
1747
|
+
pmRoot,
|
|
1748
|
+
dependencies: dependencyUpdates.additions,
|
|
1749
|
+
idPrefix: settings.id_prefix,
|
|
1750
|
+
itemFormat: settings.item_format,
|
|
1751
|
+
typeToFolder: typeRegistry.type_to_folder,
|
|
1752
|
+
allowUnresolved: options.allowUnresolvedDeps,
|
|
1753
|
+
});
|
|
1732
1754
|
const dependencyRemovals = parseDependencyRemovals(options.depRemove, settings.id_prefix);
|
|
1733
1755
|
const parsedCommentUpdates = parseLogSeed("--comment", options.comment, nowIso, author);
|
|
1734
1756
|
const commentUpdates = options.ownershipMetadataBypass === true && parsedCommentUpdates.values
|
|
@@ -1851,6 +1873,7 @@ export async function runUpdate(id, options, global) {
|
|
|
1851
1873
|
warnings: [
|
|
1852
1874
|
...workflowTransitionWarnings,
|
|
1853
1875
|
...parentReferenceWarnings,
|
|
1876
|
+
...dependencyTargetWarnings,
|
|
1854
1877
|
...orderingCycleWarnings,
|
|
1855
1878
|
...result.warnings,
|
|
1856
1879
|
],
|
|
@@ -1874,4 +1897,4 @@ export const _testOnlyUpdateCommand = {
|
|
|
1874
1897
|
resolveRuntimeUnsetDefinition: (token, registry) => resolveRuntimeUnsetFieldDefinition(token, "update", registry),
|
|
1875
1898
|
};
|
|
1876
1899
|
//# sourceMappingURL=update.js.map
|
|
1877
|
-
//# debugId=
|
|
1900
|
+
//# debugId=244583b8-2ffd-5da4-a4d3-46396fb354c0
|
|
@@ -30,7 +30,7 @@ export interface MergeDriverResult {
|
|
|
30
30
|
artifact: MergeDriverArtifact;
|
|
31
31
|
/** Path the merged content was written to. */
|
|
32
32
|
output_path: string;
|
|
33
|
-
/**
|
|
33
|
+
/** Invocation-side preference retained for non-item artifact compatibility. */
|
|
34
34
|
preferred: MergePreferredSide;
|
|
35
35
|
/** Unresolvable conflict labels: metadata field names (item), dotted key paths (json). Empty for history merges. */
|
|
36
36
|
conflicts: string[];
|
|
@@ -56,6 +56,7 @@ export interface MergeDriverResult {
|
|
|
56
56
|
item?: {
|
|
57
57
|
fields_from_theirs: string[];
|
|
58
58
|
union_fields: string[];
|
|
59
|
+
conflict_resolution: "stable_value_order";
|
|
59
60
|
};
|
|
60
61
|
/** JSON-merge key accounting; present only for the json artifact. */
|
|
61
62
|
json?: {
|
package/dist/sdk/merge/driver.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* merge never corrupts tracker storage the way raw conflict markers do.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
12
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e739a603-35c5-5df9-8d4b-3bbc0fe3e4fd")}catch(e){}}();
|
|
13
13
|
import { readFile, writeFile } from "node:fs/promises";
|
|
14
14
|
import path from "node:path";
|
|
15
15
|
import { getActiveExtensionRegistrations } from "../../core/extensions/index.js";
|
|
@@ -127,18 +127,21 @@ export async function runMergeDriver(options, global) {
|
|
|
127
127
|
schema: settings?.schema,
|
|
128
128
|
extensionFieldNames: collectRegisteredItemFieldNames(getActiveExtensionRegistrations()),
|
|
129
129
|
preferred,
|
|
130
|
+
conflictResolution: "stable_value_order",
|
|
130
131
|
});
|
|
131
132
|
merged = itemMerge.merged;
|
|
132
133
|
conflicts.push(...itemMerge.conflict_fields);
|
|
133
134
|
result.item = {
|
|
134
135
|
fields_from_theirs: itemMerge.fields_from_theirs,
|
|
135
136
|
union_fields: itemMerge.union_fields,
|
|
137
|
+
conflict_resolution: "stable_value_order",
|
|
136
138
|
};
|
|
137
139
|
if (options.itemPath !== undefined) {
|
|
138
140
|
receiptInput = {
|
|
139
141
|
cwd: process.cwd(),
|
|
140
142
|
itemPath: options.itemPath,
|
|
141
143
|
preferred,
|
|
144
|
+
conflictResolution: "stable_value_order",
|
|
142
145
|
fieldsFromTheirs: itemMerge.fields_from_theirs,
|
|
143
146
|
unionFields: itemMerge.union_fields,
|
|
144
147
|
decisions: itemMerge.conflict_decisions,
|
|
@@ -167,10 +170,10 @@ export async function runMergeDriver(options, global) {
|
|
|
167
170
|
const receiptGuidance = result.receipt === undefined
|
|
168
171
|
? 'Run "pm merge report" to inspect clone-local merge evidence.'
|
|
169
172
|
: `Run "pm merge report" and correlate receipt ${result.receipt.receipt_id} with item ${result.receipt.item_id}; clone-local discarded values are never copied into this result.`;
|
|
170
|
-
guidance.push(`Both branches changed ${conflicts.join(", ")}; the
|
|
173
|
+
guidance.push(`Both branches changed ${conflicts.join(", ")}; the item driver kept the direction-independent stable value. ${receiptGuidance} Review the merged file, re-apply the discarded change if needed, then "git add" it.`);
|
|
171
174
|
}
|
|
172
175
|
if (artifact === "history" && result.history?.reanchored) {
|
|
173
|
-
guidance.push('The merged history chain was re-anchored. Run "pm
|
|
176
|
+
guidance.push('The merged history chain was re-anchored. Run "pm merge reconcile --dry-run" to inspect the complete post-merge repair, then "pm merge reconcile" to apply it; use --force only after explicitly accepting reported discards.');
|
|
174
177
|
}
|
|
175
178
|
return {
|
|
176
179
|
ok: conflicts.length === 0,
|
|
@@ -184,4 +187,4 @@ export async function runMergeDriver(options, global) {
|
|
|
184
187
|
};
|
|
185
188
|
}
|
|
186
189
|
//# sourceMappingURL=driver.js.map
|
|
187
|
-
//# debugId=
|
|
190
|
+
//# debugId=e739a603-35c5-5df9-8d4b-3bbc0fe3e4fd
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
export { ITEM_LATEST_TIMESTAMP_FIELDS, ITEM_UNION_COLLECTION_FIELDS, mergeHistoryStreams, mergeItemDocuments, mergeJsonDocuments, mergeRelationshipEventStreams, type HistoryMergeResult, type HistoryMergeStrategy, type ItemDocumentMergeResult, type JsonDocumentMergeResult, type ItemMergeConflictDecision, type MergePreferredSide, type RelationshipStreamMergeResult, } from "./three-way.js";
|
|
10
10
|
export { listMergeReceipts, markMergeReceiptReconciled, runMergeReceiptReport, summarizeMergeReceipt, type MergeDecisionReceipt, type MergeDecisionReceiptSummary, type MergeReceiptReport, } from "./receipts.js";
|
|
11
11
|
export { MERGE_DRIVER_ARTIFACT_VALUES, runMergeDriver, type MergeDriverArtifact, type MergeDriverOptions, type MergeDriverResult, } from "./driver.js";
|
|
12
|
-
export { auditMergeAttributeFence, auditMergeDriverConfiguration, buildMergeAttributePatterns, findGitWorkspaceRoot, PM_GITATTRIBUTES_END, PM_GITATTRIBUTES_START, refreshMergeAttributeFenceIfInstalled, resolveMergeInstallContext, runMergeInstall, type MergeFenceAuditResult, type MergeDriverConfigurationAuditResult, type MergeFenceRefreshOutcome, type MergeInstallOptions, type MergeInstallContextResolution, type MergeInstallResult, } from "./install.js";
|
|
12
|
+
export { auditMergeAttributeFence, auditMergeDriverConfiguration, buildMergeAttributePatterns, findGitWorkspaceRoot, PM_GITATTRIBUTES_END, PM_GITATTRIBUTES_START, PM_GITATTRIBUTES_V2_END, PM_GITATTRIBUTES_V2_START, refreshMergeAttributeFenceIfInstalled, resolveMergeInstallContext, runMergeInstall, type MergeFenceAuditResult, type MergeDriverConfigurationAuditResult, type MergeFenceRefreshOutcome, type MergeInstallOptions, type MergeInstallContextResolution, type MergeInstallResult, } from "./install.js";
|
|
13
13
|
export { runMergeReconcile, type MergeReconcileOptions, type MergeReconcileResult, } from "./reconcile.js";
|
package/dist/sdk/merge/index.js
CHANGED
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
* this module so packages and hosts can reuse the same merge behavior.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
10
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="687855bf-7432-5691-a809-1f0406b5d8a8")}catch(e){}}();
|
|
11
11
|
export { ITEM_LATEST_TIMESTAMP_FIELDS, ITEM_UNION_COLLECTION_FIELDS, mergeHistoryStreams, mergeItemDocuments, mergeJsonDocuments, mergeRelationshipEventStreams, } from "./three-way.js";
|
|
12
12
|
export { listMergeReceipts, markMergeReceiptReconciled, runMergeReceiptReport, summarizeMergeReceipt, } from "./receipts.js";
|
|
13
13
|
export { MERGE_DRIVER_ARTIFACT_VALUES, runMergeDriver, } from "./driver.js";
|
|
14
|
-
export { auditMergeAttributeFence, auditMergeDriverConfiguration, buildMergeAttributePatterns, findGitWorkspaceRoot, PM_GITATTRIBUTES_END, PM_GITATTRIBUTES_START, refreshMergeAttributeFenceIfInstalled, resolveMergeInstallContext, runMergeInstall, } from "./install.js";
|
|
14
|
+
export { auditMergeAttributeFence, auditMergeDriverConfiguration, buildMergeAttributePatterns, findGitWorkspaceRoot, PM_GITATTRIBUTES_END, PM_GITATTRIBUTES_START, PM_GITATTRIBUTES_V2_END, PM_GITATTRIBUTES_V2_START, refreshMergeAttributeFenceIfInstalled, resolveMergeInstallContext, runMergeInstall, } from "./install.js";
|
|
15
15
|
export { runMergeReconcile, } from "./reconcile.js";
|
|
16
16
|
//# sourceMappingURL=index.js.map
|
|
17
|
-
//# debugId=
|
|
17
|
+
//# debugId=687855bf-7432-5691-a809-1f0406b5d8a8
|
|
@@ -5,6 +5,10 @@ import { resolveSourceContextWritePolicy } from "../environment/source-context.j
|
|
|
5
5
|
export declare const PM_GITATTRIBUTES_START = "# pm-cli:merge-drivers:start";
|
|
6
6
|
/** Closing marker for the pm-owned merge-driver `.gitattributes` block. */
|
|
7
7
|
export declare const PM_GITATTRIBUTES_END = "# pm-cli:merge-drivers:end";
|
|
8
|
+
/** Opening marker for the versioned fence that older releases leave untouched. */
|
|
9
|
+
export declare const PM_GITATTRIBUTES_V2_START = "# pm-cli:merge-drivers:v2:start";
|
|
10
|
+
/** Closing marker for the versioned fence that older releases leave untouched. */
|
|
11
|
+
export declare const PM_GITATTRIBUTES_V2_END = "# pm-cli:merge-drivers:v2:end";
|
|
8
12
|
/** Documents the merge install options payload exchanged by command, SDK, and package integrations. */
|
|
9
13
|
export interface MergeInstallOptions {
|
|
10
14
|
/** Preview the `.gitattributes` and `git config` changes without writing anything. */
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* mutations refresh the fenced block automatically once it is installed.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
11
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="94d2a7a8-ce00-5689-b2f6-3d4813234b55")}catch(e){}}();
|
|
12
12
|
import { readFile, realpath, writeFile } from "node:fs/promises";
|
|
13
13
|
import { execFile } from "node:child_process";
|
|
14
14
|
import path from "node:path";
|
|
@@ -30,6 +30,10 @@ const execFileAsync = promisify(execFile);
|
|
|
30
30
|
export const PM_GITATTRIBUTES_START = "# pm-cli:merge-drivers:start";
|
|
31
31
|
/** Closing marker for the pm-owned merge-driver `.gitattributes` block. */
|
|
32
32
|
export const PM_GITATTRIBUTES_END = "# pm-cli:merge-drivers:end";
|
|
33
|
+
/** Opening marker for the versioned fence that older releases leave untouched. */
|
|
34
|
+
export const PM_GITATTRIBUTES_V2_START = "# pm-cli:merge-drivers:v2:start";
|
|
35
|
+
/** Closing marker for the versioned fence that older releases leave untouched. */
|
|
36
|
+
export const PM_GITATTRIBUTES_V2_END = "# pm-cli:merge-drivers:v2:end";
|
|
33
37
|
const MERGE_FENCE_LOCK_ID = "merge-fence";
|
|
34
38
|
/**
|
|
35
39
|
* Quote one argument for the shell used by Git merge-driver configuration.
|
|
@@ -235,6 +239,13 @@ export function buildMergeAttributePatterns(trackerRelativeRoot, typeFolders) {
|
|
|
235
239
|
patterns.push(`${quoteGitAttributePattern(`${prefix}extensions/.managed-extensions.json`)} merge=pm-json`);
|
|
236
240
|
return patterns;
|
|
237
241
|
}
|
|
242
|
+
function removeManagedBlock(content, startMarker, endMarker) {
|
|
243
|
+
const start = content.indexOf(startMarker);
|
|
244
|
+
const end = content.indexOf(endMarker);
|
|
245
|
+
return start >= 0 && end > start
|
|
246
|
+
? `${content.slice(0, start)}${content.slice(end + endMarker.length)}`
|
|
247
|
+
: content.replace(startMarker, "").replace(endMarker, "");
|
|
248
|
+
}
|
|
238
249
|
async function reconcileGitattributesBlock(workspaceRoot, patterns, dryRun) {
|
|
239
250
|
const gitattributesPath = path.join(workspaceRoot, ".gitattributes");
|
|
240
251
|
let current = "";
|
|
@@ -247,17 +258,11 @@ async function reconcileGitattributesBlock(workspaceRoot, patterns, dryRun) {
|
|
|
247
258
|
}
|
|
248
259
|
}
|
|
249
260
|
const block = [
|
|
250
|
-
|
|
261
|
+
PM_GITATTRIBUTES_V2_START,
|
|
251
262
|
...patterns,
|
|
252
|
-
|
|
263
|
+
PM_GITATTRIBUTES_V2_END,
|
|
253
264
|
].join("\n");
|
|
254
|
-
const
|
|
255
|
-
const end = current.indexOf(PM_GITATTRIBUTES_END);
|
|
256
|
-
const withoutManagedBlock = start >= 0 && end > start
|
|
257
|
-
? `${current.slice(0, start)}${current.slice(end + PM_GITATTRIBUTES_END.length)}`
|
|
258
|
-
: current
|
|
259
|
-
.replace(PM_GITATTRIBUTES_START, "")
|
|
260
|
-
.replace(PM_GITATTRIBUTES_END, "");
|
|
265
|
+
const withoutManagedBlock = removeManagedBlock(removeManagedBlock(current, PM_GITATTRIBUTES_V2_START, PM_GITATTRIBUTES_V2_END), PM_GITATTRIBUTES_START, PM_GITATTRIBUTES_END);
|
|
261
266
|
const prefix = withoutManagedBlock.trimEnd();
|
|
262
267
|
const next = `${prefix.length > 0 ? `${prefix}\n\n` : ""}${block}\n`;
|
|
263
268
|
if (next === current) {
|
|
@@ -290,7 +295,8 @@ export async function auditMergeAttributeFence(pmRoot, typeFolders) {
|
|
|
290
295
|
const candidate = path.join(directory, ".gitattributes");
|
|
291
296
|
try {
|
|
292
297
|
const raw = await readFile(candidate, "utf8");
|
|
293
|
-
if (raw.includes(
|
|
298
|
+
if (raw.includes(PM_GITATTRIBUTES_V2_START) ||
|
|
299
|
+
raw.includes(PM_GITATTRIBUTES_START)) {
|
|
294
300
|
fenceDirectory = directory;
|
|
295
301
|
fenceContent = raw;
|
|
296
302
|
break;
|
|
@@ -314,11 +320,16 @@ export async function auditMergeAttributeFence(pmRoot, typeFolders) {
|
|
|
314
320
|
};
|
|
315
321
|
}
|
|
316
322
|
const fencePath = path.join(fenceDirectory, ".gitattributes");
|
|
317
|
-
const
|
|
318
|
-
const
|
|
323
|
+
const usesV2 = fenceContent.includes(PM_GITATTRIBUTES_V2_START);
|
|
324
|
+
const startMarker = usesV2
|
|
325
|
+
? PM_GITATTRIBUTES_V2_START
|
|
326
|
+
: PM_GITATTRIBUTES_START;
|
|
327
|
+
const endMarker = usesV2 ? PM_GITATTRIBUTES_V2_END : PM_GITATTRIBUTES_END;
|
|
328
|
+
const start = fenceContent.indexOf(startMarker);
|
|
329
|
+
const end = fenceContent.indexOf(endMarker);
|
|
319
330
|
const committed = end > start
|
|
320
331
|
? fenceContent
|
|
321
|
-
.slice(start +
|
|
332
|
+
.slice(start + startMarker.length, end)
|
|
322
333
|
.split("\n")
|
|
323
334
|
.map((line) => line.trim())
|
|
324
335
|
.filter((line) => line.length > 0)
|
|
@@ -408,7 +419,8 @@ export async function refreshMergeAttributeFenceIfInstalled(pmRoot) {
|
|
|
408
419
|
}
|
|
409
420
|
throw error;
|
|
410
421
|
}
|
|
411
|
-
if (!current.includes(
|
|
422
|
+
if (!current.includes(PM_GITATTRIBUTES_V2_START) &&
|
|
423
|
+
!current.includes(PM_GITATTRIBUTES_START)) {
|
|
412
424
|
return { status: "not_installed", path: gitattributesPath };
|
|
413
425
|
}
|
|
414
426
|
// Re-read after acquiring the dedicated fence lock so every concurrent
|
|
@@ -541,11 +553,11 @@ export async function installMergeFence(options) {
|
|
|
541
553
|
guidance: [
|
|
542
554
|
"Commit .gitattributes so every branch and collaborator shares the merge mapping.",
|
|
543
555
|
'git config is per-clone: each collaborator (and each fresh worktree/clone) runs "pm merge install" once.',
|
|
544
|
-
'After merging branches, run "pm
|
|
556
|
+
'After merging branches, run "pm merge reconcile --dry-run" to inspect the complete receipt and history repair, then apply "pm merge reconcile"; use --force only after explicitly accepting any discarded values.',
|
|
545
557
|
"Custom item types registered later refresh this fence automatically (pm schema add-type/remove-type); rerun pm merge install only after out-of-band type-folder edits.",
|
|
546
558
|
],
|
|
547
559
|
generated_at: nowIso(),
|
|
548
560
|
};
|
|
549
561
|
}
|
|
550
562
|
//# sourceMappingURL=install.js.map
|
|
551
|
-
//# debugId=
|
|
563
|
+
//# debugId=94d2a7a8-ce00-5689-b2f6-3d4813234b55
|
|
@@ -11,6 +11,8 @@ export interface MergeDecisionReceipt {
|
|
|
11
11
|
item_id: string;
|
|
12
12
|
/** Preferred side used for scalar conflicts. */
|
|
13
13
|
preferred: MergePreferredSide;
|
|
14
|
+
/** Scalar-conflict selection contract used by the item driver. */
|
|
15
|
+
conflict_resolution: "preferred_side" | "stable_value_order";
|
|
14
16
|
/** Fields selected cleanly from the other branch. */
|
|
15
17
|
fields_from_theirs: string[];
|
|
16
18
|
/** Collections combined from both branches. */
|
|
@@ -23,6 +25,8 @@ export interface MergeDecisionReceipt {
|
|
|
23
25
|
created_at: string;
|
|
24
26
|
/** Reconciliation timestamp, when consumed. */
|
|
25
27
|
reconciled_at?: string;
|
|
28
|
+
/** Whether decision values are recoverable locally or represented by hashes only. */
|
|
29
|
+
value_availability?: "clone_local" | "hash_only";
|
|
26
30
|
}
|
|
27
31
|
/** Privacy-safe receipt summary suitable for committed history context. */
|
|
28
32
|
export interface MergeDecisionReceiptSummary {
|
|
@@ -40,6 +44,8 @@ export interface MergeDecisionReceiptSummary {
|
|
|
40
44
|
union_fields: string[];
|
|
41
45
|
/** Preferred side used for scalar conflicts. */
|
|
42
46
|
preferred: MergePreferredSide;
|
|
47
|
+
/** Scalar-conflict selection contract used by the item driver. */
|
|
48
|
+
conflict_resolution: "preferred_side" | "stable_value_order";
|
|
43
49
|
/** Hashes proving the retained and discarded values without publishing them. */
|
|
44
50
|
decisions: Array<{
|
|
45
51
|
field: string;
|
|
@@ -65,14 +71,24 @@ export declare function writeMergeReceipt(params: {
|
|
|
65
71
|
cwd: string;
|
|
66
72
|
itemPath: string;
|
|
67
73
|
preferred: MergePreferredSide;
|
|
74
|
+
conflictResolution?: "preferred_side" | "stable_value_order";
|
|
68
75
|
fieldsFromTheirs: string[];
|
|
69
76
|
unionFields: string[];
|
|
70
77
|
decisions: ItemMergeConflictDecision[];
|
|
71
78
|
}): Promise<MergeDecisionReceipt | null>;
|
|
72
|
-
/** Read
|
|
79
|
+
/** Read clone-local receipts with explicit reconciled/lossless classification controls. */
|
|
73
80
|
export declare function listMergeReceipts(cwd: string, options?: {
|
|
74
81
|
includeReconciled?: boolean;
|
|
82
|
+
includeLossless?: boolean;
|
|
83
|
+
pmRoot?: string;
|
|
75
84
|
}): Promise<MergeDecisionReceipt[]>;
|
|
85
|
+
/** Split merge provenance into receipts with discarded values and receipts whose composition was lossless. */
|
|
86
|
+
export declare function partitionMergeReceipts(receipts: MergeDecisionReceipt[]): {
|
|
87
|
+
/** Receipts that require an explicit decision because at least one competing scalar value was discarded. */
|
|
88
|
+
pendingDecisions: MergeDecisionReceipt[];
|
|
89
|
+
/** Receipts that record provenance without a discarded competing scalar value. */
|
|
90
|
+
lossless: MergeDecisionReceipt[];
|
|
91
|
+
};
|
|
76
92
|
/** Mark a receipt as represented by a committed merge history event. */
|
|
77
93
|
export declare function markMergeReceiptReconciled(cwd: string, receipt: MergeDecisionReceipt): Promise<void>;
|
|
78
94
|
/** Report pending or historical clone-local merge decisions. */
|