param(
  [string]$ProjectRoot = "",
  [string]$TemplateRoot = "",
  [ValidateSet("full", "project")]
  [string]$InstallMode = "project",
  [ValidateSet("legacy", "thin")]
  [string]$Profile = "legacy",
  [switch]$VendorInstalled,
  [switch]$Force,
  [switch]$IncludeDocs = $true
)

Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"

function Get-PackageRoot {
  return [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot "..\.."))
}

if ([string]::IsNullOrWhiteSpace($ProjectRoot)) {
  $ProjectRoot = Get-PackageRoot
}

function Resolve-TemplateRoot {
  <#
    解析模板目录，兼容从 templates/ 或项目根目录运行。
  #>
  param(
    [string]$ProjectPath,
    [string]$ExplicitTemplateRoot
  )

  $candidates = @()
  if (-not [string]::IsNullOrWhiteSpace($ExplicitTemplateRoot)) {
    $candidates += $ExplicitTemplateRoot
  }

  $candidates += @(
    (Join-Path (Get-PackageRoot) "docs\codex-harness-engineering\templates"),
    (Join-Path (Get-PackageRoot) ".agents\docs\codex-harness-engineering\templates"),
    (Get-PackageRoot),
    (Join-Path $ProjectPath "docs\codex-harness-engineering\templates"),
    (Join-Path $ProjectPath ".agents\docs\codex-harness-engineering\templates")
  )

  foreach ($candidate in $candidates) {
    if ([string]::IsNullOrWhiteSpace($candidate)) {
      continue
    }

    $resolved = $null
    try {
      $resolved = (Resolve-Path -LiteralPath $candidate).Path
    }
    catch {
      continue
    }

    $agentsTemplate = Join-Path $resolved "runtime\AGENTS.md"
    $driverTemplate = Join-Path $resolved "runtime\codex-loop.ps1"
    if ((Test-Path -LiteralPath $agentsTemplate) -and (Test-Path -LiteralPath $driverTemplate)) {
      return $resolved
    }
  }

  throw "找不到可用模板目录。请显式传入 -TemplateRoot。"
}

function Copy-ManagedFile {
  <#
    复制单个模板文件，默认只补齐缺失文件。
  #>
  param(
    [string]$SourceRoot,
    [string]$SourceRelativePath,
    [string]$DestinationRoot,
    [string]$DestinationRelativePath,
    [bool]$Overwrite
  )

  $sourcePath = Join-Path $SourceRoot $SourceRelativePath
  if (-not (Test-Path -LiteralPath $sourcePath)) {
    throw "模板文件不存在: $sourcePath"
  }

  $destinationPath = Join-Path $DestinationRoot $DestinationRelativePath
  $destinationDirectory = Split-Path -Parent $destinationPath
  if (-not (Test-Path -LiteralPath $destinationDirectory)) {
    New-Item -ItemType Directory -Force -Path $destinationDirectory | Out-Null
  }

  if ((Test-Path -LiteralPath $destinationPath) -and (-not $Overwrite)) {
    return [PSCustomObject]@{
      Path = $destinationPath
      Action = "skipped"
    }
  }

  Copy-Item -LiteralPath $sourcePath -Destination $destinationPath -Force
  return [PSCustomObject]@{
    Path = $destinationPath
    Action = "copied"
  }
}

function Copy-ManagedDirectory {
  param(
    [string]$SourceDirectory,
    [string]$DestinationDirectory,
    [bool]$Overwrite
  )

  if (-not (Test-Path -LiteralPath $SourceDirectory)) {
    throw "模板目录不存在: $SourceDirectory"
  }

  if (Test-Path -LiteralPath $DestinationDirectory) {
    if (-not $Overwrite) {
      return [PSCustomObject]@{
        Path = $DestinationDirectory
        Action = "kept"
      }
    }

    Remove-Item -LiteralPath $DestinationDirectory -Recurse -Force
  }

  New-Item -ItemType Directory -Force -Path $DestinationDirectory | Out-Null
  $robocopyArgs = @(
    $SourceDirectory,
    $DestinationDirectory,
    "/E",
    "/COPY:DAT",
    "/DCOPY:DAT",
    "/R:2",
    "/W:1",
    "/NFL",
    "/NDL",
    "/NJH",
    "/NJS",
    "/NP"
  )

  & robocopy @robocopyArgs | Out-Null
  $robocopyExitCode = $LASTEXITCODE
  if ($robocopyExitCode -ge 8) {
    throw "复制模板目录失败: $SourceDirectory -> $DestinationDirectory (robocopy exit $robocopyExitCode)"
  }

  $global:LASTEXITCODE = 0
  return [PSCustomObject]@{
    Path = $DestinationDirectory
    Action = "copied"
  }
}

