import { b as getLogger, a0 as GATE_EVIDENCE_REQUIREMENTS, a1 as resolveWorktreeRootForHash, a2 as computeProjectHash } from './paths-2M_UxD_H.js';
import { a as attachments } from './conduit-Ca_OFWR_.js';
import './sqlite-Dsbe0wec.js';
import { join, resolve } from 'node:path';
import 'node:crypto';
import 'node:fs/promises';
import { e as eq } from './logger-ChCwlV5k.js';
import './src2-DK8DKufK.js';
import { mkdirSync, appendFileSync, existsSync, readFileSync, rmSync, readdirSync, cpSync } from 'node:fs';
import './index-IVoIz4D5.js';
import { execFileSync, execFile } from 'node:child_process';
import { homedir } from 'node:os';
import { e as __esmMin } from './chunk-DDP5xfzh.js';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
import { promisify } from 'node:util';

Promise.resolve();
/**
* Derive 3 alternative slug candidates that are NOT currently in use.
*
* Strategy (per Epic T9627 design guidance):
*   1. `<slug>-N` where N is the count-of-existing-rows + 1
*   2. `<slug>-v2`
*   3. `<slug>-new` (or `-alt` if `-new` is also taken)
*
* If a primary candidate is also taken, walk forward until a free one is
* found. The lookup is bounded by a maximum of 32 probes per candidate so
* a pathological dataset can never block the request.
*
* Re-exported under {@link deriveSlugSuggestionsForAllocator} for the
* central slug allocator (T10392) so both the late-bound
* `SlugCollisionError` path and the early-bound `reserveSlug` path emit
* the SAME suggestion shape.
*
* @task T9636
*/
async function deriveSlugSuggestions(db, base) {
	const taken = /* @__PURE__ */ new Set();
	const probes = [];
	const startCount = await db.$count(attachments);
	probes.push(`${base}-${startCount + 1}`);
	probes.push(`${base}-v2`);
	probes.push(`${base}-new`);
	const out = [];
	for (let idx = 0; idx < probes.length; idx++) {
		let candidate = probes[idx];
		let walk = 0;
		while (walk < 32) {
			if (taken.has(candidate)) {
				walk++;
				candidate = `${candidate}-x`;
				continue;
			}
			if (!await db.select().from(attachments).where(eq(attachments.slug, candidate)).get()) {
				out.push(candidate);
				taken.add(candidate);
				break;
			}
			taken.add(candidate);
			walk++;
			candidate = idx === 2 ? `${base}-alt-${walk}` : `${candidate}-x`;
		}
		if (out.length === idx + 1) continue;
		out.push(`${base}-${startCount + idx + 100}`);
	}
	return out.slice(0, 3);
}
/**
* Re-export of {@link deriveSlugSuggestions} for the central slug
* allocator (T10392).
*
* Lives in this module rather than the allocator so the suggestion
* algorithm has exactly ONE implementation. Both the late-bound
* `SlugCollisionError` path inside `attachmentStore.put` and the
* early-bound `reserveSlug` chokepoint use the same helper, so the
* suggestion shape is uniform regardless of which layer caught the
* conflict.
*
* Loose typing on `db` matches the internal `DrizzleDb` alias so
* cross-package consumers do not have to import drizzle types.
*
* @task T10392
* @internal
*/
async function deriveSlugSuggestionsForAllocator(db, base) {
	return deriveSlugSuggestions(db, base);
}
getLogger("lifecycle:ivtr");

