aid-installer 1.1.1 → 2.0.0
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 +2 -2
- package/VERSION +1 -1
- package/bin/aid +154 -20
- package/bin/aid.ps1 +186 -41
- package/dashboard/home.html +41 -4
- package/dashboard/reader/derivation.py +228 -5
- package/dashboard/reader/models.py +22 -0
- package/dashboard/reader/parsers.py +127 -0
- package/dashboard/reader/reader.py +6 -1
- package/dashboard/server/reader.mjs +313 -0
- package/dashboard/server/server.py +12 -0
- package/lib/AidInstallCore.psm1 +247 -53
- package/lib/aid-install-core.sh +170 -13
- package/package.json +9 -6
- package/scripts/vendor.js +0 -98
package/bin/aid.ps1
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# aid version Print the CLI version
|
|
14
14
|
# aid status Show AID state of the current project
|
|
15
15
|
# aid add <tool>[,...] Add tool(s) to the current project
|
|
16
|
-
# aid update [
|
|
16
|
+
# aid update [self] Update to latest; inside repo = CLI + all tools; 'self' = CLI only
|
|
17
17
|
# aid remove [<tool>... | self] Remove; no arg = ALL AID from project; 'self' = the aid CLI
|
|
18
18
|
# aid <command> -h | --help Per-command help
|
|
19
19
|
#
|
|
@@ -29,6 +29,11 @@
|
|
|
29
29
|
# Bootstrap URL - single place to update when the branch merges to master.
|
|
30
30
|
# Override with $env:AID_INSTALL_URL for tests.
|
|
31
31
|
# ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
# Enable TLS 1.2 for HTTPS. Windows PowerShell 5.1 (.NET Framework) can default to
|
|
34
|
+
# SSL3/TLS1.0, which GitHub/npm/pypi reject -> downloads fail. Harmless on PS7/.NET Core.
|
|
35
|
+
try { [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 } catch {}
|
|
36
|
+
|
|
32
37
|
$script:_AidInstallUrl = if ($env:AID_INSTALL_URL) { $env:AID_INSTALL_URL } else {
|
|
33
38
|
'https://raw.githubusercontent.com/AndreVianna/aid-methodology/master/install.ps1'
|
|
34
39
|
}
|
|
@@ -191,15 +196,19 @@ function script:Show-AidUsage {
|
|
|
191
196
|
Write-Host ' -DryRun: print the exact command(s) it would run, then exit (no changes).'
|
|
192
197
|
}
|
|
193
198
|
'update' {
|
|
194
|
-
Write-Host 'aid update [
|
|
199
|
+
Write-Host 'aid update [-Version <v>] [-FromBundle <path>] [-Force] [-DryRun] [-Target <dir>]'
|
|
195
200
|
Write-Host 'aid update self [-FromBundle <path>] [-DryRun]'
|
|
196
|
-
Write-Host ' Update to latest.
|
|
201
|
+
Write-Host ' Update to latest.'
|
|
202
|
+
Write-Host ' Outside an AID repo: updates the CLI only (no-op if already latest).'
|
|
203
|
+
Write-Host ' Inside an AID repo: updates the CLI first, then ALL installed tools to one version.'
|
|
204
|
+
Write-Host ' No per-tool selection -- any tool positional is an error (use "self" only).'
|
|
197
205
|
Write-Host ' self: COMPLETELY update the aid CLI, channel-aware:'
|
|
198
206
|
Write-Host ' npm -> npm i -g | pypi -> pipx upgrade | curl -> re-bootstrap install.ps1.'
|
|
199
207
|
Write-Host ' On Windows, elevation is the caller''s responsibility (no sudo).'
|
|
200
|
-
Write-Host ' -
|
|
208
|
+
Write-Host ' -Version <v>: pin ALL tools (and CLI) to version v.'
|
|
209
|
+
Write-Host ' -FromBundle <path>: install from a local artifact instead of @latest'
|
|
201
210
|
Write-Host ' (npm .tgz | pypi .whl | curl release-staging dir with install.ps1).'
|
|
202
|
-
Write-Host ' -DryRun: print the
|
|
211
|
+
Write-Host ' -DryRun: print the full plan (tools updated, files copied, paths pruned) and exit.'
|
|
203
212
|
}
|
|
204
213
|
'version' {
|
|
205
214
|
Write-Host 'aid version'
|
|
@@ -241,7 +250,7 @@ function script:Show-AidUsage {
|
|
|
241
250
|
Write-Host ' aid version Print the CLI version'
|
|
242
251
|
Write-Host ' aid status Show AID state of the current project'
|
|
243
252
|
Write-Host ' aid add <tool>[,...] Add tool(s) to the current project'
|
|
244
|
-
Write-Host ' aid update [
|
|
253
|
+
Write-Host ' aid update [self] Update to latest; inside repo = all tools'
|
|
245
254
|
Write-Host ' aid remove [<tool>... | self] Remove; no arg = ALL AID from project'
|
|
246
255
|
Write-Host ' aid dashboard start|stop ... Start/stop the local dashboard'
|
|
247
256
|
Write-Host ' aid projects [list|add|remove] List/register/unregister AID projects'
|
|
@@ -1448,7 +1457,7 @@ function script:Get-AidProjectState {
|
|
|
1448
1457
|
# Mirror of bash _aid_project_tools.
|
|
1449
1458
|
function script:Get-AidProjectTools {
|
|
1450
1459
|
param([string]$Path)
|
|
1451
|
-
$manifest = Join-Path $Path '.aid' '.aid-manifest.json'
|
|
1460
|
+
$manifest = Join-Path (Join-Path $Path '.aid') '.aid-manifest.json'
|
|
1452
1461
|
if (-not (Test-Path $manifest -PathType Leaf)) { return '' }
|
|
1453
1462
|
$lines = Get-Content -LiteralPath $manifest -Encoding utf8 -ErrorAction SilentlyContinue
|
|
1454
1463
|
if (-not $lines) { return '' }
|
|
@@ -1482,7 +1491,7 @@ function script:Get-AidProjectTools {
|
|
|
1482
1491
|
function script:Get-WhichTierHolds {
|
|
1483
1492
|
param([string]$Path)
|
|
1484
1493
|
$primaryReg = Join-Path $script:_AidStateHome 'registry.yml'
|
|
1485
|
-
$userReg = Join-Path $HOME '.aid' 'registry.yml'
|
|
1494
|
+
$userReg = Join-Path (Join-Path $HOME '.aid') 'registry.yml'
|
|
1486
1495
|
|
|
1487
1496
|
$primaryNorm = [System.IO.Path]::GetFullPath($script:_AidStateHome)
|
|
1488
1497
|
$userNorm = [System.IO.Path]::GetFullPath((Join-Path $HOME '.aid'))
|
|
@@ -1539,7 +1548,7 @@ function script:Invoke-AidProjectsList {
|
|
|
1539
1548
|
([System.IO.Path]::GetFullPath($script:_AidStateHome) -ne [System.IO.Path]::GetFullPath((Join-Path $HOME '.aid')))) {
|
|
1540
1549
|
Join-Path $script:_AidStateHome 'registry.yml'
|
|
1541
1550
|
} else {
|
|
1542
|
-
Join-Path $HOME '.aid' 'registry.yml'
|
|
1551
|
+
Join-Path (Join-Path $HOME '.aid') 'registry.yml'
|
|
1543
1552
|
}
|
|
1544
1553
|
Write-Host (' registry: {0}' -f $regSrc)
|
|
1545
1554
|
}
|
|
@@ -1599,7 +1608,7 @@ function script:Invoke-AidProjectsAdd {
|
|
|
1599
1608
|
$regFile = if ($tier -eq 'shared' -and $primaryNorm -ne $userNorm) {
|
|
1600
1609
|
Join-Path $script:_AidStateHome 'registry.yml'
|
|
1601
1610
|
} else {
|
|
1602
|
-
Join-Path $HOME '.aid' 'registry.yml'
|
|
1611
|
+
Join-Path (Join-Path $HOME '.aid') 'registry.yml'
|
|
1603
1612
|
}
|
|
1604
1613
|
Write-Host ("aid projects: registry file: $regFile")
|
|
1605
1614
|
}
|
|
@@ -1624,7 +1633,7 @@ function script:Invoke-AidProjectsRemove {
|
|
|
1624
1633
|
|
|
1625
1634
|
# Check if registered before unregistering (for idempotency message).
|
|
1626
1635
|
$primaryReg = Join-Path $script:_AidStateHome 'registry.yml'
|
|
1627
|
-
$userReg = Join-Path $HOME '.aid' 'registry.yml'
|
|
1636
|
+
$userReg = Join-Path (Join-Path $HOME '.aid') 'registry.yml'
|
|
1628
1637
|
$primaryNorm = [System.IO.Path]::GetFullPath($script:_AidStateHome)
|
|
1629
1638
|
$userNorm = [System.IO.Path]::GetFullPath((Join-Path $HOME '.aid'))
|
|
1630
1639
|
$found = $false
|
|
@@ -1791,7 +1800,7 @@ function script:Registry-Register {
|
|
|
1791
1800
|
$lns.Add("schema: 1")
|
|
1792
1801
|
$lns.Add("projects:")
|
|
1793
1802
|
foreach ($p in ($repos | Where-Object { $_ } | Sort-Object -Unique)) { $lns.Add(" - $p") }
|
|
1794
|
-
|
|
1803
|
+
[System.IO.File]::WriteAllText($tmp, (($lns.ToArray()) -join "`n") + "`n", [System.Text.UTF8Encoding]::new($false))
|
|
1795
1804
|
Move-Item -LiteralPath $tmp -Destination $regPath -Force -ErrorAction Stop
|
|
1796
1805
|
return $true
|
|
1797
1806
|
} catch {
|
|
@@ -1904,7 +1913,7 @@ function script:Registry-Unregister {
|
|
|
1904
1913
|
$lns.Add("schema: 1")
|
|
1905
1914
|
$lns.Add("projects:")
|
|
1906
1915
|
if ($remaining) { foreach ($p in $remaining) { $lns.Add(" - $p") } }
|
|
1907
|
-
|
|
1916
|
+
[System.IO.File]::WriteAllText($tmp, (($lns.ToArray()) -join "`n") + "`n", [System.Text.UTF8Encoding]::new($false))
|
|
1908
1917
|
Move-Item -LiteralPath $tmp -Destination $regPath -Force -ErrorAction Stop
|
|
1909
1918
|
return $true
|
|
1910
1919
|
} catch {
|
|
@@ -2006,7 +2015,7 @@ if ($script:_RawArgs.Count -eq 0) {
|
|
|
2006
2015
|
if (Test-Path $verFile -PathType Leaf) {
|
|
2007
2016
|
$cliVersion = (Get-Content -LiteralPath $verFile -Raw).Trim()
|
|
2008
2017
|
}
|
|
2009
|
-
Write-Host "AID v$cliVersion -
|
|
2018
|
+
Write-Host "AID v$cliVersion - AI Integrated Development"
|
|
2010
2019
|
Write-Host "Install, update, and manage AID across your projects."
|
|
2011
2020
|
|
|
2012
2021
|
# C6': format gate for cwd repo (.aid/ is guaranteed present here -- the
|
|
@@ -2403,7 +2412,7 @@ function script:Invoke-AidRepairSettingsEraA {
|
|
|
2403
2412
|
$sfDir = Split-Path $SettingsFile -Parent
|
|
2404
2413
|
$tmp = Join-Path $sfDir ("settings.yml.aid-tmp." + [System.IO.Path]::GetRandomFileName())
|
|
2405
2414
|
try {
|
|
2406
|
-
|
|
2415
|
+
[System.IO.File]::WriteAllText($tmp, (($lines.ToArray()) -join "`n") + "`n", [System.Text.UTF8Encoding]::new($false))
|
|
2407
2416
|
Move-Item -LiteralPath $tmp -Destination $SettingsFile -Force -ErrorAction Stop
|
|
2408
2417
|
} catch {
|
|
2409
2418
|
Remove-Item -LiteralPath $tmp -Force -ErrorAction SilentlyContinue
|
|
@@ -2774,6 +2783,7 @@ $_AidFromBundle = ''
|
|
|
2774
2783
|
$_AidForce = $false
|
|
2775
2784
|
$_AidRemoveForce = $false
|
|
2776
2785
|
$_AidTarget = ''
|
|
2786
|
+
$_AidDryRun = $false
|
|
2777
2787
|
$_AidPosTools = [System.Collections.Generic.List[string]]::new()
|
|
2778
2788
|
|
|
2779
2789
|
$remIdx = 0
|
|
@@ -2800,8 +2810,9 @@ while ($remIdx -lt $script:_RemArgs.Count) {
|
|
|
2800
2810
|
$_AidTarget = $script:_RemArgs[$remIdx]
|
|
2801
2811
|
break
|
|
2802
2812
|
}
|
|
2803
|
-
'^(-NoPath|--no-path)$'
|
|
2804
|
-
'^(-
|
|
2813
|
+
'^(-NoPath|--no-path)$' { break <# bootstrap-only; silently ignore here #> }
|
|
2814
|
+
'^(-DryRun|--dry-run)$' { $_AidDryRun = $true; break }
|
|
2815
|
+
'^(-h|--help|-Help)$' { script:Show-AidUsage $SUBCMD; script:Exit-Aid 0 }
|
|
2805
2816
|
'^-' {
|
|
2806
2817
|
script:Fail-Aid "unknown flag: $a" 2
|
|
2807
2818
|
}
|
|
@@ -2825,6 +2836,16 @@ if (-not $_AidForce -and ($env:AID_FORCE -eq '1' -or $env:AID_FORCE -eq 'true'))
|
|
|
2825
2836
|
}
|
|
2826
2837
|
if ($script:_AidVerbose) { $env:AID_VERBOSE = '1' }
|
|
2827
2838
|
|
|
2839
|
+
# FR10: 'update' no longer accepts a per-tool positional (other than 'self' which
|
|
2840
|
+
# was already consumed above). Any non-flag positional on 'aid update' is a usage error.
|
|
2841
|
+
if ($SUBCMD -eq 'update' -and $_AidToolArg) {
|
|
2842
|
+
[Console]::Error.WriteLine("ERROR: aid update: unexpected argument: '$_AidToolArg'")
|
|
2843
|
+
[Console]::Error.WriteLine(" 'aid update' updates all installed tools -- no per-tool selection.")
|
|
2844
|
+
[Console]::Error.WriteLine(" Use 'aid update self' to update the CLI only.")
|
|
2845
|
+
[Console]::Error.WriteLine(" See 'aid update -h' for usage.")
|
|
2846
|
+
script:Exit-Aid 2
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2828
2849
|
if (-not $_AidTarget) { $_AidTarget = '.' }
|
|
2829
2850
|
|
|
2830
2851
|
# Validate target directory.
|
|
@@ -2833,14 +2854,31 @@ if (-not (Test-Path $_AidTarget -PathType Container)) {
|
|
|
2833
2854
|
}
|
|
2834
2855
|
$_AidTarget = (Resolve-Path -LiteralPath $_AidTarget).Path
|
|
2835
2856
|
|
|
2836
|
-
# ----
|
|
2837
|
-
#
|
|
2838
|
-
#
|
|
2857
|
+
# ---- FR10: 'update' outside an AID repo -> update the CLI only (not offer-and-exit) ----
|
|
2858
|
+
# Outside a repo: delegates to the CLI-only update path; no tool loop.
|
|
2859
|
+
# Inside a repo: fall through to the full tool-update pass below.
|
|
2839
2860
|
# Test-AidIsProjectDir excludes the CLI state home from "is project" classification.
|
|
2840
2861
|
if ($SUBCMD -eq 'update') {
|
|
2841
2862
|
if (-not (script:Test-AidIsProjectDir -Dir $_AidTarget)) {
|
|
2842
|
-
|
|
2843
|
-
|
|
2863
|
+
# FR10 outside-repo: update the CLI only; no tool loop.
|
|
2864
|
+
$updCliVer = ''
|
|
2865
|
+
$updVerFile = Join-Path $script:_AidCodeHome 'VERSION'
|
|
2866
|
+
if (Test-Path $updVerFile -PathType Leaf) {
|
|
2867
|
+
$updCliVer = (Get-Content -LiteralPath $updVerFile -Raw -ErrorAction SilentlyContinue).Trim()
|
|
2868
|
+
}
|
|
2869
|
+
# Check if already latest using cached update-check result (no network call).
|
|
2870
|
+
$updCacheFile = Join-Path $HOME (Join-Path '.aid' '.update-check')
|
|
2871
|
+
$updCachedLatest = ''
|
|
2872
|
+
if (Test-Path $updCacheFile -PathType Leaf) {
|
|
2873
|
+
$updLines = Get-Content -LiteralPath $updCacheFile -ErrorAction SilentlyContinue
|
|
2874
|
+
if ($updLines -and $updLines.Count -ge 2) { $updCachedLatest = $updLines[1].Trim() }
|
|
2875
|
+
}
|
|
2876
|
+
if ($updCliVer -and $updCachedLatest -and ($updCliVer -eq $updCachedLatest)) {
|
|
2877
|
+
Write-Host "CLI is current (v$updCliVer)"
|
|
2878
|
+
script:Exit-Aid 0
|
|
2879
|
+
}
|
|
2880
|
+
script:Invoke-AidUpdateSelfIfStale -FromBundle $_AidFromBundle
|
|
2881
|
+
script:Exit-Aid 0
|
|
2844
2882
|
}
|
|
2845
2883
|
}
|
|
2846
2884
|
|
|
@@ -2852,8 +2890,8 @@ if ($SUBCMD -eq 'update' -and (script:Test-AidIsProjectDir -Dir $_AidTarget)) {
|
|
|
2852
2890
|
}
|
|
2853
2891
|
|
|
2854
2892
|
# ---- Self-update-if-needed preamble (FF-3 / CLI-2 / task-079) --------------
|
|
2855
|
-
# For 'update
|
|
2856
|
-
# is current before the per-repo
|
|
2893
|
+
# For 'update' inside an AID repo only (not 'add', not 'update self').
|
|
2894
|
+
# Ensures the CLI is current before the per-repo tool-update runs. WARN-not-fail.
|
|
2857
2895
|
if ($SUBCMD -eq 'update') {
|
|
2858
2896
|
script:Invoke-AidUpdateSelfIfStale -FromBundle $_AidFromBundle
|
|
2859
2897
|
}
|
|
@@ -3022,8 +3060,6 @@ function script:Prepare-AidToolStaging {
|
|
|
3022
3060
|
# Dispatch to engine.
|
|
3023
3061
|
# ---------------------------------------------------------------------------
|
|
3024
3062
|
try {
|
|
3025
|
-
$overallBlocked = $false
|
|
3026
|
-
|
|
3027
3063
|
switch ($SUBCMD) {
|
|
3028
3064
|
{ $_ -in @('add', 'update') } {
|
|
3029
3065
|
# B-table (for 'add'): writability pre-check BEFORE any .aid/ is created.
|
|
@@ -3039,33 +3075,142 @@ try {
|
|
|
3039
3075
|
}
|
|
3040
3076
|
}
|
|
3041
3077
|
|
|
3042
|
-
#
|
|
3078
|
+
# ---------------------------------------------------------------------------
|
|
3079
|
+
# FR11: aid add version selection (same-version invariant).
|
|
3080
|
+
# First-tool (no existing tools in manifest): install at the CLI version.
|
|
3081
|
+
# Additional-tool (manifest already has >=1 tool): install at the EXISTING
|
|
3082
|
+
# tools' version to keep the repo uniform. add does NOT force a repo-wide
|
|
3083
|
+
# update. -Version on add must apply to ALL tools or error (mixed-version
|
|
3084
|
+
# repo would result if the requested version differs from the existing one).
|
|
3085
|
+
# ---------------------------------------------------------------------------
|
|
3086
|
+
if ($SUBCMD -eq 'add') {
|
|
3087
|
+
$_fr11CliVer = ''
|
|
3088
|
+
$fr11VerFile = Join-Path $script:_AidCodeHome 'VERSION'
|
|
3089
|
+
if (Test-Path $fr11VerFile -PathType Leaf) {
|
|
3090
|
+
$_fr11CliVer = (Get-Content -LiteralPath $fr11VerFile -Raw -ErrorAction SilentlyContinue).Trim()
|
|
3091
|
+
}
|
|
3092
|
+
$_fr11ExistingVer = ''
|
|
3093
|
+
if (Test-Path $_AidManifest -PathType Leaf) {
|
|
3094
|
+
$fr11FirstTool = (Get-ManifestToolList -ManifestPath $_AidManifest | Select-Object -First 1)
|
|
3095
|
+
if ($fr11FirstTool) {
|
|
3096
|
+
$_fr11ExistingVer = Read-ManifestToolVersion -ManifestPath $_AidManifest -Tool $fr11FirstTool.Id
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
if ($_AidVersionArg) {
|
|
3101
|
+
# -Version on add: validate it won't create a mixed-version repo.
|
|
3102
|
+
if ($_fr11ExistingVer -and $_AidVersionArg -ne $_fr11ExistingVer) {
|
|
3103
|
+
[Console]::Error.WriteLine("ERROR: aid add: -Version $_AidVersionArg would create a mixed-version repo.")
|
|
3104
|
+
[Console]::Error.WriteLine(" Existing tools are at v$_fr11ExistingVer. Either:")
|
|
3105
|
+
[Console]::Error.WriteLine(" - Omit -Version to install at the repo version (v$_fr11ExistingVer), or")
|
|
3106
|
+
[Console]::Error.WriteLine(" - Run 'aid update -Version $_AidVersionArg' first to advance the whole repo.")
|
|
3107
|
+
script:Exit-Aid 2
|
|
3108
|
+
}
|
|
3109
|
+
# -Version provided and no conflict: apply to all tools (passed through to staging).
|
|
3110
|
+
} elseif ($_fr11ExistingVer) {
|
|
3111
|
+
# Additional-tool: pin staging to the existing repo version (not the CLI version).
|
|
3112
|
+
$_AidVersionArg = $_fr11ExistingVer
|
|
3113
|
+
# Skew notice when CLI is ahead of the repo version.
|
|
3114
|
+
if ($_fr11CliVer) {
|
|
3115
|
+
$fr11PartsA = $_fr11ExistingVer -split '\.'
|
|
3116
|
+
$fr11PartsB = $_fr11CliVer -split '\.'
|
|
3117
|
+
$fr11IsLt = $false
|
|
3118
|
+
for ($fr11i = 0; $fr11i -lt 3; $fr11i++) {
|
|
3119
|
+
$fr11rA = if ($fr11i -lt $fr11PartsA.Count) { $fr11PartsA[$fr11i] } else { '0' }
|
|
3120
|
+
$fr11rB = if ($fr11i -lt $fr11PartsB.Count) { $fr11PartsB[$fr11i] } else { '0' }
|
|
3121
|
+
if ($fr11rA -match '^(\d+)') { $fr11vA = [int]$Matches[1] } else { $fr11vA = 0 }
|
|
3122
|
+
if ($fr11rB -match '^(\d+)') { $fr11vB = [int]$Matches[1] } else { $fr11vB = 0 }
|
|
3123
|
+
if ($fr11vA -lt $fr11vB) { $fr11IsLt = $true; break }
|
|
3124
|
+
if ($fr11vA -gt $fr11vB) { break }
|
|
3125
|
+
}
|
|
3126
|
+
if ($fr11IsLt) {
|
|
3127
|
+
Write-Host "repo is at v$_fr11ExistingVer; new tool(s) installed at v$_fr11ExistingVer to keep the repo uniform. Run 'aid update' to advance all tools to v$_fr11CliVer."
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
} else {
|
|
3131
|
+
# First-tool: pin to CLI version (bundle supplies its own version; skip if so).
|
|
3132
|
+
if (-not $_AidFromBundle -and $_fr11CliVer) {
|
|
3133
|
+
$_AidVersionArg = $_fr11CliVer
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3138
|
+
# C-table (for 'update'): register-on-encounter.
|
|
3043
3139
|
# The missing-.aid/ case was already intercepted above (pre-resolve-tools).
|
|
3044
3140
|
if ($SUBCMD -eq 'update') {
|
|
3045
3141
|
script:Invoke-AidCwdClassify -Target $_AidTarget
|
|
3046
3142
|
}
|
|
3047
3143
|
|
|
3144
|
+
# ---------------------------------------------------------------------------
|
|
3145
|
+
# FR10 Stage-all-first atomicity (task-009):
|
|
3146
|
+
# PHASE 1: Stage ALL tools (resolve version, fetch, checksum-verify, extract
|
|
3147
|
+
# to temp) BEFORE any destination write. A failure here aborts with
|
|
3148
|
+
# zero destination mutation.
|
|
3149
|
+
# ---------------------------------------------------------------------------
|
|
3150
|
+
$stageMap = [System.Collections.Generic.Dictionary[string,string]]::new()
|
|
3151
|
+
$stageVersion = ''
|
|
3152
|
+
|
|
3048
3153
|
foreach ($t in $_AidTools) {
|
|
3049
|
-
Write-Host ""
|
|
3050
3154
|
script:Prepare-AidToolStaging -Tool $t -Version $_AidVersionArg -Bundle $_AidFromBundle
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3155
|
+
$stageMap[$t] = $script:_DispStagingDir
|
|
3156
|
+
if (-not $stageVersion) { $stageVersion = $script:_DispResolvedVersion }
|
|
3157
|
+
}
|
|
3158
|
+
|
|
3159
|
+
# ---------------------------------------------------------------------------
|
|
3160
|
+
# FR10 -DryRun: print the plan and exit with no writes.
|
|
3161
|
+
# ---------------------------------------------------------------------------
|
|
3162
|
+
if ($_AidDryRun) {
|
|
3163
|
+
Write-Host "--- aid $SUBCMD -DryRun plan (no writes) ---"
|
|
3164
|
+
Write-Host "Target: $_AidTarget"
|
|
3165
|
+
Write-Host "Version: $(if ($stageVersion) { $stageVersion } else { '<current>' })"
|
|
3166
|
+
foreach ($t in $_AidTools) {
|
|
3167
|
+
Write-Host ""
|
|
3168
|
+
Write-Host "Tool: $t"
|
|
3169
|
+
$dryStaging = $stageMap[$t]
|
|
3170
|
+
$dryFiles = @(Get-ChildItem -LiteralPath $dryStaging -Recurse -File -ErrorAction SilentlyContinue |
|
|
3171
|
+
Sort-Object FullName)
|
|
3172
|
+
foreach ($df in $dryFiles) {
|
|
3173
|
+
$rel = $df.FullName.Substring($dryStaging.Length).TrimStart([char]'\', [char]'/')
|
|
3174
|
+
Write-Host " copy: $rel -> $_AidTarget"
|
|
3175
|
+
}
|
|
3176
|
+
# List files that would be MOVED TO TRASH by the retired-root migration sweep
|
|
3177
|
+
# (marker 1: aid-* prefix; marker 2: inside an aid\ subtree).
|
|
3178
|
+
# Uses ListOnly=$true mode of Invoke-MigrateRetiredLayout (no writes).
|
|
3179
|
+
# The function emits paths via Write-Output; capture then display.
|
|
3180
|
+
$dryRemovePaths = @(Invoke-MigrateRetiredLayout -Target $_AidTarget -Tool $t -ListOnly $true)
|
|
3181
|
+
if ($dryRemovePaths.Count -gt 0) {
|
|
3182
|
+
Write-Host " Would MOVE TO TRASH (retired-layout migration):"
|
|
3183
|
+
foreach ($rp in $dryRemovePaths) {
|
|
3184
|
+
Write-Host " move to trash: $rp"
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
}
|
|
3188
|
+
Write-Host ""
|
|
3189
|
+
Write-Host "--- end dry-run plan ---"
|
|
3190
|
+
script:Exit-Aid 0
|
|
3191
|
+
}
|
|
3192
|
+
|
|
3193
|
+
# ---------------------------------------------------------------------------
|
|
3194
|
+
# PHASE 2: Commit all staged tools.
|
|
3195
|
+
# If any commit fails, exit non-zero with a re-run-to-heal message.
|
|
3196
|
+
# aid update is idempotent: re-running drives every tool to the target version.
|
|
3197
|
+
# ---------------------------------------------------------------------------
|
|
3198
|
+
foreach ($t in $_AidTools) {
|
|
3199
|
+
Write-Host ""
|
|
3200
|
+
Write-Host "Installing $t v$stageVersion -> $_AidTarget"
|
|
3201
|
+
$rc = Install-AidTool -StagingDir $stageMap[$t] -Tool $t -Target $_AidTarget `
|
|
3202
|
+
-Version $stageVersion -Force ([bool]$_AidForce) `
|
|
3054
3203
|
-AidVerbose $script:_AidVerbose
|
|
3055
|
-
if ($rc -
|
|
3056
|
-
|
|
3057
|
-
|
|
3204
|
+
if ($rc -ne 0) {
|
|
3205
|
+
Write-Host ""
|
|
3206
|
+
[Console]::Error.WriteLine("ERROR: aid $SUBCMD failed mid-commit for tool '$t' (rc=$rc).")
|
|
3207
|
+
[Console]::Error.WriteLine(" The repo may be at mixed versions. Re-run 'aid update' to heal.")
|
|
3058
3208
|
script:Exit-Aid $rc
|
|
3059
3209
|
}
|
|
3060
3210
|
}
|
|
3061
3211
|
|
|
3062
3212
|
Write-Host ""
|
|
3063
|
-
|
|
3064
|
-
Write-Host "Install complete with warnings: one or more root agent files were not overwritten."
|
|
3065
|
-
Write-Host "Review the *.aid-new file(s) and merge, or re-run with -Force to overwrite."
|
|
3066
|
-
script:Exit-Aid 5
|
|
3067
|
-
}
|
|
3068
|
-
Write-Host "Done. AID $($script:_DispResolvedVersion) installed into: $_AidTarget"
|
|
3213
|
+
Write-Host "Done. AID $stageVersion installed into: $_AidTarget"
|
|
3069
3214
|
|
|
3070
3215
|
# B-table (for 'add'): tier-aware registration after successful install.
|
|
3071
3216
|
# Decision #3 (unwritable) already handled above with error+abort.
|
|
@@ -3074,7 +3219,7 @@ try {
|
|
|
3074
3219
|
$_btabTier = script:Resolve-AidTier -CanonPath $_AidTarget
|
|
3075
3220
|
script:Registry-Register -Repo $_AidTarget -Tier $_btabTier
|
|
3076
3221
|
} else {
|
|
3077
|
-
# 'update
|
|
3222
|
+
# 'update': C-table register-on-encounter already ran above.
|
|
3078
3223
|
# The post-install register is idempotent; route via user tier.
|
|
3079
3224
|
script:Registry-Register -Repo $_AidTarget -Tier 'user'
|
|
3080
3225
|
}
|
package/dashboard/home.html
CHANGED
|
@@ -1581,11 +1581,13 @@ footer {
|
|
|
1581
1581
|
}
|
|
1582
1582
|
|
|
1583
1583
|
// Build the KB summary card — 5-state (UI-A, feature-007, task-065)
|
|
1584
|
-
// Reads kb_state.status LITERALLY (never re-derives client-side).
|
|
1584
|
+
// Reads kb_state.status / doc_freshness / suspect_count LITERALLY (never re-derives client-side).
|
|
1585
1585
|
// States: pending | generating | preparing | approved | outdated
|
|
1586
1586
|
// An unknown/missing status degrades to the pending (dim) treatment (DM-A2).
|
|
1587
1587
|
// Only approved/outdated are clickable (FR32); others render a dead (non-link) card.
|
|
1588
1588
|
// Clickable href is location-relative ./kb.html (LC-A3).
|
|
1589
|
+
// Freshness signal (f007 task-043): per-doc suspect marker appended after state block when
|
|
1590
|
+
// kb_state.suspect_count > 0; reads doc_freshness[] literally (absence-tolerant).
|
|
1589
1591
|
function _renderKbCard(kbState) {
|
|
1590
1592
|
// Resolve status: read literally; null kbState or missing/unknown status -> 'pending'
|
|
1591
1593
|
var KB_STATUSES = ['pending', 'generating', 'preparing', 'approved', 'outdated'];
|
|
@@ -1723,14 +1725,49 @@ footer {
|
|
|
1723
1725
|
meta.style.marginTop = '0.5rem';
|
|
1724
1726
|
meta.textContent = metaText;
|
|
1725
1727
|
card.appendChild(meta);
|
|
1726
|
-
// Outdated refresh prompt (FR18-style, FR32)
|
|
1728
|
+
// Outdated refresh prompt (FR18-style, FR32) -- per-doc language (f007/task-043)
|
|
1727
1729
|
var prompt = document.createElement('p');
|
|
1728
1730
|
prompt.className = 'meta';
|
|
1729
1731
|
prompt.style.marginTop = '0.5rem';
|
|
1730
|
-
prompt.textContent = '
|
|
1732
|
+
prompt.textContent = 'One or more docs are suspect or the KB baseline has been exceeded. Run /aid-housekeep to reconcile the affected docs. Verify: this card returns to Ready on the next refresh.';
|
|
1731
1733
|
card.appendChild(prompt);
|
|
1732
1734
|
}
|
|
1733
1735
|
|
|
1736
|
+
// Per-doc suspect marker (f007/task-043): appended after state block, absent-tolerant.
|
|
1737
|
+
// Reads kb_state.doc_freshness / suspect_count LITERALLY (no client-side re-derivation).
|
|
1738
|
+
// Shown on any coarse status when suspect_count > 0; omitted (no element added) when 0 or absent.
|
|
1739
|
+
var suspectCount = (kbState && typeof kbState.suspect_count === 'number') ? kbState.suspect_count : 0;
|
|
1740
|
+
if (suspectCount > 0) {
|
|
1741
|
+
var suspectBadge = document.createElement('span');
|
|
1742
|
+
suspectBadge.className = 'badge badge-warn kb-suspect-badge';
|
|
1743
|
+
suspectBadge.style.display = 'inline-block';
|
|
1744
|
+
suspectBadge.style.marginTop = '0.75rem';
|
|
1745
|
+
suspectBadge.style.marginBottom = '0.25rem';
|
|
1746
|
+
suspectBadge.textContent = suspectCount + ' doc' + (suspectCount === 1 ? '' : 's') + ' suspect';
|
|
1747
|
+
card.appendChild(suspectBadge);
|
|
1748
|
+
|
|
1749
|
+
// List each suspect doc with its drifted source(s) where present
|
|
1750
|
+
var freshness = (kbState && Array.isArray(kbState.doc_freshness)) ? kbState.doc_freshness : [];
|
|
1751
|
+
var suspectDocs = freshness.filter(function(d) { return d && d.verdict === 'suspect'; });
|
|
1752
|
+
if (suspectDocs.length > 0) {
|
|
1753
|
+
var suspectList = document.createElement('ul');
|
|
1754
|
+
suspectList.className = 'meta kb-suspect-list';
|
|
1755
|
+
suspectList.style.marginTop = '0.25rem';
|
|
1756
|
+
suspectList.style.paddingLeft = '1.25rem';
|
|
1757
|
+
for (var si = 0; si < suspectDocs.length; si++) {
|
|
1758
|
+
var sd = suspectDocs[si];
|
|
1759
|
+
var li = document.createElement('li');
|
|
1760
|
+
var docLabel = sd.doc || '(unknown)';
|
|
1761
|
+
if (sd.suspect_sources && sd.suspect_sources.length > 0) {
|
|
1762
|
+
docLabel += ' — source: ' + sd.suspect_sources.join(', ');
|
|
1763
|
+
}
|
|
1764
|
+
li.textContent = docLabel;
|
|
1765
|
+
suspectList.appendChild(li);
|
|
1766
|
+
}
|
|
1767
|
+
card.appendChild(suspectList);
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1734
1771
|
return card;
|
|
1735
1772
|
}
|
|
1736
1773
|
|
|
@@ -1764,7 +1801,7 @@ footer {
|
|
|
1764
1801
|
var li1 = document.createElement('li');
|
|
1765
1802
|
li1.appendChild(document.createTextNode('In this repo, run: '));
|
|
1766
1803
|
var codeEl = document.createElement('code');
|
|
1767
|
-
codeEl.textContent = '/aid-
|
|
1804
|
+
codeEl.textContent = '/aid-describe';
|
|
1768
1805
|
li1.appendChild(codeEl);
|
|
1769
1806
|
li1.appendChild(document.createTextNode(' — begins a new work (creates .aid/work-NNN-<name>/ + its STATE.md).'));
|
|
1770
1807
|
ol.appendChild(li1);
|