@pzy560117/codex-harness 0.1.9 → 0.1.11

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/README.md CHANGED
@@ -106,7 +106,7 @@ harness init --plan
106
106
  ### 钉住远程版本初始化
107
107
 
108
108
  ```powershell
109
- npx @pzy560117/codex-harness init --version 0.1.9
109
+ npx @pzy560117/codex-harness init --version 0.1.11
110
110
  ```
111
111
 
112
112
  适合 release smoke 或回滚到某个已发布版本。
@@ -613,6 +613,7 @@ $rootFiles = @(
613
613
  @{ Source = "prompts\worker-role\harness-writer.md"; Destination = ".codex\prompts\worker-role\harness-writer.md" },
614
614
  @{ Source = "runtime\smoke-task.json"; Destination = "tools\harness\templates\smoke-task.json" },
615
615
  @{ Source = "runtime\project-task-template.json"; Destination = "tools\harness\templates\project-task-template.json" },
616
+ @{ Source = "runtime\feature-task-reference.json"; Destination = "tools\harness\templates\feature-task-reference.json" },
616
617
  @{ Source = "tools\harness\task-structure-lint.ps1"; Destination = "tools\harness\task-structure-lint.ps1" },
617
618
  @{ Source = "runtime\verify.ps1"; Destination = "tools\harness\verify.ps1" },
618
619
  @{ Source = "tools\harness\docs-lint.ps1"; Destination = "tools\harness\docs-lint.ps1" },
@@ -667,7 +668,8 @@ $contextFiles = @(
667
668
  @{ Source = "context\API_MAP.md"; Destination = "docs\ai\API_MAP.md" },
668
669
  @{ Source = "context\DB_SCHEMA.md"; Destination = "docs\ai\DB_SCHEMA.md" },
669
670
  @{ Source = "context\KNOWN_ISSUES.md"; Destination = "docs\ai\KNOWN_ISSUES.md" },
670
- @{ Source = "context\CHANGELOG_AI.md"; Destination = "docs\ai\CHANGELOG_AI.md" }
671
+ @{ Source = "context\CHANGELOG_AI.md"; Destination = "docs\ai\CHANGELOG_AI.md" },
672
+ @{ Source = "context\service-dependency-matrix.yaml"; Destination = ".service-matrix\dependencies.yaml" }
671
673
  )
672
674
 
673
675
  foreach ($file in $contextFiles) {
@@ -20,8 +20,12 @@ param(
20
20
  [switch]$InitGitIfNeeded
21
21
  )
22
22
 
23
- Set-StrictMode -Version Latest
24
- $ErrorActionPreference = "Stop"
23
+ Set-StrictMode -Version Latest
24
+ $ErrorActionPreference = "Stop"
25
+
26
+ function Get-PackageRoot {
27
+ return [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot "..\.."))
28
+ }
25
29
 
26
30
  function Write-Step {
27
31
  param([string]$Message)
@@ -214,7 +218,7 @@ function Write-InstallPlan {
214
218
  }
215
219
  }
216
220
 
217
- function Get-ManifestEntriesForMode {
221
+ function Get-ManifestEntriesForMode {
218
222
  param(
219
223
  [object]$ManifestInfo,
220
224
  [string]$InstallMode,
@@ -249,8 +253,17 @@ function Get-ManifestEntriesForMode {
249
253
  })
250
254
  }
251
255
 
252
- return $modeEntries
253
- }
256
+ return $modeEntries
257
+ }
258
+
259
+ function Get-ThinProjectExcludedDestinations {
260
+ return @(
261
+ "docs/testing/",
262
+ "docs/harness/",
263
+ "docs/requirement-prep-kit/",
264
+ "docs/knowledge/"
265
+ )
266
+ }
254
267
 
