pi-revit 0.2.7 → 0.2.8

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/CHANGELOG.md CHANGED
@@ -7,6 +7,17 @@ Format follows [Keep a Changelog](https://keepachangelog.com/); version headers
7
7
  Every published version gets an entry with **Added** / **Changed** / **Fixed** sections
8
8
  describing what the user will notice — not internal refactors.
9
9
 
10
+ ## [0.2.8] - 2026-07-21
11
+
12
+ ### Fixed
13
+ - `search_api_docs`: overload-targeted queries no longer fail on comma spacing.
14
+ `Wall.Create(Document,Curve` (no space) and `Wall.Create( Document, Curve` now match the
15
+ same overloads as `Wall.Create(Document, Curve` — the query's spacing around commas and
16
+ parentheses is normalized to the rendered signature style before matching.
17
+
18
+ Requires redeploying the Revit add-in (`scripts\deploy.ps1` with Revit closed, then restart
19
+ Revit).
20
+
10
21
  ## [0.2.7] - 2026-07-21
11
22
 
12
23
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-revit",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "Native Pi connector for Autodesk Revit. Run npx.cmd -y pi-revit for the full Windows install.",
5
5
  "author": "Ahmad Altahlawi",
6
6
  "license": "MIT",
@@ -1,80 +1,80 @@
1
- #Requires -Version 5.1
2
- <#
3
- Sets up the pi-revit user environment on this PC:
4
-
5
- 1. Workspace at Documents\pi-revit (AGENTS.md conventions, Models\ output tree,
6
- double-click launcher). An existing AGENTS.md is never overwritten.
7
- 2. Global `pi-revit` command installed next to the `pi` command, so any terminal can run:
8
- pi-revit -> Pi in the workspace
9
- pi-revit -c -> continue the last session
10
- Model output sorts itself: the Revit tools file each export under
11
- Models\<model title>\ automatically, keyed by the document it came from.
12
-
13
- Idempotent — safe to re-run. Usage:
14
- scripts\setup-workspace.ps1
15
- scripts\setup-workspace.ps1 -WorkspaceDir "D:\work\pi-revit"
16
- #>
17
- param(
18
- [string]$WorkspaceDir = (Join-Path ([Environment]::GetFolderPath('MyDocuments')) 'pi-revit')
19
- )
20
-
21
- $ErrorActionPreference = 'Stop'
22
- $templates = Join-Path (Split-Path $PSScriptRoot -Parent) 'workspace'
23
-
24
- # 1. Workspace folders. Models\ is where the Revit tools file per-model output.
25
- New-Item -ItemType Directory -Force -Path (Join-Path $WorkspaceDir 'Models') | Out-Null
26
-
27
- # Conventions / notes: copy only when missing so user edits survive re-runs.
28
- $workspaceAgents = Join-Path $WorkspaceDir 'AGENTS.md'
29
- if (-not (Test-Path $workspaceAgents)) {
30
- Copy-Item (Join-Path $templates 'AGENTS.md') $workspaceAgents
31
- }
32
-
33
- # Launcher is code, not user data: always refresh.
34
- Copy-Item (Join-Path $templates 'pi-revit-here.cmd') (Join-Path $WorkspaceDir 'pi-revit.cmd') -Force
35
-
36
- Write-Host "Workspace ready: $WorkspaceDir" -ForegroundColor Green
37
-
38
- # 2. Global pi-revit command next to pi (that directory is on PATH by definition).
39
- # The template's workspace path is rewritten to honor -WorkspaceDir.
40
- # Under `npx pi-revit`, npx prepends its ephemeral cache's node_modules\.bin to
41
- # PATH, and that folder holds a pi shim pulled in via peerDependencies. A launcher
42
- # written next to that shim lands in a folder that is neither on the user's own
43
- # PATH nor long-lived, so skip pi entries inside this package's node_modules tree
44
- # or any npx cache and use the user's permanent pi instead.
45
- function Get-PermanentPiCommand {
46
- # Long-form both sides of the prefix comparison: PATH entries may carry 8.3
47
- # short names (AHMAD~1.TAH) while $PSScriptRoot is normalized, and a form
48
- # mismatch would silently defeat the own-tree exclusion.
49
- function Resolve-LongPath([string]$p) {
50
- try { (Get-Item -LiteralPath $p -ErrorAction Stop).FullName } catch { $p }
51
- }
52
- $ownTree = $null
53
- $repoRoot = Resolve-LongPath (Split-Path $PSScriptRoot -Parent)
54
- $idx = $repoRoot.LastIndexOf('\node_modules\', [StringComparison]::OrdinalIgnoreCase)
55
- if ($idx -ge 0) { $ownTree = $repoRoot.Substring(0, $idx + '\node_modules\'.Length) }
56
- Get-Command pi -All -ErrorAction SilentlyContinue | Where-Object {
57
- if (-not $_.Source) { return $false }
58
- $src = Resolve-LongPath $_.Source
59
- ($src -notmatch '\\_npx\\') -and
60
- (-not $ownTree -or -not $src.StartsWith($ownTree, [StringComparison]::OrdinalIgnoreCase))
61
- } | Select-Object -First 1
62
- }
63
-
64
- $pi = Get-PermanentPiCommand
65
- if ($pi) {
66
- $binDir = Split-Path $pi.Source -Parent
67
- # Literal line swap (no regex): the workspace path may contain characters
68
- # like $ that a -replace replacement string would misinterpret.
69
- $globalCmd = Get-Content (Join-Path $templates 'pi-revit-global.cmd') | ForEach-Object {
70
- if ($_ -like 'set "WORKSPACE=*') { 'set "WORKSPACE=' + $WorkspaceDir + '"' } else { $_ }
71
- }
72
- # cmd.exe parses .cmd files in the console's OEM code page: write the launcher
73
- # in that encoding so workspace paths with non-ASCII characters (user names,
74
- # localized folder names) stay intact.
75
- Set-Content -Path (Join-Path $binDir 'pi-revit.cmd') -Value $globalCmd -Encoding Oem
76
- Write-Host "Global command installed: $(Join-Path $binDir 'pi-revit.cmd')" -ForegroundColor Green
77
- Write-Host 'Run pi-revit from any terminal (pi-revit -c continues the last session).'
78
- } else {
79
- Write-Warning 'No permanent pi command found on PATH. Install Pi first (npm install -g --ignore-scripts @earendil-works/pi-coding-agent), then run npx.cmd -y pi-revit again (or re-run this script) to get the global pi-revit command.'
80
- }
1
+ #Requires -Version 5.1
2
+ <#
3
+ Sets up the pi-revit user environment on this PC:
4
+
5
+ 1. Workspace at Documents\pi-revit (AGENTS.md conventions, Models\ output tree,
6
+ double-click launcher). An existing AGENTS.md is never overwritten.
7
+ 2. Global `pi-revit` command installed next to the `pi` command, so any terminal can run:
8
+ pi-revit -> Pi in the workspace
9
+ pi-revit -c -> continue the last session
10
+ Model output sorts itself: the Revit tools file each export under
11
+ Models\<model title>\ automatically, keyed by the document it came from.
12
+
13
+ Idempotent — safe to re-run. Usage:
14
+ scripts\setup-workspace.ps1
15
+ scripts\setup-workspace.ps1 -WorkspaceDir "D:\work\pi-revit"
16
+ #>
17
+ param(
18
+ [string]$WorkspaceDir = (Join-Path ([Environment]::GetFolderPath('MyDocuments')) 'pi-revit')
19
+ )
20
+
21
+ $ErrorActionPreference = 'Stop'
22
+ $templates = Join-Path (Split-Path $PSScriptRoot -Parent) 'workspace'
23
+
24
+ # 1. Workspace folders. Models\ is where the Revit tools file per-model output.
25
+ New-Item -ItemType Directory -Force -Path (Join-Path $WorkspaceDir 'Models') | Out-Null
26
+
27
+ # Conventions / notes: copy only when missing so user edits survive re-runs.
28
+ $workspaceAgents = Join-Path $WorkspaceDir 'AGENTS.md'
29
+ if (-not (Test-Path $workspaceAgents)) {
30
+ Copy-Item (Join-Path $templates 'AGENTS.md') $workspaceAgents
31
+ }
32
+
33
+ # Launcher is code, not user data: always refresh.
34
+ Copy-Item (Join-Path $templates 'pi-revit-here.cmd') (Join-Path $WorkspaceDir 'pi-revit.cmd') -Force
35
+
36
+ Write-Host "Workspace ready: $WorkspaceDir" -ForegroundColor Green
37
+
38
+ # 2. Global pi-revit command next to pi (that directory is on PATH by definition).
39
+ # The template's workspace path is rewritten to honor -WorkspaceDir.
40
+ # Under `npx pi-revit`, npx prepends its ephemeral cache's node_modules\.bin to
41
+ # PATH, and that folder holds a pi shim pulled in via peerDependencies. A launcher
42
+ # written next to that shim lands in a folder that is neither on the user's own
43
+ # PATH nor long-lived, so skip pi entries inside this package's node_modules tree
44
+ # or any npx cache and use the user's permanent pi instead.
45
+ function Get-PermanentPiCommand {
46
+ # Long-form both sides of the prefix comparison: PATH entries may carry 8.3
47
+ # short names (SOMEUS~1.NAM) while $PSScriptRoot is normalized, and a form
48
+ # mismatch would silently defeat the own-tree exclusion.
49
+ function Resolve-LongPath([string]$p) {
50
+ try { (Get-Item -LiteralPath $p -ErrorAction Stop).FullName } catch { $p }
51
+ }
52
+ $ownTree = $null
53
+ $repoRoot = Resolve-LongPath (Split-Path $PSScriptRoot -Parent)
54
+ $idx = $repoRoot.LastIndexOf('\node_modules\', [StringComparison]::OrdinalIgnoreCase)
55
+ if ($idx -ge 0) { $ownTree = $repoRoot.Substring(0, $idx + '\node_modules\'.Length) }
56
+ Get-Command pi -All -ErrorAction SilentlyContinue | Where-Object {
57
+ if (-not $_.Source) { return $false }
58
+ $src = Resolve-LongPath $_.Source
59
+ ($src -notmatch '\\_npx\\') -and
60
+ (-not $ownTree -or -not $src.StartsWith($ownTree, [StringComparison]::OrdinalIgnoreCase))
61
+ } | Select-Object -First 1
62
+ }
63
+
64
+ $pi = Get-PermanentPiCommand
65
+ if ($pi) {
66
+ $binDir = Split-Path $pi.Source -Parent
67
+ # Literal line swap (no regex): the workspace path may contain characters
68
+ # like $ that a -replace replacement string would misinterpret.
69
+ $globalCmd = Get-Content (Join-Path $templates 'pi-revit-global.cmd') | ForEach-Object {
70
+ if ($_ -like 'set "WORKSPACE=*') { 'set "WORKSPACE=' + $WorkspaceDir + '"' } else { $_ }
71
+ }
72
+ # cmd.exe parses .cmd files in the console's OEM code page: write the launcher
73
+ # in that encoding so workspace paths with non-ASCII characters (user names,
74
+ # localized folder names) stay intact.
75
+ Set-Content -Path (Join-Path $binDir 'pi-revit.cmd') -Value $globalCmd -Encoding Oem
76
+ Write-Host "Global command installed: $(Join-Path $binDir 'pi-revit.cmd')" -ForegroundColor Green
77
+ Write-Host 'Run pi-revit from any terminal (pi-revit -c continues the last session).'
78
+ } else {
79
+ Write-Warning 'No permanent pi command found on PATH. Install Pi first (npm install -g --ignore-scripts @earendil-works/pi-coding-agent), then run npx.cmd -y pi-revit again (or re-run this script) to get the global pi-revit command.'
80
+ }
@@ -1,146 +1,146 @@
1
- #Requires -Version 5.1
2
- <#
3
- Removes everything the pi-revit install scripts placed on this PC:
4
-
5
- - Revit bridge add-in: %APPDATA%\Autodesk\Revit\Addins\<version>\RevitBridge.addin
6
- %APPDATA%\Autodesk\Revit\Addins\<version>\RevitBridge\
7
- - Global command: the pi-revit command next to the pi command
8
- - Bridge runtime: %APPDATA%\RevitBridge\ (per-start connection token / bridge.json)
9
- - Pi package: the pi-revit registration (pi remove), best-effort when pi is on PATH
10
-
11
- The workspace at Documents\pi-revit holds YOUR data (AGENTS.md notes, per-project
12
- session history) and is preserved by default. Pass -RemoveWorkspace to delete it too.
13
-
14
- Pi itself (the global coding agent) is yours to manage and is never touched.
15
-
16
- Close Revit before running. Idempotent — safe to re-run.
17
-
18
- Usage:
19
- scripts\uninstall.ps1
20
- scripts\uninstall.ps1 -RevitVersion 2027
21
- scripts\uninstall.ps1 -RemoveWorkspace
22
- #>
23
- param(
24
- [string]$RevitVersion = '',
25
- [string]$WorkspaceDir = (Join-Path ([Environment]::GetFolderPath('MyDocuments')) 'pi-revit'),
26
- [switch]$RemoveWorkspace
27
- )
28
-
29
- $ErrorActionPreference = 'Stop'
30
-
31
- function Remove-IfExists {
32
- param([string]$Path, [string]$Label)
33
- if (Test-Path -LiteralPath $Path) {
34
- Remove-Item -LiteralPath $Path -Recurse -Force
35
- Write-Host "Removed $Label : $Path" -ForegroundColor Green
36
- } else {
37
- Write-Host "Not present, skipped $Label : $Path"
38
- }
39
- }
40
-
41
- # 1. Revit add-in. With no -RevitVersion, sweep every Addins\<version> folder so the
42
- # user need not remember which Revit they deployed to.
43
- $addinsRoot = Join-Path $env:APPDATA 'Autodesk\Revit\Addins'
44
- $versions = if ($RevitVersion) {
45
- @($RevitVersion)
46
- } elseif (Test-Path -LiteralPath $addinsRoot) {
47
- Get-ChildItem -LiteralPath $addinsRoot -Directory | ForEach-Object { $_.Name }
48
- } else {
49
- @()
50
- }
51
- foreach ($v in $versions) {
52
- $dir = Join-Path $addinsRoot $v
53
- Remove-IfExists (Join-Path $dir 'RevitBridge.addin') "Revit $v add-in manifest"
54
- Remove-IfExists (Join-Path $dir 'RevitBridge') "Revit $v add-in folder"
55
- }
56
-
57
- # 2. Global pi-revit command next to the user's permanent pi. When this script runs
58
- # from an npx cache or a node_modules copy, PATH may lead Get-Command to a pi shim
59
- # inside that ephemeral tree first (see setup-workspace.ps1) — the launcher was
60
- # never installed there, so resolve the permanent pi the same way setup does.
61
- function Get-PermanentPiCommand {
62
- # Long-form both sides of the prefix comparison: PATH entries may carry 8.3
63
- # short names (AHMAD~1.TAH) while $PSScriptRoot is normalized, and a form
64
- # mismatch would silently defeat the own-tree exclusion.
65
- function Resolve-LongPath([string]$p) {
66
- try { (Get-Item -LiteralPath $p -ErrorAction Stop).FullName } catch { $p }
67
- }
68
- $ownTree = $null
69
- $repoRoot = Resolve-LongPath (Split-Path $PSScriptRoot -Parent)
70
- $idx = $repoRoot.LastIndexOf('\node_modules\', [StringComparison]::OrdinalIgnoreCase)
71
- if ($idx -ge 0) { $ownTree = $repoRoot.Substring(0, $idx + '\node_modules\'.Length) }
72
- Get-Command pi -All -ErrorAction SilentlyContinue | Where-Object {
73
- if (-not $_.Source) { return $false }
74
- $src = Resolve-LongPath $_.Source
75
- ($src -notmatch '\\_npx\\') -and
76
- (-not $ownTree -or -not $src.StartsWith($ownTree, [StringComparison]::OrdinalIgnoreCase))
77
- } | Select-Object -First 1
78
- }
79
-
80
- $pi = Get-Command pi -ErrorAction SilentlyContinue
81
- $piPermanent = Get-PermanentPiCommand
82
- if ($piPermanent) {
83
- $binDir = Split-Path $piPermanent.Source -Parent
84
- Remove-IfExists (Join-Path $binDir 'pi-revit.cmd') 'global pi-revit command'
85
- } else {
86
- Write-Host 'No permanent pi found on PATH; skipping the global pi-revit command.'
87
- }
88
-
89
- # 3. Bridge runtime folder (connection token; recreated on each Revit start).
90
- Remove-IfExists (Join-Path $env:APPDATA 'RevitBridge') 'bridge runtime folder'
91
-
92
- # 4. Pi package registration. Pi keys a package by its install source: the npm
93
- # installer (npx.cmd -y pi-revit) registers `npm:pi-revit`, while an install
94
- # from a clone of this repo (`pi install ./`) registers the repo path resolved
95
- # from the repo root. Try both forms; each succeeds only for the source that
96
- # is actually registered, so a machine with both gets both removed.
97
- if ($pi) {
98
- $repoRoot = Split-Path $PSScriptRoot -Parent
99
- # When this script runs from the npm-installed copy, `pi remove npm:pi-revit`
100
- # deletes the very folder the script lives in — and Windows fails that delete
101
- # (EBUSY) while any working directory sits inside it. Step our own process out
102
- # if needed; the calling shell's location we can only warn about.
103
- if ($repoRoot -match '\\node_modules\\' -and
104
- (Get-Location).Path.StartsWith($repoRoot, [StringComparison]::OrdinalIgnoreCase)) {
105
- Set-Location $env:SystemRoot
106
- Write-Warning "This PowerShell was started inside $repoRoot. If the package removal below fails, run 'cd \' in your shell and re-run the uninstall."
107
- }
108
- try {
109
- $removed = @()
110
- # './' resolves against the repo root, so it runs from there — and first,
111
- # while this folder is guaranteed to still exist. 'npm:pi-revit' then runs
112
- # from a neutral directory so no working directory blocks the folder delete.
113
- foreach ($source in @('./', 'npm:pi-revit')) {
114
- Push-Location $(if ($source -eq './') { $repoRoot } else { $env:SystemRoot })
115
- try {
116
- $global:LASTEXITCODE = 0
117
- & pi remove $source
118
- if ($LASTEXITCODE -eq 0) {
119
- $removed += $source
120
- }
121
- } finally {
122
- Pop-Location
123
- }
124
- }
125
- if ($removed.Count -gt 0) {
126
- Write-Host "Removed the pi-revit Pi package ($($removed -join ', '))." -ForegroundColor Green
127
- } else {
128
- Write-Warning "No pi-revit Pi package registration was found. If pi still lists it, run 'pi remove npm:pi-revit' (npm install) or 'pi remove ./' from this repo (install from source)."
129
- }
130
- } catch {
131
- Write-Warning "Could not auto-remove the Pi package; run 'pi remove npm:pi-revit' (npm install) or 'pi remove ./' from this repo (install from source). ($_)"
132
- }
133
- }
134
-
135
- # 5. Workspace (user data) — opt-in only.
136
- if ($RemoveWorkspace) {
137
- Remove-IfExists $WorkspaceDir 'workspace'
138
- } else {
139
- Write-Host ''
140
- Write-Host "Workspace preserved (your notes + session history): $WorkspaceDir" -ForegroundColor Yellow
141
- Write-Host 'Pass -RemoveWorkspace to delete it too.'
142
- }
143
-
144
- Write-Host ''
145
- Write-Host 'pi-revit uninstalled. Pi itself is untouched; remove it yourself if you want:' -ForegroundColor Green
146
- Write-Host ' npm uninstall -g @earendil-works/pi-coding-agent'
1
+ #Requires -Version 5.1
2
+ <#
3
+ Removes everything the pi-revit install scripts placed on this PC:
4
+
5
+ - Revit bridge add-in: %APPDATA%\Autodesk\Revit\Addins\<version>\RevitBridge.addin
6
+ %APPDATA%\Autodesk\Revit\Addins\<version>\RevitBridge\
7
+ - Global command: the pi-revit command next to the pi command
8
+ - Bridge runtime: %APPDATA%\RevitBridge\ (per-start connection token / bridge.json)
9
+ - Pi package: the pi-revit registration (pi remove), best-effort when pi is on PATH
10
+
11
+ The workspace at Documents\pi-revit holds YOUR data (AGENTS.md notes, per-project
12
+ session history) and is preserved by default. Pass -RemoveWorkspace to delete it too.
13
+
14
+ Pi itself (the global coding agent) is yours to manage and is never touched.
15
+
16
+ Close Revit before running. Idempotent — safe to re-run.
17
+
18
+ Usage:
19
+ scripts\uninstall.ps1
20
+ scripts\uninstall.ps1 -RevitVersion 2027
21
+ scripts\uninstall.ps1 -RemoveWorkspace
22
+ #>
23
+ param(
24
+ [string]$RevitVersion = '',
25
+ [string]$WorkspaceDir = (Join-Path ([Environment]::GetFolderPath('MyDocuments')) 'pi-revit'),
26
+ [switch]$RemoveWorkspace
27
+ )
28
+
29
+ $ErrorActionPreference = 'Stop'
30
+
31
+ function Remove-IfExists {
32
+ param([string]$Path, [string]$Label)
33
+ if (Test-Path -LiteralPath $Path) {
34
+ Remove-Item -LiteralPath $Path -Recurse -Force
35
+ Write-Host "Removed $Label : $Path" -ForegroundColor Green
36
+ } else {
37
+ Write-Host "Not present, skipped $Label : $Path"
38
+ }
39
+ }
40
+
41
+ # 1. Revit add-in. With no -RevitVersion, sweep every Addins\<version> folder so the
42
+ # user need not remember which Revit they deployed to.
43
+ $addinsRoot = Join-Path $env:APPDATA 'Autodesk\Revit\Addins'
44
+ $versions = if ($RevitVersion) {
45
+ @($RevitVersion)
46
+ } elseif (Test-Path -LiteralPath $addinsRoot) {
47
+ Get-ChildItem -LiteralPath $addinsRoot -Directory | ForEach-Object { $_.Name }
48
+ } else {
49
+ @()
50
+ }
51
+ foreach ($v in $versions) {
52
+ $dir = Join-Path $addinsRoot $v
53
+ Remove-IfExists (Join-Path $dir 'RevitBridge.addin') "Revit $v add-in manifest"
54
+ Remove-IfExists (Join-Path $dir 'RevitBridge') "Revit $v add-in folder"
55
+ }
56
+
57
+ # 2. Global pi-revit command next to the user's permanent pi. When this script runs
58
+ # from an npx cache or a node_modules copy, PATH may lead Get-Command to a pi shim
59
+ # inside that ephemeral tree first (see setup-workspace.ps1) — the launcher was
60
+ # never installed there, so resolve the permanent pi the same way setup does.
61
+ function Get-PermanentPiCommand {
62
+ # Long-form both sides of the prefix comparison: PATH entries may carry 8.3
63
+ # short names (SOMEUS~1.NAM) while $PSScriptRoot is normalized, and a form
64
+ # mismatch would silently defeat the own-tree exclusion.
65
+ function Resolve-LongPath([string]$p) {
66
+ try { (Get-Item -LiteralPath $p -ErrorAction Stop).FullName } catch { $p }
67
+ }
68
+ $ownTree = $null
69
+ $repoRoot = Resolve-LongPath (Split-Path $PSScriptRoot -Parent)
70
+ $idx = $repoRoot.LastIndexOf('\node_modules\', [StringComparison]::OrdinalIgnoreCase)
71
+ if ($idx -ge 0) { $ownTree = $repoRoot.Substring(0, $idx + '\node_modules\'.Length) }
72
+ Get-Command pi -All -ErrorAction SilentlyContinue | Where-Object {
73
+ if (-not $_.Source) { return $false }
74
+ $src = Resolve-LongPath $_.Source
75
+ ($src -notmatch '\\_npx\\') -and
76
+ (-not $ownTree -or -not $src.StartsWith($ownTree, [StringComparison]::OrdinalIgnoreCase))
77
+ } | Select-Object -First 1
78
+ }
79
+
80
+ $pi = Get-Command pi -ErrorAction SilentlyContinue
81
+ $piPermanent = Get-PermanentPiCommand
82
+ if ($piPermanent) {
83
+ $binDir = Split-Path $piPermanent.Source -Parent
84
+ Remove-IfExists (Join-Path $binDir 'pi-revit.cmd') 'global pi-revit command'
85
+ } else {
86
+ Write-Host 'No permanent pi found on PATH; skipping the global pi-revit command.'
87
+ }
88
+
89
+ # 3. Bridge runtime folder (connection token; recreated on each Revit start).
90
+ Remove-IfExists (Join-Path $env:APPDATA 'RevitBridge') 'bridge runtime folder'
91
+
92
+ # 4. Pi package registration. Pi keys a package by its install source: the npm
93
+ # installer (npx.cmd -y pi-revit) registers `npm:pi-revit`, while an install
94
+ # from a clone of this repo (`pi install ./`) registers the repo path resolved
95
+ # from the repo root. Try both forms; each succeeds only for the source that
96
+ # is actually registered, so a machine with both gets both removed.
97
+ if ($pi) {
98
+ $repoRoot = Split-Path $PSScriptRoot -Parent
99
+ # When this script runs from the npm-installed copy, `pi remove npm:pi-revit`
100
+ # deletes the very folder the script lives in — and Windows fails that delete
101
+ # (EBUSY) while any working directory sits inside it. Step our own process out
102
+ # if needed; the calling shell's location we can only warn about.
103
+ if ($repoRoot -match '\\node_modules\\' -and
104
+ (Get-Location).Path.StartsWith($repoRoot, [StringComparison]::OrdinalIgnoreCase)) {
105
+ Set-Location $env:SystemRoot
106
+ Write-Warning "This PowerShell was started inside $repoRoot. If the package removal below fails, run 'cd \' in your shell and re-run the uninstall."
107
+ }
108
+ try {
109
+ $removed = @()
110
+ # './' resolves against the repo root, so it runs from there — and first,
111
+ # while this folder is guaranteed to still exist. 'npm:pi-revit' then runs
112
+ # from a neutral directory so no working directory blocks the folder delete.
113
+ foreach ($source in @('./', 'npm:pi-revit')) {
114
+ Push-Location $(if ($source -eq './') { $repoRoot } else { $env:SystemRoot })
115
+ try {
116
+ $global:LASTEXITCODE = 0
117
+ & pi remove $source
118
+ if ($LASTEXITCODE -eq 0) {
119
+ $removed += $source
120
+ }
121
+ } finally {
122
+ Pop-Location
123
+ }
124
+ }
125
+ if ($removed.Count -gt 0) {
126
+ Write-Host "Removed the pi-revit Pi package ($($removed -join ', '))." -ForegroundColor Green
127
+ } else {
128
+ Write-Warning "No pi-revit Pi package registration was found. If pi still lists it, run 'pi remove npm:pi-revit' (npm install) or 'pi remove ./' from this repo (install from source)."
129
+ }
130
+ } catch {
131
+ Write-Warning "Could not auto-remove the Pi package; run 'pi remove npm:pi-revit' (npm install) or 'pi remove ./' from this repo (install from source). ($_)"
132
+ }
133
+ }
134
+
135
+ # 5. Workspace (user data) — opt-in only.
136
+ if ($RemoveWorkspace) {
137
+ Remove-IfExists $WorkspaceDir 'workspace'
138
+ } else {
139
+ Write-Host ''
140
+ Write-Host "Workspace preserved (your notes + session history): $WorkspaceDir" -ForegroundColor Yellow
141
+ Write-Host 'Pass -RemoveWorkspace to delete it too.'
142
+ }
143
+
144
+ Write-Host ''
145
+ Write-Host 'pi-revit uninstalled. Pi itself is untouched; remove it yourself if you want:' -ForegroundColor Green
146
+ Write-Host ' npm uninstall -g @earendil-works/pi-coding-agent'
@@ -1,5 +1,6 @@
1
1
  using System.IO;
2
2
  using System.Text;
3
+ using System.Text.RegularExpressions;
3
4
  using System.Text.Json;
4
5
  using System.Xml;
5
6
  using System.Xml.Linq;
@@ -124,7 +125,13 @@ namespace RevitBridge.Tools
124
125
 
125
126
  private static (List<ApiMember> Top, int Total) Search(DocIndex index, string query, char? kindFilter, int maxResults)
126
127
  {
128
+ // Signatures are rendered exactly one way ("Name(Type, Type)"): normalize the
129
+ // query's spacing around commas and parentheses so 'Wall.Create(Document,Curve'
130
+ // and 'Wall.Create( Document, Curve' hit the same rendered text instead of
131
+ // failing on typography.
127
132
  string q = query.ToLowerInvariant();
133
+ q = Regex.Replace(q, @"\s*,\s*", ", ");
134
+ q = Regex.Replace(q, @"\(\s+", "(");
128
135
  string[] words = q.Split(WordSeparators, StringSplitOptions.RemoveEmptyEntries);
129
136
 
130
137
  var scored = new List<(ApiMember Member, int Score)>();