//#region ../core/dist/lifecycle/stages.js
/**
* Pipeline Stage Definitions and Transitions
*
* Defines the 9-stage RCASD-IVTR pipeline with stage metadata,
* transition rules, and prerequisite mappings.
*
* Stages (in order):
*   1. Research              - Information gathering and exploration
*   2. Consensus             - Multi-agent decisions and validation
*   3. Architecture Decision - Architecture Decision Records
*   4. Specification         - Specification and documentation
*   5. Decomposition         - Task breakdown and planning
*   6. Implementation        - Code execution and building
*   7. Validation            - Static analysis, type checking, quality gates
*   8. Testing               - Test execution and coverage
*   9. Release               - Version management and publishing
*
* @task T4800 - Implement Canonical SQLite Pipeline State Machine
* @epic T4798 - Lifecycle persistence improvements
* @audit T4799 - Unified stage names (replaces scattered definitions)
*
* NOTE: This file provides the canonical stage definitions. All other
* stage definitions in the codebase should reference these.
* Stage names MUST match the DB CHECK constraint in lifecycle_stages.stage_name.
*/
var PIPELINE_STAGES = [
	"research",
	"consensus",
	"architecture_decision",
	"specification",
	"decomposition",
	"implementation",
	"validation",
	"testing",
	"release"
];
/**
* Canonical stage definitions with complete metadata.
*
* @task T4800
* @audit T4799 - Replaces legacy STAGE_DEFINITIONS from index.ts
*/
var STAGE_DEFINITIONS = {
	research: {
		stage: "research",
		name: "Research",
		description: "Information gathering, exploration, and knowledge acquisition",
		order: 1,
		category: "planning",
		skippable: false,
		defaultTimeoutHours: 48,
		requiredGates: ["prerequisites-met"],
		expectedArtifacts: ["research-report", "findings-document"]
	},
	consensus: {
		stage: "consensus",
		name: "Consensus",
		description: "Multi-agent decision making and validation of research findings",
		order: 2,
		category: "decision",
		skippable: true,
		defaultTimeoutHours: 24,
		requiredGates: ["research-complete", "agreement-reached"],
		expectedArtifacts: ["consensus-record", "decision-log"]
	},
	architecture_decision: {
		stage: "architecture_decision",
		name: "Architecture Decision",
		description: "Architecture Decision Records - documenting significant technical decisions",
		order: 3,
		category: "decision",
		skippable: true,
		defaultTimeoutHours: 24,
		requiredGates: ["decisions-documented", "review-completed"],
		expectedArtifacts: ["adr-document"]
	},
	specification: {
		stage: "specification",
		name: "Specification",
		description: "Specification writing - RFC-style documentation of requirements and design",
		order: 4,
		category: "planning",
		skippable: false,
		defaultTimeoutHours: 72,
		requiredGates: ["spec-complete", "spec-reviewed"],
		expectedArtifacts: [
			"spec-document",
			"api-spec",
			"design-doc"
		]
	},
	decomposition: {
		stage: "decomposition",
		name: "Decomposition",
		description: "Task breakdown - splitting work into atomic, executable tasks",
		order: 5,
		category: "planning",
		skippable: false,
		defaultTimeoutHours: 24,
		requiredGates: ["tasks-created", "dependencies-mapped"],
		expectedArtifacts: ["task-breakdown", "dependency-graph"]
	},
	implementation: {
		stage: "implementation",
		name: "Implementation",
		description: "Implementation - writing code and building features",
		order: 6,
		category: "execution",
		skippable: false,
		defaultTimeoutHours: null,
		requiredGates: ["code-complete", "lint-passing"],
		expectedArtifacts: ["source-code", "implementation-notes"]
	},
	validation: {
		stage: "validation",
		name: "Validation",
		description: "Verification - static analysis, type checking, and quality gates",
		order: 7,
		category: "validation",
		skippable: false,
		defaultTimeoutHours: 12,
		requiredGates: ["static-analysis-pass", "type-check-pass"],
		expectedArtifacts: ["verification-report"]
	},
	testing: {
		stage: "testing",
		name: "Testing",
		description: "Testing - running test suites and ensuring coverage",
		order: 8,
		category: "validation",
		skippable: false,
		defaultTimeoutHours: 24,
		requiredGates: ["tests-pass", "coverage-met"],
		expectedArtifacts: ["test-results", "coverage-report"]
	},
	release: {
		stage: "release",
		name: "Release",
		description: "Release - versioning, publishing, and deployment",
		order: 9,
		category: "delivery",
		skippable: true,
		defaultTimeoutHours: 4,
		requiredGates: [
			"version-bumped",
			"changelog-updated",
			"artifacts-published"
		],
		expectedArtifacts: [
			"version-tag",
			"release-notes",
			"published-package"
		]
	}
};
/**
* Stage order mapping for quick lookups.
*
* @task T4800
*/
var STAGE_ORDER = {
	research: 1,
	consensus: 2,
	architecture_decision: 3,
	specification: 4,
	decomposition: 5,
	implementation: 6,
	validation: 7,
	testing: 8,
	release: 9
};
/**
* Prerequisites for each stage - which stages must be completed before entering.
*
* @task T4800
* @audit T4799 - Canonical prerequisite map
*/
var STAGE_PREREQUISITES = {
	research: [],
	consensus: ["research"],
	architecture_decision: ["research", "consensus"],
	specification: [
		"research",
		"consensus",
		"architecture_decision"
	],
	decomposition: ["research", "specification"],
	implementation: [
		"research",
		"specification",
		"decomposition"
	],
	validation: ["implementation"],
	testing: ["implementation", "validation"],
	release: [
		"implementation",
		"validation",
		"testing"
	]
};
/**
* Accepted shorthand aliases mapped to their canonical stage names.
*
* These allow users to type shorter names like `architecture` instead of
* `architecture_decision` on the CLI without breaking the state machine.
* The canonical name is always what gets persisted to the database.
*
* @task T929
*/
var STAGE_ALIASES = {
	architecture: "architecture_decision",
	adr: "architecture_decision",
	spec: "specification",
	decompose: "decomposition",
	implement: "implementation",
	verify: "validation",
	validate: "validation",
	test: "testing"
};
/**
* Resolve a stage name or alias to the canonical stage name.
*
* If `stage` is already a canonical stage name it is returned unchanged.
* If it is a known alias the canonical name is returned.
* Otherwise the original string is returned (callers should validate after).
*
* @param stage - Stage name or alias to resolve
* @returns Canonical stage name
*
* @task T929
* @example
* resolveStageAlias('architecture')       // => 'architecture_decision'
* resolveStageAlias('architecture_decision') // => 'architecture_decision'
* resolveStageAlias('unknown')            // => 'unknown'
*/
function resolveStageAlias(stage) {
	return STAGE_ALIASES[stage] ?? stage;
}
/**
* Check if a stage name is valid.
*
* @param stage - Stage name to validate
* @returns True if valid stage name
*
* @task T4800
*/
function isValidStage(stage) {
	return PIPELINE_STAGES.includes(stage);
}
/**
* Get stages by category.
*
* @param category - Category to filter by
* @returns Array of stages in that category
*
* @task T4800
*/
function getStagesByCategory(category) {
	return PIPELINE_STAGES.filter((stage) => STAGE_DEFINITIONS[stage].category === category);
}
getStagesByCategory("planning");
getStagesByCategory("decision");
getStagesByCategory("execution");
getStagesByCategory("validation");
getStagesByCategory("delivery");