function Sync-TemplateCodexAgents {
  param(
    [string]$TemplateRoot,
    [string]$ProjectPath,
    [bool]$Overwrite
  )

  $results = @()
  $agentsSourceRoot = Join-Path $TemplateRoot "config\agents"
  if (-not (Test-Path -LiteralPath $agentsSourceRoot)) {
    throw "找不到 Codex agents 模板目录: $agentsSourceRoot"
  }

  foreach ($file in Get-ChildItem -LiteralPath $agentsSourceRoot -Recurse -File) {
    $relativePath = $file.FullName.Substring($agentsSourceRoot.Length + 1)
    $results += Copy-ManagedFile `
      -SourceRoot $agentsSourceRoot `
      -SourceRelativePath $relativePath `
      -DestinationRoot $ProjectPath `
      -DestinationRelativePath (Join-Path ".codex\agents" $relativePath) `
      -Overwrite:$Overwrite
  }

  return $results
}

function Sync-TemplateCodexRules {
  param(
    [string]$TemplateRoot,
    [string]$ProjectPath,
    [bool]$Overwrite
  )

  $results = @()
  $rulesSourceRoot = Join-Path $TemplateRoot "config\rules"
  if (-not (Test-Path -LiteralPath $rulesSourceRoot)) {
    throw "找不到 Codex rules 模板目录: $rulesSourceRoot"
  }

  foreach ($file in Get-ChildItem -LiteralPath $rulesSourceRoot -Recurse -File) {
    $relativePath = $file.FullName.Substring($rulesSourceRoot.Length + 1)
    $results += Copy-ManagedFile `
      -SourceRoot $rulesSourceRoot `
      -SourceRelativePath $relativePath `
      -DestinationRoot $ProjectPath `
      -DestinationRelativePath (Join-Path ".codex\rules" $relativePath) `
      -Overwrite:$Overwrite
  }

  return $results
}

function Ensure-TaskFile {
  <#
    确保 task.json 存在，并补齐 runtime.driver。
  #>
  param(
    [string]$SourceRoot,
    [string]$DestinationRoot
  )

  $taskPath = Join-Path $DestinationRoot "task.json"
  if (-not (Test-Path -LiteralPath $taskPath)) {
    return Copy-ManagedFile -SourceRoot $SourceRoot -SourceRelativePath "runtime\smoke-task.json" -DestinationRoot $DestinationRoot -DestinationRelativePath "task.json" -Overwrite:$false
  }

  $taskContent = Get-Content -LiteralPath $taskPath -Raw
  if ([string]::IsNullOrWhiteSpace($taskContent)) {
    return Copy-ManagedFile -SourceRoot $SourceRoot -SourceRelativePath "runtime\smoke-task.json" -DestinationRoot $DestinationRoot -DestinationRelativePath "task.json" -Overwrite:$true
  }

  $taskDocument = $taskContent | ConvertFrom-Json
  if ($null -eq $taskDocument.runtime) {
    $taskDocument | Add-Member -NotePropertyName "runtime" -NotePropertyValue ([PSCustomObject]@{}) -Force
  }

  $canonicalDriver = "powershell -NoProfile -ExecutionPolicy Bypass -File .\tools\harness\codex-loop.ps1"
  $driverPattern = 'tools[\\/]+harness[\\/]+tools[\\/]+harness[\\/]+codex-loop\.ps1'

  if ([string]::IsNullOrWhiteSpace($taskDocument.runtime.driver)) {
    $taskDocument.runtime.driver = $canonicalDriver
    $taskDocument | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $taskPath -Encoding UTF8
    return [PSCustomObject]@{
      Path = $taskPath
      Action = "updated"
    }
  }

  if ([string]$taskDocument.runtime.driver -match $driverPattern) {
    $taskDocument.runtime.driver = $canonicalDriver
    $taskDocument | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $taskPath -Encoding UTF8
    return [PSCustomObject]@{
      Path = $taskPath
      Action = "updated"
    }
  }

  return [PSCustomObject]@{
    Path = $taskPath
    Action = "kept"
  }
}

function Write-BootstrapSummary {
  <#
    输出自动配置结果，便于人工确认。
  #>
  param([object[]]$Results)

  foreach ($result in $Results) {
    Write-Output ("[{0}] {1}" -f $result.Action.ToUpperInvariant(), $result.Path)
  }
}

function Get-PackageRootFromTemplateRoot {
  param([string]$TemplateRoot)

  $engineeringRoot = Split-Path -Parent $TemplateRoot
  $docsRoot = Split-Path -Parent $engineeringRoot
  return Split-Path -Parent $docsRoot
}

