@unbrained/pm-cli 2026.10.7 → 2026.10.8
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 +15 -0
- package/dist/cli-bundle/bundle-manifest.json +152 -152
- package/dist/cli-bundle/chunks/chunk-34L2BS2Z.js +3 -0
- package/dist/cli-bundle/chunks/chunk-FOLSEOJ2.js +20 -0
- package/dist/cli-bundle/chunks/{chunk-A4QWRU7D.js → chunk-HFCIAXLP.js} +5 -5
- package/dist/cli-bundle/chunks/chunk-JDTBPW4Y.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-TG3IOQUG.js → chunk-K6E2FFUT.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-VU77O6HC.js → chunk-L7U5FSZ5.js} +2 -2
- package/dist/cli-bundle/chunks/{chunk-N2PFAWVV.js → chunk-MJVRF67I.js} +3 -3
- package/dist/cli-bundle/chunks/{chunk-GJ2OJKRM.js → chunk-OG66KEOF.js} +79 -79
- package/dist/cli-bundle/chunks/{chunk-MOXX7D3F.js → chunk-RCFZ6H2Y.js} +2 -2
- package/dist/cli-bundle/chunks/chunk-TNU56MZI.js +8 -0
- package/dist/cli-bundle/chunks/chunk-UGFN5NJ2.js +2 -0
- package/dist/cli-bundle/chunks/{chunk-TON7H63A.js → chunk-ZBVAZ7XX.js} +53 -52
- package/dist/cli-bundle/chunks/{chunk-DWH555SN.js → chunk-ZHIMZ65M.js} +16 -16
- package/dist/cli-bundle/chunks/{register-list-query-CBJELTDX.js → register-list-query-PYVSPGPV.js} +2 -2
- package/dist/cli-bundle/chunks/{register-mutation-JRH6EGSE.js → register-mutation-WXP3YLIN.js} +2 -2
- package/dist/cli-bundle/chunks/register-operations-WL25C3NP.js +2 -0
- package/dist/cli-bundle/chunks/register-setup-PFKYNEQI.js +2 -0
- package/dist/cli-bundle/focused-chunks/chunk-2KSPGWLH.js +20 -0
- package/dist/cli-bundle/focused-chunks/{chunk-PBNQZV33.js → chunk-6TKAFFEB.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-EPOCI7ZX.js → chunk-A3W6HFFO.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-2YICTWWA.js → chunk-BDT5EALU.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-3BKRCR57.js → chunk-DRHJOG5X.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-XIGFEA3W.js → chunk-EOUORVJA.js} +2 -2
- package/dist/cli-bundle/focused-chunks/chunk-F2ME5MJY.js +3 -0
- package/dist/cli-bundle/focused-chunks/{chunk-QY4Z23QC.js → chunk-L3CZNKZE.js} +11 -11
- package/dist/cli-bundle/focused-chunks/{chunk-QEYEDXRI.js → chunk-LZQGEVKT.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-FWWFCLDM.js → chunk-MW2TQHZ3.js} +60 -59
- package/dist/cli-bundle/focused-chunks/{chunk-HMG5F5EC.js → chunk-OLCJ2PJS.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-SIR5RFJX.js → chunk-OSKXYRYZ.js} +27 -27
- package/dist/cli-bundle/focused-chunks/{chunk-NRSA5ZB2.js → chunk-PBPPIGUL.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-7X3QD5V4.js → chunk-PEBOVLEG.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-4FKCHJGV.js → chunk-V3EPBB6V.js} +2 -2
- package/dist/cli-bundle/focused-chunks/{chunk-3NSZ5C4A.js → chunk-XT7JAVHI.js} +2 -2
- package/dist/cli-bundle/main.js +2 -2
- 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 +2 -2
- 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 +51 -50
- 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 +4 -4
- package/dist/core/extensions/item-fields.d.ts +6 -1
- package/dist/core/extensions/item-fields.js +1 -1
- package/dist/core/fs/fs-utils.d.ts +19 -4
- package/dist/core/fs/fs-utils.js +2 -2
- package/dist/core/lock/lock.d.ts +9 -2
- package/dist/core/lock/lock.js +2 -2
- package/dist/core/store/settings.js +2 -2
- package/dist/core/telemetry/runtime.d.ts +1 -1
- package/dist/core/telemetry/runtime.js +4 -4
- package/dist/sdk/generated/generated-error-code-catalog-part-2.js +1 -1
- package/dist/sdk/governance/health.js +2 -2
- package/dist/sdk/history-repair.js +1 -1
- package/dist/sdk/item-transaction.js +1 -1
- package/dist/sdk/merge/abandoned-receipts.js +1 -1
- package/dist/sdk/merge/driver.js +1 -1
- package/dist/sdk/merge/install.js +3 -2
- package/dist/sdk/merge/receipt-operation.d.ts +5 -5
- package/dist/sdk/merge/receipt-operation.js +1 -1
- package/dist/sdk/merge/receipts.d.ts +1 -1
- package/dist/sdk/merge/receipts.js +3 -3
- package/dist/sdk/merge/worktree-config.d.ts +2 -0
- package/dist/sdk/merge/worktree-config.js +1 -1
- package/dist/sdk/public-surface.json +1 -1
- package/docs/BUILD_AND_RELEASE_ACCEPTANCE.md +36 -100
- package/docs/MERGE_SAFETY.md +61 -6
- package/docs/PACKED_FIRST_RUN.md +26 -42
- package/docs/README.md +1 -0
- package/docs/SDK_AUDITED_MUTATIONS.md +18 -0
- package/docs/SDK_STORAGE_LIFECYCLE.md +35 -0
- package/docs/generated/REFUSAL_CLOSURE_CENSUS.md +4 -3
- package/marketplace.json +2 -2
- 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/package.json +1 -1
- package/packages/pm-digital-twin/package.json +1 -1
- package/packages/pm-governance-audit/package.json +1 -1
- package/packages/pm-guide-shell/package.json +1 -1
- package/packages/pm-kanban/package.json +1 -1
- package/packages/pm-lifecycle-hooks/package.json +1 -1
- package/packages/pm-linked-test-adapters/package.json +1 -1
- package/packages/pm-search-advanced/package.json +1 -1
- package/packages/pm-templates/package.json +1 -1
- package/packages/pm-todos/package.json +1 -1
- package/packages/pm-vcs/package.json +1 -1
- package/plugins/pm-claude/.claude-plugin/plugin.json +1 -1
- package/plugins/pm-claude/package.json +2 -2
- package/plugins/pm-codex/.codex-plugin/plugin.json +1 -1
- package/plugins/pm-codex/package.json +2 -2
- package/plugins/pm-codex/plugin.json +1 -1
- package/runtime-dependencies.json +2 -2
- package/dist/cli-bundle/chunks/chunk-754AV3DC.js +0 -8
- package/dist/cli-bundle/chunks/chunk-CEM35QB2.js +0 -2
- package/dist/cli-bundle/chunks/chunk-CMIU2NDK.js +0 -20
- package/dist/cli-bundle/chunks/chunk-GSQK3VUT.js +0 -2
- package/dist/cli-bundle/chunks/chunk-WUOFG4JY.js +0 -3
- package/dist/cli-bundle/chunks/register-operations-FYV7CUBF.js +0 -2
- package/dist/cli-bundle/chunks/register-setup-M5VO6JUH.js +0 -2
- package/dist/cli-bundle/focused-chunks/chunk-3RJ4VK7U.js +0 -3
- package/dist/cli-bundle/focused-chunks/chunk-H5VREEUE.js +0 -20
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3fe6f853-6742-5305-b722-0cc74547f367")}catch{}})();import{runHistoryRepair}from"../history-repair.js";import{isOriginalGitStateRestored}from"./receipt-operation.js";import{markMergeReceiptReconciled,summarizeMergeReceipt}from"./receipts.js";async function settleAbandonedMergeReceipts(params){if(params.cwd===null)return[];const settled=[];for(const receipt of params.receipts){if(receipt.operation===void 0||!await isOriginalGitStateRestored(params.cwd,receipt.item_path,receipt.operation))continue;const mergeAbandonmentProof={gitWorkspaceRoot:params.cwd,receipt};await runHistoryRepair(receipt.item_id,{dryRun:!0,mergeAbandonmentProof},params.global),params.dryRun||(await runHistoryRepair(receipt.item_id,{author:params.author??params.global.author,mergeAbandonmentProof,message:params.message??`Settle ${receipt.operation.kind} receipt after exact original Git state restoration`,auditOperation:"merge_reconcile",forceAuditEntry:!0,auditContext:{merge:{abandoned_receipts:[{...summarizeMergeReceipt(receipt),reason:"original_git_state_restored",operation:receipt.operation}]}}},params.global),await markMergeReceiptReconciled(params.cwd,receipt,{requireExisting:!0,settlement:"original_git_state_restored"})),settled.push(receipt.id)}return settled}export{settleAbandonedMergeReceipts};
|
|
2
2
|
//# sourceMappingURL=abandoned-receipts.js.map
|
package/dist/sdk/merge/driver.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="932450d7-963b-566b-a5ad-1b577a895e8e")}catch{}})();import{readFile,writeFile}from"node:fs/promises";import path from"node:path";import{getActiveExtensionRegistrations}from"../../core/extensions/index.js";import{collectRegisteredItemFieldNames}from"../../core/extensions/item-fields.js";import{pathExists}from"../../core/fs/fs-utils.js";import{parseItemDocument}from"../../core/item/item-format.js";import{EXIT_CODE}from"../../core/shared/constants.js";import{PmCliError}from"../../core/shared/errors.js";import{nowIso}from"../../core/shared/time.js";import{getSettingsPath,resolvePmRoot}from"../../core/store/paths.js";import{readSettings}from"../../core/store/settings.js";import{hashItemScalarDecisionValue,mergeHistoryStreams,mergeItemDocuments,mergeJsonDocuments,mergeRelationshipEventStreams}from"./three-way.js";import{captureMergeReceiptOperation}from"./receipt-operation.js";import{summarizeMergeReceipt,writeMergeReceipt}from"./receipts.js";const MERGE_DRIVER_ARTIFACT_VALUES=["item","history","relationship","json"];function resolveArtifact(value){const normalized=value.trim().toLowerCase();if(MERGE_DRIVER_ARTIFACT_VALUES.includes(normalized))return normalized;throw new PmCliError(`Unknown merge artifact "${value}". Supported values: ${MERGE_DRIVER_ARTIFACT_VALUES.join(", ")}.`,EXIT_CODE.USAGE)}function resolvePreferredSide(value){if(value===void 0)return"ours";const normalized=value.trim().toLowerCase();if(normalized==="ours"||normalized==="theirs")return normalized;throw new PmCliError(`Unknown --prefer value "${value}". Supported values: ours, theirs.`,EXIT_CODE.USAGE)}async function readSideFile(filePath,label){try{return await readFile(filePath,"utf8")}catch{throw new PmCliError(`Cannot read merge ${label} file at ${filePath}.`,EXIT_CODE.NOT_FOUND)}}async function loadOptionalSettings(global2){const pmRoot=resolvePmRoot(process.cwd(),global2.path);return await pathExists(getSettingsPath(pmRoot))?readSettings(pmRoot):null}function itemFormatForPath(filePath,settings){return filePath.endsWith(".md")?"json_markdown":filePath.endsWith(".toon")?"toon":settings?.item_format??"toon"}async function runMergeDriver(options,global2){const artifact=resolveArtifact(options.artifact),preferred=resolvePreferredSide(options.prefer),outputPath=path.resolve(options.outputPath??options.oursPath),[baseRaw,oursRaw,theirsRaw]=await Promise.all([readSideFile(options.basePath,"base"),readSideFile(options.oursPath,"ours"),readSideFile(options.theirsPath,"theirs")]);let merged,receiptInput;const conflicts=[],result={};if(artifact==="history"){const historyMerge=mergeHistoryStreams(baseRaw,oursRaw,theirsRaw);merged=historyMerge.merged,result.history={strategy:historyMerge.strategy,common_entries:historyMerge.common_entries,entries_from_ours:historyMerge.entries_from_ours,entries_from_theirs:historyMerge.entries_from_theirs,entries_total:historyMerge.entries_total,reanchored:historyMerge.reanchored}}else if(artifact==="relationship"){const relationshipMerge=mergeRelationshipEventStreams(baseRaw,oursRaw,theirsRaw);merged=relationshipMerge.merged,result.relationship={strategy:relationshipMerge.strategy,common_entries:relationshipMerge.common_entries,entries_from_ours:relationshipMerge.entries_from_ours,entries_from_theirs:relationshipMerge.entries_from_theirs,entries_total:relationshipMerge.entries_total,reanchored:relationshipMerge.reanchored}}else if(artifact==="item"){const settings=await loadOptionalSettings(global2),itemFormat=itemFormatForPath(options.itemPath??outputPath,settings),extensionFieldNames=collectRegisteredItemFieldNames(getActiveExtensionRegistrations()),itemMerge=mergeItemDocuments(baseRaw,oursRaw,theirsRaw,{format:itemFormat,schema:settings?.schema,extensionFieldNames,preferred,conflictResolution:"latest_document_update"});if(merged=itemMerge.merged,conflicts.push(...itemMerge.conflict_fields),result.item={fields_from_theirs:itemMerge.fields_from_theirs,union_fields:itemMerge.union_fields,conflict_resolution:"latest_document_update",requested_preference_applied:!1},options.itemPath!==void 0){const mergedDocument=parseItemDocument(merged,{format:itemFormat,schema:settings?.schema,extensionFieldNames}),mergedMetadata=mergedDocument.metadata,receiptFields=[...new Set([...itemMerge.fields_from_theirs,...itemMerge.union_fields,...itemMerge.conflict_decisions.map(decision=>decision.field)])];receiptInput={cwd:process.cwd(),itemPath:options.itemPath,preferred,conflictResolution:"latest_document_update",fieldsFromTheirs:itemMerge.fields_from_theirs,unionFields:itemMerge.union_fields,mergedFieldHashes:Object.fromEntries(receiptFields.map(field=>[field,hashItemScalarDecisionValue(field==="body"?mergedDocument.body:mergedMetadata[field])])),decisions:itemMerge.conflict_decisions,operation:await captureMergeReceiptOperation(process.cwd(),options.itemPath,oursRaw)}}}else{const jsonMerge=mergeJsonDocuments(baseRaw,oursRaw,theirsRaw,{preferred});merged=jsonMerge.merged,conflicts.push(...jsonMerge.conflict_paths),result.json={paths_from_theirs:jsonMerge.paths_from_theirs}}if(await writeFile(outputPath,merged,"utf8"),receiptInput!==void 0){const receipt=await writeMergeReceipt(receiptInput);receipt!==null&&(result.receipt=summarizeMergeReceipt(receipt))}const guidance=[];if(conflicts.length>0){const receiptGuidance=result.receipt===void 0?'Run "pm merge report" to inspect clone-local merge evidence.':`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.`;guidance.push(`Both branches changed ${conflicts.join(", ")}; the item driver kept the value from the later document update, with stable value order only as an equal-timestamp tie-break. --prefer does not apply to convergent item scalar conflicts. ${receiptGuidance} Review the merged file, re-apply the discarded change if needed, then "git add" it.`)}return artifact==="history"&&result.history?.reanchored&&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.'),{ok:conflicts.length===0,artifact,output_path:outputPath,requested_preference:preferred,conflicts,...result,guidance,generated_at:nowIso()}}export{MERGE_DRIVER_ARTIFACT_VALUES,runMergeDriver};
|
|
2
2
|
//# sourceMappingURL=driver.js.map
|
|
@@ -1,7 +1,8 @@
|
|
|
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]="5bcde7f0-1785-530a-91bb-80f2793fb8cf")}catch{}})();import{assertInitializedTracker}from"../environment/tracker-preflight.js";import{isFileMissingError,readFileIfExists,writeFileAtomic}from"../../core/fs/fs-utils.js";import{access,readFile,realpath}from"node:fs/promises";import{constants}from"node:fs";import{execFile}from"node:child_process";import path from"node:path";import{promisify}from"node:util";import{pathExists}from"../../core/fs/fs-utils.js";import{resolveItemTypeRegistry}from"../../core/item/type-registry.js";import{acquireLock}from"../../core/lock/lock.js";import{resolvePmPackageRootFromModule}from"../../core/packages/root.js";import{EXIT_CODE}from"../../core/shared/constants.js";import{PmCliError}from"../../core/shared/errors.js";import{resolveAuthor}from"../../core/shared/author.js";import{nowIso}from"../../core/shared/time.js";import{resolvePmRoot}from"../../core/store/paths.js";import{readSettings,resolveGovernanceKnobs}from"../../core/store/settings.js";import{isPathOutsideRoot}from"../workspace.js";import{resolveSourceContextWritePolicy}from"../environment/source-context.js";import{gitWorkspaceEnvironment,resolveMergeDriverConfigScope}from"./worktree-config.js";import{discoverProjectRuntimeVersionPins}from"../environment/project-runtime-compatibility.js";const execFileAsync=promisify(execFile),PM_GITATTRIBUTES_START="# pm-cli:merge-drivers:start",PM_GITATTRIBUTES_END="# pm-cli:merge-drivers:end",PM_GITATTRIBUTES_V2_START="# pm-cli:merge-drivers:v2:start",PM_GITATTRIBUTES_V2_END="# pm-cli:merge-drivers:v2:end",MERGE_FENCE_LOCK_ID="merge-fence",MERGE_ATTRIBUTES_LOCK_ID="merge-attributes";function quoteMergeDriverArgument(value){return`'${value.replaceAll("'",`'"'"'`)}'`}async function resolveMatchingBunLauncher(candidate,version){const resolvedCandidate=await realpath(candidate);if(/(?:^|[\\/])bun-node-[^\\/]+[\\/]bun(?:\.exe)?$/iu.test(resolvedCandidate))return;const{stdout}=await execFileAsync(candidate,["--version"],{encoding:"utf8",windowsHide:!0,timeout:1e4});return stdout.trim()===version?resolvedCandidate:void 0}async function resolveMergeDriverCliCommand(){const packageRoot=resolvePmPackageRootFromModule(import.meta.url,["../../.."]);let executable=process.execPath,bunLauncherFound=!1;const runtimeIdentity=await realpath(process.execPath),bunVersion=process.versions.bun,pathCandidates=(process.env.PATH??"").split(path.delimiter).filter(directory=>path.isAbsolute(directory)).map(directory=>path.join(directory,bunVersion===void 0?path.basename(process.execPath):process.platform==="win32"?"bun.exe":"bun")),candidates=bunVersion===void 0?pathCandidates:[process.env.npm_execpath??"",...pathCandidates,runtimeIdentity].filter(candidate=>path.isAbsolute(candidate)&&/^(?:bun|bun\.exe)$/iu.test(path.basename(candidate)));for(const candidate of candidates)try{if(await access(candidate,constants.X_OK),bunVersion!==void 0){const launcher=await resolveMatchingBunLauncher(candidate,bunVersion);if(launcher!==void 0){executable=launcher,bunLauncherFound=!0;break}continue}if(candidate!==runtimeIdentity&&await realpath(candidate)===runtimeIdentity){executable=candidate;break}}catch{}if(bunVersion!==void 0&&!bunLauncherFound)throw new PmCliError("Cannot install Bun merge drivers without a durable executable matching the current Bun version.",EXIT_CODE.DEPENDENCY_FAILED,{code:"merge_bun_launcher_unavailable",why:"The current Bun process may be a temporary bunx launcher that Git cannot reuse after this command exits.",nextSteps:["Run with a durable version-matched Bun executable, expose one on an absolute PATH entry, or invoke pm through a Bun runner that publishes an absolute npm_execpath.","Retry pm merge install, then check pm health --strict-exit before merging branches."]});return`${quoteMergeDriverArgument(executable)} ${quoteMergeDriverArgument(path.join(packageRoot,"dist","cli.js"))}`}const MERGE_DRIVER_DEFINITIONS=[{key:"pm-item-toon",name:"pm field-aware TOON item document merge",artifact:"item",itemPath:"%P"},{key:"pm-item-markdown",name:"pm field-aware JSON-markdown item document merge",artifact:"item",itemPath:"%P"},{key:"pm-history",name:"pm append-only history stream merge",artifact:"history",itemPath:void 0},{key:"pm-relationship",name:"pm append-only relationship event store merge",artifact:"relationship",itemPath:void 0},{key:"pm-json",name:"pm key-level JSON config merge",artifact:"json",itemPath:void 0}];function resolveMergeInstallContext(options){const explicitPath=options.explicitPath?.trim(),sourceWorkspaceRoot=options.environment.PM_SOURCE_WORKSPACE_ROOT?.trim(),sourcePmRoot=options.environment.PM_SOURCE_PM_PATH?.trim(),sourcePolicy=resolveSourceContextWritePolicy(options.environment),sourceCoordinatesAvailable=!!(sourceWorkspaceRoot&&sourcePmRoot),sourceContextSelected=explicitPath===void 0&&sourceCoordinatesAvailable&&(options.dryRun||sourcePolicy.source_writes_allowed);if(explicitPath!==void 0){const pmRoot=resolvePmRoot(options.cwd,explicitPath);return{pm_root:pmRoot,workspace_start:pmRoot,source_coordinates_available:sourceCoordinatesAvailable,source_context_selected:!1,source_policy:sourcePolicy}}return sourceContextSelected?{pm_root:path.resolve(sourcePmRoot),workspace_start:path.resolve(sourceWorkspaceRoot),source_coordinates_available:!0,source_context_selected:!0,source_policy:sourcePolicy}:{pm_root:sourceCoordinatesAvailable?resolvePmRoot(options.cwd,".agents/pm"):resolvePmRoot(options.cwd),workspace_start:options.cwd,source_coordinates_available:sourceCoordinatesAvailable,source_context_selected:!1,source_policy:sourcePolicy}}async function findGitWorkspaceRoot(cwd){try{const{stdout}=await execFileAsync("git",["rev-parse","--show-toplevel"],{cwd,env:gitWorkspaceEnvironment(),encoding:"utf8",windowsHide:!0,timeout:1e4});return await realpath(stdout.trim())}catch{return null}}async function resolveGitWorkspaceRoot(cwd){const workspaceRoot=await findGitWorkspaceRoot(cwd);if(workspaceRoot===null)throw new PmCliError("pm merge install requires a git repository (merge drivers are git configuration).",EXIT_CODE.USAGE);return workspaceRoot}function toPosixRelative(fromPath,toPath){return path.relative(fromPath,toPath).replaceAll("\\","/")}function quoteGitAttributePattern(value){return`"${value.replaceAll("\\","\\\\").replaceAll('"','\\"')}"`}function readSingleQuotedArgument(command,offset){if(command[offset]!=="'")return null;let value="";for(let index=offset+1;index<command.length;index+=1){if(command.startsWith(`'"'"'`,index)){value+="'",index+=4;continue}if(command[index]==="'")return{value,nextOffset:index+1};value+=command[index]}return null}async function isMergeDriverWorkspaceCompatible(packageRoot,workspaceRoot,version){if(discoverProjectRuntimeVersionPins(workspaceRoot).filter(pin=>pin.constraint==="exact").some(pin=>pin.version!==version))return!1;const driverWorkspace=await findGitWorkspaceRoot(packageRoot);if(driverWorkspace!==null&&driverWorkspace!==await realpath(workspaceRoot)){const commonDirectories=await Promise.all([driverWorkspace,workspaceRoot].map(async cwd=>{const result=await execFileAsync("git",["rev-parse","--path-format=absolute","--git-common-dir"],{cwd,env:gitWorkspaceEnvironment(),timeout:1e4});return realpath(result.stdout.trim())}));if(commonDirectories[0]===commonDirectories[1])return!1}return!0}async function isPortableMergeDriverCommand(configured,expectedSuffix,workspaceRoot){const nodeArgument=readSingleQuotedArgument(configured,0);if(nodeArgument===null||configured[nodeArgument.nextOffset]!==" ")return!1;const cliArgument=readSingleQuotedArgument(configured,nodeArgument.nextOffset+1);if(cliArgument===null||configured.slice(cliArgument.nextOffset)!==expectedSuffix||!/^(?:node|bun)(?:\.exe)?$/iu.test(path.basename(nodeArgument.value))||path.basename(cliArgument.value)!=="cli.js"||path.basename(path.dirname(cliArgument.value))!=="dist"||!await pathExists(nodeArgument.value)||!await pathExists(cliArgument.value))return!1;try{const packageRoot=path.dirname(path.dirname(cliArgument.value)),manifest=JSON.parse(await readFile(path.join(packageRoot,"package.json"),"utf8")),pmBin=typeof manifest.bin=="string"?manifest.bin:manifest.bin?.pm;return await isMergeDriverWorkspaceCompatible(packageRoot,workspaceRoot,manifest.version)?manifest.name==="@unbrained/pm-cli"&&pmBin==="dist/cli.js":!1}catch{return!1}}function buildMergeAttributePatterns(trackerRelativeRoot,typeFolders){const prefix=trackerRelativeRoot.length>0?`${trackerRelativeRoot}/`:"",patterns=[`${quoteGitAttributePattern(`${prefix}**/*.toon`)} merge=pm-item-toon`,`${quoteGitAttributePattern(`${prefix}**/*.md`)} merge=pm-item-markdown`];for(const folder of typeFolders)patterns.push(`${quoteGitAttributePattern(`${prefix}${folder}/*.toon`)} merge=pm-item-toon`),patterns.push(`${quoteGitAttributePattern(`${prefix}${folder}/*.md`)} merge=pm-item-markdown`);return patterns.push(`${quoteGitAttributePattern(`${prefix}**/*.jsonl`)} merge=pm-relationship`),patterns.push(`${quoteGitAttributePattern(`${prefix}history/*.jsonl`)} merge=pm-history`),patterns.push(`${quoteGitAttributePattern(`${prefix}settings.json`)} merge=pm-json`),patterns.push(`${quoteGitAttributePattern(`${prefix}**/*.json`)} merge=pm-json`),patterns.push(`${quoteGitAttributePattern(`${prefix}extensions/**`)} -merge`),patterns.push(`${quoteGitAttributePattern(`${prefix}extensions/.managed-extensions.json`)} merge=pm-json`),patterns}function managedMergeBlocks(content){const blocks=[];let cursor=0;for(;cursor<content.length;){const legacyStart=content.indexOf(PM_GITATTRIBUTES_START,cursor),versionedStart=content.indexOf(PM_GITATTRIBUTES_V2_START,cursor),start=legacyStart===-1?versionedStart:versionedStart===-1?legacyStart:Math.min(legacyStart,versionedStart);if(start===-1)break;const versioned=start===versionedStart,startMarker=versioned?PM_GITATTRIBUTES_V2_START:PM_GITATTRIBUTES_START,endMarker=versioned?PM_GITATTRIBUTES_V2_END:PM_GITATTRIBUTES_END,closing=content.indexOf(endMarker,start+startMarker.length),end=closing===-1?content.length:closing+endMarker.length;blocks.push({start,end,closed:closing!==-1,lines:content.slice(start+startMarker.length,closing===-1?end:closing).split(`
|
|
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]="36ccb98d-6645-52fe-aac2-be11f3a63c25")}catch{}})();import{assertInitializedTracker}from"../environment/tracker-preflight.js";import{isFileMissingError,readFileIfExists,writeFileAtomic}from"../../core/fs/fs-utils.js";import{access,readFile,realpath}from"node:fs/promises";import{constants}from"node:fs";import{execFile}from"node:child_process";import path from"node:path";import{promisify}from"node:util";import{pathExists}from"../../core/fs/fs-utils.js";import{resolveItemTypeRegistry}from"../../core/item/type-registry.js";import{acquireLock}from"../../core/lock/lock.js";import{resolvePmPackageRootFromModule}from"../../core/packages/root.js";import{EXIT_CODE}from"../../core/shared/constants.js";import{PmCliError}from"../../core/shared/errors.js";import{resolveAuthor}from"../../core/shared/author.js";import{nowIso}from"../../core/shared/time.js";import{resolvePmRoot}from"../../core/store/paths.js";import{readSettings,resolveGovernanceKnobs}from"../../core/store/settings.js";import{isPathOutsideRoot}from"../workspace.js";import{resolveSourceContextWritePolicy}from"../environment/source-context.js";import{gitWorkspaceEnvironment,resolveMergeDriverConfigScope,writeMergeDriverGitConfig}from"./worktree-config.js";import{discoverProjectRuntimeVersionPins}from"../environment/project-runtime-compatibility.js";const execFileAsync=promisify(execFile),PM_GITATTRIBUTES_START="# pm-cli:merge-drivers:start",PM_GITATTRIBUTES_END="# pm-cli:merge-drivers:end",PM_GITATTRIBUTES_V2_START="# pm-cli:merge-drivers:v2:start",PM_GITATTRIBUTES_V2_END="# pm-cli:merge-drivers:v2:end",MERGE_FENCE_LOCK_ID="merge-fence",MERGE_ATTRIBUTES_LOCK_ID="merge-attributes";function quoteMergeDriverArgument(value){return`'${value.replaceAll("'",`'"'"'`)}'`}async function resolveMatchingBunLauncher(candidate,version){const resolvedCandidate=await realpath(candidate);if(/(?:^|[\\/])bun-node-[^\\/]+[\\/]bun(?:\.exe)?$/iu.test(resolvedCandidate))return;const{stdout}=await execFileAsync(candidate,["--version"],{encoding:"utf8",windowsHide:!0,timeout:1e4});return stdout.trim()===version?resolvedCandidate:void 0}async function resolveMergeDriverCliCommand(){const packageRoot=resolvePmPackageRootFromModule(import.meta.url,["../../.."]);let executable=process.execPath,bunLauncherFound=!1;const runtimeIdentity=await realpath(process.execPath),bunVersion=process.versions.bun,pathCandidates=(process.env.PATH??"").split(path.delimiter).filter(directory=>path.isAbsolute(directory)).map(directory=>path.join(directory,bunVersion===void 0?path.basename(process.execPath):process.platform==="win32"?"bun.exe":"bun")),candidates=bunVersion===void 0?pathCandidates:[process.env.npm_execpath??"",...pathCandidates,runtimeIdentity].filter(candidate=>path.isAbsolute(candidate)&&/^(?:bun|bun\.exe)$/iu.test(path.basename(candidate)));for(const candidate of candidates)try{if(await access(candidate,constants.X_OK),bunVersion!==void 0){const launcher=await resolveMatchingBunLauncher(candidate,bunVersion);if(launcher!==void 0){executable=launcher,bunLauncherFound=!0;break}continue}if(candidate!==runtimeIdentity&&await realpath(candidate)===runtimeIdentity){executable=candidate;break}}catch{}if(bunVersion!==void 0&&!bunLauncherFound)throw new PmCliError("Cannot install Bun merge drivers without a durable executable matching the current Bun version.",EXIT_CODE.DEPENDENCY_FAILED,{code:"merge_bun_launcher_unavailable",why:"The current Bun process may be a temporary bunx launcher that Git cannot reuse after this command exits.",nextSteps:["Run with a durable version-matched Bun executable, expose one on an absolute PATH entry, or invoke pm through a Bun runner that publishes an absolute npm_execpath.","Retry pm merge install, then check pm health --strict-exit before merging branches."]});return`${quoteMergeDriverArgument(executable)} ${quoteMergeDriverArgument(path.join(packageRoot,"dist","cli.js"))}`}const MERGE_DRIVER_DEFINITIONS=[{key:"pm-item-toon",name:"pm field-aware TOON item document merge",artifact:"item",itemPath:"%P"},{key:"pm-item-markdown",name:"pm field-aware JSON-markdown item document merge",artifact:"item",itemPath:"%P"},{key:"pm-history",name:"pm append-only history stream merge",artifact:"history",itemPath:void 0},{key:"pm-relationship",name:"pm append-only relationship event store merge",artifact:"relationship",itemPath:void 0},{key:"pm-json",name:"pm key-level JSON config merge",artifact:"json",itemPath:void 0}];function resolveMergeInstallContext(options){const explicitPath=options.explicitPath?.trim(),sourceWorkspaceRoot=options.environment.PM_SOURCE_WORKSPACE_ROOT?.trim(),sourcePmRoot=options.environment.PM_SOURCE_PM_PATH?.trim(),sourcePolicy=resolveSourceContextWritePolicy(options.environment),sourceCoordinatesAvailable=!!(sourceWorkspaceRoot&&sourcePmRoot),sourceContextSelected=explicitPath===void 0&&sourceCoordinatesAvailable&&(options.dryRun||sourcePolicy.source_writes_allowed);if(explicitPath!==void 0){const pmRoot=resolvePmRoot(options.cwd,explicitPath);return{pm_root:pmRoot,workspace_start:pmRoot,source_coordinates_available:sourceCoordinatesAvailable,source_context_selected:!1,source_policy:sourcePolicy}}return sourceContextSelected?{pm_root:path.resolve(sourcePmRoot),workspace_start:path.resolve(sourceWorkspaceRoot),source_coordinates_available:!0,source_context_selected:!0,source_policy:sourcePolicy}:{pm_root:sourceCoordinatesAvailable?resolvePmRoot(options.cwd,".agents/pm"):resolvePmRoot(options.cwd),workspace_start:options.cwd,source_coordinates_available:sourceCoordinatesAvailable,source_context_selected:!1,source_policy:sourcePolicy}}async function findGitWorkspaceRoot(cwd){try{const{stdout}=await execFileAsync("git",["rev-parse","--show-toplevel"],{cwd,env:gitWorkspaceEnvironment(),encoding:"utf8",windowsHide:!0,timeout:1e4});return await realpath(stdout.trim())}catch{return null}}async function resolveGitWorkspaceRoot(cwd){const workspaceRoot=await findGitWorkspaceRoot(cwd);if(workspaceRoot===null)throw new PmCliError("pm merge install requires a git repository (merge drivers are git configuration).",EXIT_CODE.USAGE);return workspaceRoot}function toPosixRelative(fromPath,toPath){return path.relative(fromPath,toPath).replaceAll("\\","/")}function quoteGitAttributePattern(value){return`"${value.replaceAll("\\","\\\\").replaceAll('"','\\"')}"`}function readSingleQuotedArgument(command,offset){if(command[offset]!=="'")return null;let value="";for(let index=offset+1;index<command.length;index+=1){if(command.startsWith(`'"'"'`,index)){value+="'",index+=4;continue}if(command[index]==="'")return{value,nextOffset:index+1};value+=command[index]}return null}async function isMergeDriverWorkspaceCompatible(packageRoot,workspaceRoot,version){if(discoverProjectRuntimeVersionPins(workspaceRoot).filter(pin=>pin.constraint==="exact").some(pin=>pin.version!==version))return!1;const driverWorkspace=await findGitWorkspaceRoot(packageRoot);if(driverWorkspace!==null&&driverWorkspace!==await realpath(workspaceRoot)){const commonDirectories=await Promise.all([driverWorkspace,workspaceRoot].map(async cwd=>{const result=await execFileAsync("git",["rev-parse","--path-format=absolute","--git-common-dir"],{cwd,env:gitWorkspaceEnvironment(),timeout:1e4});return realpath(result.stdout.trim())}));if(commonDirectories[0]===commonDirectories[1])return!1}return!0}async function isPortableMergeDriverCommand(configured,expectedSuffix,workspaceRoot){const nodeArgument=readSingleQuotedArgument(configured,0);if(nodeArgument===null||configured[nodeArgument.nextOffset]!==" ")return!1;const cliArgument=readSingleQuotedArgument(configured,nodeArgument.nextOffset+1);if(cliArgument===null||configured.slice(cliArgument.nextOffset)!==expectedSuffix||!/^(?:node|bun)(?:\.exe)?$/iu.test(path.basename(nodeArgument.value))||path.basename(cliArgument.value)!=="cli.js"||path.basename(path.dirname(cliArgument.value))!=="dist"||!await pathExists(nodeArgument.value)||!await pathExists(cliArgument.value))return!1;try{const packageRoot=path.dirname(path.dirname(cliArgument.value)),manifest=JSON.parse(await readFile(path.join(packageRoot,"package.json"),"utf8")),pmBin=typeof manifest.bin=="string"?manifest.bin:manifest.bin?.pm;return await isMergeDriverWorkspaceCompatible(packageRoot,workspaceRoot,manifest.version)?manifest.name==="@unbrained/pm-cli"&&pmBin==="dist/cli.js":!1}catch{return!1}}function buildMergeAttributePatterns(trackerRelativeRoot,typeFolders){const prefix=trackerRelativeRoot.length>0?`${trackerRelativeRoot}/`:"",patterns=[`${quoteGitAttributePattern(`${prefix}**/*.toon`)} merge=pm-item-toon`,`${quoteGitAttributePattern(`${prefix}**/*.md`)} merge=pm-item-markdown`];for(const folder of typeFolders)patterns.push(`${quoteGitAttributePattern(`${prefix}${folder}/*.toon`)} merge=pm-item-toon`),patterns.push(`${quoteGitAttributePattern(`${prefix}${folder}/*.md`)} merge=pm-item-markdown`);return patterns.push(`${quoteGitAttributePattern(`${prefix}**/*.jsonl`)} merge=pm-relationship`),patterns.push(`${quoteGitAttributePattern(`${prefix}history/*.jsonl`)} merge=pm-history`),patterns.push(`${quoteGitAttributePattern(`${prefix}settings.json`)} merge=pm-json`),patterns.push(`${quoteGitAttributePattern(`${prefix}**/*.json`)} merge=pm-json`),patterns.push(`${quoteGitAttributePattern(`${prefix}extensions/**`)} -merge`),patterns.push(`${quoteGitAttributePattern(`${prefix}extensions/.managed-extensions.json`)} merge=pm-json`),patterns}function managedMergeBlocks(content){const blocks=[];let cursor=0;for(;cursor<content.length;){const legacyStart=content.indexOf(PM_GITATTRIBUTES_START,cursor),versionedStart=content.indexOf(PM_GITATTRIBUTES_V2_START,cursor),start=legacyStart===-1?versionedStart:versionedStart===-1?legacyStart:Math.min(legacyStart,versionedStart);if(start===-1)break;const versioned=start===versionedStart,startMarker=versioned?PM_GITATTRIBUTES_V2_START:PM_GITATTRIBUTES_START,endMarker=versioned?PM_GITATTRIBUTES_V2_END:PM_GITATTRIBUTES_END,closing=content.indexOf(endMarker,start+startMarker.length),end=closing===-1?content.length:closing+endMarker.length;blocks.push({start,end,closed:closing!==-1,lines:content.slice(start+startMarker.length,closing===-1?end:closing).split(`
|
|
2
2
|
`).map(line=>line.trim()).filter(Boolean)}),cursor=end}return blocks}function blockBelongsToTracker(lines,patterns,trackerRelativeRoot){const ownedPatterns=new Set(patterns),prefix=quoteGitAttributePattern(trackerRelativeRoot.length>0?`${trackerRelativeRoot}/`:"").slice(0,-1);return lines.some(line=>ownedPatterns.has(line)||line.startsWith(prefix)&&/^[^/]+\/\*\.(?:toon|md)" merge=pm-item-(?:toon|markdown)$/u.test(line.slice(prefix.length)))}async function reconcileGitattributesBlock(workspaceRoot,trackerRelativeRoot,patterns,dryRun){const gitattributesPath=path.join(workspaceRoot,".gitattributes"),gitDirectory=dryRun?null:(await execFileAsync("git",["rev-parse","--absolute-git-dir"],{cwd:workspaceRoot,env:gitWorkspaceEnvironment(),encoding:"utf8",windowsHide:!0,timeout:1e4})).stdout.trim(),releaseLock=gitDirectory===null?null:await acquireLock(gitDirectory,MERGE_ATTRIBUTES_LOCK_ID,120,"merge-fence",!1,!0,5e3);try{const current=await readFileIfExists(gitattributesPath)??"",block=[PM_GITATTRIBUTES_V2_START,...patterns,PM_GITATTRIBUTES_V2_END].join(`
|
|
3
3
|
`),blocks=managedMergeBlocks(current),owned=blocks.filter(candidate=>blockBelongsToTracker(candidate.lines,patterns,trackerRelativeRoot));owned.length===0&&trackerRelativeRoot===".agents/pm"&&blocks.length===1&&blocks[0].lines.every(line=>!line.includes(".agents/pm/"))&&owned.push(blocks[0]);let next;if(owned.length>0){const first=owned[0];next=current;for(const duplicate of owned.slice(1).reverse())next=`${next.slice(0,duplicate.start)}${next.slice(duplicate.end)}`;next=`${next.slice(0,first.start)}${block}${next.slice(first.end)}`}else{const prefix=current.trimEnd();next=`${prefix.length>0?`${prefix}
|
|
4
4
|
|
|
5
5
|
`:""}${block}
|
|
6
|
-
`}return next===current?{path:gitattributesPath,changed:!1}:(dryRun||await writeFileAtomic(gitattributesPath,next),{path:gitattributesPath,changed:!0})}finally{await releaseLock?.()}}function resolveProjectMergeTypeFolders(settings){const registry=resolveItemTypeRegistry(settings,null);return[...new Set(Object.values(registry.type_to_folder))].sort((left,right)=>left.localeCompare(right))}async function auditMergeAttributeFence(pmRoot,typeFolders){const resolvedRoot=path.resolve(pmRoot);let fenceDirectory=null,fenceContent="",directory=resolvedRoot;for(let depth=0;depth<8;depth+=1){const candidate=path.join(directory,".gitattributes");try{const raw=await readFile(candidate,"utf8");if(raw.includes(PM_GITATTRIBUTES_V2_START)||raw.includes(PM_GITATTRIBUTES_START)){fenceDirectory=directory,fenceContent=raw;break}}catch{}const parent=path.dirname(directory);if(parent===directory)break;directory=parent}if(fenceDirectory===null)return{status:"not_installed",missing_patterns:[],stale_patterns:[],schema_scope:"project"};const fencePath=path.join(fenceDirectory,".gitattributes"),relativeRoot=toPosixRelative(fenceDirectory,resolvedRoot),blocks=managedMergeBlocks(fenceContent),expected=buildMergeAttributePatterns(relativeRoot,typeFolders),owned=blocks.filter(block=>blockBelongsToTracker(block.lines,expected,relativeRoot)),committed=owned.flatMap(block=>block.closed?block.lines:[]),committedSet=new Set(committed),expectedSet=new Set(expected),missing=expected.filter(line=>!committedSet.has(line)),stale=committed.filter(line=>!expectedSet.has(line));return{status:owned.length!==1||!owned[0].closed||missing.length>0||stale.length>0?"drift":"ok",path:fencePath,missing_patterns:missing,stale_patterns:stale,schema_scope:"project"}}async function auditMergeDriverConfiguration(workspaceRoot){const missingKeys=[],driftedKeys=[];for(const definition of MERGE_DRIVER_DEFINITIONS){const key=`merge.${definition.key}.driver`,expectedSuffix=` merge driver ${definition.artifact} "%O" "%A" "%B"${definition.itemPath===void 0?"":` --item-path ${definition.itemPath}`}`;try{const{stdout}=await execFileAsync("git",["config","--get",key],{cwd:workspaceRoot,env:gitWorkspaceEnvironment(),encoding:"utf8",windowsHide:!0,timeout:1e4}),configured=stdout.trim();await isPortableMergeDriverCommand(configured,expectedSuffix,workspaceRoot)||driftedKeys.push(key)}catch{missingKeys.push(key)}}return{status:missingKeys.length>0?"missing":driftedKeys.length>0?"drift":"ok",missing_keys:missingKeys,drifted_keys:driftedKeys}}async function refreshMergeAttributeFenceIfInstalled(pmRoot){let workspaceRoot;try{workspaceRoot=await resolveGitWorkspaceRoot(path.resolve(pmRoot))}catch{return{status:"no_git"}}const trackerRelativeRoot=toPosixRelative(workspaceRoot,path.resolve(pmRoot)),lockSettings=await readSettings(pmRoot),owner=resolveAuthor(void 0,lockSettings.author_default),releaseLock=await acquireLock(pmRoot,MERGE_FENCE_LOCK_ID,lockSettings.locks.ttl_seconds,owner,!1,resolveGovernanceKnobs(lockSettings).force_required_for_stale_lock,lockSettings.locks.wait_ms);try{const gitattributesPath=path.join(workspaceRoot,".gitattributes");let current;try{current=await readFile(gitattributesPath,"utf8")}catch(error){if(error instanceof Error&&"code"in error&&isFileMissingError(error))return{status:"not_installed",path:gitattributesPath};throw error}if(!current.includes(PM_GITATTRIBUTES_V2_START)&&!current.includes(PM_GITATTRIBUTES_START))return{status:"not_installed",path:gitattributesPath};const settings=await readSettings(pmRoot),typeFolders=resolveProjectMergeTypeFolders(settings),outcome=await reconcileGitattributesBlock(workspaceRoot,trackerRelativeRoot,buildMergeAttributePatterns(trackerRelativeRoot,typeFolders),!1);return{status:outcome.changed?"refreshed":"unchanged",path:outcome.path}}finally{await releaseLock()}}async function runMergeInstall(options,global2){const context=resolveMergeInstallContext({cwd:process.cwd(),explicitPath:global2.path,dryRun:options.dryRun===!0,environment:process.env}),pmRoot=context.pm_root;await assertInitializedTracker(pmRoot);const workspaceRoot=await resolveGitWorkspaceRoot(context.workspace_start);return installMergeFence({pmRoot,workspaceRoot,dryRun:options.dryRun===!0})}async function
|
|
6
|
+
`}return next===current?{path:gitattributesPath,changed:!1}:(dryRun||await writeFileAtomic(gitattributesPath,next),{path:gitattributesPath,changed:!0})}finally{await releaseLock?.()}}function resolveProjectMergeTypeFolders(settings){const registry=resolveItemTypeRegistry(settings,null);return[...new Set(Object.values(registry.type_to_folder))].sort((left,right)=>left.localeCompare(right))}async function auditMergeAttributeFence(pmRoot,typeFolders){const resolvedRoot=path.resolve(pmRoot);let fenceDirectory=null,fenceContent="",directory=resolvedRoot;for(let depth=0;depth<8;depth+=1){const candidate=path.join(directory,".gitattributes");try{const raw=await readFile(candidate,"utf8");if(raw.includes(PM_GITATTRIBUTES_V2_START)||raw.includes(PM_GITATTRIBUTES_START)){fenceDirectory=directory,fenceContent=raw;break}}catch{}const parent=path.dirname(directory);if(parent===directory)break;directory=parent}if(fenceDirectory===null)return{status:"not_installed",missing_patterns:[],stale_patterns:[],schema_scope:"project"};const fencePath=path.join(fenceDirectory,".gitattributes"),relativeRoot=toPosixRelative(fenceDirectory,resolvedRoot),blocks=managedMergeBlocks(fenceContent),expected=buildMergeAttributePatterns(relativeRoot,typeFolders),owned=blocks.filter(block=>blockBelongsToTracker(block.lines,expected,relativeRoot)),committed=owned.flatMap(block=>block.closed?block.lines:[]),committedSet=new Set(committed),expectedSet=new Set(expected),missing=expected.filter(line=>!committedSet.has(line)),stale=committed.filter(line=>!expectedSet.has(line));return{status:owned.length!==1||!owned[0].closed||missing.length>0||stale.length>0?"drift":"ok",path:fencePath,missing_patterns:missing,stale_patterns:stale,schema_scope:"project"}}async function auditMergeDriverConfiguration(workspaceRoot){const missingKeys=[],driftedKeys=[];for(const definition of MERGE_DRIVER_DEFINITIONS){const key=`merge.${definition.key}.driver`,expectedSuffix=` merge driver ${definition.artifact} "%O" "%A" "%B"${definition.itemPath===void 0?"":` --item-path ${definition.itemPath}`}`;try{const{stdout}=await execFileAsync("git",["config","--get",key],{cwd:workspaceRoot,env:gitWorkspaceEnvironment(),encoding:"utf8",windowsHide:!0,timeout:1e4}),configured=stdout.trim();await isPortableMergeDriverCommand(configured,expectedSuffix,workspaceRoot)||driftedKeys.push(key)}catch{missingKeys.push(key)}}return{status:missingKeys.length>0?"missing":driftedKeys.length>0?"drift":"ok",missing_keys:missingKeys,drifted_keys:driftedKeys}}async function refreshMergeAttributeFenceIfInstalled(pmRoot){let workspaceRoot;try{workspaceRoot=await resolveGitWorkspaceRoot(path.resolve(pmRoot))}catch{return{status:"no_git"}}const trackerRelativeRoot=toPosixRelative(workspaceRoot,path.resolve(pmRoot)),lockSettings=await readSettings(pmRoot),owner=resolveAuthor(void 0,lockSettings.author_default),releaseLock=await acquireLock(pmRoot,MERGE_FENCE_LOCK_ID,lockSettings.locks.ttl_seconds,owner,!1,resolveGovernanceKnobs(lockSettings).force_required_for_stale_lock,lockSettings.locks.wait_ms);try{const gitattributesPath=path.join(workspaceRoot,".gitattributes");let current;try{current=await readFile(gitattributesPath,"utf8")}catch(error){if(error instanceof Error&&"code"in error&&isFileMissingError(error))return{status:"not_installed",path:gitattributesPath};throw error}if(!current.includes(PM_GITATTRIBUTES_V2_START)&&!current.includes(PM_GITATTRIBUTES_START))return{status:"not_installed",path:gitattributesPath};const settings=await readSettings(pmRoot),typeFolders=resolveProjectMergeTypeFolders(settings),outcome=await reconcileGitattributesBlock(workspaceRoot,trackerRelativeRoot,buildMergeAttributePatterns(trackerRelativeRoot,typeFolders),!1);return{status:outcome.changed?"refreshed":"unchanged",path:outcome.path}}finally{await releaseLock()}}async function runMergeInstall(options,global2){const context=resolveMergeInstallContext({cwd:process.cwd(),explicitPath:global2.path,dryRun:options.dryRun===!0,environment:process.env}),pmRoot=context.pm_root;await assertInitializedTracker(pmRoot);const workspaceRoot=await resolveGitWorkspaceRoot(context.workspace_start);return installMergeFence({pmRoot,workspaceRoot,dryRun:options.dryRun===!0})}async function installMergeDriverConfiguration(workspaceRoot,entries){const commonDirectory=(await execFileAsync("git",["rev-parse","--path-format=absolute","--git-common-dir"],{cwd:workspaceRoot,env:gitWorkspaceEnvironment(),timeout:1e4})).stdout.trim(),release=await acquireLock(commonDirectory,"merge-driver-config",120,"merge-install",!1,!0,5e3);try{const scope=await resolveMergeDriverConfigScope(workspaceRoot);let stdout;try{stdout=(await execFileAsync("git",["config",scope,"--null","--get-regexp","."],{cwd:workspaceRoot,env:gitWorkspaceEnvironment(),timeout:1e4})).stdout}catch(error){if(typeof error!="object"||error===null||!("code"in error)||error.code!==1)throw error;stdout=""}const current=new Map(stdout.split("\0").filter(Boolean).map(entry=>{const separator=entry.indexOf(`
|
|
7
|
+
`);return[entry.slice(0,separator),entry.slice(separator+1)]}));for(const entry of entries)current.get(entry.key)!==entry.value&&await writeMergeDriverGitConfig(workspaceRoot,[scope,entry.key,entry.value])}finally{await release()}}async function installMergeFence(options){const pmRoot=path.resolve(options.pmRoot),workspaceRoot=path.resolve(options.workspaceRoot),dryRun=options.dryRun===!0;let canonicalPmRoot,canonicalWorkspaceRoot;try{[canonicalPmRoot,canonicalWorkspaceRoot]=await Promise.all([realpath(pmRoot),realpath(workspaceRoot)])}catch(error){throw new PmCliError(`Cannot resolve tracker root ${pmRoot} or workspace root ${workspaceRoot}: ${String(error)}`,EXIT_CODE.NOT_FOUND,{code:"merge_root_not_found",nextSteps:["Initialize the tracker and ensure both paths are accessible.",'Retry "pm merge install" from the repository workspace.']})}const trackerRelativeRoot=toPosixRelative(canonicalWorkspaceRoot,canonicalPmRoot);if(isPathOutsideRoot(trackerRelativeRoot))throw new PmCliError(`Tracker root ${pmRoot} is outside the git repository ${workspaceRoot}; there is nothing to configure for this repository.`,EXIT_CODE.USAGE);const settings=await readSettings(canonicalPmRoot),typeFolders=resolveProjectMergeTypeFolders(settings),patterns=buildMergeAttributePatterns(trackerRelativeRoot,typeFolders),gitConfigEntries=[],cliCommand=await resolveMergeDriverCliCommand();for(const definition of MERGE_DRIVER_DEFINITIONS)gitConfigEntries.push({key:`merge.${definition.key}.name`,value:definition.name}),gitConfigEntries.push({key:`merge.${definition.key}.driver`,value:`${cliCommand} merge driver ${definition.artifact} "%O" "%A" "%B"${definition.itemPath===void 0?"":` --item-path ${definition.itemPath}`}`});if(!dryRun)try{await installMergeDriverConfiguration(canonicalWorkspaceRoot,gitConfigEntries)}catch{throw new PmCliError(`Cannot install repository-local merge drivers in ${canonicalWorkspaceRoot}. Ensure the repository Git config is writable and no other Git process holds its lock, then retry.`,EXIT_CODE.DEPENDENCY_FAILED,{code:"merge_git_config_unwritable",why:"pm merge install must persist clone-local driver commands before publishing their shared .gitattributes mappings.",nextSteps:["Make the repository Git config writable or wait for the process holding its lock to finish.",'Retry "pm merge install"; the operation is idempotent.','Use "pm merge install --dry-run --json" when the workspace is intentionally read-only.']})}const gitattributes=await reconcileGitattributesBlock(canonicalWorkspaceRoot,trackerRelativeRoot,patterns,dryRun);return{ok:!0,dry_run:dryRun,workspace_root:canonicalWorkspaceRoot,pm_root:canonicalPmRoot,gitattributes:{path:gitattributes.path,changed:gitattributes.changed,patterns,schema_scope:"project"},git_config:gitConfigEntries,guidance:["Commit .gitattributes so every branch and collaborator shares the merge mapping.",'git config is per-clone: each collaborator (and each fresh worktree/clone) runs "pm merge install" once.','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.',"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."],generated_at:nowIso()}}export{PM_GITATTRIBUTES_END,PM_GITATTRIBUTES_START,PM_GITATTRIBUTES_V2_END,PM_GITATTRIBUTES_V2_START,auditMergeAttributeFence,auditMergeDriverConfiguration,buildMergeAttributePatterns,findGitWorkspaceRoot,installMergeFence,refreshMergeAttributeFenceIfInstalled,resolveMergeInstallContext,resolveProjectMergeTypeFolders,runMergeInstall};
|
|
7
8
|
//# sourceMappingURL=install.js.map
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
/** Immutable pre-
|
|
1
|
+
/** Immutable pre-operation coordinates, without branch names or item contents. */
|
|
2
2
|
export interface MergeReceiptOperation {
|
|
3
3
|
/** Git operation whose original state can be checked after it ends. */
|
|
4
|
-
kind: "rebase";
|
|
5
|
-
/** Commit from which the
|
|
4
|
+
kind: "rebase" | "merge";
|
|
5
|
+
/** Commit from which the operation began. */
|
|
6
6
|
original_head: string;
|
|
7
7
|
/** Original item blob at that commit. */
|
|
8
8
|
original_blob: string;
|
|
9
9
|
}
|
|
10
|
-
/** Capture
|
|
11
|
-
export declare function captureMergeReceiptOperation(cwd: string, itemPath: string): Promise<MergeReceiptOperation | undefined>;
|
|
10
|
+
/** Capture original Git coordinates; plain merges require Git's incoming-head signal and the exact ours blob. */
|
|
11
|
+
export declare function captureMergeReceiptOperation(cwd: string, itemPath: string, originalItemRaw?: string): Promise<MergeReceiptOperation | undefined>;
|
|
12
12
|
/** Validate only the bounded, privacy-safe operation schema accepted by receipt readers. */
|
|
13
13
|
export declare function isMergeReceiptOperation(value: unknown): value is MergeReceiptOperation;
|
|
14
14
|
/** Prove HEAD, index, and working item all match the captured origin after Git leaves the operation. */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="af5442e7-c8af-5d81-8c89-7f1a98159cec")}catch{}})();import{execFile}from"node:child_process";import{createHash}from"node:crypto";import{readdir}from"node:fs/promises";import path from"node:path";import{promisify}from"node:util";import{readBoundedRegularFile}from"./receipt-file-boundary.js";const execFileAsync=promisify(execFile),GIT_OBJECT_ID=/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/u;async function captureMergeReceiptOperation(cwd,itemPath,originalItemRaw){const trimmedItemPath=itemPath.trim(),normalizedItemPath=/^(['"])(.*)\1$/su.exec(trimmedItemPath)?.[2]??trimmedItemPath;for(const backend of["rebase-merge","rebase-apply"])try{const{stdout:marker}=await execFileAsync("git",["rev-parse","--path-format=absolute","--git-path",`${backend}/orig-head`],{cwd,timeout:1e4}),originalHead=(await readBoundedRegularFile(marker.trim(),128))?.trim();if(originalHead===void 0||!GIT_OBJECT_ID.test(originalHead))continue;const{stdout}=await execFileAsync("git",["rev-parse","--verify",`${originalHead}:${normalizedItemPath}`],{cwd,timeout:1e4}),originalBlob=stdout.trim();return{kind:"rebase",original_head:originalHead,original_blob:originalBlob}}catch{}if(originalItemRaw!==void 0&&Object.keys(process.env).some(key=>/^GITHEAD_[a-f0-9]{40}(?:[a-f0-9]{24})?$/u.test(key)))try{const{stdout:heads}=await execFileAsync("git",["rev-parse","HEAD","ORIG_HEAD"],{cwd,timeout:1e4}),[head,originalHead]=heads.trim().split(/\r?\n/u);if(head!==originalHead||!GIT_OBJECT_ID.test(head))return;const{stdout}=await execFileAsync("git",["rev-parse","--verify",`${head}:${normalizedItemPath}`],{cwd,timeout:1e4}),originalBlob=stdout.trim(),oursBlob=createHash(originalBlob.length===40?"sha1":"sha256").update(`blob ${Buffer.byteLength(originalItemRaw)}\0`).update(originalItemRaw).digest("hex");return originalBlob!==oursBlob?void 0:{kind:"merge",original_head:head,original_blob:originalBlob}}catch{}}function isMergeReceiptOperation(value){if(typeof value!="object"||value===null||Array.isArray(value))return!1;const record=value;return Object.keys(record).length===3&&(record.kind==="rebase"||record.kind==="merge")&&typeof record.original_head=="string"&&GIT_OBJECT_ID.test(record.original_head)&&typeof record.original_blob=="string"&&GIT_OBJECT_ID.test(record.original_blob)}async function isOriginalGitStateRestored(cwd,itemPath,operation,expectedItemRaw){if(expectedItemRaw!==void 0&&createHash(operation.original_blob.length===40?"sha1":"sha256").update(`blob ${Buffer.byteLength(expectedItemRaw)}\0`).update(expectedItemRaw).digest("hex")!==operation.original_blob)return!1;try{const{stdout:gitDirectory}=await execFileAsync("git",["rev-parse","--absolute-git-dir"],{cwd,timeout:1e4}),activeMarkers=new Set(["rebase-merge","rebase-apply","MERGE_HEAD","CHERRY_PICK_HEAD","REVERT_HEAD"]);if((await readdir(gitDirectory.trim())).some(entry=>activeMarkers.has(entry)))return!1;const{stdout:head}=await execFileAsync("git",["rev-parse","HEAD"],{cwd,timeout:1e4});if(head.trim()!==operation.original_head)return!1;const{stdout:originalBlob}=await execFileAsync("git",["rev-parse","--verify",`HEAD:${itemPath}`],{cwd,timeout:1e4});if(originalBlob.trim()!==operation.original_blob)return!1;const{stdout:blob}=await execFileAsync("git",["hash-object","--",path.resolve(cwd,itemPath)],{cwd,timeout:1e4});return blob.trim()!==operation.original_blob?!1:(await execFileAsync("git",["diff","--cached","--quiet","HEAD","--",itemPath],{cwd,timeout:1e4}),!0)}catch{return!1}}export{captureMergeReceiptOperation,isMergeReceiptOperation,isOriginalGitStateRestored};
|
|
2
2
|
//# sourceMappingURL=receipt-operation.js.map
|
|
@@ -29,7 +29,7 @@ export interface MergeDecisionReceipt {
|
|
|
29
29
|
merged_field_hashes?: Record<string, string>;
|
|
30
30
|
/** Full recoverable scalar decisions, retained only in the clone. */
|
|
31
31
|
decisions: ItemMergeConflictDecision[];
|
|
32
|
-
/** Immutable original Git coordinates captured while the driver runs during a rebase. */
|
|
32
|
+
/** Immutable original Git coordinates captured while the driver runs during a merge or rebase. */
|
|
33
33
|
operation?: MergeReceiptOperation;
|
|
34
34
|
/** Explicit audited disposition when the original Git state was restored instead of merging. */
|
|
35
35
|
settlement?: "original_git_state_restored";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
2
|
-
`}}function receiptProvenanceFingerprint(receipt,legacy=!1){return sha256Hex(stableStringify({id:receipt.id,item_id:receipt.item_id,item_path:receipt.item_path,created_at:receipt.created_at,requested_preference:receipt.requested_preference??receipt.preferred??"ours",conflict_resolution:receipt.conflict_resolution??"preferred_side",fields_from_theirs:receipt.fields_from_theirs,union_fields:receipt.union_fields,merged_field_hashes:receipt.merged_field_hashes??null,operation:receipt.operation??null,decisions:legacy?receipt.decisions.map(decision=>({field:decision.field,retained_hash:sha256Hex(stableStringify(encodeItemScalarDecisionValue(decision.retained))),discarded_hash:sha256Hex(stableStringify(encodeItemScalarDecisionValue(decision.discarded)))})):summarizeMergeReceipt(receipt).decisions}))}function receiptProvenanceFingerprints(receipt){const fingerprints=[receiptProvenanceFingerprint(receipt)];return receipt.value_policy===void 0&&(receipt.value_availability===void 0||receipt.value_availability==="clone_local")&&fingerprints.push(receiptProvenanceFingerprint(receipt,!0)),fingerprints}function mergeReceiptCopyLifecycle(local,durable){
|
|
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]="6e5e4691-4858-5a54-82b0-65b97d929b57")}catch{}})();import{execFile}from"node:child_process";import{randomUUID}from"node:crypto";import{readdir,stat}from"node:fs/promises";import path from"node:path";import{promisify}from"node:util";import{readHistoryEntries}from"../../core/history/read.js";import{verifyHistoryChainWithVersion}from"../../core/history/replay.js";import{ensureDir,isFileAbsentError,isFileMissingError,pathExists,writeFileAtomic}from"../../core/fs/fs-utils.js";import{sha256Hex,stableStringify}from"../../core/shared/serialization.js";import{nowIso}from"../../core/shared/time.js";import{encodeItemScalarDecisionValue,hashItemScalarDecisionValue,isItemScalarMissingValue}from"./three-way.js";import{readBoundedRegularFile}from"./receipt-file-boundary.js";import{DURABLE_VALUE_POLICY,durableValueEvidence,isSafeReceiptId,isMergeDecisionReceipt,isPrehashedValue,normalizeLegacyReceipt,receiptCollectionValidationPath,receiptValidationError}from"./receipt-schema.js";import{isSafeReceiptId as isSafeReceiptId2}from"./receipt-schema.js";const execFileAsync=promisify(execFile),RECEIPT_FILE_MAX_BYTES=16*1024*1024,RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT=100;async function resolveReceiptDirectory(cwd){try{const{stdout}=await execFileAsync("git",["rev-parse","--path-format=absolute","--git-path","pm-merge-receipts"],{cwd,encoding:"utf8",windowsHide:!0,timeout:1e4});return stdout.trim()}catch{return null}}async function resolveTrackerRootFromItemPath(cwd,itemPath){let directory=path.dirname(path.resolve(cwd,itemPath));for(let depth=0;depth<12;depth+=1){if(await pathExists(path.join(directory,"settings.json")))return directory;const parent=path.dirname(directory);if(parent===directory)break;directory=parent}return null}function durableReceiptDirectory(pmRoot){return path.join(pmRoot,"merge-receipts")}function receiptFileName(id){return`${id}.json`}async function prepareReceiptSettlement(params){let raw;try{raw=params.readReceipt?await params.readReceipt(params.receiptPath):await readBoundedRegularFile(params.receiptPath,RECEIPT_FILE_MAX_BYTES)}catch(error){if(isFileAbsentError(error))return null;throw error}if(raw===null)throw new Error(`Receipt ${params.receiptId} settlement source is not a bounded regular file.`);let parsed;try{parsed=normalizeLegacyReceipt(JSON.parse(raw))}catch{throw new Error(`Receipt ${params.receiptId} settlement source is not valid JSON.`)}if(!isMergeDecisionReceipt(parsed,params.evidenceSource)||parsed.id!==params.receiptId||params.settlement!==void 0&&parsed.operation===void 0||path.basename(params.receiptPath)!==receiptFileName(parsed.id))throw new Error(`Receipt ${params.receiptId} settlement source failed schema or identity validation.`);const{evidence_source:_evidenceSource,...persistedReceipt}=parsed;return{path:params.receiptPath,fingerprints:receiptProvenanceFingerprints(parsed),modern:parsed.value_policy!==void 0,content:`${JSON.stringify({...persistedReceipt,state:"reconciled",reconciled_at:params.reconciledAt,...params.settlement?{settlement:params.settlement}:{}},null,2)}
|
|
2
|
+
`}}function receiptProvenanceFingerprint(receipt,legacy=!1){return sha256Hex(stableStringify({id:receipt.id,item_id:receipt.item_id,item_path:receipt.item_path,created_at:receipt.created_at,requested_preference:receipt.requested_preference??receipt.preferred??"ours",requested_preference_applied:receipt.requested_preference_applied??(receipt.conflict_resolution??"preferred_side")==="preferred_side",conflict_resolution:receipt.conflict_resolution??"preferred_side",fields_from_theirs:receipt.fields_from_theirs,union_fields:receipt.union_fields,merged_field_hashes:receipt.merged_field_hashes??null,operation:receipt.operation??null,decisions:legacy?receipt.decisions.map(decision=>({field:decision.field,retained_hash:sha256Hex(stableStringify(encodeItemScalarDecisionValue(decision.retained))),discarded_hash:sha256Hex(stableStringify(encodeItemScalarDecisionValue(decision.discarded)))})):summarizeMergeReceipt(receipt).decisions}))}function receiptProvenanceFingerprints(receipt){const fingerprints=[receiptProvenanceFingerprint(receipt)];return receipt.value_policy===void 0&&(receipt.value_availability===void 0||receipt.value_availability==="clone_local")&&fingerprints.push(receiptProvenanceFingerprint(receipt,!0)),fingerprints}function mergeReceiptCopyLifecycle(local,durable){const{reconciled_at:_reconciledAt,settlement:_settlement,...pendingLocal}=local;return durable.state==="reconciled"?{...pendingLocal,state:"reconciled",reconciled_at:durable.reconciled_at,...durable.settlement===void 0?{}:{settlement:durable.settlement}}:{...pendingLocal,state:"pending"}}async function retainAuditedDurableSettlements(receipts,durableReceipts,pmRoot){const histories=new Map;for(const durable of durableReceipts){const receipt=receipts.get(durable.id);if(durable.state!=="reconciled"||receipt===void 0)continue;let entries=histories.get(receipt.item_id);if(entries===void 0){try{entries=await readHistoryEntries(path.join(pmRoot,"history",`${receipt.item_id}.jsonl`),receipt.item_id),verifyHistoryChainWithVersion(entries).ok||(entries=[])}catch{entries=[]}histories.set(receipt.item_id,entries)}const abandoned=receipt.settlement==="original_git_state_restored",expected=stableStringify({...summarizeMergeReceipt(receipt),...abandoned?{reason:receipt.settlement,operation:receipt.operation}:{}});if(!entries.some(entry=>{if(entry.op!=="merge_reconcile"||entry.record_hash_version===void 0)return!1;const merge=entry.context?.merge;if(typeof merge!="object"||merge===null||Array.isArray(merge))return!1;const summaries=merge[abandoned?"abandoned_receipts":"receipts"];return Array.isArray(summaries)&&summaries.some(summary=>stableStringify(summary)===expected)})){const{reconciled_at:_reconciledAt,settlement:_settlement,...pending}=receipt;receipts.set(receipt.id,{...pending,state:"pending"})}}}function summarizeMergeReceipt(receipt){return{receipt_id:receipt.id,item_id:receipt.item_id,item_path:receipt.item_path,conflict_fields:receipt.decisions.map(decision=>decision.field),fields_from_theirs:receipt.fields_from_theirs,union_fields:receipt.union_fields,requested_preference:receipt.requested_preference??receipt.preferred??"ours",requested_preference_applied:receipt.requested_preference_applied??(receipt.conflict_resolution??"preferred_side")==="preferred_side",conflict_resolution:receipt.conflict_resolution,decisions:receipt.decisions.map(decision=>({field:decision.field,retained_hash:isPrehashedValue(decision.retained)??hashItemScalarDecisionValue(isItemScalarMissingValue(decision.retained)?void 0:decision.retained),discarded_hash:isPrehashedValue(decision.discarded)??hashItemScalarDecisionValue(isItemScalarMissingValue(decision.discarded)?void 0:decision.discarded)}))}}async function writeMergeReceipt(params){const directory=await resolveReceiptDirectory(params.cwd);if(directory===null)return null;const trimmedItemPath=params.itemPath.trim(),itemPath=/^(['"])(.*)\1$/su.exec(trimmedItemPath)?.[2]??trimmedItemPath,itemId=path.basename(itemPath,path.extname(itemPath)),receipt={version:1,id:randomUUID(),item_path:itemPath.replaceAll("\\","/"),item_id:itemId,requested_preference:params.preferred,requested_preference_applied:(params.conflictResolution??"preferred_side")==="preferred_side",conflict_resolution:params.conflictResolution??"preferred_side",fields_from_theirs:[...params.fieldsFromTheirs],union_fields:[...params.unionFields],...params.mergedFieldHashes?{merged_field_hashes:{...params.mergedFieldHashes}}:{},decisions:structuredClone(params.decisions).map(decision=>({...decision,base:encodeItemScalarDecisionValue(decision.base),ours:encodeItemScalarDecisionValue(decision.ours),theirs:encodeItemScalarDecisionValue(decision.theirs),retained:encodeItemScalarDecisionValue(decision.retained),discarded:encodeItemScalarDecisionValue(decision.discarded)})),...params.operation?{operation:params.operation}:{},state:"pending",created_at:nowIso(),value_availability:"clone_local"};await ensureDir(directory),await writeFileAtomic(path.join(directory,receiptFileName(receipt.id)),`${JSON.stringify(receipt,null,2)}
|
|
3
3
|
`);const trackerRoot=await resolveTrackerRootFromItemPath(params.cwd,receipt.item_path);if(trackerRoot!==null){const durableDirectory=durableReceiptDirectory(trackerRoot),durableDecisions=receipt.decisions.map(decision=>({field:decision.field,base:null,ours:null,theirs:null,retained:durableValueEvidence(decision.field,decision.retained),discarded:durableValueEvidence(decision.field,decision.discarded),retained_side:decision.retained_side,resolution_basis:decision.resolution_basis})),inlineValueCount=durableDecisions.reduce((count,decision)=>count+(Object.hasOwn(decision.retained,"pm_value")?1:0)+(Object.hasOwn(decision.discarded,"pm_value")?1:0),0),durableReceipt={...receipt,decisions:durableDecisions,value_availability:inlineValueCount===0?"hash_only":inlineValueCount===durableDecisions.length*2?"bounded_inline":"mixed",value_policy:DURABLE_VALUE_POLICY};await ensureDir(durableDirectory),await writeFileAtomic(path.join(durableDirectory,receiptFileName(receipt.id)),`${JSON.stringify(durableReceipt,null,2)}
|
|
4
|
-
`)}return receipt}async function readReceiptsFromDirectory(directory,evidenceSource){let names;try{names=await readdir(directory)}catch(error){const absent=await receiptDirectoryFailureMeansAbsent(directory,error);return{receipts:[],invalid_evidence_count:absent?0:1,invalid_evidence:absent?[]:[{evidence_source:evidenceSource,reason:"directory_unreadable"}],invalid_evidence_truncated:!1}}const receipts=[];let invalidEvidenceCount=0;const invalidEvidence=[],recordInvalidEvidence=(name,candidate)=>{if(invalidEvidenceCount+=1,invalidEvidence.length>=RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT)return;const receiptId=name.slice(0,-5);invalidEvidence.push({evidence_source:evidenceSource,reason:candidate.reason,...candidate.validation_path?{validation_path:candidate.validation_path}:{},...candidate.validation_error===void 0?{}:{validation_error:candidate.validation_error},...isSafeReceiptId(receiptId)?{receipt_id:receiptId}:{candidate_name_hash:sha256Hex(name)}})};for(const name of names.sort((left,right)=>left.localeCompare(right))){if(!name.endsWith(".json"))continue;const candidate=await inspectReceiptCandidate(directory,name,evidenceSource);candidate.receipt!==void 0?receipts.push(candidate.receipt):recordInvalidEvidence(name,candidate)}return{receipts,invalid_evidence_count:invalidEvidenceCount,invalid_evidence:invalidEvidence,invalid_evidence_truncated:invalidEvidenceCount>invalidEvidence.length}}async function receiptDirectoryFailureMeansAbsent(directory,error,inspectAncestor=stat){if(!isFileMissingError(error))return!1;let ancestor=directory;for(;;)try{return(await inspectAncestor(ancestor)).isDirectory()}catch(ancestorError){if(!isFileMissingError(ancestorError))return!1;const parent=path.dirname(ancestor);if(parent===ancestor)return!0;ancestor=parent}}async function inspectReceiptCandidate(directory,name,evidenceSource){let raw;try{raw=await readBoundedRegularFile(path.join(directory,name),RECEIPT_FILE_MAX_BYTES)}catch{return{reason:"candidate_unreadable"}}if(raw===null)return{reason:"candidate_not_bounded_regular_file"};let parsed;try{parsed=normalizeLegacyReceipt(JSON.parse(raw))}catch{return{reason:"candidate_invalid_json"}}const validationError=receiptValidationError(parsed,evidenceSource);if(validationError!==null)return{reason:new Set(["receipt_id","item_id","item_path"]).has(validationError)?"identity_invalid":"schema_invalid",validation_error:validationError,...validationError==="collections"?{validation_path:receiptCollectionValidationPath(parsed)}:{}};const receipt=parsed;if(name!==receiptFileName(receipt.id))return{reason:"identity_invalid",validation_error:"filename"};const{preferred:legacyPreference,evidence_source:_serializedEvidenceSource,...receiptWithoutRuntimeKeys}=receipt;return{receipt:{...receiptWithoutRuntimeKeys,requested_preference:receipt.requested_preference??legacyPreference??"ours",requested_preference_applied:receipt.requested_preference_applied??(receipt.conflict_resolution??"preferred_side")==="preferred_side",conflict_resolution:receipt.conflict_resolution??"preferred_side",evidence_source:evidenceSource}}}async function inspectMergeReceiptEvidence(cwd,options={}){const directory=await resolveReceiptDirectory(cwd),local=directory===null?{receipts:[],invalid_evidence_count:0,invalid_evidence:[],invalid_evidence_truncated:!1}:await readReceiptsFromDirectory(directory,"clone_local"),trackerRoot=options.pmRoot??path.join(cwd,".agents","pm"),durable=await readReceiptsFromDirectory(durableReceiptDirectory(trackerRoot),"durable"),receipts=new Map(durable.receipts.map(receipt=>[receipt.id,receipt]));let divergentCopyCount=0;const divergentCopyEvidence=[];for(const receipt of local.receipts){const durableCopy=receipts.get(receipt.id);if(durableCopy!==void 0&&!(durableCopy.value_policy===void 0?receiptProvenanceFingerprints(receipt):[receiptProvenanceFingerprint(receipt)]).includes(receiptProvenanceFingerprint(durableCopy))){receipts.delete(receipt.id),divergentCopyCount+=1,local.invalid_evidence.length+durable.invalid_evidence.length+divergentCopyEvidence.length<RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT&&divergentCopyEvidence.push({evidence_source:"clone_local_and_durable",reason:"copy_provenance_mismatch",receipt_id:receipt.id});continue}receipts.set(receipt.id,durableCopy===void 0?receipt:mergeReceiptCopyLifecycle(receipt,durableCopy))}return{receipts:[...receipts.values()].filter(receipt=>(options.includeReconciled||receipt.state==="pending")&&(options.includeLossless!==!1||receipt.decisions.length>0)).sort((left,right)=>left.created_at.localeCompare(right.created_at)),invalid_evidence_count:local.invalid_evidence_count+durable.invalid_evidence_count+divergentCopyCount,invalid_evidence:[...local.invalid_evidence,...durable.invalid_evidence,...divergentCopyEvidence].slice(0,RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT),invalid_evidence_truncated:local.invalid_evidence_truncated||durable.invalid_evidence_truncated||local.invalid_evidence_count+durable.invalid_evidence_count+divergentCopyCount>RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT,clone_local_evidence_resolved:directory!==null}}async function listMergeReceipts(cwd,options={}){return(await inspectMergeReceiptEvidence(cwd,options)).receipts}function partitionMergeReceipts(receipts){const pendingDecisions=[],lossless=[];for(const receipt of receipts)(Array.isArray(receipt.decisions)&&receipt.decisions.length>0?pendingDecisions:lossless).push(receipt);return{pendingDecisions,lossless}}async function markMergeReceiptReconciled(cwd,receipt,options={}){const directory=await resolveReceiptDirectory(cwd);if(directory===null){if(options.requireExisting===!0)throw new Error(`Receipt ${receipt.id} disappeared before settlement.`);return}const receiptEvidenceSource=receipt.evidence_source??"clone_local";if(!isMergeDecisionReceipt(receipt,receiptEvidenceSource))throw new Error("Merge receipt trusted settlement input failed schema validation.");const reconciledAt=nowIso(),localPath=path.join(directory,receiptFileName(receipt.id)),trackerRoot=await resolveTrackerRootFromItemPath(cwd,receipt.item_path),durablePath=trackerRoot===null?null:path.join(durableReceiptDirectory(trackerRoot),receiptFileName(receipt.id)),writes=(await Promise.all([prepareReceiptSettlement({receiptPath:localPath,receiptId:receipt.id,evidenceSource:"clone_local",reconciledAt,settlement:options.settlement}),...durablePath===null?[]:[prepareReceiptSettlement({receiptPath:durablePath,receiptId:receipt.id,evidenceSource:"durable",reconciledAt,settlement:options.settlement})]])).filter(entry=>entry!==null);if(writes.length===0){if(options.requireExisting===!0)throw new Error(`Receipt ${receipt.id} disappeared before settlement.`);return}if(!(writes.some(write=>write.modern)?[receiptProvenanceFingerprint(receipt)]:receiptProvenanceFingerprints(receipt)).some(fingerprint=>writes.every(write=>write.fingerprints.includes(fingerprint))))throw new Error(`Receipt ${receipt.id} settlement copies disagree on immutable merge provenance.`);for(const write of writes)await writeFileAtomic(write.path,write.content)}async function runMergeReceiptReport(options){const receipts=await listMergeReceipts(options.cwd??process.cwd(),{...options,includeLossless:!0});return{ok:!0,count:receipts.length,receipts,generated_at:nowIso()}}async function runMergeReceiptEvidenceReport(options){const evidence=await inspectMergeReceiptEvidence(options.cwd??process.cwd(),{...options,includeLossless:!0}),complete=evidence.clone_local_evidence_resolved===!0&&evidence.invalid_evidence_count===0;return{ok:complete,complete,count:evidence.receipts.length,invalid_evidence_count:evidence.invalid_evidence_count,invalid_evidence:evidence.invalid_evidence,invalid_evidence_truncated:evidence.invalid_evidence_truncated,clone_local_evidence_resolved:evidence.clone_local_evidence_resolved,receipts:evidence.receipts,generated_at:nowIso()}}const _testOnlyMergeReceipts={prepareReceiptSettlement,receiptDirectoryFailureMeansAbsent};export{_testOnlyMergeReceipts,inspectMergeReceiptEvidence,isSafeReceiptId2 as isSafeReceiptId,listMergeReceipts,markMergeReceiptReconciled,partitionMergeReceipts,runMergeReceiptEvidenceReport,runMergeReceiptReport,summarizeMergeReceipt,writeMergeReceipt};
|
|
4
|
+
`)}return receipt}async function readReceiptsFromDirectory(directory,evidenceSource){let names;try{names=await readdir(directory)}catch(error){const absent=await receiptDirectoryFailureMeansAbsent(directory,error);return{receipts:[],invalid_evidence_count:absent?0:1,invalid_evidence:absent?[]:[{evidence_source:evidenceSource,reason:"directory_unreadable"}],invalid_evidence_truncated:!1}}const receipts=[];let invalidEvidenceCount=0;const invalidEvidence=[],recordInvalidEvidence=(name,candidate)=>{if(invalidEvidenceCount+=1,invalidEvidence.length>=RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT)return;const receiptId=name.slice(0,-5);invalidEvidence.push({evidence_source:evidenceSource,reason:candidate.reason,...candidate.validation_path?{validation_path:candidate.validation_path}:{},...candidate.validation_error===void 0?{}:{validation_error:candidate.validation_error},...isSafeReceiptId(receiptId)?{receipt_id:receiptId}:{candidate_name_hash:sha256Hex(name)}})};for(const name of names.sort((left,right)=>left.localeCompare(right))){if(!name.endsWith(".json"))continue;const candidate=await inspectReceiptCandidate(directory,name,evidenceSource);candidate.receipt!==void 0?receipts.push(candidate.receipt):recordInvalidEvidence(name,candidate)}return{receipts,invalid_evidence_count:invalidEvidenceCount,invalid_evidence:invalidEvidence,invalid_evidence_truncated:invalidEvidenceCount>invalidEvidence.length}}async function receiptDirectoryFailureMeansAbsent(directory,error,inspectAncestor=stat){if(!isFileMissingError(error))return!1;let ancestor=directory;for(;;)try{return(await inspectAncestor(ancestor)).isDirectory()}catch(ancestorError){if(!isFileMissingError(ancestorError))return!1;const parent=path.dirname(ancestor);if(parent===ancestor)return!0;ancestor=parent}}async function inspectReceiptCandidate(directory,name,evidenceSource){let raw;try{raw=await readBoundedRegularFile(path.join(directory,name),RECEIPT_FILE_MAX_BYTES)}catch{return{reason:"candidate_unreadable"}}if(raw===null)return{reason:"candidate_not_bounded_regular_file"};let parsed;try{parsed=normalizeLegacyReceipt(JSON.parse(raw))}catch{return{reason:"candidate_invalid_json"}}const validationError=receiptValidationError(parsed,evidenceSource);if(validationError!==null)return{reason:new Set(["receipt_id","item_id","item_path"]).has(validationError)?"identity_invalid":"schema_invalid",validation_error:validationError,...validationError==="collections"?{validation_path:receiptCollectionValidationPath(parsed)}:{}};const receipt=parsed;if(name!==receiptFileName(receipt.id))return{reason:"identity_invalid",validation_error:"filename"};const{preferred:legacyPreference,evidence_source:_serializedEvidenceSource,...receiptWithoutRuntimeKeys}=receipt;return{receipt:{...receiptWithoutRuntimeKeys,requested_preference:receipt.requested_preference??legacyPreference??"ours",requested_preference_applied:receipt.requested_preference_applied??(receipt.conflict_resolution??"preferred_side")==="preferred_side",conflict_resolution:receipt.conflict_resolution??"preferred_side",evidence_source:evidenceSource}}}async function inspectMergeReceiptEvidence(cwd,options={}){const directory=await resolveReceiptDirectory(cwd),local=directory===null?{receipts:[],invalid_evidence_count:0,invalid_evidence:[],invalid_evidence_truncated:!1}:await readReceiptsFromDirectory(directory,"clone_local"),trackerRoot=options.pmRoot??path.join(cwd,".agents","pm"),durable=await readReceiptsFromDirectory(durableReceiptDirectory(trackerRoot),"durable"),receipts=new Map(durable.receipts.map(receipt=>[receipt.id,receipt]));let divergentCopyCount=0;const divergentCopyEvidence=[];for(const receipt of local.receipts){const durableCopy=receipts.get(receipt.id);if(durableCopy!==void 0&&!(durableCopy.value_policy===void 0?receiptProvenanceFingerprints(receipt):[receiptProvenanceFingerprint(receipt)]).includes(receiptProvenanceFingerprint(durableCopy))){receipts.delete(receipt.id),divergentCopyCount+=1,local.invalid_evidence.length+durable.invalid_evidence.length+divergentCopyEvidence.length<RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT&&divergentCopyEvidence.push({evidence_source:"clone_local_and_durable",reason:"copy_provenance_mismatch",receipt_id:receipt.id});continue}receipts.set(receipt.id,durableCopy===void 0?receipt:mergeReceiptCopyLifecycle(receipt,durableCopy))}return await retainAuditedDurableSettlements(receipts,durable.receipts,trackerRoot),{receipts:[...receipts.values()].filter(receipt=>(options.includeReconciled||receipt.state==="pending")&&(options.includeLossless!==!1||receipt.decisions.length>0)).sort((left,right)=>left.created_at.localeCompare(right.created_at)),invalid_evidence_count:local.invalid_evidence_count+durable.invalid_evidence_count+divergentCopyCount,invalid_evidence:[...local.invalid_evidence,...durable.invalid_evidence,...divergentCopyEvidence].slice(0,RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT),invalid_evidence_truncated:local.invalid_evidence_truncated||durable.invalid_evidence_truncated||local.invalid_evidence_count+durable.invalid_evidence_count+divergentCopyCount>RECEIPT_INVALID_EVIDENCE_DETAIL_LIMIT,clone_local_evidence_resolved:directory!==null}}async function listMergeReceipts(cwd,options={}){return(await inspectMergeReceiptEvidence(cwd,options)).receipts}function partitionMergeReceipts(receipts){const pendingDecisions=[],lossless=[];for(const receipt of receipts)(Array.isArray(receipt.decisions)&&receipt.decisions.length>0?pendingDecisions:lossless).push(receipt);return{pendingDecisions,lossless}}async function markMergeReceiptReconciled(cwd,receipt,options={}){const directory=await resolveReceiptDirectory(cwd);if(directory===null){if(options.requireExisting===!0)throw new Error(`Receipt ${receipt.id} disappeared before settlement.`);return}const receiptEvidenceSource=receipt.evidence_source??"clone_local";if(!isMergeDecisionReceipt(receipt,receiptEvidenceSource))throw new Error("Merge receipt trusted settlement input failed schema validation.");const reconciledAt=nowIso(),localPath=path.join(directory,receiptFileName(receipt.id)),trackerRoot=await resolveTrackerRootFromItemPath(cwd,receipt.item_path),durablePath=trackerRoot===null?null:path.join(durableReceiptDirectory(trackerRoot),receiptFileName(receipt.id)),writes=(await Promise.all([prepareReceiptSettlement({receiptPath:localPath,receiptId:receipt.id,evidenceSource:"clone_local",reconciledAt,settlement:options.settlement}),...durablePath===null?[]:[prepareReceiptSettlement({receiptPath:durablePath,receiptId:receipt.id,evidenceSource:"durable",reconciledAt,settlement:options.settlement})]])).filter(entry=>entry!==null);if(writes.length===0){if(options.requireExisting===!0)throw new Error(`Receipt ${receipt.id} disappeared before settlement.`);return}if(!(writes.some(write=>write.modern)?[receiptProvenanceFingerprint(receipt)]:receiptProvenanceFingerprints(receipt)).some(fingerprint=>writes.every(write=>write.fingerprints.includes(fingerprint))))throw new Error(`Receipt ${receipt.id} settlement copies disagree on immutable merge provenance.`);for(const write of writes)await writeFileAtomic(write.path,write.content)}async function runMergeReceiptReport(options){const receipts=await listMergeReceipts(options.cwd??process.cwd(),{...options,includeLossless:!0});return{ok:!0,count:receipts.length,receipts,generated_at:nowIso()}}async function runMergeReceiptEvidenceReport(options){const evidence=await inspectMergeReceiptEvidence(options.cwd??process.cwd(),{...options,includeLossless:!0}),complete=evidence.clone_local_evidence_resolved===!0&&evidence.invalid_evidence_count===0;return{ok:complete,complete,count:evidence.receipts.length,invalid_evidence_count:evidence.invalid_evidence_count,invalid_evidence:evidence.invalid_evidence,invalid_evidence_truncated:evidence.invalid_evidence_truncated,clone_local_evidence_resolved:evidence.clone_local_evidence_resolved,receipts:evidence.receipts,generated_at:nowIso()}}const _testOnlyMergeReceipts={prepareReceiptSettlement,receiptDirectoryFailureMeansAbsent};export{_testOnlyMergeReceipts,inspectMergeReceiptEvidence,isSafeReceiptId2 as isSafeReceiptId,listMergeReceipts,markMergeReceiptReconciled,partitionMergeReceipts,runMergeReceiptEvidenceReport,runMergeReceiptReport,summarizeMergeReceipt,writeMergeReceipt};
|
|
5
5
|
//# sourceMappingURL=receipts.js.map
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
/** Write clone-local configuration after a bounded wait for Git's own exclusive lock. Retry only the native lock-exists diagnostic; never remove another writer's lock or retry malformed and unwritable configuration. */
|
|
2
|
+
export declare function writeMergeDriverGitConfig(cwd: string, args: string[]): Promise<void>;
|
|
1
3
|
/** Preserve caller tools and preferences while binding Git repository discovery and writes to the explicit cwd. */
|
|
2
4
|
export declare function gitWorkspaceEnvironment(): NodeJS.ProcessEnv;
|
|
3
5
|
/**
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
1
|
+
(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},n=new e.Error().stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="f8f33f3d-854e-5cb4-b0bf-8d2d89da27e8")}catch{}})();import{execFile}from"node:child_process";import path from"node:path";import{promisify}from"node:util";import{setTimeout as delay}from"node:timers/promises";const execFileAsync=promisify(execFile);async function writeMergeDriverGitConfig(cwd,args){const deadline=performance.now()+5e3;let backoff=25;for(;;)try{await execFileAsync("git",["config",...args],{cwd,env:{...gitWorkspaceEnvironment(),LC_ALL:"C"},timeout:1e4});return}catch(error){const remaining=deadline-performance.now();if(typeof error!="object"||error===null||!("stderr"in error)||typeof error.stderr!="string"||!/could not lock config file [^\r\n]+: File exists/u.test(error.stderr)||remaining<=0)throw error;await delay(Math.min(backoff,remaining)),backoff=Math.min(backoff*2,200)}}function gitWorkspaceEnvironment(){const env={...process.env};for(const key of["GIT_DIR","GIT_WORK_TREE","GIT_COMMON_DIR","GIT_INDEX_FILE","GIT_OBJECT_DIRECTORY","GIT_ALTERNATE_OBJECT_DIRECTORIES","GIT_NAMESPACE","GIT_CEILING_DIRECTORIES","GIT_DISCOVERY_ACROSS_FILESYSTEM"])delete env[key];return env}async function readLocalGitConfig(cwd,key){try{return(await execFileAsync("git",["config","--local",...key==="core.bare"||key==="extensions.worktreeConfig"?["--type=bool"]:[],"--get",key],{cwd,env:gitWorkspaceEnvironment(),timeout:1e4})).stdout.trim()}catch(error){if(typeof error=="object"&&error!==null&&"code"in error&&error.code===1)return;throw error}}async function resolveMergeDriverConfigScope(workspaceRoot){if(await readLocalGitConfig(workspaceRoot,"extensions.worktreeConfig")==="true")return"--worktree";const{stdout}=await execFileAsync("git",["rev-parse","--path-format=absolute","--git-dir","--git-common-dir"],{cwd:workspaceRoot,env:gitWorkspaceEnvironment(),timeout:1e4}),[gitDir,commonDir]=stdout.trim().split(/\r?\n/);if(gitDir===commonDir)return"--local";const mainConfig=path.join(commonDir,"config.worktree");for(const key of["core.bare","core.worktree"]){const value=await readLocalGitConfig(workspaceRoot,key);value===void 0||key==="core.bare"&&value!=="true"||(await writeMergeDriverGitConfig(workspaceRoot,["--file",mainConfig,key,value]),await writeMergeDriverGitConfig(workspaceRoot,["--local","--unset-all",key]))}for(const driver of["pm-item-toon","pm-item-markdown","pm-history","pm-relationship","pm-json"])for(const field of["name","driver"]){const key=`merge.${driver}.${field}`,value=await readLocalGitConfig(workspaceRoot,key);value!==void 0&&await writeMergeDriverGitConfig(workspaceRoot,["--file",mainConfig,key,value])}return await writeMergeDriverGitConfig(workspaceRoot,["--local","extensions.worktreeConfig","true"]),"--worktree"}export{gitWorkspaceEnvironment,resolveMergeDriverConfigScope,writeMergeDriverGitConfig};
|
|
2
2
|
//# sourceMappingURL=worktree-config.js.map
|