//#endregion
//#region ../core/dist/tasks/tool-resolver.js
/**
* Canonical (project-agnostic) tool names accepted by `cleo verify
* --evidence "tool:<name>"`.
*
* Each canonical name maps to a project-specific command via
* {@link resolveToolCommand}. Adding a new canonical tool requires:
*
*   1. Adding the name here.
*   2. Adding a default for each {@link ProjectType} in `LANGUAGE_DEFAULTS`.
*   3. Updating {@link checkGateEvidenceMinimum} if the new tool can satisfy
*      a verification gate.
*/
var CANONICAL_TOOLS = [
	"test",
	"build",
	"lint",
	"typecheck",
	"audit",
	"security-scan",
	"nexus-impact-full"
];
/**
* Mapping of legacy hardcoded tool names → canonical name.
*
* @task T1534
*/
var LEGACY_TOOL_ALIASES = {
	"pnpm-test": "test",
	"npm-test": "test",
	"yarn-test": "test",
	"bun-test": "test",
	vitest: "test",
	jest: "test",
	pytest: "test",
	"cargo-test": "test",
	"go-test": "test",
	"pnpm-build": "build",
	"npm-build": "build",
	"yarn-build": "build",
	"bun-build": "build",
	"cargo-build": "build",
	"go-build": "build",
	biome: "lint",
	eslint: "lint",
	prettier: "lint",
	ruff: "lint",
	clippy: "lint",
	tsc: "typecheck",
	mypy: "typecheck",
	pyright: "typecheck",
	audit: "audit",
	"pnpm-audit": "audit",
	"npm-audit": "audit",
	"cargo-audit": "audit"
};
/**
* Set of all valid `tool:<name>` payloads — canonical names plus legacy
* aliases. Returned by {@link listValidToolNames} for help / validation
* surfaces.
*
* @task T1534
*/
function listValidToolNames() {
	return [...new Set([...CANONICAL_TOOLS, ...Object.keys(LEGACY_TOOL_ALIASES)])].sort();
}
Object.freeze(listValidToolNames());
Object.freeze(Object.fromEntries(Object.entries(GATE_EVIDENCE_REQUIREMENTS).map(([gate, spec]) => [gate, spec.oneOf.map((set) => [...set])])));

