aid-installer 1.1.1 → 2.0.1
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 +158 -20
- package/bin/aid.ps1 +189 -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 +439 -63
- package/lib/aid-install-core.sh +384 -36
- 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
|
}
|
|
@@ -130,6 +135,9 @@ function script:Test-AidIsProjectDir {
|
|
|
130
135
|
# The current .aid/ layout version. Bumped ONLY on a breaking layout change,
|
|
131
136
|
# never on every CLI release. Defined exactly once; all comparisons read this.
|
|
132
137
|
# Integer must equal the bash AID_SUPPORTED_FORMAT in bin/aid.
|
|
138
|
+
# NOTE (work-007 C6): the install-time settings seed also stamps this value. On a
|
|
139
|
+
# bump, update ALL carriers together: this line, bin/aid AID_SUPPORTED_FORMAT, and
|
|
140
|
+
# lib/AidInstallCore.psm1 $script:_AidSupportedFormat (the PS seed's source).
|
|
133
141
|
# ---------------------------------------------------------------------------
|
|
134
142
|
Set-Variable -Name AidSupportedFormat -Value 1 -Option Constant -Scope Script
|
|
135
143
|
|
|
@@ -191,15 +199,19 @@ function script:Show-AidUsage {
|
|
|
191
199
|
Write-Host ' -DryRun: print the exact command(s) it would run, then exit (no changes).'
|
|
192
200
|
}
|
|
193
201
|
'update' {
|
|
194
|
-
Write-Host 'aid update [
|
|
202
|
+
Write-Host 'aid update [-Version <v>] [-FromBundle <path>] [-Force] [-DryRun] [-Target <dir>]'
|
|
195
203
|
Write-Host 'aid update self [-FromBundle <path>] [-DryRun]'
|
|
196
|
-
Write-Host ' Update to latest.
|
|
204
|
+
Write-Host ' Update to latest.'
|
|
205
|
+
Write-Host ' Outside an AID repo: updates the CLI only (no-op if already latest).'
|
|
206
|
+
Write-Host ' Inside an AID repo: updates the CLI first, then ALL installed tools to one version.'
|
|
207
|
+
Write-Host ' No per-tool selection -- any tool positional is an error (use "self" only).'
|
|
197
208
|
Write-Host ' self: COMPLETELY update the aid CLI, channel-aware:'
|
|
198
209
|
Write-Host ' npm -> npm i -g | pypi -> pipx upgrade | curl -> re-bootstrap install.ps1.'
|
|
199
210
|
Write-Host ' On Windows, elevation is the caller''s responsibility (no sudo).'
|
|
200
|
-
Write-Host ' -
|
|
211
|
+
Write-Host ' -Version <v>: pin ALL tools (and CLI) to version v.'
|
|
212
|
+
Write-Host ' -FromBundle <path>: install from a local artifact instead of @latest'
|
|
201
213
|
Write-Host ' (npm .tgz | pypi .whl | curl release-staging dir with install.ps1).'
|
|
202
|
-
Write-Host ' -DryRun: print the
|
|
214
|
+
Write-Host ' -DryRun: print the full plan (tools updated, files copied, paths pruned) and exit.'
|
|
203
215
|
}
|
|
204
216
|
'version' {
|
|
205
217
|
Write-Host 'aid version'
|
|
@@ -241,7 +253,7 @@ function script:Show-AidUsage {
|
|
|
241
253
|
Write-Host ' aid version Print the CLI version'
|
|
242
254
|
Write-Host ' aid status Show AID state of the current project'
|
|
243
255
|
Write-Host ' aid add <tool>[,...] Add tool(s) to the current project'
|
|
244
|
-
Write-Host ' aid update [
|
|
256
|
+
Write-Host ' aid update [self] Update to latest; inside repo = all tools'
|
|
245
257
|
Write-Host ' aid remove [<tool>... | self] Remove; no arg = ALL AID from project'
|
|
246
258
|
Write-Host ' aid dashboard start|stop ... Start/stop the local dashboard'
|
|
247
259
|
Write-Host ' aid projects [list|add|remove] List/register/unregister AID projects'
|
|
@@ -1448,7 +1460,7 @@ function script:Get-AidProjectState {
|
|
|
1448
1460
|
# Mirror of bash _aid_project_tools.
|
|
1449
1461
|
function script:Get-AidProjectTools {
|
|
1450
1462
|
param([string]$Path)
|
|
1451
|
-
$manifest = Join-Path $Path '.aid' '.aid-manifest.json'
|
|
1463
|
+
$manifest = Join-Path (Join-Path $Path '.aid') '.aid-manifest.json'
|
|
1452
1464
|
if (-not (Test-Path $manifest -PathType Leaf)) { return '' }
|
|
1453
1465
|
$lines = Get-Content -LiteralPath $manifest -Encoding utf8 -ErrorAction SilentlyContinue
|
|
1454
1466
|
if (-not $lines) { return '' }
|
|
@@ -1482,7 +1494,7 @@ function script:Get-AidProjectTools {
|
|
|
1482
1494
|
function script:Get-WhichTierHolds {
|
|
1483
1495
|
param([string]$Path)
|
|
1484
1496
|
$primaryReg = Join-Path $script:_AidStateHome 'registry.yml'
|
|
1485
|
-
$userReg = Join-Path $HOME '.aid' 'registry.yml'
|
|
1497
|
+
$userReg = Join-Path (Join-Path $HOME '.aid') 'registry.yml'
|
|
1486
1498
|
|
|
1487
1499
|
$primaryNorm = [System.IO.Path]::GetFullPath($script:_AidStateHome)
|
|
1488
1500
|
$userNorm = [System.IO.Path]::GetFullPath((Join-Path $HOME '.aid'))
|
|
@@ -1539,7 +1551,7 @@ function script:Invoke-AidProjectsList {
|
|
|
1539
1551
|
([System.IO.Path]::GetFullPath($script:_AidStateHome) -ne [System.IO.Path]::GetFullPath((Join-Path $HOME '.aid')))) {
|
|
1540
1552
|
Join-Path $script:_AidStateHome 'registry.yml'
|
|
1541
1553
|
} else {
|
|
1542
|
-
Join-Path $HOME '.aid' 'registry.yml'
|
|
1554
|
+
Join-Path (Join-Path $HOME '.aid') 'registry.yml'
|
|
1543
1555
|
}
|
|
1544
1556
|
Write-Host (' registry: {0}' -f $regSrc)
|
|
1545
1557
|
}
|
|
@@ -1599,7 +1611,7 @@ function script:Invoke-AidProjectsAdd {
|
|
|
1599
1611
|
$regFile = if ($tier -eq 'shared' -and $primaryNorm -ne $userNorm) {
|
|
1600
1612
|
Join-Path $script:_AidStateHome 'registry.yml'
|
|
1601
1613
|
} else {
|
|
1602
|
-
Join-Path $HOME '.aid' 'registry.yml'
|
|
1614
|
+
Join-Path (Join-Path $HOME '.aid') 'registry.yml'
|
|
1603
1615
|
}
|
|
1604
1616
|
Write-Host ("aid projects: registry file: $regFile")
|
|
1605
1617
|
}
|
|
@@ -1624,7 +1636,7 @@ function script:Invoke-AidProjectsRemove {
|
|
|
1624
1636
|
|
|
1625
1637
|
# Check if registered before unregistering (for idempotency message).
|
|
1626
1638
|
$primaryReg = Join-Path $script:_AidStateHome 'registry.yml'
|
|
1627
|
-
$userReg = Join-Path $HOME '.aid' 'registry.yml'
|
|
1639
|
+
$userReg = Join-Path (Join-Path $HOME '.aid') 'registry.yml'
|
|
1628
1640
|
$primaryNorm = [System.IO.Path]::GetFullPath($script:_AidStateHome)
|
|
1629
1641
|
$userNorm = [System.IO.Path]::GetFullPath((Join-Path $HOME '.aid'))
|
|
1630
1642
|
$found = $false
|
|
@@ -1791,7 +1803,7 @@ function script:Registry-Register {
|
|
|
1791
1803
|
$lns.Add("schema: 1")
|
|
1792
1804
|
$lns.Add("projects:")
|
|
1793
1805
|
foreach ($p in ($repos | Where-Object { $_ } | Sort-Object -Unique)) { $lns.Add(" - $p") }
|
|
1794
|
-
|
|
1806
|
+
[System.IO.File]::WriteAllText($tmp, (($lns.ToArray()) -join "`n") + "`n", [System.Text.UTF8Encoding]::new($false))
|
|
1795
1807
|
Move-Item -LiteralPath $tmp -Destination $regPath -Force -ErrorAction Stop
|
|
1796
1808
|
return $true
|
|
1797
1809
|
} catch {
|
|
@@ -1904,7 +1916,7 @@ function script:Registry-Unregister {
|
|
|
1904
1916
|
$lns.Add("schema: 1")
|
|
1905
1917
|
$lns.Add("projects:")
|
|
1906
1918
|
if ($remaining) { foreach ($p in $remaining) { $lns.Add(" - $p") } }
|
|
1907
|
-
|
|
1919
|
+
[System.IO.File]::WriteAllText($tmp, (($lns.ToArray()) -join "`n") + "`n", [System.Text.UTF8Encoding]::new($false))
|
|
1908
1920
|
Move-Item -LiteralPath $tmp -Destination $regPath -Force -ErrorAction Stop
|
|
1909
1921
|
return $true
|
|
1910
1922
|
} catch {
|
|
@@ -2006,7 +2018,7 @@ if ($script:_RawArgs.Count -eq 0) {
|
|
|
2006
2018
|
if (Test-Path $verFile -PathType Leaf) {
|
|
2007
2019
|
$cliVersion = (Get-Content -LiteralPath $verFile -Raw).Trim()
|
|
2008
2020
|
}
|
|
2009
|
-
Write-Host "AID v$cliVersion -
|
|
2021
|
+
Write-Host "AID v$cliVersion - AI Integrated Development"
|
|
2010
2022
|
Write-Host "Install, update, and manage AID across your projects."
|
|
2011
2023
|
|
|
2012
2024
|
# C6': format gate for cwd repo (.aid/ is guaranteed present here -- the
|
|
@@ -2403,7 +2415,7 @@ function script:Invoke-AidRepairSettingsEraA {
|
|
|
2403
2415
|
$sfDir = Split-Path $SettingsFile -Parent
|
|
2404
2416
|
$tmp = Join-Path $sfDir ("settings.yml.aid-tmp." + [System.IO.Path]::GetRandomFileName())
|
|
2405
2417
|
try {
|
|
2406
|
-
|
|
2418
|
+
[System.IO.File]::WriteAllText($tmp, (($lines.ToArray()) -join "`n") + "`n", [System.Text.UTF8Encoding]::new($false))
|
|
2407
2419
|
Move-Item -LiteralPath $tmp -Destination $SettingsFile -Force -ErrorAction Stop
|
|
2408
2420
|
} catch {
|
|
2409
2421
|
Remove-Item -LiteralPath $tmp -Force -ErrorAction SilentlyContinue
|
|
@@ -2774,6 +2786,7 @@ $_AidFromBundle = ''
|
|
|
2774
2786
|
$_AidForce = $false
|
|
2775
2787
|
$_AidRemoveForce = $false
|
|
2776
2788
|
$_AidTarget = ''
|
|
2789
|
+
$_AidDryRun = $false
|
|
2777
2790
|
$_AidPosTools = [System.Collections.Generic.List[string]]::new()
|
|
2778
2791
|
|
|
2779
2792
|
$remIdx = 0
|
|
@@ -2800,8 +2813,9 @@ while ($remIdx -lt $script:_RemArgs.Count) {
|
|
|
2800
2813
|
$_AidTarget = $script:_RemArgs[$remIdx]
|
|
2801
2814
|
break
|
|
2802
2815
|
}
|
|
2803
|
-
'^(-NoPath|--no-path)$'
|
|
2804
|
-
'^(-
|
|
2816
|
+
'^(-NoPath|--no-path)$' { break <# bootstrap-only; silently ignore here #> }
|
|
2817
|
+
'^(-DryRun|--dry-run)$' { $_AidDryRun = $true; break }
|
|
2818
|
+
'^(-h|--help|-Help)$' { script:Show-AidUsage $SUBCMD; script:Exit-Aid 0 }
|
|
2805
2819
|
'^-' {
|
|
2806
2820
|
script:Fail-Aid "unknown flag: $a" 2
|
|
2807
2821
|
}
|
|
@@ -2825,6 +2839,16 @@ if (-not $_AidForce -and ($env:AID_FORCE -eq '1' -or $env:AID_FORCE -eq 'true'))
|
|
|
2825
2839
|
}
|
|
2826
2840
|
if ($script:_AidVerbose) { $env:AID_VERBOSE = '1' }
|
|
2827
2841
|
|
|
2842
|
+
# FR10: 'update' no longer accepts a per-tool positional (other than 'self' which
|
|
2843
|
+
# was already consumed above). Any non-flag positional on 'aid update' is a usage error.
|
|
2844
|
+
if ($SUBCMD -eq 'update' -and $_AidToolArg) {
|
|
2845
|
+
[Console]::Error.WriteLine("ERROR: aid update: unexpected argument: '$_AidToolArg'")
|
|
2846
|
+
[Console]::Error.WriteLine(" 'aid update' updates all installed tools -- no per-tool selection.")
|
|
2847
|
+
[Console]::Error.WriteLine(" Use 'aid update self' to update the CLI only.")
|
|
2848
|
+
[Console]::Error.WriteLine(" See 'aid update -h' for usage.")
|
|
2849
|
+
script:Exit-Aid 2
|
|
2850
|
+
}
|
|
2851
|
+
|
|
2828
2852
|
if (-not $_AidTarget) { $_AidTarget = '.' }
|
|
2829
2853
|
|
|
2830
2854
|
# Validate target directory.
|
|
@@ -2833,14 +2857,31 @@ if (-not (Test-Path $_AidTarget -PathType Container)) {
|
|
|
2833
2857
|
}
|
|
2834
2858
|
$_AidTarget = (Resolve-Path -LiteralPath $_AidTarget).Path
|
|
2835
2859
|
|
|
2836
|
-
# ----
|
|
2837
|
-
#
|
|
2838
|
-
#
|
|
2860
|
+
# ---- FR10: 'update' outside an AID repo -> update the CLI only (not offer-and-exit) ----
|
|
2861
|
+
# Outside a repo: delegates to the CLI-only update path; no tool loop.
|
|
2862
|
+
# Inside a repo: fall through to the full tool-update pass below.
|
|
2839
2863
|
# Test-AidIsProjectDir excludes the CLI state home from "is project" classification.
|
|
2840
2864
|
if ($SUBCMD -eq 'update') {
|
|
2841
2865
|
if (-not (script:Test-AidIsProjectDir -Dir $_AidTarget)) {
|
|
2842
|
-
|
|
2843
|
-
|
|
2866
|
+
# FR10 outside-repo: update the CLI only; no tool loop.
|
|
2867
|
+
$updCliVer = ''
|
|
2868
|
+
$updVerFile = Join-Path $script:_AidCodeHome 'VERSION'
|
|
2869
|
+
if (Test-Path $updVerFile -PathType Leaf) {
|
|
2870
|
+
$updCliVer = (Get-Content -LiteralPath $updVerFile -Raw -ErrorAction SilentlyContinue).Trim()
|
|
2871
|
+
}
|
|
2872
|
+
# Check if already latest using cached update-check result (no network call).
|
|
2873
|
+
$updCacheFile = Join-Path $HOME (Join-Path '.aid' '.update-check')
|
|
2874
|
+
$updCachedLatest = ''
|
|
2875
|
+
if (Test-Path $updCacheFile -PathType Leaf) {
|
|
2876
|
+
$updLines = Get-Content -LiteralPath $updCacheFile -ErrorAction SilentlyContinue
|
|
2877
|
+
if ($updLines -and $updLines.Count -ge 2) { $updCachedLatest = $updLines[1].Trim() }
|
|
2878
|
+
}
|
|
2879
|
+
if ($updCliVer -and $updCachedLatest -and ($updCliVer -eq $updCachedLatest)) {
|
|
2880
|
+
Write-Host "CLI is current (v$updCliVer)"
|
|
2881
|
+
script:Exit-Aid 0
|
|
2882
|
+
}
|
|
2883
|
+
script:Invoke-AidUpdateSelfIfStale -FromBundle $_AidFromBundle
|
|
2884
|
+
script:Exit-Aid 0
|
|
2844
2885
|
}
|
|
2845
2886
|
}
|
|
2846
2887
|
|
|
@@ -2852,8 +2893,8 @@ if ($SUBCMD -eq 'update' -and (script:Test-AidIsProjectDir -Dir $_AidTarget)) {
|
|
|
2852
2893
|
}
|
|
2853
2894
|
|
|
2854
2895
|
# ---- Self-update-if-needed preamble (FF-3 / CLI-2 / task-079) --------------
|
|
2855
|
-
# For 'update
|
|
2856
|
-
# is current before the per-repo
|
|
2896
|
+
# For 'update' inside an AID repo only (not 'add', not 'update self').
|
|
2897
|
+
# Ensures the CLI is current before the per-repo tool-update runs. WARN-not-fail.
|
|
2857
2898
|
if ($SUBCMD -eq 'update') {
|
|
2858
2899
|
script:Invoke-AidUpdateSelfIfStale -FromBundle $_AidFromBundle
|
|
2859
2900
|
}
|
|
@@ -3022,8 +3063,6 @@ function script:Prepare-AidToolStaging {
|
|
|
3022
3063
|
# Dispatch to engine.
|
|
3023
3064
|
# ---------------------------------------------------------------------------
|
|
3024
3065
|
try {
|
|
3025
|
-
$overallBlocked = $false
|
|
3026
|
-
|
|
3027
3066
|
switch ($SUBCMD) {
|
|
3028
3067
|
{ $_ -in @('add', 'update') } {
|
|
3029
3068
|
# B-table (for 'add'): writability pre-check BEFORE any .aid/ is created.
|
|
@@ -3039,33 +3078,142 @@ try {
|
|
|
3039
3078
|
}
|
|
3040
3079
|
}
|
|
3041
3080
|
|
|
3042
|
-
#
|
|
3081
|
+
# ---------------------------------------------------------------------------
|
|
3082
|
+
# FR11: aid add version selection (same-version invariant).
|
|
3083
|
+
# First-tool (no existing tools in manifest): install at the CLI version.
|
|
3084
|
+
# Additional-tool (manifest already has >=1 tool): install at the EXISTING
|
|
3085
|
+
# tools' version to keep the repo uniform. add does NOT force a repo-wide
|
|
3086
|
+
# update. -Version on add must apply to ALL tools or error (mixed-version
|
|
3087
|
+
# repo would result if the requested version differs from the existing one).
|
|
3088
|
+
# ---------------------------------------------------------------------------
|
|
3089
|
+
if ($SUBCMD -eq 'add') {
|
|
3090
|
+
$_fr11CliVer = ''
|
|
3091
|
+
$fr11VerFile = Join-Path $script:_AidCodeHome 'VERSION'
|
|
3092
|
+
if (Test-Path $fr11VerFile -PathType Leaf) {
|
|
3093
|
+
$_fr11CliVer = (Get-Content -LiteralPath $fr11VerFile -Raw -ErrorAction SilentlyContinue).Trim()
|
|
3094
|
+
}
|
|
3095
|
+
$_fr11ExistingVer = ''
|
|
3096
|
+
if (Test-Path $_AidManifest -PathType Leaf) {
|
|
3097
|
+
$fr11FirstTool = (Get-ManifestToolList -ManifestPath $_AidManifest | Select-Object -First 1)
|
|
3098
|
+
if ($fr11FirstTool) {
|
|
3099
|
+
$_fr11ExistingVer = Read-ManifestToolVersion -ManifestPath $_AidManifest -Tool $fr11FirstTool.Id
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
if ($_AidVersionArg) {
|
|
3104
|
+
# -Version on add: validate it won't create a mixed-version repo.
|
|
3105
|
+
if ($_fr11ExistingVer -and $_AidVersionArg -ne $_fr11ExistingVer) {
|
|
3106
|
+
[Console]::Error.WriteLine("ERROR: aid add: -Version $_AidVersionArg would create a mixed-version repo.")
|
|
3107
|
+
[Console]::Error.WriteLine(" Existing tools are at v$_fr11ExistingVer. Either:")
|
|
3108
|
+
[Console]::Error.WriteLine(" - Omit -Version to install at the repo version (v$_fr11ExistingVer), or")
|
|
3109
|
+
[Console]::Error.WriteLine(" - Run 'aid update -Version $_AidVersionArg' first to advance the whole repo.")
|
|
3110
|
+
script:Exit-Aid 2
|
|
3111
|
+
}
|
|
3112
|
+
# -Version provided and no conflict: apply to all tools (passed through to staging).
|
|
3113
|
+
} elseif ($_fr11ExistingVer) {
|
|
3114
|
+
# Additional-tool: pin staging to the existing repo version (not the CLI version).
|
|
3115
|
+
$_AidVersionArg = $_fr11ExistingVer
|
|
3116
|
+
# Skew notice when CLI is ahead of the repo version.
|
|
3117
|
+
if ($_fr11CliVer) {
|
|
3118
|
+
$fr11PartsA = $_fr11ExistingVer -split '\.'
|
|
3119
|
+
$fr11PartsB = $_fr11CliVer -split '\.'
|
|
3120
|
+
$fr11IsLt = $false
|
|
3121
|
+
for ($fr11i = 0; $fr11i -lt 3; $fr11i++) {
|
|
3122
|
+
$fr11rA = if ($fr11i -lt $fr11PartsA.Count) { $fr11PartsA[$fr11i] } else { '0' }
|
|
3123
|
+
$fr11rB = if ($fr11i -lt $fr11PartsB.Count) { $fr11PartsB[$fr11i] } else { '0' }
|
|
3124
|
+
if ($fr11rA -match '^(\d+)') { $fr11vA = [int]$Matches[1] } else { $fr11vA = 0 }
|
|
3125
|
+
if ($fr11rB -match '^(\d+)') { $fr11vB = [int]$Matches[1] } else { $fr11vB = 0 }
|
|
3126
|
+
if ($fr11vA -lt $fr11vB) { $fr11IsLt = $true; break }
|
|
3127
|
+
if ($fr11vA -gt $fr11vB) { break }
|
|
3128
|
+
}
|
|
3129
|
+
if ($fr11IsLt) {
|
|
3130
|
+
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."
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
} else {
|
|
3134
|
+
# First-tool: pin to CLI version (bundle supplies its own version; skip if so).
|
|
3135
|
+
if (-not $_AidFromBundle -and $_fr11CliVer) {
|
|
3136
|
+
$_AidVersionArg = $_fr11CliVer
|
|
3137
|
+
}
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
|
|
3141
|
+
# C-table (for 'update'): register-on-encounter.
|
|
3043
3142
|
# The missing-.aid/ case was already intercepted above (pre-resolve-tools).
|
|
3044
3143
|
if ($SUBCMD -eq 'update') {
|
|
3045
3144
|
script:Invoke-AidCwdClassify -Target $_AidTarget
|
|
3046
3145
|
}
|
|
3047
3146
|
|
|
3147
|
+
# ---------------------------------------------------------------------------
|
|
3148
|
+
# FR10 Stage-all-first atomicity (task-009):
|
|
3149
|
+
# PHASE 1: Stage ALL tools (resolve version, fetch, checksum-verify, extract
|
|
3150
|
+
# to temp) BEFORE any destination write. A failure here aborts with
|
|
3151
|
+
# zero destination mutation.
|
|
3152
|
+
# ---------------------------------------------------------------------------
|
|
3153
|
+
$stageMap = [System.Collections.Generic.Dictionary[string,string]]::new()
|
|
3154
|
+
$stageVersion = ''
|
|
3155
|
+
|
|
3048
3156
|
foreach ($t in $_AidTools) {
|
|
3049
|
-
Write-Host ""
|
|
3050
3157
|
script:Prepare-AidToolStaging -Tool $t -Version $_AidVersionArg -Bundle $_AidFromBundle
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3158
|
+
$stageMap[$t] = $script:_DispStagingDir
|
|
3159
|
+
if (-not $stageVersion) { $stageVersion = $script:_DispResolvedVersion }
|
|
3160
|
+
}
|
|
3161
|
+
|
|
3162
|
+
# ---------------------------------------------------------------------------
|
|
3163
|
+
# FR10 -DryRun: print the plan and exit with no writes.
|
|
3164
|
+
# ---------------------------------------------------------------------------
|
|
3165
|
+
if ($_AidDryRun) {
|
|
3166
|
+
Write-Host "--- aid $SUBCMD -DryRun plan (no writes) ---"
|
|
3167
|
+
Write-Host "Target: $_AidTarget"
|
|
3168
|
+
Write-Host "Version: $(if ($stageVersion) { $stageVersion } else { '<current>' })"
|
|
3169
|
+
foreach ($t in $_AidTools) {
|
|
3170
|
+
Write-Host ""
|
|
3171
|
+
Write-Host "Tool: $t"
|
|
3172
|
+
$dryStaging = $stageMap[$t]
|
|
3173
|
+
$dryFiles = @(Get-ChildItem -LiteralPath $dryStaging -Recurse -File -ErrorAction SilentlyContinue |
|
|
3174
|
+
Sort-Object FullName)
|
|
3175
|
+
foreach ($df in $dryFiles) {
|
|
3176
|
+
$rel = $df.FullName.Substring($dryStaging.Length).TrimStart([char]'\', [char]'/')
|
|
3177
|
+
Write-Host " copy: $rel -> $_AidTarget"
|
|
3178
|
+
}
|
|
3179
|
+
# List files that would be MOVED TO TRASH by the retired-root migration sweep
|
|
3180
|
+
# (marker 1: aid-* prefix; marker 2: inside an aid\ subtree).
|
|
3181
|
+
# Uses ListOnly=$true mode of Invoke-MigrateRetiredLayout (no writes).
|
|
3182
|
+
# The function emits paths via Write-Output; capture then display.
|
|
3183
|
+
$dryRemovePaths = @(Invoke-MigrateRetiredLayout -Target $_AidTarget -Tool $t -ListOnly $true)
|
|
3184
|
+
if ($dryRemovePaths.Count -gt 0) {
|
|
3185
|
+
Write-Host " Would MOVE TO TRASH (retired-layout migration):"
|
|
3186
|
+
foreach ($rp in $dryRemovePaths) {
|
|
3187
|
+
Write-Host " move to trash: $rp"
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
Write-Host ""
|
|
3192
|
+
Write-Host "--- end dry-run plan ---"
|
|
3193
|
+
script:Exit-Aid 0
|
|
3194
|
+
}
|
|
3195
|
+
|
|
3196
|
+
# ---------------------------------------------------------------------------
|
|
3197
|
+
# PHASE 2: Commit all staged tools.
|
|
3198
|
+
# If any commit fails, exit non-zero with a re-run-to-heal message.
|
|
3199
|
+
# aid update is idempotent: re-running drives every tool to the target version.
|
|
3200
|
+
# ---------------------------------------------------------------------------
|
|
3201
|
+
foreach ($t in $_AidTools) {
|
|
3202
|
+
Write-Host ""
|
|
3203
|
+
Write-Host "Installing $t v$stageVersion -> $_AidTarget"
|
|
3204
|
+
$rc = Install-AidTool -StagingDir $stageMap[$t] -Tool $t -Target $_AidTarget `
|
|
3205
|
+
-Version $stageVersion -Force ([bool]$_AidForce) `
|
|
3054
3206
|
-AidVerbose $script:_AidVerbose
|
|
3055
|
-
if ($rc -
|
|
3056
|
-
|
|
3057
|
-
|
|
3207
|
+
if ($rc -ne 0) {
|
|
3208
|
+
Write-Host ""
|
|
3209
|
+
[Console]::Error.WriteLine("ERROR: aid $SUBCMD failed mid-commit for tool '$t' (rc=$rc).")
|
|
3210
|
+
[Console]::Error.WriteLine(" The repo may be at mixed versions. Re-run 'aid update' to heal.")
|
|
3058
3211
|
script:Exit-Aid $rc
|
|
3059
3212
|
}
|
|
3060
3213
|
}
|
|
3061
3214
|
|
|
3062
3215
|
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"
|
|
3216
|
+
Write-Host "Done. AID $stageVersion installed into: $_AidTarget"
|
|
3069
3217
|
|
|
3070
3218
|
# B-table (for 'add'): tier-aware registration after successful install.
|
|
3071
3219
|
# Decision #3 (unwritable) already handled above with error+abort.
|
|
@@ -3074,7 +3222,7 @@ try {
|
|
|
3074
3222
|
$_btabTier = script:Resolve-AidTier -CanonPath $_AidTarget
|
|
3075
3223
|
script:Registry-Register -Repo $_AidTarget -Tier $_btabTier
|
|
3076
3224
|
} else {
|
|
3077
|
-
# 'update
|
|
3225
|
+
# 'update': C-table register-on-encounter already ran above.
|
|
3078
3226
|
# The post-install register is idempotent; route via user tier.
|
|
3079
3227
|
script:Registry-Register -Repo $_AidTarget -Tier 'user'
|
|
3080
3228
|
}
|
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);
|