function Normalize-LockManifestPath {
  param([string]$Path)

  $raw = if ($null -eq $Path) { "" } else { [string]$Path }
  $normalized = $raw.Trim().Replace('\', '/')
  while ($normalized.StartsWith('./', [System.StringComparison]::Ordinal)) {
    $normalized = $normalized.Substring(2)
  }

  return $normalized.TrimStart('/').TrimEnd('/')
}

function Resolve-LockManifestSourcePath {
  param(
    [string]$PackageRoot,
    [string]$SourceRelativePath
  )

  $normalizedSource = Normalize-LockManifestPath -Path $SourceRelativePath
  if (
    $normalizedSource.Equals('templates', [System.StringComparison]::OrdinalIgnoreCase) -or
    $normalizedSource.StartsWith('templates/', [System.StringComparison]::OrdinalIgnoreCase)
  ) {
    return Join-Path (Join-Path $PackageRoot "docs\codex-harness-engineering") ($normalizedSource.Replace('/', '\'))
  }

  return Join-Path $PackageRoot ($normalizedSource.Replace('/', '\'))
}

function Get-FileSha256 {
  param([string]$Path)

  $hashAlgorithm = [System.Security.Cryptography.SHA256]::Create()
  try {
    $stream = [System.IO.File]::OpenRead($Path)
    try {
      $hashBytes = $hashAlgorithm.ComputeHash($stream)
    }
    finally {
      $stream.Dispose()
    }
  }
  finally {
    $hashAlgorithm.Dispose()
  }

  return ([System.BitConverter]::ToString($hashBytes)).Replace('-', '').ToLowerInvariant()
}

function Add-LockManagedFile {
  param(
    [System.Collections.Generic.List[object]]$ManagedFiles,
    [string]$Path,
    [string]$Source,
    [string]$Scope,
    [string]$Kind,
    [string]$TargetPath
  )

  $ManagedFiles.Add([pscustomobject]@{
    path = Normalize-LockManifestPath -Path $Path
    source = Normalize-LockManifestPath -Path $Source
    scope = $Scope
    kind = $Kind
    mutable = $false
    sha256 = Get-FileSha256 -Path $TargetPath
  })
}

function Get-LockManagedFiles {
  param(
    [string]$PackageRoot,
    [string]$ProjectPath,
    [string]$InstallMode,
    [bool]$VendorInstalled
  )

  $installManifestPath = Join-Path $PackageRoot "install-manifest.json"
  if (-not (Test-Path -LiteralPath $installManifestPath -PathType Leaf)) {
    return @()
  }

  try {
    $installManifest = Get-Content -LiteralPath $installManifestPath -Raw | ConvertFrom-Json
  }
  catch {
    return @()
  }

  $includedScopes = @("project")
  if ($VendorInstalled) {
    $includedScopes += "vendor"
  }

  $managedFiles = New-Object System.Collections.Generic.List[object]
  foreach ($entry in @($installManifest.entries)) {
    $scope = [string]$entry.scope
    $mutable = [bool]$entry.mutable
    $kind = [string]$entry.kind
    $destination = Normalize-LockManifestPath -Path ([string]$entry.destination)
    $source = Normalize-LockManifestPath -Path ([string]$entry.source)

    if ($includedScopes -notcontains $scope) {
      continue
    }

    if ($mutable) {
      continue
    }

    if ($kind -eq "generated-lock" -or $destination -eq ".codex-harness/locks/package.lock.json") {
      continue
    }

    $sourcePath = Resolve-LockManifestSourcePath -PackageRoot $PackageRoot -SourceRelativePath $source
    $sourceIsFile = Test-Path -LiteralPath $sourcePath -PathType Leaf
    $sourceIsDirectory = Test-Path -LiteralPath $sourcePath -PathType Container
    if ((-not $sourceIsFile) -and (-not $sourceIsDirectory)) {
      continue
    }

    $targetPath = Join-Path $ProjectPath ($destination.Replace('/', '\'))
    if ($sourceIsFile) {
      if (-not (Test-Path -LiteralPath $targetPath -PathType Leaf)) {
        continue
      }

      Add-LockManagedFile `
        -ManagedFiles $managedFiles `
        -Path $destination `
        -Source $source `
        -Scope $scope `
        -Kind $kind `
        -TargetPath $targetPath
      continue
    }

    if (-not (Test-Path -LiteralPath $targetPath -PathType Container)) {
      continue
    }

    $sourceDirectory = [System.IO.Path]::GetFullPath($sourcePath).TrimEnd('\', '/')
    $destinationRoot = $destination.TrimEnd('/')
    $sourceRoot = $source.TrimEnd('/')
    foreach ($sourceFile in @(Get-ChildItem -LiteralPath $sourceDirectory -Recurse -File | Sort-Object FullName)) {
      $relativeFilePath = $sourceFile.FullName.Substring($sourceDirectory.Length).TrimStart('\', '/').Replace('\', '/')
      $targetFilePath = Join-Path $targetPath ($relativeFilePath.Replace('/', '\'))
      if (-not (Test-Path -LiteralPath $targetFilePath -PathType Leaf)) {
        continue
      }

      Add-LockManagedFile `
        -ManagedFiles $managedFiles `
        -Path ($destinationRoot + "/" + $relativeFilePath) `
        -Source ($sourceRoot + "/" + $relativeFilePath) `
        -Scope $scope `
        -Kind $kind `
        -TargetPath $targetFilePath
    }
  }

  return @($managedFiles.ToArray())
}

function Write-PackageLock {
  param(
    [string]$TemplateRoot,
    [string]$ProjectPath,
    [string]$InstallMode,
    [bool]$VendorInstalled
  )

  $packageRoot = Get-PackageRootFromTemplateRoot -TemplateRoot $TemplateRoot
  $aiKitManifestPath = Join-Path $packageRoot "ai-sync\ai-kit-manifest.json"
  $installManifestPath = Join-Path $packageRoot "install-manifest.json"
  $sourceCommit = ""
  $packageVersion = ""
  $managedFiles = Get-LockManagedFiles `
    -PackageRoot $packageRoot `
    -ProjectPath $ProjectPath `
    -InstallMode $InstallMode `
    -VendorInstalled:$VendorInstalled

  if (Test-Path -LiteralPath $aiKitManifestPath -PathType Leaf) {
    try {
      $aiKitManifest = Get-Content -LiteralPath $aiKitManifestPath -Raw | ConvertFrom-Json
      $sourceCommit = [string]$aiKitManifest.source.commit
    }
    catch {
      $sourceCommit = ""
    }
  }

  if (Test-Path -LiteralPath $installManifestPath -PathType Leaf) {
    try {
      $installManifest = Get-Content -LiteralPath $installManifestPath -Raw | ConvertFrom-Json
      $packageVersion = [string]$installManifest.version
    }
    catch {
      $packageVersion = ""
    }
  }

  $lockDirectory = Join-Path $ProjectPath ".codex-harness\locks"
  if (-not (Test-Path -LiteralPath $lockDirectory -PathType Container)) {
    New-Item -ItemType Directory -Force -Path $lockDirectory | Out-Null
  }

  $lockDocument = [pscustomobject]@{
    lockVersion = "0.1"
    package = "codex-harness"
    version = $packageVersion
    sourceCommit = $sourceCommit
    installMode = $InstallMode
    vendor = $VendorInstalled
    installedAt = (Get-Date).ToString("o")
    source = [pscustomobject]@{
      packageRoot = $packageRoot
      commit = $sourceCommit
    }
    manifests = [pscustomobject]@{
      aiKit = if (Test-Path -LiteralPath $aiKitManifestPath -PathType Leaf) { "ai-sync/ai-kit-manifest.json" } else { "" }
      install = if (Test-Path -LiteralPath $installManifestPath -PathType Leaf) { "install-manifest.json" } else { "" }
    }
    managedFiles = @($managedFiles)
  }

  $lockPath = Join-Path $lockDirectory "package.lock.json"
  $lockDocument | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $lockPath -Encoding UTF8

  return [PSCustomObject]@{
    Path = $lockPath
    Action = "written"
  }
}

function Write-HarnessConfig {
  param(
    [string]$TemplateRoot,
    [string]$ProjectPath,
    [bool]$VendorInstalled
  )

  $packageRoot = Get-PackageRootFromTemplateRoot -TemplateRoot $TemplateRoot
  $installManifestPath = Join-Path $packageRoot "install-manifest.json"
  $packageVersion = ""
  if (Test-Path -LiteralPath $installManifestPath -PathType Leaf) {
    try {
      $installManifest = Get-Content -LiteralPath $installManifestPath -Raw | ConvertFrom-Json
      $packageVersion = [string]$installManifest.version
    }
    catch {
      $packageVersion = ""
    }
  }

  $configDirectory = Join-Path $ProjectPath ".codex-harness\state"
  if (-not (Test-Path -LiteralPath $configDirectory -PathType Container)) {
    New-Item -ItemType Directory -Force -Path $configDirectory | Out-Null
  }

  $configDocument = [pscustomobject]@{
    package = "codex-harness"
    version = $packageVersion
    packageRoot = $packageRoot
    installScope = if ($VendorInstalled) { "vendor" } else { "project" }
    vendor = $VendorInstalled
  }

  $configPath = Join-Path $configDirectory "config.json"
  $configDocument | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $configPath -Encoding UTF8
  return [PSCustomObject]@{
    Path = $configPath
    Action = "written"
  }
}

function Write-InstallManifestSnapshot {
  param(
    [string]$TemplateRoot,
    [string]$ProjectPath
  )

  $packageRoot = Get-PackageRootFromTemplateRoot -TemplateRoot $TemplateRoot
  $installManifestPath = Join-Path $packageRoot "install-manifest.json"
  if (-not (Test-Path -LiteralPath $installManifestPath -PathType Leaf)) {
    return [PSCustomObject]@{
      Path = (Join-Path $ProjectPath ".codex-harness\manifests\install-manifest.json")
      Action = "missing-source"
    }
  }

  $snapshotDirectory = Join-Path $ProjectPath ".codex-harness\manifests"
  if (-not (Test-Path -LiteralPath $snapshotDirectory -PathType Container)) {
    New-Item -ItemType Directory -Force -Path $snapshotDirectory | Out-Null
  }

  $snapshotPath = Join-Path $snapshotDirectory "install-manifest.json"
  Copy-Item -LiteralPath $installManifestPath -Destination $snapshotPath -Force
  return [PSCustomObject]@{
    Path = $snapshotPath
    Action = "written"
  }
}

$resolvedProjectRoot = (Resolve-Path -LiteralPath $ProjectRoot).Path
$resolvedTemplateRoot = Resolve-TemplateRoot -ProjectPath $resolvedProjectRoot -ExplicitTemplateRoot $TemplateRoot
$results = @()

$rootFiles = @(
  @{ Source = "runtime\AGENTS.md"; Destination = "AGENTS.md" },
  @{ Source = "bootstrap-codex-harness.ps1"; Destination = "tools\install\bootstrap-codex-harness.ps1" },
  @{ Source = "runtime\codex-loop.ps1"; Destination = "tools\harness\codex-loop.ps1" },
  @{ Source = "runtime\doctor.ps1"; Destination = "tools\harness\doctor.ps1" },
  @{ Source = "config\codex-config.toml"; Destination = ".codex\config.toml" },
  @{ Source = "config\codex-readme.md"; Destination = ".codex\README.md" },
  @{ Source = "hooks\hooks.json"; Destination = ".codex\hooks.json" },
  @{ Source = "hooks\hook-stop-verify.ps1"; Destination = "tools\harness\hook-stop-verify.ps1" },
  @{ Source = "scripts\harness\harness-governance-check.ps1"; Destination = "scripts\harness\harness-governance-check.ps1" },
  @{ Source = "scripts\ai-workflow\check-ai-sync-drift.ps1"; Destination = "tools\install\ai-workflow\check-ai-sync-drift.ps1" },
  @{ Source = "runtime\task-run-profile.json"; Destination = ".codex\task-run-profile.json" },
  @{ Source = "prompts\implement-one-task.md"; Destination = ".codex\prompts\implement-one-task.md" },
  @{ Source = "prompts\controller-loop.md"; Destination = ".codex\prompts\controller-loop.md" },
  @{ Source = "prompts\review-one-task.md"; Destination = ".codex\prompts\review-one-task.md" },
  @{ Source = "prompts\review-stage1-spec.md"; Destination = ".codex\prompts\review-stage1-spec.md" },
  @{ Source = "prompts\review-stage2-quality.md"; Destination = ".codex\prompts\review-stage2-quality.md" },
  @{ Source = "prompts\visual-evaluator.md"; Destination = ".codex\prompts\visual-evaluator.md" },
  @{ Source = "prompts\failure-triage.md"; Destination = ".codex\prompts\failure-triage.md" },
  @{ Source = "prompts\repair-one-finding.md"; Destination = ".codex\prompts\repair-one-finding.md" },
  @{ Source = "prompts\harness-audit.md"; Destination = ".codex\prompts\harness-audit.md" },
  @{ Source = "prompts\worker-role\frontend-worker.md"; Destination = ".codex\prompts\worker-role\frontend-worker.md" },
  @{ Source = "prompts\worker-role\backend-worker.md"; Destination = ".codex\prompts\worker-role\backend-worker.md" },
  @{ Source = "prompts\worker-role\test-runner.md"; Destination = ".codex\prompts\worker-role\test-runner.md" },
  @{ Source = "prompts\worker-role\docs-worker.md"; Destination = ".codex\prompts\worker-role\docs-worker.md" },
  @{ Source = "prompts\worker-role\harness-writer.md"; Destination = ".codex\prompts\worker-role\harness-writer.md" },
  @{ Source = "runtime\smoke-task.json"; Destination = "tools\harness\templates\smoke-task.json" },
  @{ Source = "runtime\project-task-template.json"; Destination = "tools\harness\templates\project-task-template.json" },
  @{ Source = "runtime\feature-task-reference.json"; Destination = "tools\harness\templates\feature-task-reference.json" },
  @{ Source = "tools\harness\task-structure-lint.ps1"; Destination = "tools\harness\task-structure-lint.ps1" },
  @{ Source = "tools\harness\task-protocol-lint.ps1"; Destination = "tools\harness\task-protocol-lint.ps1" },
  @{ Source = "tools\harness\business-goal-lint.ps1"; Destination = "tools\harness\business-goal-lint.ps1" },
  @{ Source = "tools\harness\product-spec-lint.ps1"; Destination = "tools\harness\product-spec-lint.ps1" },
  @{ Source = "tools\harness\acceptance-contract-lint.ps1"; Destination = "tools\harness\acceptance-contract-lint.ps1" },
  @{ Source = "tools\harness\contract-lint.ps1"; Destination = "tools\harness\contract-lint.ps1" },
  @{ Source = "tools\harness\domain-model-lint.ps1"; Destination = "tools\harness\domain-model-lint.ps1" },
  @{ Source = "tools\harness\backend-lint.ps1"; Destination = "tools\harness\backend-lint.ps1" },
  @{ Source = "tools\harness\architecture-boundary-lint.ps1"; Destination = "tools\harness\architecture-boundary-lint.ps1" },
  @{ Source = "tools\harness\security-lint.ps1"; Destination = "tools\harness\security-lint.ps1" },
  @{ Source = "tools\harness\impact-lint.ps1"; Destination = "tools\harness\impact-lint.ps1" },
  @{ Source = "tools\harness\test-strategy-lint.ps1"; Destination = "tools\harness\test-strategy-lint.ps1" },
  @{ Source = "tools\harness\implementation-plan-lint.ps1"; Destination = "tools\harness\implementation-plan-lint.ps1" },
  @{ Source = "tools\harness\execution-boundary-lint.ps1"; Destination = "tools\harness\execution-boundary-lint.ps1" },
  @{ Source = "tools\harness\review-evidence-lint.ps1"; Destination = "tools\harness\review-evidence-lint.ps1" },
  @{ Source = "tools\harness\truth-source-lint.ps1"; Destination = "tools\harness\truth-source-lint.ps1" },
  @{ Source = "runtime\verify.ps1"; Destination = "tools\harness\verify.ps1" },
  @{ Source = "tools\harness\docs-lint.ps1"; Destination = "tools\harness\docs-lint.ps1" },
  @{ Source = "tools\harness\data-lint.ps1"; Destination = "tools\harness\data-lint.ps1" },
  @{ Source = "tools\harness\integration-lint.ps1"; Destination = "tools\harness\integration-lint.ps1" },
  @{ Source = "tools\harness\mobile-lint.ps1"; Destination = "tools\harness\mobile-lint.ps1" },
  @{ Source = "tools\harness\acceptance-lint.ps1"; Destination = "tools\harness\acceptance-lint.ps1" },
  @{ Source = "tools\harness\session-lint.ps1"; Destination = "tools\harness\session-lint.ps1" },
  @{ Source = "config\env-check.ps1"; Destination = "tools\install\env-check.ps1" },
  @{ Source = "trace\trace.schema.json"; Destination = "docs\harness\trace.schema.json" },
  @{ Source = "runtime\task.schema.json"; Destination = "docs\harness\task.schema.json" }
)

foreach ($file in $rootFiles) {
  $results += Copy-ManagedFile -SourceRoot $resolvedTemplateRoot -SourceRelativePath $file.Source -DestinationRoot $resolvedProjectRoot -DestinationRelativePath $file.Destination -Overwrite:$Force.IsPresent
}

$results += Sync-TemplateCodexAgents -TemplateRoot $resolvedTemplateRoot -ProjectPath $resolvedProjectRoot -Overwrite:$Force.IsPresent
$results += Sync-TemplateCodexRules -TemplateRoot $resolvedTemplateRoot -ProjectPath $resolvedProjectRoot -Overwrite:$Force.IsPresent

$packageAssetsRoot = Join-Path $resolvedTemplateRoot "package-assets"
if (Test-Path -LiteralPath $packageAssetsRoot) {
  $results += Copy-ManagedDirectory `
    -SourceDirectory (Join-Path $packageAssetsRoot "skills") `
    -DestinationDirectory (Join-Path $resolvedProjectRoot ".agents\skills") `
    -Overwrite:$Force.IsPresent

  $results += Copy-ManagedDirectory `
    -SourceDirectory (Join-Path $packageAssetsRoot "workflows") `
    -DestinationDirectory (Join-Path $resolvedProjectRoot ".agents\workflows") `
    -Overwrite:$Force.IsPresent
}

$results += Ensure-TaskFile -SourceRoot $resolvedTemplateRoot -DestinationRoot $resolvedProjectRoot

$progressPath = Join-Path $resolvedProjectRoot "progress.txt"
if (-not (Test-Path -LiteralPath $progressPath)) {
  $results += Copy-ManagedFile -SourceRoot $resolvedTemplateRoot -SourceRelativePath "runtime\progress.txt" -DestinationRoot $resolvedProjectRoot -DestinationRelativePath "progress.txt" -Overwrite:$false
}
else {
  $results += [PSCustomObject]@{
    Path = $progressPath
    Action = "kept"
  }
}

$contextFiles = @(
  @{ Source = "context\repo-map.md"; Destination = "docs\ai\repo-map.md" },
  @{ Source = "context\architecture-brief.md"; Destination = "docs\ai\architecture-brief.md" },
  @{ Source = "context\CURRENT_TASK.md"; Destination = "docs\ai\CURRENT_TASK.md" },
  @{ Source = "context\PROJECT_CONTEXT.md"; Destination = "docs\ai\PROJECT_CONTEXT.md" },
  @{ Source = "context\DECISIONS.md"; Destination = "docs\ai\DECISIONS.md" },
  @{ Source = "context\API_MAP.md"; Destination = "docs\ai\API_MAP.md" },
  @{ Source = "context\DB_SCHEMA.md"; Destination = "docs\ai\DB_SCHEMA.md" },
  @{ Source = "context\KNOWN_ISSUES.md"; Destination = "docs\ai\KNOWN_ISSUES.md" },
  @{ Source = "context\CHANGELOG_AI.md"; Destination = "docs\ai\CHANGELOG_AI.md" },
  @{ Source = "context\service-dependency-matrix.yaml"; Destination = ".service-matrix\dependencies.yaml" },
  @{ Source = "context\feature-pack.md"; Destination = "docs\context\feature-pack.md" },
  @{ Source = "context\domain-model.md"; Destination = "docs\context\domain-model.md" }
)

foreach ($file in $contextFiles) {
  $results += Copy-ManagedFile -SourceRoot $resolvedTemplateRoot -SourceRelativePath $file.Source -DestinationRoot $resolvedProjectRoot -DestinationRelativePath $file.Destination -Overwrite:$Force.IsPresent
}

$architectureFiles = @(
  @{ Source = "docs\architecture-constraints.md"; Destination = "docs\architecture\constraints.md" }
)

foreach ($file in $architectureFiles) {
  $results += Copy-ManagedFile -SourceRoot $resolvedTemplateRoot -SourceRelativePath $file.Source -DestinationRoot $resolvedProjectRoot -DestinationRelativePath $file.Destination -Overwrite:$Force.IsPresent
}

$productRoot = Join-Path $resolvedTemplateRoot "product"
if (Test-Path -LiteralPath $productRoot) {
  foreach ($file in Get-ChildItem -LiteralPath $productRoot -Recurse -File) {
    $relativePath = $file.FullName.Substring($productRoot.Length + 1)
    $results += Copy-ManagedFile `
      -SourceRoot $productRoot `
      -SourceRelativePath $relativePath `
      -DestinationRoot $resolvedProjectRoot `
      -DestinationRelativePath (Join-Path "docs\product" $relativePath) `
      -Overwrite:$Force.IsPresent
  }
}

$results += Copy-ManagedFile `
  -SourceRoot $resolvedTemplateRoot `
  -SourceRelativePath "context\dev-plan.md" `
  -DestinationRoot $resolvedProjectRoot `
  -DestinationRelativePath "plans\features\_template.dev-plan.md" `
  -Overwrite:$Force.IsPresent

$results += Write-PackageLock `
  -TemplateRoot $resolvedTemplateRoot `
  -ProjectPath $resolvedProjectRoot `
  -InstallMode $InstallMode `
  -VendorInstalled:$VendorInstalled.IsPresent

$results += Write-HarnessConfig `
  -TemplateRoot $resolvedTemplateRoot `
  -ProjectPath $resolvedProjectRoot `
  -VendorInstalled:$VendorInstalled.IsPresent

$results += Write-InstallManifestSnapshot `
  -TemplateRoot $resolvedTemplateRoot `
  -ProjectPath $resolvedProjectRoot

$specRoot = Join-Path $resolvedTemplateRoot "spec"
if (Test-Path -LiteralPath $specRoot) {
  foreach ($file in Get-ChildItem -LiteralPath $specRoot -Recurse -File) {
    $relativePath = $file.FullName.Substring($specRoot.Length + 1)
    $results += Copy-ManagedFile `
      -SourceRoot $specRoot `
      -SourceRelativePath $relativePath `
      -DestinationRoot $resolvedProjectRoot `
      -DestinationRelativePath (Join-Path "docs\spec" $relativePath) `
      -Overwrite:$Force.IsPresent
  }
}

$testingFiles = @(
  @{ Source = "testing\ACCEPTANCE_CRITERIA.md"; Destination = "docs\testing\ACCEPTANCE_CRITERIA.md" },
  @{ Source = "testing\ACCEPTANCE_EXAMPLES.md"; Destination = "docs\testing\ACCEPTANCE_EXAMPLES.md" },
  @{ Source = "testing\NATURAL_LANGUAGE_TEST_CASES.md"; Destination = "docs\testing\NATURAL_LANGUAGE_TEST_CASES.md" },
  @{ Source = "testing\EVIDENCE_PROTOCOL.md"; Destination = "docs\testing\EVIDENCE_PROTOCOL.md" },
  @{ Source = "testing\REGRESSION_PLAN.md"; Destination = "docs\testing\REGRESSION_PLAN.md" },
  @{ Source = "testing\RISK_BASED_TEST_PLAN.md"; Destination = "docs\testing\RISK_BASED_TEST_PLAN.md" },
  @{ Source = "testing\TEST_DATA_MATRIX.md"; Destination = "docs\testing\TEST_DATA_MATRIX.md" },
  @{ Source = "testing\test-plan-template.md"; Destination = "docs\testing\test-plan-template.md" },
  @{ Source = "testing\TEST_STRATEGY.md"; Destination = "docs\testing\TEST_STRATEGY.md" },
  @{ Source = "testing\TRACEABILITY_MATRIX.md"; Destination = "docs\testing\TRACEABILITY_MATRIX.md" },
  @{ Source = "testing\test-matrix.md"; Destination = "docs\testing\test-matrix.md" },
  @{ Source = "testing\e2e-plan.md"; Destination = "docs\testing\e2e-plan.md" },
  @{ Source = "testing\test-data-plan.md"; Destination = "docs\testing\test-data-plan.md" },
  @{ Source = "testing\failure-triage.md"; Destination = "docs\testing\failure-triage.md" },
  @{ Source = "testing\coverage-policy.md"; Destination = "docs\testing\coverage-policy.md" },
  @{ Source = "testing\failure-findings.example.json"; Destination = "docs\testing\failure-findings.example.json" },
  @{ Source = "testing\test-report.md"; Destination = "docs\testing\test-report.md" },
  @{ Source = "testing\verify-matrix.md"; Destination = "docs\testing\verify-matrix.md" }
)

if ($Profile -eq "legacy") {
  foreach ($file in $testingFiles) {
    $results += Copy-ManagedFile -SourceRoot $resolvedTemplateRoot -SourceRelativePath $file.Source -DestinationRoot $resolvedProjectRoot -DestinationRelativePath $file.Destination -Overwrite:$Force.IsPresent
  }
}

if ($Profile -eq "legacy" -and $IncludeDocs) {
  $docFiles = @(
    @{ Source = "docs\harness-architecture.md"; Destination = "docs/harness/architecture.md" },
    @{ Source = "docs\knowledge-architecture.md"; Destination = "docs/harness/knowledge-architecture.md" },
    @{ Source = "docs\knowledge-import.md"; Destination = "docs/harness/knowledge-import.md" },
    @{ Source = "docs\knowledge-lint.md"; Destination = "docs/harness/knowledge-lint.md" },
    @{ Source = "docs\prompt-knowledge-integration.md"; Destination = "docs/harness/prompt-knowledge-integration.md" },
    @{ Source = "docs\mcp-knowledge-governance.md"; Destination = "docs/harness/mcp-knowledge-governance.md" },
    @{ Source = "docs\code-semantics-and-navigation.md"; Destination = "docs/harness/code-semantics-and-navigation.md" },
    @{ Source = "docs\code-quality-model.md"; Destination = "docs/harness/code-quality-model.md" },
    @{ Source = "docs\rule-governance.md"; Destination = "docs/harness/rule-governance.md" },
    @{ Source = "docs\governance-auto-repair.md"; Destination = "docs/harness/governance-auto-repair.md" },
    @{ Source = "docs\regression-rules.md"; Destination = "docs/harness/regression-rules.md" },
    @{ Source = "docs\service-dependency-matrix.md"; Destination = "docs/harness/service-dependency-matrix.md" },
    @{ Source = "docs\team-knowledge-sync.md"; Destination = "docs/harness/team-knowledge-sync.md" },
    @{ Source = "docs\trace-format.md"; Destination = "docs/harness/trace-format.md" },
    @{ Source = "docs\task-session-strategy.md"; Destination = "docs/harness/task-session-strategy.md" },
    @{ Source = "docs\spec-to-ui-to-code-workflow.md"; Destination = "docs/harness/spec-to-ui-to-code-workflow.md" },
    @{ Source = "docs\frontend-quality-rules.md"; Destination = "docs/harness/frontend-quality-rules.md" },
    @{ Source = "docs\install-manifest-governance.md"; Destination = "docs/harness/install-manifest-governance.md" },
    @{ Source = "governance\sandbox-policy.md"; Destination = "docs/harness/sandbox-policy.md" },
    @{ Source = "docs\new-project-usage.md"; Destination = "docs/harness/new-project-usage.md" }
  )

  foreach ($file in $docFiles) {
    $results += Copy-ManagedFile -SourceRoot $resolvedTemplateRoot -SourceRelativePath $file.Source -DestinationRoot $resolvedProjectRoot -DestinationRelativePath $file.Destination -Overwrite:$Force.IsPresent
  }

  $requirementPrepRoot = Join-Path $resolvedTemplateRoot "docs\requirement-prep-kit"
  if (Test-Path -LiteralPath $requirementPrepRoot) {
    foreach ($file in Get-ChildItem -LiteralPath $requirementPrepRoot -File) {
      $results += Copy-ManagedFile `
        -SourceRoot $requirementPrepRoot `
        -SourceRelativePath $file.Name `
        -DestinationRoot $resolvedProjectRoot `
        -DestinationRelativePath (Join-Path "docs\requirement-prep-kit" $file.Name) `
        -Overwrite:$Force.IsPresent
    }
  }

  $knowledgeFiles = @(
    @{ Source = "knowledge\knowledge-catalog.md"; Destination = "docs/knowledge/knowledge-catalog.md" },
    @{ Source = "knowledge\catalog.md"; Destination = "docs/knowledge/catalog.md" },
    @{ Source = "knowledge\decisions\DECISION-HARNESS-001.md"; Destination = "docs/knowledge/decisions/DECISION-HARNESS-001.md" },
    @{ Source = "knowledge\guidelines\GUIDELINE-RULES-001.md"; Destination = "docs/knowledge/guidelines/GUIDELINE-RULES-001.md" }
  )

  foreach ($file in $knowledgeFiles) {
    $results += Copy-ManagedFile -SourceRoot $resolvedTemplateRoot -SourceRelativePath $file.Source -DestinationRoot $resolvedProjectRoot -DestinationRelativePath $file.Destination -Overwrite:$Force.IsPresent
  }
}

Write-Output "Bootstrap completed."
Write-BootstrapSummary -Results $results