//#region ../worktree/dist/napi-binding.js
/**
* ESM-friendly bridge to the bundled worktree Node-API native addon.
*
* The napi-rs loader staged into `native/worktree-napi.cjs` exposes its surface as
* `module.exports = nativeBinding` — Node.js's CJS-to-ESM interop cannot
* statically detect named exports from a dynamic require(), so consumers route
* through this bridge instead of importing the native loader directly.
*
* This module wraps the native binding via `createRequire` so the import looks
* like a regular dynamic require from a CJS context. All consumers in this
* package import napi functions from THIS module, never directly from the
* native loader.
*
* Resolution order (first hit wins):
*
*   1. Bundled loader at `../native/worktree-napi.cjs` (published
*      `@cleocode/worktree` tarball).
*   2. Repo-local crate loader at `../../../crates/worktree-napi/index.cjs`
*      (source-tree execution after a local napi build).
*   3. **Core-managed cache** (T11580 · R10-L1): the host-triple `.node`
*      resolved by the shared `@cleocode/core` postinstall picker under
*      `<cache>/cleo/napi-bin/<version>/worktree-napi.<triple>.node`. This is
*      the Distribution Pattern P2 runtime hand-off — the picker downloads +
*      sha256-verifies the addon; this loader simply `require()`s the cached
*      file (the `.node` exports `module.exports = nativeBinding`, so no `.cjs`
*      wrapper is needed). Picked newest-version-first.
*
* @task T9982
* @task T11580
*/
/**
* Resolve the platform triple for the current host, mirroring the napi loader's
* `tripleName()` and the core picker's `resolveTriple()`. Returns `null` for
* unsupported platform/arch (e.g. macOS x64, for which no prebuild ships).
*
* @returns The host triple, or `null` when unsupported.
*/
function resolveHostTriple() {
	const { platform, arch } = process;
	if (platform === "linux" && arch === "x64") return "linux-x64-gnu";
	if (platform === "linux" && arch === "arm64") return "linux-arm64-gnu";
	if (platform === "darwin" && arch === "arm64") return "darwin-arm64";
	if (platform === "win32" && arch === "x64") return "win32-x64-msvc";
	return null;
}
/**
* Base cache directory holding the per-version `napi-bin` subdirs that the
* `@cleocode/core` picker writes to. Mirrors `cacheDir()` in
* `packages/core/scripts/napi-binary-picker.mjs` (env-paths('cleo').cache /
* napi-bin) without importing `@cleocode/core` (a devDependency only).
*
* @returns Absolute path to `<cache>/cleo/napi-bin`.
*/
function napiBinCacheRoot() {
	const p = process.platform;
	if (p === "win32") return join(process.env.LOCALAPPDATA ?? join(homedir(), "AppData", "Local"), "cleo", "Cache", "napi-bin");
	if (p === "darwin") return join(homedir(), "Library", "Caches", "cleo", "napi-bin");
	const xdg = process.env.XDG_CACHE_HOME;
	return join(xdg?.startsWith("/") ? xdg : join(homedir(), ".cache"), "cleo", "napi-bin");
}
/**
* Find the core-managed cached `worktree-napi.<triple>.node` for the host,
* preferring the newest version directory. Returns `null` when no cached addon
* exists (the common case in a fully-bundled install — tiers 1/2 win first).
*
* @returns Absolute path to the cached `.node`, or `null`.
*/
function resolveCoreManagedNapiPath() {
	const triple = resolveHostTriple();
	if (triple === null) return null;
	const root = napiBinCacheRoot();
	if (!existsSync(root)) return null;
	let versions;
	try {
		versions = readdirSync(root).sort().reverse();
	} catch {
		return null;
	}
	for (const version of versions) {
		const candidate = join(root, version, `worktree-napi.${triple}.node`);
		if (existsSync(candidate)) return candidate;
	}
	return null;
}
function getNative() {
	if (nativeBinding !== null) return nativeBinding;
	if (existsSync(bundledNativeLoaderPath)) {
		nativeBinding = require_(bundledNativeLoaderPath);
		return nativeBinding;
	}
	if (existsSync(repoLocalNativeLoaderPath)) try {
		nativeBinding = require_(repoLocalNativeLoaderPath);
		return nativeBinding;
	} catch {
		if (isTestRuntime()) {
			nativeBinding = createTestFallbackNativeModule();
			return nativeBinding;
		}
		throw new Error(`@cleocode/worktree: failed to load repo-local native loader at ${repoLocalNativeLoaderPath}. Run \`pnpm dlx @napi-rs/cli@3 build --release\` inside \`crates/worktree-napi/\` for source-tree execution.`);
	}
	const coreManagedNapiPath = resolveCoreManagedNapiPath();
	if (coreManagedNapiPath !== null) try {
		nativeBinding = require_(coreManagedNapiPath);
		return nativeBinding;
	} catch {
		if (isTestRuntime()) {
			nativeBinding = createTestFallbackNativeModule();
			return nativeBinding;
		}
		throw new Error(`@cleocode/worktree: failed to load core-managed native addon at ${coreManagedNapiPath}. The @cleocode/core postinstall picker resolved a cached binary that could not be loaded — reinstall @cleocode/core or clear the napi-bin cache.`);
	}
	if (isTestRuntime()) {
		nativeBinding = createTestFallbackNativeModule();
		return nativeBinding;
	}
	throw new Error(`@cleocode/worktree: missing bundled native loader at ${bundledNativeLoaderPath}. The release package must include native/worktree-napi.cjs and worktree-napi.<triple>.node files, or @cleocode/core must resolve worktree-napi via its postinstall picker (Pattern P2).`);
}
function isTestRuntime() {
	return process.env.NODE_ENV === "test" || process.env.VITEST !== void 0;
}
function createTestFallbackNativeModule() {
	const copyPathsParallelFallback = (srcDir, destDir, paths, opts) => {
		let copiedCount = 0;
		const failedPaths = [];
		for (const relativePath of paths) {
			const source = join(srcDir, relativePath);
			const destination = join(destDir, relativePath);
			if (opts.rootGuard !== void 0) {
				const guardedRoot = resolve(opts.rootGuard);
				if (!resolve(destination).startsWith(guardedRoot)) {
					failedPaths.push(relativePath);
					continue;
				}
			}
			try {
				cpSync(source, destination, {
					recursive: true,
					force: opts.force
				});
				copiedCount += 1;
			} catch {
				failedPaths.push(relativePath);
			}
		}
		return {
			copiedCount,
			skippedCount: paths.length - copiedCount,
			failedPaths,
			totalBytes: 0
		};
	};
	return {
		copyPathsParallel: copyPathsParallelFallback,
		destroyWorktree() {
			return {
				removed: false,
				branchDeleted: false
			};
		},
		readWorktreeInclude(repoRoot) {
			const includePath = join(repoRoot, ".worktreeinclude");
			if (!existsSync(includePath)) return [];
			return readFileSync(includePath, "utf-8").split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).map((line) => ({
				pattern: line.startsWith("!") ? line.slice(1) : line,
				isNegation: line.startsWith("!")
			}));
		},
		applyInclude(patterns, srcDir, destDir, opts) {
			return copyPathsParallelFallback(srcDir, destDir, patterns.filter((pattern) => !pattern.isNegation).map((pattern) => pattern.pattern), opts);
		},
		listWorktrees() {
			return [];
		},
		pruneWorktrees(opts) {
			return {
				integrationTarget: opts.integrationTarget,
				candidates: []
			};
		},
		removeDir(opts) {
			rmSync(opts.path, {
				recursive: true,
				force: true
			});
			return {
				files: 0,
				bytes: 0
			};
		},
		provisionWorktree(_opts) {
			return {
				path: "",
				branch: "",
				head: ""
			};
		},
		integrateWorktree(_opts) {
			return {
				taskId: "",
				targetBranch: "",
				merged: false,
				mergeCommit: "",
				commitCount: 0,
				rebased: false,
				error: "integrateWorktree not available in test fallback"
			};
		}
	};
}
var require_, bundledNativeLoaderPath, repoLocalNativeLoaderPath, nativeBinding, destroyWorktree, integrateWorktree;
var init_napi_binding = __esmMin((() => {
	require_ = createRequire(import.meta.url);
	bundledNativeLoaderPath = fileURLToPath(new URL("../native/worktree-napi.cjs", import.meta.url));
	repoLocalNativeLoaderPath = fileURLToPath(new URL("../../../crates/worktree-napi/index.cjs", import.meta.url));
	nativeBinding = null;
	destroyWorktree = (opts) => getNative().destroyWorktree(opts);
	integrateWorktree = (opts) => getNative().integrateWorktree(opts);
}));
//#endregion
//#region ../worktree/dist/copy-on-write.js
init_napi_binding();
promisify(execFile);
/**
* Run a git command synchronously and return trimmed stdout.
*
* @param args - Git argument array (do NOT include "git" as first element).
* @param cwd - Working directory for the git command.
* @param timeoutMs - Optional timeout override in milliseconds. Defaults to
*   {@link DEFAULT_GIT_TIMEOUT_MS}. Pass `0` to disable (NOT recommended).
* @returns Trimmed stdout string.
* @throws Error if the command exits non-zero or exceeds the timeout.
* @task T9545
*/
function gitSync(args, cwd, timeoutMs) {
	return execFileSync("git", args, {
		cwd,
		encoding: "utf-8",
		stdio: [
			"pipe",
			"pipe",
			"pipe"
		],
		timeout: 18e4
	}).trim();
}
/**
* Run a git command synchronously, returning false instead of throwing on error.
*
* Useful for best-effort cleanup operations where failure is non-fatal.
*
* @param args - Git argument array.
* @param cwd - Working directory.
* @param timeoutMs - Optional timeout override in milliseconds. Defaults to
*   {@link DEFAULT_GIT_TIMEOUT_MS}.
* @returns true on exit 0, false otherwise (including timeout).
* @task T9545
*/
function gitSilent(args, cwd, timeoutMs) {
	try {
		execFileSync("git", args, {
			cwd,
			stdio: "pipe",
			timeout: timeoutMs ?? 18e4
		});
		return true;
	} catch {
		return false;
	}
}
/**
* Determine the git root directory for a given project path.
*
* @param projectRoot - Absolute path to start the search from.
* @returns Absolute path to the git root.
* @throws Error if not inside a git repository.
*/
function getGitRoot(projectRoot) {
	try {
		return gitSync(["rev-parse", "--show-toplevel"], projectRoot);
	} catch {
		throw new Error(`Not a git repository: ${projectRoot}`);
	}
}
//#endregion
//#region ../worktree/dist/worktree-include.js
init_napi_binding();
//#endregion
//#region ../worktree/dist/worktree-destroy.js
init_napi_binding();
//#endregion
//#region ../worktree/dist/worktree-list.js
init_napi_binding();
//#endregion
//#region ../worktree/dist/worktree-prune.js
init_napi_binding();
//#endregion
//#region ../worktree/dist/index.js
init_napi_binding();
//#endregion
//#region ../core/dist/spawn/branch-lock.js
/**
* Resolve the worktree root directory for a project.
*
* Delegates to the canonical paths-SSoT helpers in `@cleocode/paths`. The
* resolved directory follows the XDG canonical layout per D029:
*
*   Linux:   ~/.local/share/cleo/worktrees/<projectHash>/
*   macOS:   ~/Library/Application Support/cleo/worktrees/<projectHash>/
*   Windows: %LOCALAPPDATA%\cleo\Data\worktrees\<projectHash>\
*
* T9984: previously hand-rolled `createHash('sha256').update(projectRoot)` +
* `process.env['XDG_DATA_HOME']` — both violations of the paths-SSoT lint
* (`packages/paths/` is the only legitimate source of these computations).
* Now routes through `computeProjectHash` and `resolveWorktreeRootForHash`.
*
* @param projectRoot - Absolute path to the project root.
* @returns Absolute path to the worktree root directory.
*
* @task T1118
* @task T1120
* @task T9984
*/
function resolveAgentWorktreeRoot(projectRoot) {
	return resolveWorktreeRootForHash(computeProjectHash(projectRoot));
}
/**
* Prune the worktree for a single completed or cancelled task.
*
* This function does NOT integrate commits — it is called after
* {@link completeAgentWorktreeViaMerge} (or `cleo complete`) has already
* recorded the task as done. It simply removes the worktree filesystem entry
* and the `task/<taskId>` branch if the branch has no commits ahead of the
* base ref.
*
* Behaviour:
* - Returns `{ status: 'skipped' }` when no worktree exists for the task.
* - Unlocks the worktree before removing (handles locked worktrees created by spawn).
* - Falls back to `rmSync` if `git worktree remove` fails.
* - Deletes `task/<taskId>` branch only when it has 0 commits ahead of the
*   current HEAD (i.e. the branch has already been merged or is empty).
*   When commits are still present the branch is left in place and reported in
*   the result — callers should use `completeAgentWorktreeViaMerge` first.
* - Always writes a `--force` remove with an audit log entry (`.cleo/audit/worktree-prune.jsonl`)
*   when the worktree is detected as dirty.
* - Never throws — failures are returned in `{ status: 'error', error }`.
*
* @param taskId     - The CLEO task ID (e.g. "T1462").
* @param projectRoot - Absolute path to the project root.
* @param opts.auditLogPath - Override path for the audit JSONL (testing).
* @returns Prune outcome.
*
* @task T1462
* @adr ADR-055
*/
function pruneWorktree(taskId, projectRoot, opts = {}) {
	const branch = `task/${taskId}`;
	let gitRoot;
	try {
		gitRoot = getGitRoot(projectRoot);
	} catch (err) {
		return {
			taskId,
			status: "error",
			worktreeRemoved: false,
			branchDeleted: false,
			wasDirty: false,
			error: `Not a git repo: ${err instanceof Error ? err.message : String(err)}`
		};
	}
	const worktreePath = join(resolveAgentWorktreeRoot(projectRoot), taskId);
	if (!existsSync(worktreePath)) {
		let branchDeleted = false;
		try {
			if (gitSync([
				"branch",
				"--list",
				branch
			], gitRoot)) {
				gitSync([
					"branch",
					"-D",
					branch
				], gitRoot);
				branchDeleted = true;
			} else branchDeleted = true;
		} catch {}
		return {
			taskId,
			status: "skipped",
			worktreeRemoved: false,
			branchDeleted,
			wasDirty: false
		};
	}
	let wasDirty = false;
	try {
		wasDirty = gitSync(["status", "--porcelain"], worktreePath).length > 0;
	} catch {}
	if (wasDirty) try {
		const auditDir = opts.auditLogPath ? opts.auditLogPath.split("/").slice(0, -1).join("/") : join(projectRoot, ".cleo", "audit");
		mkdirSync(auditDir, { recursive: true });
		appendFileSync(opts.auditLogPath ?? join(auditDir, "worktree-prune.jsonl"), JSON.stringify({
			timestamp: (/* @__PURE__ */ new Date()).toISOString(),
			taskId,
			worktreePath,
			action: "force-remove-dirty",
			agent: process.env["CLEO_AGENT_ID"] ?? "cleo"
		}) + "\n", "utf-8");
	} catch {}
	let worktreeRemoved = false;
	try {
		worktreeRemoved = destroyWorktree({
			repoRoot: gitRoot,
			worktreePath,
			force: true
		}).removed;
		if (worktreeRemoved && existsSync(worktreePath)) worktreeRemoved = false;
	} catch {}
	if (!worktreeRemoved) {
		gitSilent([
			"worktree",
			"unlock",
			worktreePath
		], gitRoot);
		try {
			rmSync(worktreePath, {
				recursive: true,
				force: true
			});
			gitSilent(["worktree", "prune"], gitRoot);
			worktreeRemoved = true;
		} catch (err) {
			return {
				taskId,
				status: "error",
				worktreeRemoved: false,
				branchDeleted: false,
				wasDirty,
				error: `Failed to remove worktree: ${err instanceof Error ? err.message : String(err)}`
			};
		}
	}
	let branchDeleted = false;
	try {
		if (gitSync([
			"branch",
			"--list",
			branch
		], gitRoot)) {
			let baseRef;
			try {
				baseRef = gitSync([
					"rev-parse",
					"--abbrev-ref",
					"HEAD"
				], gitRoot);
			} catch {
				baseRef = "main";
			}
			if (gitSync([
				"log",
				"--format=%H",
				`${baseRef}..${branch}`
			], gitRoot).split("\n").map((s) => s.trim()).filter(Boolean).length === 0) {
				gitSync([
					"branch",
					"-D",
					branch
				], gitRoot);
				branchDeleted = true;
			} else branchDeleted = false;
		} else branchDeleted = true;
	} catch {}
	return {
		taskId,
		status: "pruned",
		worktreeRemoved,
		branchDeleted,
		wasDirty
	};
}
/**
* Probe order for default-branch fallback when neither config nor
* `origin/HEAD` resolves. Order matches industry convention frequency.
*/
var DEFAULT_BRANCH_PROBE_ORDER = [
	"main",
	"master",
	"develop",
	"trunk"
];
/**
* Resolve the project's default integration branch in a project-agnostic way.
*
* Resolution order (per ADR-062):
*
* 1. `.cleo/config.json::git.defaultBranch` (explicit override).
* 2. `git symbolic-ref refs/remotes/origin/HEAD` (what the remote calls
*    default — works for `master`, `main`, `trunk`, etc.).
* 3. Probe local branches in order: `main`, `master`, `develop`, `trunk`.
* 4. Fallback to `'main'`.
*
* @param projectRoot - Absolute path to the project root.
* @returns The resolved default branch name (never throws).
*
* @task T1587
* @adr ADR-062
*/
function getDefaultBranch(projectRoot) {
	const configPath = join(projectRoot, ".cleo", "config.json");
	if (existsSync(configPath)) try {
		const raw = readFileSync(configPath, "utf-8");
		const fromCfg = JSON.parse(raw).git?.defaultBranch;
		if (typeof fromCfg === "string" && fromCfg.length > 0) return fromCfg;
	} catch {}
	let gitRoot;
	try {
		gitRoot = getGitRoot(projectRoot);
	} catch {
		return "main";
	}
	try {
		const stripped = gitSync(["symbolic-ref", "refs/remotes/origin/HEAD"], gitRoot).replace(/^refs\/remotes\/origin\//, "").trim();
		if (stripped.length > 0) return stripped;
	} catch {}
	for (const candidate of DEFAULT_BRANCH_PROBE_ORDER) try {
		if (gitSync([
			"branch",
			"--list",
			candidate
		], gitRoot).length > 0) return candidate;
	} catch {}
	return "main";
}
/**
* Complete a worker task's worktree via `git merge --no-ff` (ADR-062).
*
* Canonical worktree integration per ADR-062. Preserves the full agent
* commit graph instead of rewriting SHAs, so `git log --grep "T<id>"`
* returns the originating commits with their original authorship.
*
* Steps performed inside the worktree at
* `~/.local/share/cleo/worktrees/<projectHash>/<taskId>/`:
*
* 1. Resolve target branch via {@link getDefaultBranch} (or `opts.targetBranch`
*    override). NEVER hardcodes "main".
* 2. `git fetch origin` then `git rebase origin/<targetBranch>` inside the
*    worktree. Conflicts cause an early non-fatal return — the agent must
*    re-resolve before completion.
* 3. From the project's git root on `<targetBranch>`, run
*    `git merge --no-ff task/<taskId> -m "Merge T<id>: <title>"` so the
*    merge commit subject is `git log --grep`-friendly.
* 4. Capture the merge commit SHA and report it.
* 5. Delegate worktree+branch removal to {@link pruneWorktree} (T1462).
*
* Project-agnostic: no string in this function hardcodes "main", "master",
* or any other branch name. Test fixtures pass arbitrary `targetBranch`.
*
* @param taskId - The CLEO task ID (e.g. `"T1587"`).
* @param projectRoot - Absolute path to the project root.
* @param opts.targetBranch - Override the resolved default branch.
* @param opts.taskTitle - Task title used in the merge commit message subject.
* @param opts.skipFetch - Skip the `git fetch origin` step (test fixtures).
* @returns Merge integration result.
*
* @task T1587
* @adr ADR-062
*/
function completeAgentWorktreeViaMerge(taskId, projectRoot, opts = {}) {
	const branch = `task/${taskId}`;
	const targetBranch = opts.targetBranch ?? getDefaultBranch(projectRoot);
	let gitRoot;
	try {
		gitRoot = getGitRoot(projectRoot);
	} catch (err) {
		return {
			taskId,
			targetBranch,
			merged: false,
			mergeCommit: "",
			commitCount: 0,
			rebased: false,
			worktreeRemoved: false,
			branchDeleted: false,
			error: `Not a git repo: ${err instanceof Error ? err.message : String(err)}`
		};
	}
	const worktreePath = join(resolveAgentWorktreeRoot(projectRoot), taskId);
	const result = integrateWorktree({
		repoRoot: gitRoot,
		worktreePath,
		branch,
		targetBranch,
		taskTitle: opts.taskTitle,
		skipFetch: opts.skipFetch ?? false
	});
	if (!result.merged) return {
		taskId,
		targetBranch,
		merged: false,
		mergeCommit: "",
		commitCount: result.commitCount,
		rebased: result.rebased,
		worktreeRemoved: false,
		branchDeleted: false,
		error: result.error
	};
	const pruneResult = pruneWorktree(taskId, projectRoot);
	return {
		taskId,
		targetBranch,
		merged: true,
		mergeCommit: result.mergeCommit,
		commitCount: result.commitCount,
		rebased: result.rebased,
		worktreeRemoved: pruneResult.worktreeRemoved,
		branchDeleted: pruneResult.branchDeleted,
		error: pruneResult.error
	};
}
/**
* Complete a worker task's worktree integration via merge, cleanup, and audit log.
*
* This is the orchestrator-facing convenience wrapper around
* `completeAgentWorktreeViaMerge`. In addition to the merge+prune steps it:
*
* 1. Delegates all merge and cleanup to `completeAgentWorktreeViaMerge`.
* 2. Appends a structured entry to `.cleo/audit/worktree-integration.jsonl`
*    recording the merge commit, task ID, and cleanup outcome.
*
* Orchestrators MUST call this (not `completeAgentWorktreeViaMerge` directly)
* so every integration is auditable.
*
* @param taskId - The CLEO task ID (e.g. `"T1587"`).
* @param projectRoot - Absolute path to the project root.
* @param opts.targetBranch - Override the resolved default branch.
* @param opts.taskTitle - Task title used in the merge commit message subject.
* @param opts.skipFetch - Skip the `git fetch origin` step (test fixtures).
* @param opts.auditLogPath - Override the audit JSONL path (testing).
* @returns Integration result including audit log path.
*
* @task T9043
* @adr ADR-062
*/
function completeAgentWorktreeIntegration(taskId, projectRoot, opts = {}) {
	const mergeResult = completeAgentWorktreeViaMerge(taskId, projectRoot, {
		targetBranch: opts.targetBranch,
		taskTitle: opts.taskTitle,
		skipFetch: opts.skipFetch
	});
	let auditLogEntry = null;
	try {
		const auditDir = opts.auditLogPath ? opts.auditLogPath.split("/").slice(0, -1).join("/") : join(projectRoot, ".cleo", "audit");
		mkdirSync(auditDir, { recursive: true });
		const logPath = opts.auditLogPath ?? join(auditDir, "worktree-integration.jsonl");
		appendFileSync(logPath, JSON.stringify({
			timestamp: (/* @__PURE__ */ new Date()).toISOString(),
			taskId,
			mergeCommit: mergeResult.mergeCommit,
			merged: mergeResult.merged,
			worktreeRemoved: mergeResult.worktreeRemoved,
			branchDeleted: mergeResult.branchDeleted,
			error: mergeResult.error ?? null,
			agent: process.env["CLEO_AGENT_ID"] ?? "cleo"
		}) + "\n", "utf-8");
		auditLogEntry = logPath;
	} catch {}
	return {
		...mergeResult,
		auditLogEntry
	};
}

export { PIPELINE_STAGES as P, STAGE_PREREQUISITES as S, STAGE_ORDER as a, STAGE_DEFINITIONS as b, completeAgentWorktreeIntegration as c, deriveSlugSuggestionsForAllocator as d, isValidStage as i, resolveStageAlias as r };
//# sourceMappingURL=branch-lock-qP1EkZ7p.js.map