255
268
  function Get-InstallManifestVersion {
256
269
  param([object]$ManifestInfo)
@@ -283,7 +296,7 @@ function Get-PackageSourceCommit {
283
296
  function Read-PackageLockOrNull {
284
297
  param([string]$ProjectRoot)
285
298
 
286
- $lockPath = Join-Path $ProjectRoot ".codex-harness\package.lock.json"
299
+ $lockPath = Join-Path $ProjectRoot ".codex-harness\locks\package.lock.json"
287
300
  if (-not (Test-Path -LiteralPath $lockPath -PathType Leaf)) {
288
301
  return $null
289
302
  }
@@ -462,7 +475,7 @@ function Write-UpgradePlan {
462
475
  $lockInfo = Read-PackageLockOrNull -ProjectRoot $ProjectRoot
463
476
  if ($null -eq $lockInfo) {
464
477
  Write-Output "Status: missing-lock"
465
- Write-Output "Reason: .codex-harness/locks/package.lock.json 不存在,无法安全区分包管理文件和用户文件。"
478
+ Write-Output "Reason: .codex-harness/locks/package.lock.json 不存在,无法安全区分包管理文件和用户文件。"
466
479
  return
467
480
  }
468
481
 
@@ -598,11 +611,11 @@ function Get-VendorManifestFileRecords {
598
611
  $templateRoot = Join-Path $packageRoot "docs\codex-harness-engineering\templates"
599
612
  $fullPackageRootMappings = @(
600
613
  @{ SourceRoot = $templateRoot; Source = "runtime\AGENTS.md"; Destination = ".agents/AGENTS.md"; Kind = "runtime" },
601
- @{ SourceRoot = $templateRoot; Source = "tools/install/bootstrap-codex-harness.ps1"; Destination = ".agents/tools/install/bootstrap-codex-harness.ps1"; Kind = "runtime" },
602
- @{ SourceRoot = $templateRoot; Source = "runtime\tools/harness/codex-loop.ps1"; Destination = ".agents/codex-loop.ps1"; Kind = "runtime" },
603
- @{ SourceRoot = $templateRoot; Source = "config\tools/install/env-check.ps1"; Destination = ".agents/tools/install/env-check.ps1"; Kind = "runtime" },
604
- @{ SourceRoot = $templateRoot; Source = "runtime\tools/harness/verify.ps1"; Destination = ".agents/tools/harness/verify.ps1"; Kind = "runtime" },
605
- @{ SourceRoot = $templateRoot; Source = "trace\docs/harness/trace.schema.json"; Destination = ".agents/docs/harness/trace.schema.json"; Kind = "runtime" }
614
+ @{ SourceRoot = $templateRoot; Source = "bootstrap-codex-harness.ps1"; Destination = ".agents/bootstrap-codex-harness.ps1"; Kind = "runtime" },
615
+ @{ SourceRoot = $templateRoot; Source = "runtime\codex-loop.ps1"; Destination = ".agents/codex-loop.ps1"; Kind = "runtime" },
616
+ @{ SourceRoot = $templateRoot; Source = "config\env-check.ps1"; Destination = ".agents/env-check.ps1"; Kind = "runtime" },
617
+ @{ SourceRoot = $templateRoot; Source = "runtime\verify.ps1"; Destination = ".agents/verify.ps1"; Kind = "runtime" },
618
+ @{ SourceRoot = $templateRoot; Source = "trace\trace.schema.json"; Destination = ".agents/trace.schema.json"; Kind = "runtime" }
606
619
  )
607
620
 
608
621
  foreach ($mapping in $fullPackageRootMappings) {
@@ -890,7 +903,7 @@ function Write-MigrationAdoptPackageLock {
890
903
  [object[]]$AdoptRecords
891
904
  )
892
905
 
893
- $lockDirectory = Join-Path $ProjectRoot ".codex-harness"
906
+ $lockDirectory = Join-Path $ProjectRoot ".codex-harness\locks"
894
907
  if (-not (Test-Path -LiteralPath $lockDirectory -PathType Container)) {
895
908
  New-Item -ItemType Directory -Force -Path $lockDirectory | Out-Null
896
909
  }
@@ -957,7 +970,7 @@ function Invoke-MigrationApply {
957
970
  $blockedRecords = @($records | Where-Object { @("blocked-user-drift", "unknown-legacy-file", "manual-review") -contains [string]$_.Action })
958
971
  $plannedWrites = @()
959
972
  if ($adoptRecords.Count -gt 0) {
960
- $plannedWrites = @(".codex-harness/locks/package.lock.json", ".codex-harness/state/config.json")
973
+ $plannedWrites = @(".codex-harness/locks/package.lock.json", ".codex-harness/state/config.json")
961
974
  }
962
975
 
963
976
  if (-not [bool]$plan.AgentsExists) {
@@ -1035,7 +1048,7 @@ function Invoke-MigrationApply {
1035
1048
  }
1036
1049
 
1037
1050
  Write-Output ("WrittenManagedFiles: {0}" -f $adoptRecords.Count)
1038
- Write-Output "nextSteps: 运行 tools/harness/doctor.ps1 和 refresh-agent-package.ps1 -CheckOnly 验证迁移后的 lock。"
1051
+ Write-Output "nextSteps: 运行 doctor.ps1 和 refresh-agent-package.ps1 -CheckOnly 验证迁移后的 lock。"
1039
1052
  }
1040
1053
 
1041
1054
  function Get-InstalledModeFromLock {
@@ -1161,7 +1174,7 @@ function Get-InstallLockManagedFiles {
1161
1174
  continue
1162
1175
  }
1163
1176
 
1164
- if ([string]$entry.Kind -eq "generated-lock" -or [string]$entry.Destination -eq ".codex-harness/locks/package.lock.json") {
1177
+ if ([string]$entry.Kind -eq "generated-lock" -or [string]$entry.Destination -eq ".codex-harness/locks/package.lock.json") {
1165
1178
  continue
1166
1179
  }
1167
1180
 
@@ -1224,7 +1237,7 @@ function Write-InstalledPackageLock {
1224
1237
  $packageVersion = Get-InstallManifestVersion -ManifestInfo $ManifestInfo
1225
1238
  $aiKitManifestPath = Join-Path $PackageRoot "ai-sync\ai-kit-manifest.json"
1226
1239
 
1227
- $lockDirectory = Join-Path $ProjectRoot ".codex-harness"
1240
+ $lockDirectory = Join-Path $ProjectRoot ".codex-harness\locks"
1228
1241
  if (-not (Test-Path -LiteralPath $lockDirectory -PathType Container)) {
1229
1242
  New-Item -ItemType Directory -Force -Path $lockDirectory | Out-Null
1230
1243
  }
@@ -1265,7 +1278,7 @@ function Write-ProjectHarnessConfig {
1265
1278
  [string]$PackageRoot
1266
1279
  )
1267
1280
 
1268
- $configDirectory = Join-Path $ProjectRoot ".codex-harness"
1281
+ $configDirectory = Join-Path $ProjectRoot ".codex-harness\state"
1269
1282
  if (-not (Test-Path -LiteralPath $configDirectory -PathType Container)) {
1270
1283
  New-Item -ItemType Directory -Force -Path $configDirectory | Out-Null
1271
1284
  }
@@ -1362,7 +1375,7 @@ function Invoke-UpgradeExecution {
1362
1375
 
1363
1376
  $lockInfo = Read-PackageLockOrNull -ProjectRoot $ProjectRoot
1364
1377
  if ($null -eq $lockInfo) {
1365
- throw "missing-lock: .codex-harness/locks/package.lock.json 不存在,无法安全执行升级。"
1378
+ throw "missing-lock: .codex-harness/locks/package.lock.json 不存在,无法安全执行升级。"
1366
1379
  }
1367
1380
 
1368
1381
  $lockDocument = $lockInfo.Document
@@ -1535,7 +1548,7 @@ function Invoke-UninstallExecution {
1535
1548
 
1536
1549
  $lockInfo = Read-PackageLockOrNull -ProjectRoot $ProjectRoot
1537
1550
  if ($null -eq $lockInfo) {
1538
- throw "missing-lock: .codex-harness/locks/package.lock.json 不存在,无法安全执行卸载。"
1551
+ throw "missing-lock: .codex-harness/locks/package.lock.json 不存在,无法安全执行卸载。"
1539
1552
  }
1540
1553
 
1541
1554
  $lockDocument = $lockInfo.Document
@@ -1649,11 +1662,11 @@ function Test-GitRepository {
1649
1662
  }
1650
1663
  }
1651
1664
 
1652
- function Assert-GitRepoOrInit {
1653
- param(
1654
- [string]$Root,
1655
- [bool]$AllowInit
1656
- )
1665
+ function Assert-GitRepoOrInit {
1666
+ param(
1667
+ [string]$Root,
1668
+ [bool]$AllowInit
1669
+ )
1657
1670
 
1658
1671
  $repoExists = Test-GitRepository -Root $Root
1659
1672
 
@@ -1661,15 +1674,32 @@ function Assert-GitRepoOrInit {
1661
1674
  return $true
1662
1675
  }
1663
1676
 
1664
- if (-not $AllowInit) {
1665
- throw "目标目录不是 Git 仓库: $Root。请先初始化 Git,或传入 -InitGitIfNeeded。"
1666
- }
1667
-
1668
- Write-Step "目标目录不是 Git 仓库,执行 git init。"
1669
- & git -C $Root init | Out-Null
1670
- if ($LASTEXITCODE -ne 0) {
1671
- throw "git init 失败: $Root"
1672
- }
1677
+ if (-not $AllowInit) {
1678
+ throw "目标目录不是 Git 仓库: $Root。请先初始化 Git,或传入 -InitGitIfNeeded。"
1679
+ }
1680
+
1681
+ $codeGraphCommand = Get-Command codegraph -ErrorAction SilentlyContinue
1682
+ if ($null -eq $codeGraphCommand) {
1683
+ throw "目标目录不是 Git 仓库: $Root。自动初始化前需要先执行 codegraph init -i,但当前环境找不到 codegraph 命令。"
1684
+ }
1685
+
1686
+ Write-Step "目标目录不是 Git 仓库,先执行 codegraph init -i。"
1687
+ Push-Location $Root
1688
+ try {
1689
+ & $codeGraphCommand.Source init -i | Out-Host
1690
+ if ($LASTEXITCODE -ne 0) {
1691
+ throw "codegraph init -i 失败: $Root"
1692
+ }
1693
+ }
1694
+ finally {
1695
+ Pop-Location
1696
+ }
1697
+
1698
+ Write-Step "目标目录不是 Git 仓库,执行 git init。"
1699
+ & git -C $Root init | Out-Null
1700
+ if ($LASTEXITCODE -ne 0) {
1701
+ throw "git init 失败: $Root"
1702
+ }
1673
1703
 
1674
1704
  return $false
1675
1705
  }
@@ -2018,7 +2048,7 @@ function Copy-ManifestEntries {
2018
2048
  }
2019
2049
  }
2020
2050
 
2021
- function Overlay-DirectoryIfPresent {
2051
+ function Overlay-DirectoryIfPresent {
2022
2052
  param(
2023
2053
  [string]$SourceDirectory,
2024
2054
  [string]$DestinationDirectory
@@ -2052,8 +2082,8 @@ function Overlay-DirectoryIfPresent {
2052
2082
  }
2053
2083
  }
2054
2084
 
2055
- function Ensure-ReadmeForSmoke {
2056
- param([string]$Root)
2085
+ function Ensure-ReadmeForSmoke {
2086
+ param([string]$Root)
2057
2087
 
2058
2088
  $readmePath = Join-Path $Root "README.md"
2059
2089
  if (Test-Path -LiteralPath $readmePath) {
@@ -2063,14 +2093,48 @@ function Ensure-ReadmeForSmoke {
2063
2093
  @(
2064
2094
  "# Project README",
2065
2095
  "",
2066
- "This README was generated by tools/install/install-agent.ps1 to support the initial smoke task.",
2096
+ "This README was generated by install-agent.ps1 to support the initial smoke task.",
2067
2097
  "Replace it with project-specific content after harness setup is verified."
2068
2098
  ) | Set-Content -LiteralPath $readmePath -Encoding UTF8
2069
-
2070
- return $readmePath
2071
- }
2072
-
2073
- function Copy-Package {
2099
+
2100
+ return $readmePath
2101
+ }
2102
+
2103
+ function Assert-InstalledProjectScopeSurface {
2104
+ param(
2105
+ [object]$ManifestInfo,
2106
+ [string]$ProjectRoot,
2107
+ [switch]$ThinProjectProfile
2108
+ )
2109
+
2110
+ $projectEntries = @(Get-ManifestEntriesForMode -ManifestInfo $ManifestInfo -InstallMode "project" -ThinProjectProfile:$ThinProjectProfile.IsPresent)
2111
+
2112
+ $missingPaths = @()
2113
+ foreach ($entry in $projectEntries) {
2114
+ $targetPath = [string]$entry.TargetPath
2115
+ if ([string]::IsNullOrWhiteSpace($targetPath)) {
2116
+ continue
2117
+ }
2118
+
2119
+ if ($entry.SourceKind -eq "directory") {
2120
+ if (-not (Test-Path -LiteralPath $targetPath -PathType Container)) {
2121
+ $missingPaths += $entry.Destination
2122
+ }
2123
+ continue
2124
+ }
2125
+
2126
+ if (-not (Test-Path -LiteralPath $targetPath -PathType Leaf)) {
2127
+ $missingPaths += $entry.Destination
2128
+ }
2129
+ }
2130
+
2131
+ if ($missingPaths.Count -gt 0) {
2132
+ $details = ($missingPaths | Sort-Object -Unique | ForEach-Object { "- $_" }) -join "`n"
2133
+ throw "project scope 安装后缺少以下真相源或运行文件:`n$details"
2134
+ }
2135
+ }
2136
+
2137
+ function Copy-Package {
2074
2138
  param(
2075
2139
  [string]$SourceRoot,
2076
2140
  [string]$DestinationRoot,
@@ -2089,14 +2153,14 @@ function Copy-Package {
2089
2153
 
2090
2154
  $rootFileMappings = @(
2091
2155
  @{ SourceRoot = $templateRoot; Source = "runtime\AGENTS.md"; Destination = "AGENTS.md" },
2092
- @{ SourceRoot = $templateRoot; Source = "tools/install/bootstrap-codex-harness.ps1"; Destination = "tools/install/bootstrap-codex-harness.ps1" },
2093
- @{ SourceRoot = $templateRoot; Source = "runtime\tools/harness/codex-loop.ps1"; Destination = "tools/harness/codex-loop.ps1" },
2094
- @{ SourceRoot = $templateRoot; Source = "config\tools/install/env-check.ps1"; Destination = "tools/install/env-check.ps1" },
2095
- @{ SourceRoot = $templateRoot; Source = "runtime\tools/harness/verify.ps1"; Destination = "tools/harness/verify.ps1" },
2096
- @{ SourceRoot = $templateRoot; Source = "trace\docs/harness/trace.schema.json"; Destination = "docs/harness/trace.schema.json" },
2156
+ @{ SourceRoot = $templateRoot; Source = "bootstrap-codex-harness.ps1"; Destination = "bootstrap-codex-harness.ps1" },
2157
+ @{ SourceRoot = $templateRoot; Source = "runtime\codex-loop.ps1"; Destination = "codex-loop.ps1" },
2158
+ @{ SourceRoot = $templateRoot; Source = "config\env-check.ps1"; Destination = "env-check.ps1" },
2159
+ @{ SourceRoot = $templateRoot; Source = "runtime\verify.ps1"; Destination = "verify.ps1" },
2160
+ @{ SourceRoot = $templateRoot; Source = "trace\trace.schema.json"; Destination = "trace.schema.json" },
2097
2161
  @{ SourceRoot = $SourceRoot; Source = "install-manifest.json"; Destination = "install-manifest.json" },
2098
2162
  @{ SourceRoot = $SourceRoot; Source = "install-manifest.schema.json"; Destination = "install-manifest.schema.json" },
2099
- @{ SourceRoot = $packageAssetsRoot; Source = "root\tools/install/install-agent.ps1"; Destination = "tools/install/install-agent.ps1" },
2163
+ @{ SourceRoot = $packageAssetsRoot; Source = "root\install-agent.ps1"; Destination = "install-agent.ps1" },
2100
2164
  @{ SourceRoot = $packageAssetsRoot; Source = "root\install-agent-here.ps1"; Destination = "install-agent-here.ps1" },
2101
2165
  @{ SourceRoot = $packageAssetsRoot; Source = "root\README.md"; Destination = "README.md" },
2102
2166
  @{ SourceRoot = $packageAssetsRoot; Source = "root\PACKAGE.md"; Destination = "PACKAGE.md" }
@@ -2135,10 +2199,10 @@ function Copy-Package {
2135
2199
  -DestinationRelativePath "docs\codex-harness-engineering\templates"
2136
2200
  }
2137
2201
 
2138
- $sourceRoot = [System.IO.Path]::GetFullPath($PSScriptRoot)
2139
- if ([string]::IsNullOrWhiteSpace($ProjectRoot)) {
2140
- $ProjectRoot = $sourceRoot
2141
- }
2202
+ $sourceRoot = Get-PackageRoot
2203
+ if ([string]::IsNullOrWhiteSpace($ProjectRoot)) {
2204
+ $ProjectRoot = $sourceRoot
2205
+ }
2142
2206
 
2143
2207
  $resolvedProjectRoot = [System.IO.Path]::GetFullPath($ProjectRoot)
2144
2208
  $targetAgentsRoot = Join-Path $resolvedProjectRoot ".agents"
@@ -2315,7 +2379,7 @@ try {
2315
2379
  $scopeUserPackage = Install-UserPackageLayer -ManifestInfo $installManifestInfo -PackageRoot $effectiveSourceRoot
2316
2380
  }
2317
2381
 
2318
- $bootstrapScript = Join-Path $effectiveSourceRoot "tools/install/bootstrap-codex-harness.ps1"
2382
+ $bootstrapScript = Join-Path $effectiveSourceRoot "tools\install\bootstrap-codex-harness.ps1"
2319
2383
  Write-Step "同步项目根 runtime 文件 (mode=$Mode)"
2320
2384
  $bootstrapArgs = @(
2321
2385
  '-NoProfile',
@@ -2334,7 +2398,7 @@ try {
2334
2398
 
2335
2399
  & powershell @bootstrapArgs | Out-Host
2336
2400
  if ($LASTEXITCODE -ne 0) {
2337
- throw "tools/install/bootstrap-codex-harness.ps1 执行失败: $resolvedProjectRoot"
2401
+ throw "bootstrap-codex-harness.ps1 执行失败: $resolvedProjectRoot"
2338
2402
  }
2339
2403
  }
2340
2404
  elseif ($Mode -eq "vendor") {
@@ -2362,9 +2426,9 @@ try {
2362
2426
  New-Item -ItemType Directory -Path $targetAgentsRoot | Out-Null
2363
2427
  Copy-Package -SourceRoot $effectiveSourceRoot -DestinationRoot $targetAgentsRoot -InstallMode $Mode
2364
2428
 
2365
- $bootstrapScript = Join-Path $targetAgentsRoot "tools/install/bootstrap-codex-harness.ps1"
2429
+ $bootstrapScript = Join-Path $targetAgentsRoot "bootstrap-codex-harness.ps1"
2366
2430
 
2367
- Write-Step "调用 tools/install/bootstrap-codex-harness.ps1 同步项目根 runtime 文件"
2431
+ Write-Step "调用 bootstrap-codex-harness.ps1 同步项目根 runtime 文件"
2368
2432
  $bootstrapArgs = @(
2369
2433
  '-NoProfile',
2370
2434
  '-ExecutionPolicy', 'Bypass',
@@ -2380,7 +2444,7 @@ try {
2380
2444
 
2381
2445
  & powershell @bootstrapArgs | Out-Host
2382
2446
  if ($LASTEXITCODE -ne 0) {
2383
- throw "tools/install/bootstrap-codex-harness.ps1 执行失败: $resolvedProjectRoot"
2447
+ throw "bootstrap-codex-harness.ps1 执行失败: $resolvedProjectRoot"
2384
2448
  }
2385
2449
  }
2386
2450
 
@@ -2395,25 +2459,31 @@ try {
2395
2459
  Write-Step "已写入 package lock: $lockPath"
2396
2460
  }
2397
2461
 
2398
- if ($Mode -eq "project" -or $Mode -eq "vendor") {
2399
- $configPackageRoot = if ($Mode -eq "vendor") { $targetAgentsRoot } elseif ($null -ne $scopeUserPackage) { [string]$scopeUserPackage.PackageRoot } else { $effectiveSourceRoot }
2400
- $configPath = Write-ProjectHarnessConfig `
2401
- -ManifestInfo $installManifestInfo `
2462
+ if ($Mode -eq "project" -or $Mode -eq "vendor") {
2463
+ $configPackageRoot = if ($Mode -eq "vendor") { $targetAgentsRoot } elseif ($null -ne $scopeUserPackage) { [string]$scopeUserPackage.PackageRoot } else { $effectiveSourceRoot }
2464
+ $configPath = Write-ProjectHarnessConfig `
2465
+ -ManifestInfo $installManifestInfo `
2402
2466
  -ProjectRoot $resolvedProjectRoot `
2403
2467
  -InstallScope $Mode `
2404
2468
  -VendorInstalled:($Mode -eq "vendor") `
2405
- -PackageRoot $configPackageRoot
2406
- Write-Step "已写入 harness config: $configPath"
2407
- }
2408
-
2409
- $generatedReadme = $null
2469
+ -PackageRoot $configPackageRoot
2470
+ Write-Step "已写入 harness config: $configPath"
2471
+ }
2472
+
2473
+ if ($Mode -eq "project") {
2474
+ $thinProjectInstall = $Scope -eq "project" -or $defaultThinInstall
2475
+ Assert-InstalledProjectScopeSurface -ManifestInfo $installManifestInfo -ProjectRoot $resolvedProjectRoot -ThinProjectProfile:$thinProjectInstall
2476
+ Write-Step "project scope 真相源与运行文件已按 manifest 落地"
2477
+ }
2478
+
2479
+ $generatedReadme = $null
2410
2480
  if ($InitSmoke) {
2411
2481
  $generatedReadme = Ensure-ReadmeForSmoke -Root $resolvedProjectRoot
2412
2482
  if ($null -ne $generatedReadme) {
2413
2483
  Write-Step "为 smoke 初始化补充 README.md: $generatedReadme"
2414
2484
  }
2415
2485
 
2416
- $smokeTaskPath = Join-Path $resolvedProjectRoot "smoke-task.json"
2486
+ $smokeTaskPath = Join-Path $resolvedProjectRoot "tools\harness\templates\smoke-task.json"
2417
2487
  $taskPath = Join-Path $resolvedProjectRoot "task.json"
2418
2488
  if (-not (Test-Path -LiteralPath $smokeTaskPath)) {
2419
2489
  throw "找不到 smoke-task.json: $smokeTaskPath"
@@ -2490,16 +2560,19 @@ try {
2490
2560
  Write-Output ("SmokeInitialized: {0}" -f $InitSmoke.IsPresent)
2491
2561
  Write-Output ("BaselineCommitted: {0}" -f $baselineCommitted)
2492
2562
  Write-Output ("BaselinePolicy: {0}" -f $baselinePolicy)
2493
- if ($Mode -eq "full" -or $Mode -eq "project") {
2494
- Write-Output ""
2495
- Write-Output "Next steps:"
2496
- Write-Output ("- 裁剪 `"{0}`" 和 `"{1}`" 为目标项目事实" -f (Join-Path $resolvedProjectRoot 'docs\ai\repo-map.md'), (Join-Path $resolvedProjectRoot 'docs\ai\architecture-brief.md'))
2497
- Write-Output ("- powershell -NoProfile -ExecutionPolicy Bypass -File `"{0}`"" -f (Join-Path $resolvedProjectRoot 'tools/install/env-check.ps1'))
2498
- Write-Output ("- powershell -NoProfile -ExecutionPolicy Bypass -File `"{0}`"" -f (Join-Path $resolvedProjectRoot 'tools/harness/verify.ps1'))
2499
- Write-Output ("- powershell -NoProfile -ExecutionPolicy Bypass -File `"{0}`"" -f (Join-Path $resolvedProjectRoot 'tools/harness/codex-loop.ps1'))
2500
- }
2501
- }
2502
- finally {
2563
+ if ($Mode -eq "full" -or $Mode -eq "project") {
2564
+ Write-Output ""
2565
+ Write-Output "Next steps:"
2566
+ Write-Output ("- 先裁剪 `"{0}`"、`"{1}`" 和 `"{2}`" 为目标项目事实" -f (Join-Path $resolvedProjectRoot 'docs\ai\repo-map.md'), (Join-Path $resolvedProjectRoot 'docs\ai\architecture-brief.md'), (Join-Path $resolvedProjectRoot 'docs\ai\CURRENT_TASK.md'))
2567
+ Write-Output ("- 复杂项目继续补齐 `"{0}`"、`"{1}`"、`"{2}`"、`"{3}`"、`"{4}`"、`"{5}`"" -f (Join-Path $resolvedProjectRoot 'docs\ai\PROJECT_CONTEXT.md'), (Join-Path $resolvedProjectRoot 'docs\ai\DECISIONS.md'), (Join-Path $resolvedProjectRoot 'docs\ai\API_MAP.md'), (Join-Path $resolvedProjectRoot 'docs\ai\DB_SCHEMA.md'), (Join-Path $resolvedProjectRoot 'docs\ai\KNOWN_ISSUES.md'), (Join-Path $resolvedProjectRoot 'docs\ai\CHANGELOG_AI.md'))
2568
+ Write-Output ("- powershell -NoProfile -ExecutionPolicy Bypass -File `"{0}`"" -f (Join-Path $resolvedProjectRoot 'tools\install\env-check.ps1'))
2569
+ Write-Output ("- powershell -NoProfile -ExecutionPolicy Bypass -File `"{0}`"" -f (Join-Path $resolvedProjectRoot 'tools\harness\verify.ps1'))
2570
+ Write-Output ("- 如需接入外部知识或代码语义工具,先读 `"{0}`" 和 `"{1}`"" -f (Join-Path $resolvedProjectRoot 'docs\harness\mcp-knowledge-governance.md'), (Join-Path $resolvedProjectRoot 'docs\harness\code-semantics-and-navigation.md'))
2571
+ Write-Output ("- 如需 7x24 长时间推进,可在 Codex app 中使用 `/goal`;推荐先读 `"{0}`" 和 `"{1}`"" -f (Join-Path $resolvedProjectRoot 'docs\codex-harness-engineering\goal-harness-integration-guide.md'), (Join-Path $resolvedProjectRoot 'docs\codex-harness-engineering\examples\goal-templates.md'))
2572
+ Write-Output ("- powershell -NoProfile -ExecutionPolicy Bypass -File `"{0}`"" -f (Join-Path $resolvedProjectRoot 'tools\harness\codex-loop.ps1'))
2573
+ }
2574
+ }
2575
+ finally {
2503
2576
  if (($null -ne $stagedSourceRoot) -and (Test-Path -LiteralPath $stagedSourceRoot)) {
2504
2577
  Remove-Item -LiteralPath $stagedSourceRoot -Recurse -Force -ErrorAction SilentlyContinue
2505
2578
  }
@@ -576,6 +576,15 @@ function Test-DoctorThinLegacyResidue {
576
576
  return $false
577
577
  }
578
578
 
579
+ function Get-ThinProjectExcludedDestinations {
580
+ return @(
581
+ "docs/testing/",
582
+ "docs/harness/",
583
+ "docs/requirement-prep-kit/",
584
+ "docs/knowledge/"
585
+ )
586
+ }
587
+
579
588
  function Test-ProjectScopeInstallSurface {
580
589
  param(
581
590
  [string]$Root,
@@ -594,6 +603,17 @@ function Test-ProjectScopeInstallSurface {
594
603
  continue
595
604
  }
596
605
 
606
+ $skipForThinProject = $false
607
+ foreach ($excludedDestination in @(Get-ThinProjectExcludedDestinations)) {
608
+ if ($destinationRaw.Replace('\', '/').StartsWith($excludedDestination, [System.StringComparison]::OrdinalIgnoreCase)) {
609
+ $skipForThinProject = $true
610
+ break
611
+ }
612
+ }
613
+ if ($skipForThinProject) {
614
+ continue
615
+ }
616
+
597
617
  $normalizedDestination = $destinationRaw.Replace('/', '\').TrimStart('\')
598
618
  $expectsDirectory = $destinationRaw.Trim().Replace('\', '/').EndsWith('/', [System.StringComparison]::Ordinal)
599
619
  $targetPath = Join-Path $Root $normalizedDestination
@@ -1265,17 +1285,18 @@ elseif (-not $isVendorProjectInstall) {
1265
1285
  Add-DoctorError -Errors ([ref]$errors) -Message "run profile 不是合法 JSON: $runProfileRelativePath"
1266
1286
  }
1267
1287
 
1268
- $allowedTaskKinds = @(
1269
- "harness",
1270
- "smoke",
1271
- "feature_research",
1272
- "feature_spec",
1273
- "feature_design",
1274
- "feature_plan",
1275
- "feature_impl",
1276
- "release",
1277
- "archive"
1278
- )
1288
+ $allowedTaskKinds = @(
1289
+ "harness",
1290
+ "smoke",
1291
+ "feature_research",
1292
+ "feature_spec",
1293
+ "feature_design",
1294
+ "feature_plan",
1295
+ "testcase_design",
1296
+ "feature_impl",
1297
+ "release",
1298
+ "archive"
1299
+ )
1279
1300
  $allowedGateProfiles = @(
1280
1301
  "lightweight",
1281
1302
  "research_required",