@ornexus/neocortex 4.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.

Potentially problematic release.


This version of @ornexus/neocortex might be problematic. Click here for more details.

Files changed (121) hide show
  1. package/LICENSE +56 -0
  2. package/README.md +32 -0
  3. package/install.js +486 -0
  4. package/install.ps1 +1790 -0
  5. package/install.sh +1587 -0
  6. package/package.json +104 -0
  7. package/packages/client/dist/adapters/adapter-registry.d.ts +61 -0
  8. package/packages/client/dist/adapters/adapter-registry.js +106 -0
  9. package/packages/client/dist/adapters/antigravity-adapter.d.ts +18 -0
  10. package/packages/client/dist/adapters/antigravity-adapter.js +77 -0
  11. package/packages/client/dist/adapters/claude-code-adapter.d.ts +19 -0
  12. package/packages/client/dist/adapters/claude-code-adapter.js +79 -0
  13. package/packages/client/dist/adapters/codex-adapter.d.ts +19 -0
  14. package/packages/client/dist/adapters/codex-adapter.js +80 -0
  15. package/packages/client/dist/adapters/cursor-adapter.d.ts +19 -0
  16. package/packages/client/dist/adapters/cursor-adapter.js +115 -0
  17. package/packages/client/dist/adapters/gemini-adapter.d.ts +18 -0
  18. package/packages/client/dist/adapters/gemini-adapter.js +71 -0
  19. package/packages/client/dist/adapters/index.d.ts +19 -0
  20. package/packages/client/dist/adapters/index.js +21 -0
  21. package/packages/client/dist/adapters/platform-detector.d.ts +46 -0
  22. package/packages/client/dist/adapters/platform-detector.js +106 -0
  23. package/packages/client/dist/adapters/target-adapter.d.ts +70 -0
  24. package/packages/client/dist/adapters/target-adapter.js +12 -0
  25. package/packages/client/dist/adapters/vscode-adapter.d.ts +19 -0
  26. package/packages/client/dist/adapters/vscode-adapter.js +72 -0
  27. package/packages/client/dist/agent/refresh-stubs.d.ts +65 -0
  28. package/packages/client/dist/agent/refresh-stubs.js +234 -0
  29. package/packages/client/dist/agent/update-agent-yaml.d.ts +26 -0
  30. package/packages/client/dist/agent/update-agent-yaml.js +102 -0
  31. package/packages/client/dist/agent/update-description.d.ts +45 -0
  32. package/packages/client/dist/agent/update-description.js +251 -0
  33. package/packages/client/dist/cache/crypto-utils.d.ts +30 -0
  34. package/packages/client/dist/cache/crypto-utils.js +76 -0
  35. package/packages/client/dist/cache/encrypted-cache.d.ts +30 -0
  36. package/packages/client/dist/cache/encrypted-cache.js +94 -0
  37. package/packages/client/dist/cache/in-memory-asset-cache.d.ts +59 -0
  38. package/packages/client/dist/cache/in-memory-asset-cache.js +70 -0
  39. package/packages/client/dist/cache/index.d.ts +13 -0
  40. package/packages/client/dist/cache/index.js +13 -0
  41. package/packages/client/dist/cli.d.ts +14 -0
  42. package/packages/client/dist/cli.js +194 -0
  43. package/packages/client/dist/commands/activate.d.ts +55 -0
  44. package/packages/client/dist/commands/activate.js +390 -0
  45. package/packages/client/dist/commands/cache-status.d.ts +39 -0
  46. package/packages/client/dist/commands/cache-status.js +112 -0
  47. package/packages/client/dist/commands/invoke.d.ts +70 -0
  48. package/packages/client/dist/commands/invoke.js +490 -0
  49. package/packages/client/dist/config/resolver-selection.d.ts +40 -0
  50. package/packages/client/dist/config/resolver-selection.js +278 -0
  51. package/packages/client/dist/config/secure-config.d.ts +78 -0
  52. package/packages/client/dist/config/secure-config.js +269 -0
  53. package/packages/client/dist/constants.d.ts +25 -0
  54. package/packages/client/dist/constants.js +25 -0
  55. package/packages/client/dist/context/context-collector.d.ts +28 -0
  56. package/packages/client/dist/context/context-collector.js +222 -0
  57. package/packages/client/dist/context/context-sanitizer.d.ts +28 -0
  58. package/packages/client/dist/context/context-sanitizer.js +145 -0
  59. package/packages/client/dist/index.d.ts +55 -0
  60. package/packages/client/dist/index.js +38 -0
  61. package/packages/client/dist/license/index.d.ts +5 -0
  62. package/packages/client/dist/license/index.js +5 -0
  63. package/packages/client/dist/license/license-client.d.ts +79 -0
  64. package/packages/client/dist/license/license-client.js +257 -0
  65. package/packages/client/dist/machine/fingerprint.d.ts +34 -0
  66. package/packages/client/dist/machine/fingerprint.js +160 -0
  67. package/packages/client/dist/machine/index.d.ts +5 -0
  68. package/packages/client/dist/machine/index.js +5 -0
  69. package/packages/client/dist/resilience/circuit-breaker.d.ts +70 -0
  70. package/packages/client/dist/resilience/circuit-breaker.js +170 -0
  71. package/packages/client/dist/resilience/degradation-manager.d.ts +67 -0
  72. package/packages/client/dist/resilience/degradation-manager.js +164 -0
  73. package/packages/client/dist/resilience/freshness-indicator.d.ts +59 -0
  74. package/packages/client/dist/resilience/freshness-indicator.js +100 -0
  75. package/packages/client/dist/resilience/index.d.ts +8 -0
  76. package/packages/client/dist/resilience/index.js +8 -0
  77. package/packages/client/dist/resilience/recovery-detector.d.ts +59 -0
  78. package/packages/client/dist/resilience/recovery-detector.js +74 -0
  79. package/packages/client/dist/resolvers/asset-resolver.d.ts +79 -0
  80. package/packages/client/dist/resolvers/asset-resolver.js +13 -0
  81. package/packages/client/dist/resolvers/local-resolver.d.ts +26 -0
  82. package/packages/client/dist/resolvers/local-resolver.js +218 -0
  83. package/packages/client/dist/resolvers/remote-resolver.d.ts +91 -0
  84. package/packages/client/dist/resolvers/remote-resolver.js +282 -0
  85. package/packages/client/dist/telemetry/index.d.ts +5 -0
  86. package/packages/client/dist/telemetry/index.js +5 -0
  87. package/packages/client/dist/telemetry/offline-queue.d.ts +57 -0
  88. package/packages/client/dist/telemetry/offline-queue.js +131 -0
  89. package/packages/client/dist/tier/index.d.ts +5 -0
  90. package/packages/client/dist/tier/index.js +5 -0
  91. package/packages/client/dist/tier/tier-aware-client.d.ts +97 -0
  92. package/packages/client/dist/tier/tier-aware-client.js +260 -0
  93. package/packages/client/dist/types/index.d.ts +140 -0
  94. package/packages/client/dist/types/index.js +38 -0
  95. package/postinstall.js +272 -0
  96. package/targets-stubs/antigravity/README.md +36 -0
  97. package/targets-stubs/antigravity/gemini.md +22 -0
  98. package/targets-stubs/antigravity/install-antigravity.sh +44 -0
  99. package/targets-stubs/antigravity/mcp-config.json +9 -0
  100. package/targets-stubs/antigravity/skill/SKILL.md +67 -0
  101. package/targets-stubs/claude-code/README.md +20 -0
  102. package/targets-stubs/claude-code/neocortex.agent.yaml +24 -0
  103. package/targets-stubs/claude-code/neocortex.md +125 -0
  104. package/targets-stubs/codex/README.md +32 -0
  105. package/targets-stubs/codex/agents.md +61 -0
  106. package/targets-stubs/codex/config-mcp.toml +6 -0
  107. package/targets-stubs/codex/install-codex.sh +61 -0
  108. package/targets-stubs/cursor/README.md +33 -0
  109. package/targets-stubs/cursor/agent.md +94 -0
  110. package/targets-stubs/cursor/install-cursor.sh +35 -0
  111. package/targets-stubs/cursor/mcp.json +11 -0
  112. package/targets-stubs/gemini-cli/README.md +34 -0
  113. package/targets-stubs/gemini-cli/agent.md +101 -0
  114. package/targets-stubs/gemini-cli/gemini.md +16 -0
  115. package/targets-stubs/gemini-cli/install-gemini.sh +56 -0
  116. package/targets-stubs/gemini-cli/settings-mcp.json +11 -0
  117. package/targets-stubs/vscode/README.md +34 -0
  118. package/targets-stubs/vscode/agent.md +102 -0
  119. package/targets-stubs/vscode/copilot-instructions.md +16 -0
  120. package/targets-stubs/vscode/install-vscode.sh +42 -0
  121. package/targets-stubs/vscode/mcp.json +13 -0
package/install.ps1 ADDED
@@ -0,0 +1,1790 @@
1
+ # Neocortex - Instalador Windows
2
+ # Development Orchestrator
3
+
4
+ param(
5
+ [switch]$Yes,
6
+ [switch]$Debug,
7
+ [switch]$SkipProject,
8
+ [switch]$CreateProject,
9
+ [switch]$Quiet,
10
+ [switch]$NoBanner,
11
+ [switch]$CleanupLegacy,
12
+ [switch]$Local,
13
+ [switch]$Help,
14
+ [string]$Targets = "",
15
+ # SSoT: packages/client/src/constants.ts DEFAULT_SERVER_URL
16
+ [string]$ServerUrl = "https://api.neocortex.sh"
17
+ )
18
+
19
+ $VERSION = "4.0.1"
20
+
21
+ # =============================================================================
22
+ # CONFIGURACOES
23
+ # =============================================================================
24
+
25
+ $ErrorActionPreference = "Continue"
26
+ $script:Errors = 0
27
+ $script:MigrationDetected = $false
28
+ $script:MigrationSources = @()
29
+ $script:LegacyItems = @()
30
+ $script:LegacyWarnings = 0
31
+
32
+ $AUTO_YES = $Yes
33
+ $DEBUG_MODE = $Debug
34
+ $SKIP_PROJECT_DIRS = $SkipProject
35
+ $QUIET_MODE = $Quiet
36
+ $NO_BANNER = $NoBanner
37
+ # LOCAL_MODE removed (Epic 50): thin-client ALWAYS, zero IP on client
38
+ $LOCAL_MODE = $false
39
+ $NEOCORTEX_SERVER_URL = $ServerUrl
40
+
41
+ function Test-Interactive {
42
+ try {
43
+ if (-not [Environment]::UserInteractive) { return $false }
44
+ if ($null -eq $Host.UI -or $null -eq $Host.UI.RawUI) { return $false }
45
+ return $true
46
+ } catch { return $false }
47
+ }
48
+
49
+ if (-not (Test-Interactive)) {
50
+ $AUTO_YES = $true
51
+ }
52
+
53
+ # =============================================================================
54
+ # AJUDA
55
+ # =============================================================================
56
+
57
+ if ($Help) {
58
+ Write-Host ""
59
+ Write-Host " Neocortex Installer v$VERSION" -ForegroundColor White
60
+ Write-Host " Development Orchestrator" -ForegroundColor DarkGray
61
+ Write-Host ""
62
+ Write-Host " Uso: npx @ornexus/neocortex [opcoes]"
63
+ Write-Host ""
64
+ Write-Host " Opcoes:" -ForegroundColor DarkGray
65
+ Write-Host " -Yes Modo automatico (Claude Code only)" -ForegroundColor Cyan
66
+ Write-Host " -Targets <lista> Plataformas separadas por virgula" -ForegroundColor Cyan
67
+ Write-Host " -CreateProject Instalar estrutura no projeto" -ForegroundColor Cyan
68
+ Write-Host " -SkipProject Nao perguntar sobre projeto" -ForegroundColor Cyan
69
+ Write-Host " -Quiet Modo silencioso" -ForegroundColor Cyan
70
+ Write-Host " -CleanupLegacy (Redundante) Limpeza agora e automatica" -ForegroundColor Cyan
71
+ Write-Host " -Local (Removido) Thin-client obrigatorio, zero IP no client" -ForegroundColor DarkGray
72
+ Write-Host " -ServerUrl <url> URL do server Neocortex" -ForegroundColor Cyan
73
+ Write-Host " -Debug Modo debug" -ForegroundColor Cyan
74
+ Write-Host " -Help Mostra esta ajuda" -ForegroundColor Cyan
75
+ Write-Host ""
76
+ Write-Host " Plataformas: claude-code, cursor, vscode, gemini-cli, codex, antigravity" -ForegroundColor DarkGray
77
+ exit 0
78
+ }
79
+
80
+ # =============================================================================
81
+ # FUNCOES DE LOG
82
+ # =============================================================================
83
+
84
+ function Write-Step {
85
+ param([int]$Num, [int]$Total, [string]$Message)
86
+ Write-Host ""
87
+ Write-Host " [$Num/$Total] " -ForegroundColor Cyan -NoNewline
88
+ Write-Host $Message -ForegroundColor White
89
+ }
90
+
91
+ function Write-Ok {
92
+ param([string]$Message)
93
+ if (-not $QUIET_MODE) {
94
+ Write-Host " " -NoNewline
95
+ Write-Host "[ok]" -ForegroundColor Green -NoNewline
96
+ Write-Host " $Message"
97
+ }
98
+ }
99
+
100
+ function Write-Warn {
101
+ param([string]$Message)
102
+ Write-Host " " -NoNewline
103
+ Write-Host "[!]" -ForegroundColor Yellow -NoNewline
104
+ Write-Host " $Message"
105
+ }
106
+
107
+ function Write-Fail {
108
+ param([string]$Message)
109
+ Write-Host " " -NoNewline
110
+ Write-Host "[x]" -ForegroundColor Red -NoNewline
111
+ Write-Host " $Message"
112
+ }
113
+
114
+ function Write-Info {
115
+ param([string]$Message)
116
+ if (-not $QUIET_MODE) {
117
+ Write-Host " -> " -ForegroundColor DarkGray -NoNewline
118
+ Write-Host $Message -ForegroundColor DarkGray
119
+ }
120
+ }
121
+
122
+ function Write-Dbg {
123
+ param([string]$Message)
124
+ if ($DEBUG_MODE) {
125
+ Write-Host " [debug] $Message" -ForegroundColor DarkGray
126
+ }
127
+ }
128
+
129
+ # =============================================================================
130
+ # UTF-8 BOM-FREE WRITE HELPER (Epic 63 - Story 63.1)
131
+ # PowerShell 5.1 writes UTF-8 WITH BOM via Out-File -Encoding utf8 and
132
+ # Set-Content -Encoding utf8. Node.js JSON.parse fails on BOM prefix.
133
+ # This helper uses .NET API to write UTF-8 WITHOUT BOM, compatible with
134
+ # both PowerShell 5.1 and 7+.
135
+ # =============================================================================
136
+
137
+ function Write-Utf8NoBom {
138
+ param(
139
+ [string]$Path,
140
+ [string]$Content
141
+ )
142
+ $utf8NoBom = [System.Text.UTF8Encoding]::new($false)
143
+ [System.IO.File]::WriteAllText($Path, $Content, $utf8NoBom)
144
+ }
145
+
146
+ # =============================================================================
147
+ # ACL HELPERS (Story 66.1 - Windows file permission hardening)
148
+ # Fail-open: never throws, never blocks installation
149
+ # =============================================================================
150
+
151
+ function Set-FileAcl {
152
+ param([string]$Path)
153
+ try {
154
+ $username = $env:USERNAME
155
+ if (-not $username) { return }
156
+ & icacls $Path /inheritance:r /grant:r "${username}:(F)" 2>$null | Out-Null
157
+ } catch { }
158
+ }
159
+
160
+ function Set-DirAcl {
161
+ param([string]$Path)
162
+ try {
163
+ $username = $env:USERNAME
164
+ if (-not $username) { return }
165
+ & icacls $Path /inheritance:r /grant:r "${username}:(OI)(CI)(F)" 2>$null | Out-Null
166
+ } catch { }
167
+ }
168
+
169
+ function Read-HostWithTimeout {
170
+ param([int]$TimeoutSeconds = 10, [string]$Default = "n")
171
+ try {
172
+ if (-not (Test-Interactive)) { return $Default }
173
+ $endTime = [DateTime]::Now.AddSeconds($TimeoutSeconds)
174
+ while (-not $Host.UI.RawUI.KeyAvailable) {
175
+ if ([DateTime]::Now -ge $endTime) {
176
+ Write-Host ""
177
+ return $Default
178
+ }
179
+ Start-Sleep -Milliseconds 100
180
+ }
181
+ return Read-Host
182
+ } catch { return $Default }
183
+ }
184
+
185
+ # =============================================================================
186
+ # BANNER
187
+ # =============================================================================
188
+
189
+ function Show-Banner {
190
+ if ($QUIET_MODE) { return }
191
+ if ($NO_BANNER) { return }
192
+
193
+ Write-Host ""
194
+ Write-Host " #######" -ForegroundColor Cyan
195
+ Write-Host " ### ########" -ForegroundColor Cyan
196
+ Write-Host " ######### #####" -ForegroundColor Cyan
197
+ Write-Host -NoNewline " ## ############## " -ForegroundColor Cyan
198
+ Write-Host "N E O C O R T E X" -ForegroundColor White
199
+ Write-Host -NoNewline " ## ### ###### ## " -ForegroundColor Cyan
200
+ Write-Host "v$VERSION" -ForegroundColor White
201
+ Write-Host " ## ### ### ##" -ForegroundColor Cyan
202
+ Write-Host -NoNewline " ## ###### ### ## " -ForegroundColor Cyan
203
+ Write-Host "OrNexus Team" -ForegroundColor DarkGray
204
+ Write-Host " ############### ##" -ForegroundColor Cyan
205
+ Write-Host " ##### ########" -ForegroundColor Cyan
206
+ Write-Host " ######## ##" -ForegroundColor Cyan
207
+ Write-Host " #######" -ForegroundColor Cyan
208
+ Write-Host ""
209
+ }
210
+
211
+ # =============================================================================
212
+ # FUNCOES DE COPIA (silenciosas)
213
+ # =============================================================================
214
+
215
+ function Copy-Silent {
216
+ param([string]$Source, [string]$Destination)
217
+ Write-Dbg "Copiando: $Source -> $Destination"
218
+ if (Test-Path $Source -PathType Leaf) {
219
+ try {
220
+ # Epic 65: -ErrorAction Stop converts non-terminating errors to terminating
221
+ # Without this, Copy-Item on Windows silently fails and try/catch never triggers
222
+ Copy-Item -Path $Source -Destination $Destination -Force -ErrorAction Stop
223
+ # Post-copy verification: confirm file arrived at destination
224
+ $destFile = if ($Destination.EndsWith('\') -or $Destination.EndsWith('/') -or (Test-Path $Destination -PathType Container)) {
225
+ Join-Path $Destination (Split-Path $Source -Leaf)
226
+ } else { $Destination }
227
+ if (-not (Test-Path $destFile -PathType Leaf)) {
228
+ Write-Dbg "Copy-Item retornou OK mas arquivo nao existe no destino: $destFile"
229
+ $script:Errors++
230
+ return $false
231
+ }
232
+ return $true
233
+ }
234
+ catch {
235
+ Write-Dbg "Copy-Item falhou: $_"
236
+ $script:Errors++
237
+ return $false
238
+ }
239
+ }
240
+ Write-Dbg "Arquivo nao encontrado: $Source"
241
+ $script:Errors++
242
+ return $false
243
+ }
244
+
245
+ function Copy-DirSilent {
246
+ param([string]$Source, [string]$Destination)
247
+ Write-Dbg "Copiando dir: $Source -> $Destination"
248
+ if (Test-Path $Source -PathType Container) {
249
+ try {
250
+ Copy-Item -Path $Source -Destination $Destination -Recurse -Force -ErrorAction Stop
251
+ return $true
252
+ }
253
+ catch {
254
+ Write-Dbg "Copy-Item dir falhou: $_"
255
+ return $false
256
+ }
257
+ }
258
+ return $false
259
+ }
260
+
261
+ # =============================================================================
262
+ # DETECCAO DO DIRETORIO FONTE
263
+ # =============================================================================
264
+
265
+ function Get-SourceDirectory {
266
+ if ($PSScriptRoot) {
267
+ $script:SourceDir = $PSScriptRoot
268
+ } else {
269
+ $script:SourceDir = Get-Location
270
+ }
271
+ Write-Dbg "Source: $script:SourceDir"
272
+
273
+ if (-not (Test-Path "$script:SourceDir\targets-stubs\claude-code\neocortex.md") -and
274
+ -not (Test-Path "$script:SourceDir\targets\claude-code\neocortex.md") -and
275
+ -not (Test-Path "$script:SourceDir\neocortex.md")) {
276
+ Write-Dbg "Stubs nao encontrados em PSScriptRoot, buscando em paths alternativos..."
277
+ $possibleDirs = @(
278
+ $script:SourceDir,
279
+ # Scoped paths (primary) -- npm publishes as @ornexus/neocortex
280
+ "$env:APPDATA\npm\node_modules\@ornexus\neocortex",
281
+ "$env:LOCALAPPDATA\npm-cache\_npx\*\node_modules\@ornexus\neocortex",
282
+ ".\node_modules\@ornexus\neocortex",
283
+ # Unscoped paths (fallback for backward compat)
284
+ "$env:APPDATA\npm\node_modules\neocortex",
285
+ "$env:LOCALAPPDATA\npm-cache\_npx\*\node_modules\neocortex",
286
+ ".\node_modules\neocortex"
287
+ )
288
+ $script:SourceFound = $false
289
+ foreach ($dir in $possibleDirs) {
290
+ # Epic 64 (Story 64.6): Debug each possibleDir tested
291
+ Write-Dbg "Get-SourceDirectory: testing $dir"
292
+ $expandedDirs = Get-Item $dir -ErrorAction SilentlyContinue
293
+ foreach ($expanded in $expandedDirs) {
294
+ $found = (Test-Path "$($expanded.FullName)\targets-stubs\claude-code\neocortex.md") -or
295
+ (Test-Path "$($expanded.FullName)\targets\claude-code\neocortex.md") -or
296
+ (Test-Path "$($expanded.FullName)\neocortex.md")
297
+ Write-Dbg "Get-SourceDirectory: $($expanded.FullName) found=$found"
298
+ if ($found) {
299
+ $script:SourceDir = $expanded.FullName
300
+ $script:SourceFound = $true
301
+ break
302
+ }
303
+ }
304
+ if ($script:SourceFound) { break }
305
+ }
306
+ # Epic 65: Emit visible warning when stubs cannot be found anywhere
307
+ if (-not $script:SourceFound) {
308
+ Write-Warn "Arquivos de instalacao (stubs) nao encontrados em nenhum path conhecido"
309
+ Write-Warn "PSScriptRoot: $PSScriptRoot"
310
+ Write-Warn "Tente reinstalar: npm install -g @ornexus/neocortex"
311
+ }
312
+ }
313
+ }
314
+
315
+ # =============================================================================
316
+ # DETECCAO DE VERSAO ANTIGA
317
+ # =============================================================================
318
+
319
+ function Test-OldInstallation {
320
+ Write-Dbg "Verificando instalacoes antigas..."
321
+ $destDir = "$env:USERPROFILE\.claude\agents\neocortex"
322
+
323
+ $versionFile = "$destDir\.version"
324
+ if (Test-Path $versionFile) {
325
+ $installedVersion = (Get-Content $versionFile -Raw).Trim()
326
+ $pkgJsonPath = Join-Path $script:SourceDir "package.json"
327
+ if (Test-Path $pkgJsonPath) {
328
+ $pkgJson = Get-Content $pkgJsonPath -Raw | ConvertFrom-Json -ErrorAction SilentlyContinue
329
+ if ($pkgJson.version) {
330
+ if ($installedVersion -eq $pkgJson.version) {
331
+ Write-Info "Reinstalando v$($pkgJson.version)"
332
+ } else {
333
+ Write-Info "Atualizando v$installedVersion -> v$($pkgJson.version)"
334
+ }
335
+ }
336
+ }
337
+ }
338
+ }
339
+
340
+ function Test-ProjectMigrationNeeds {
341
+ $sources = @()
342
+ if (Test-Path ".neocortex\orchestrator.db") { $sources += "orchestrator.db" }
343
+ @("bmad-output\sprint-status.yaml", ".neocortex\sprint-status.yaml", "docs\sprint-status.yaml") | ForEach-Object {
344
+ if (Test-Path $_) { $sources += $_ }
345
+ }
346
+ if ($sources.Count -gt 0) { return $sources }
347
+ return $null
348
+ }
349
+
350
+ # =============================================================================
351
+ # LIMPEZA AUTOMATICA DE ARTEFATOS LEGADOS (Invoke-AutoCleanupLegacy)
352
+ # Unifica: Test-LegacyArtifacts + Invoke-CleanupLegacy + Remove-LegacyIP
353
+ # + Remove-LegacyIPProject + npm globals + cross-platform cleanup
354
+ # Roda AUTOMATICAMENTE a cada instalacao - sem necessidade de -CleanupLegacy
355
+ # Idempotente: rodar multiplas vezes sem efeitos colaterais
356
+ # Seguro: NAO remove dados do usuario (stories, epics, state.json, config.json)
357
+ # =============================================================================
358
+
359
+ function Invoke-AutoCleanupLegacy {
360
+ $removed = 0
361
+ $claudeDir = "$env:USERPROFILE\.claude"
362
+ $neocortexDir = "$claudeDir\agents\neocortex"
363
+ $skillsDir = "$claudeDir\skills\neocortex"
364
+
365
+ Write-Dbg "Executando limpeza automatica de artefatos legados..."
366
+
367
+ # --- Helper: remove e loga ---
368
+ function Remove-LegacyItem {
369
+ param([string]$Target, [string]$Label)
370
+ if (Test-Path $Target) {
371
+ $displayItem = $Target -replace [regex]::Escape($env:USERPROFILE), "~"
372
+ try {
373
+ Remove-Item -Path $Target -Recurse -Force -ErrorAction Stop
374
+ Write-Info "Removido: $displayItem ($Label)"
375
+ $script:autoRemoved++
376
+ } catch {
377
+ Write-Dbg "Falha ao remover: $displayItem"
378
+ }
379
+ }
380
+ }
381
+
382
+ $script:autoRemoved = 0
383
+
384
+ # --- Categoria 1: Pacotes NPM globais legados ---
385
+ $npmCmd = Get-Command npm -ErrorAction SilentlyContinue
386
+ if ($npmCmd) {
387
+ foreach ($pkg in @("@ornexus/neocortex-cli", "@ornexus-ai/neocortex")) {
388
+ $npmList = & npm list -g $pkg --depth=0 2>$null
389
+ if ($npmList -match [regex]::Escape($pkg)) {
390
+ try {
391
+ & npm uninstall -g $pkg 2>$null
392
+ if ($LASTEXITCODE -eq 0) {
393
+ Write-Info "Removido: $pkg (pacote npm global legado)"
394
+ $script:autoRemoved++
395
+ }
396
+ } catch {
397
+ Write-Dbg "Falha ao remover pacote npm: $pkg"
398
+ }
399
+ }
400
+ }
401
+
402
+ # Verificar binario neocortex-cli no PATH
403
+ $ncliCmd = Get-Command neocortex-cli -ErrorAction SilentlyContinue
404
+ if ($ncliCmd -and $ncliCmd.Source -match "node_modules|npm") {
405
+ try {
406
+ Remove-Item -Path $ncliCmd.Source -Force -ErrorAction Stop
407
+ Write-Info "Removido: $($ncliCmd.Source) (binario neocortex-cli legado)"
408
+ $script:autoRemoved++
409
+ } catch {
410
+ Write-Dbg "Falha ao remover binario neocortex-cli"
411
+ }
412
+ }
413
+ }
414
+
415
+ # --- Categoria 2: Claude Code (~\.claude\) ---
416
+ # IP proprietaria de versoes anteriores
417
+ Remove-LegacyItem "$neocortexDir\core" "IP legada"
418
+ Remove-LegacyItem $skillsDir "skills legadas"
419
+ Remove-LegacyItem "$neocortexDir\workflow.md" "workflow removido no Tier 3"
420
+ Remove-LegacyItem "$neocortexDir\package.json" "arquivo desnecessario"
421
+ Remove-LegacyItem "$neocortexDir\README.md" "arquivo desnecessario"
422
+
423
+ # Step folders legados
424
+ foreach ($folder in @("steps-c", "steps-e", "steps-p", "steps-r", "steps-u")) {
425
+ Remove-LegacyItem "$neocortexDir\$folder" "steps legados"
426
+ }
427
+
428
+ # Artefatos de instalacoes anteriores
429
+ Remove-LegacyItem "$claudeDir\agents\.git" "repo git antigo"
430
+ Remove-LegacyItem "$claudeDir\.claude" "diretorio aninhado (erro BMAD)"
431
+ Remove-LegacyItem "$claudeDir\agents-ldtn" "diretorio legado"
432
+ Remove-LegacyItem "$claudeDir\.superclaude-metadata.json" "metadata SuperClaude"
433
+
434
+ # Backups SuperClaude antigos
435
+ if (Test-Path "$claudeDir\backups" -PathType Container) {
436
+ Get-ChildItem -Path "$claudeDir\backups" -Filter "superclaude_backup_*.tar.gz" -File -ErrorAction SilentlyContinue | ForEach-Object {
437
+ Remove-LegacyItem $_.FullName "backup SuperClaude antigo"
438
+ }
439
+ }
440
+
441
+ # --- Categoria 3: Cursor ---
442
+ Remove-LegacyItem "$env:USERPROFILE\.cursor\neocortex" "configs Cursor legadas"
443
+ # .cursorrules com referencias neocortex (verificar antes de remover)
444
+ $cursorrules = "$env:USERPROFILE\.cursorrules"
445
+ if (Test-Path $cursorrules -PathType Leaf) {
446
+ $content = Get-Content $cursorrules -Raw -ErrorAction SilentlyContinue
447
+ if ($content -match "(?i)neocortex|ornexus|synapse") {
448
+ Remove-LegacyItem $cursorrules "cursorrules com refs legadas"
449
+ }
450
+ }
451
+
452
+ # --- Categoria 4: VS Code ---
453
+ Remove-LegacyItem "$env:USERPROFILE\.vscode\neocortex" "configs VS Code legadas"
454
+ # .instructions.md com referencias neocortex antigo
455
+ $instructionsMd = "$env:USERPROFILE\.instructions.md"
456
+ if (Test-Path $instructionsMd -PathType Leaf) {
457
+ $content = Get-Content $instructionsMd -Raw -ErrorAction SilentlyContinue
458
+ if ($content -match "(?i)neocortex|ornexus|synapse") {
459
+ Remove-LegacyItem $instructionsMd "instructions.md com refs legadas"
460
+ }
461
+ }
462
+
463
+ # --- Categoria 5: Gemini CLI ---
464
+ Remove-LegacyItem "$env:USERPROFILE\.gemini\neocortex" "configs Gemini legadas"
465
+
466
+ # --- Categoria 6: Codex ---
467
+ Remove-LegacyItem "$env:USERPROFILE\.codex\neocortex" "configs Codex legadas"
468
+
469
+ # --- Categoria 7: Antigravity ---
470
+ # Configs legadas de Antigravity sao gerenciadas pelo adapter, sem path fixo global
471
+
472
+ # --- Categoria 8: Plaintext cache cleanup (Epic 62 - GAP 1) ---
473
+ $cacheDir = "$env:USERPROFILE\.neocortex\cache"
474
+ if (Test-Path $cacheDir -PathType Container) {
475
+ # Remove plaintext menu-cache.json
476
+ Remove-LegacyItem "$cacheDir\menu-cache.json" "cache plaintext (menu)"
477
+
478
+ # Remove any non-.enc files in cache dir (excluding directories)
479
+ Get-ChildItem -Path $cacheDir -File -ErrorAction SilentlyContinue | Where-Object {
480
+ $_.Extension -ne ".enc"
481
+ } | ForEach-Object {
482
+ Remove-LegacyItem $_.FullName "cache plaintext"
483
+ }
484
+ }
485
+
486
+ # --- Resultado ---
487
+ $removed = $script:autoRemoved
488
+ if ($removed -gt 0) {
489
+ Write-Ok "$removed artefato(s) legado(s) removido(s) automaticamente"
490
+ } else {
491
+ Write-Dbg "Nenhum artefato legado encontrado"
492
+ }
493
+
494
+ # Resetar contadores legados (compatibilidade)
495
+ $script:LegacyItems = @()
496
+ $script:LegacyWarnings = 0
497
+ }
498
+
499
+ # Cleanup de IP legada em projetos individuais (project-level)
500
+ function Invoke-AutoCleanupLegacyProject {
501
+ param([string]$ProjectDir)
502
+
503
+ $neocortexDir = "$ProjectDir\.claude\agents\neocortex"
504
+ $skillsDir = "$ProjectDir\.claude\skills\neocortex"
505
+ $cleaned = $false
506
+
507
+ # Remover core/ e seus subdiretorios
508
+ if (Test-Path "$neocortexDir\core") {
509
+ Remove-Item -Path "$neocortexDir\core" -Recurse -Force -ErrorAction SilentlyContinue
510
+ $cleaned = $true
511
+ }
512
+
513
+ # Remover step folders
514
+ foreach ($folder in @("steps-c", "steps-e", "steps-p", "steps-r", "steps-u")) {
515
+ if (Test-Path "$neocortexDir\$folder") {
516
+ Remove-Item -Path "$neocortexDir\$folder" -Recurse -Force -ErrorAction SilentlyContinue
517
+ $cleaned = $true
518
+ }
519
+ }
520
+
521
+ # Remover skills
522
+ if (Test-Path $skillsDir) {
523
+ Remove-Item -Path $skillsDir -Recurse -Force -ErrorAction SilentlyContinue
524
+ $cleaned = $true
525
+ }
526
+
527
+ # Remover arquivos desnecessarios
528
+ foreach ($file in @("package.json", "README.md", "workflow.md")) {
529
+ if (Test-Path "$neocortexDir\$file") {
530
+ Remove-Item -Path "$neocortexDir\$file" -Force -ErrorAction SilentlyContinue
531
+ $cleaned = $true
532
+ }
533
+ }
534
+
535
+ if ($cleaned) {
536
+ Write-Info "IP proprietaria removida do projeto (agora servida via server remoto)"
537
+ }
538
+ }
539
+
540
+ # =============================================================================
541
+ # VERIFICACAO POS-INSTALACAO
542
+ # =============================================================================
543
+
544
+ function Verify-Installation {
545
+ $fails = 0
546
+ $warns = 0
547
+ $report = @()
548
+
549
+ if ($script:SelectedTargets -notcontains "claude-code") {
550
+ return $true
551
+ }
552
+
553
+ # --- Layer 1: File existence + minimum size ---
554
+ $criticalFiles = @(
555
+ @{ Name = "neocortex.md"; MinBytes = 512; Label = "Agent principal (stub)" },
556
+ @{ Name = "neocortex.agent.yaml"; MinBytes = 128; Label = "Agent config YAML (stub)" }
557
+ )
558
+
559
+ foreach ($entry in $criticalFiles) {
560
+ $fpath = Join-Path $script:DestDir $entry.Name
561
+ $fname = $entry.Name
562
+ # Epic 64 (Story 64.6): Debug file verification details
563
+ $fileExists = Test-Path $fpath -PathType Leaf
564
+ $fileSize = if ($fileExists) { (Get-Item $fpath).Length } else { 0 }
565
+ Write-Dbg "Verify-Installation: $fname exists=$fileExists size=$fileSize path=$fpath"
566
+
567
+ if (-not (Test-Path $fpath -PathType Leaf)) {
568
+ $report += @{ Status = "FAIL"; Detail = "$fname (nao encontrado)" }
569
+ $fails++
570
+ } else {
571
+ $fileInfo = Get-Item $fpath
572
+ $size = $fileInfo.Length
573
+
574
+ if ($size -lt $entry.MinBytes) {
575
+ $report += @{ Status = "FAIL"; Detail = "$fname ($size bytes - possivelmente corrompido, minimo $($entry.MinBytes))" }
576
+ $fails++
577
+ } else {
578
+ # --- Layer 2: Content marker (frontmatter) ---
579
+ $ext = [System.IO.Path]::GetExtension($fname)
580
+ if ($ext -eq ".md") {
581
+ $firstLine = (Get-Content $fpath -TotalCount 1 -ErrorAction SilentlyContinue)
582
+ if ($firstLine -ne "---") {
583
+ $report += @{ Status = "WARN"; Detail = "$fname (formato invalido - sem frontmatter)" }
584
+ $warns++
585
+ } else {
586
+ $displaySize = if ($size -ge 1024) { "$([math]::Floor($size / 1024))KB" } else { "${size}B" }
587
+ $report += @{ Status = "OK"; Detail = "$fname ($displaySize)" }
588
+ }
589
+ } else {
590
+ $displaySize = if ($size -ge 1024) { "$([math]::Floor($size / 1024))KB" } else { "${size}B" }
591
+ $report += @{ Status = "OK"; Detail = "$fname ($displaySize)" }
592
+ }
593
+ }
594
+ }
595
+ }
596
+
597
+ if ($LOCAL_MODE) {
598
+ # --- Layer 3: Step directories (local mode only) ---
599
+ foreach ($dir in @("steps-c", "steps-e", "steps-p", "steps-r", "steps-u")) {
600
+ $dirPath = Join-Path $script:DestDir $dir
601
+ if (-not (Test-Path $dirPath -PathType Container)) {
602
+ $report += @{ Status = "FAIL"; Detail = "$dir/ (diretorio nao encontrado)" }
603
+ $fails++
604
+ } else {
605
+ $mdCount = (Get-ChildItem -Path $dirPath -Filter "*.md" -File -ErrorAction SilentlyContinue).Count
606
+ if ($mdCount -eq 0) {
607
+ $report += @{ Status = "WARN"; Detail = "$dir/ (vazio - nenhum arquivo .md)" }
608
+ $warns++
609
+ } else {
610
+ $report += @{ Status = "OK"; Detail = "$dir/ ($mdCount arquivos)" }
611
+ }
612
+ }
613
+ }
614
+
615
+ # --- Layer 3b: Core directory (local mode only) ---
616
+ $corePath = Join-Path $script:DestDir "core"
617
+ if (-not (Test-Path $corePath -PathType Container)) {
618
+ $report += @{ Status = "FAIL"; Detail = "core/ (diretorio nao encontrado)" }
619
+ $fails++
620
+ } else {
621
+ $report += @{ Status = "OK"; Detail = "core/" }
622
+ }
623
+ } else {
624
+ # --- Layer 3: Thin client config (remote mode) ---
625
+ $configFile = "$env:USERPROFILE\.neocortex\config.json"
626
+ if (Test-Path $configFile -PathType Leaf) {
627
+ $report += @{ Status = "OK"; Detail = "~\.neocortex\config.json (thin client configured)" }
628
+ } else {
629
+ $report += @{ Status = "WARN"; Detail = "~\.neocortex\config.json (nao encontrado)" }
630
+ $warns++
631
+ }
632
+
633
+ # Verify NO IP directories exist
634
+ $ipFound = $false
635
+ foreach ($dir in @("core", "steps-c", "steps-e", "steps-p", "steps-r", "steps-u")) {
636
+ if (Test-Path (Join-Path $script:DestDir $dir) -PathType Container) {
637
+ $report += @{ Status = "WARN"; Detail = "$dir/ ainda existe (deveria ter sido removido)" }
638
+ $warns++
639
+ $ipFound = $true
640
+ }
641
+ }
642
+ if (-not $ipFound) {
643
+ $report += @{ Status = "OK"; Detail = "Zero IP no filesystem (modo remoto)" }
644
+ }
645
+ }
646
+
647
+ # --- Layer 4: Tool availability (Story 66.4 AC1/AC2) ---
648
+ $claudeCmd = Get-Command claude -ErrorAction SilentlyContinue
649
+ if (-not $claudeCmd) {
650
+ $claudeCmd = Get-Command claude.exe -ErrorAction SilentlyContinue
651
+ }
652
+ if (-not $claudeCmd) {
653
+ $report += @{ Status = "WARN"; Detail = "Claude Code CLI nao encontrado no PATH" }
654
+ $warns++
655
+ Write-Info "Instale Claude Code: https://claude.ai/download"
656
+ } else {
657
+ $report += @{ Status = "OK"; Detail = "Claude Code CLI encontrado" }
658
+ }
659
+
660
+ $ncCmd = Get-Command neocortex-client -ErrorAction SilentlyContinue
661
+ if (-not $ncCmd) {
662
+ $ncCmd = Get-Command "neocortex-client.cmd" -ErrorAction SilentlyContinue
663
+ }
664
+ if (-not $ncCmd) {
665
+ $report += @{ Status = "WARN"; Detail = "neocortex-client nao encontrado no PATH" }
666
+ $warns++
667
+ Write-Info "Pode ser necessario reabrir o terminal apos npm install -g"
668
+ } else {
669
+ $report += @{ Status = "OK"; Detail = "neocortex-client encontrado" }
670
+ }
671
+
672
+ # --- Display report ---
673
+ if ($fails -eq 0 -and $warns -eq 0) {
674
+ if (-not $QUIET_MODE) {
675
+ Write-Ok "Instalacao verificada"
676
+ }
677
+ return $true
678
+ }
679
+
680
+ # Epic 64 (Story 64.3): In quiet mode, report FAILs before returning
681
+ if ($QUIET_MODE) {
682
+ if ($fails -gt 0) {
683
+ # Critical failures MUST be visible even in quiet mode
684
+ Write-Fail "Verificacao falhou: $fails arquivo(s) critico(s) faltando"
685
+ foreach ($entry in ($report | Where-Object { $_.Status -eq "FAIL" })) {
686
+ Write-Fail " $($entry.Detail)"
687
+ }
688
+ return $false
689
+ }
690
+ return $true # In quiet mode, skip warnings-only report
691
+ }
692
+
693
+ Write-Host ""
694
+ Write-Info "Verificacao pos-instalacao:"
695
+ foreach ($entry in $report) {
696
+ switch ($entry.Status) {
697
+ "OK" { Write-Host " " -NoNewline; Write-Host "[ok]" -ForegroundColor Green -NoNewline; Write-Host " $($entry.Detail)" }
698
+ "WARN" { Write-Host " " -NoNewline; Write-Host "[!]" -ForegroundColor Yellow -NoNewline; Write-Host " $($entry.Detail)" }
699
+ "FAIL" { Write-Host " " -NoNewline; Write-Host "[x]" -ForegroundColor Red -NoNewline; Write-Host " $($entry.Detail)" }
700
+ }
701
+ }
702
+
703
+ if ($fails -gt 0) { return $false }
704
+ return $true
705
+ }
706
+
707
+ # =============================================================================
708
+ # TIER 3: CONFIG DO THIN CLIENT
709
+ # =============================================================================
710
+
711
+ function Set-ThinClientConfig {
712
+ $configDir = "$env:USERPROFILE\.neocortex"
713
+ $configFile = "$configDir\config.json"
714
+
715
+ New-Item -ItemType Directory -Path $configDir -Force -ErrorAction SilentlyContinue | Out-Null
716
+ New-Item -ItemType Directory -Path "$configDir\cache" -Force -ErrorAction SilentlyContinue | Out-Null
717
+
718
+ # Story 66.1 AC5: Apply ACLs on ~/.neocortex/ and cache/
719
+ Set-DirAcl $configDir
720
+ Set-DirAcl "$configDir\cache"
721
+
722
+ if (Test-Path $configFile) {
723
+ try {
724
+ $existingConfig = Get-Content $configFile -Raw | ConvertFrom-Json -ErrorAction SilentlyContinue
725
+ if ($existingConfig.mode -eq "active" -or $existingConfig.mode -eq "local" -or $existingConfig.mode -eq "remote") {
726
+ # --- Config schema migration (Epic 62 - GAP 4) ---
727
+ if (-not $existingConfig.configVersion) {
728
+ Write-Dbg "Migrando schema do config.json (adicionando configVersion)"
729
+ try {
730
+ # Add configVersion
731
+ $existingConfig | Add-Member -NotePropertyName "configVersion" -NotePropertyValue 1 -Force
732
+ # Remove known obsolete fields
733
+ $existingConfig.PSObject.Properties.Remove("version")
734
+ $existingConfig.PSObject.Properties.Remove("cache")
735
+ # Clean obsolete tier:3 from old base template
736
+ if ($existingConfig.tier -eq 3 -and $existingConfig.mode -eq "pending-activation") {
737
+ $existingConfig.PSObject.Properties.Remove("tier")
738
+ }
739
+ Write-Utf8NoBom -Path $configFile -Content ($existingConfig | ConvertTo-Json -Depth 5)
740
+ Write-Dbg "Config migrada para configVersion 1"
741
+ } catch {
742
+ Write-Dbg "Falha na migracao do config: $_"
743
+ }
744
+ }
745
+ # --- Fix stale localhost serverUrl (Epic 70 - Story 70.02) ----
746
+ # If config has localhost serverUrl and installer has production URL,
747
+ # update serverUrl while preserving all other config fields.
748
+ $existingServerUrl = $existingConfig.serverUrl
749
+ if ($existingServerUrl -match '^https?://(localhost|127\.0\.0\.1|0\.0\.0\.0)(:\d+)?') {
750
+ if ($NEOCORTEX_SERVER_URL -ne $existingServerUrl) {
751
+ Write-Dbg "Fixing stale localhost serverUrl: $existingServerUrl -> $NEOCORTEX_SERVER_URL"
752
+ try {
753
+ $existingConfig.serverUrl = $NEOCORTEX_SERVER_URL
754
+ Write-Utf8NoBom -Path $configFile -Content ($existingConfig | ConvertTo-Json -Depth 5)
755
+ Set-FileAcl $configFile
756
+ Write-Dbg "serverUrl updated to $NEOCORTEX_SERVER_URL"
757
+ } catch {
758
+ Write-Dbg "Failed to update serverUrl: $_"
759
+ }
760
+ }
761
+ }
762
+
763
+ # --- Fix stale ornexus.com serverUrl (Epic P46 - Story P46.04) ----
764
+ if ($existingServerUrl -match 'api\.neocortex\.ornexus\.com') {
765
+ Write-Dbg "Fixing old ornexus.com serverUrl: $existingServerUrl -> $NEOCORTEX_SERVER_URL"
766
+ try {
767
+ $existingConfig.serverUrl = $NEOCORTEX_SERVER_URL
768
+ Write-Utf8NoBom -Path $configFile -Content ($existingConfig | ConvertTo-Json -Depth 5)
769
+ Set-FileAcl $configFile
770
+ Write-Dbg "serverUrl updated from ornexus.com to $NEOCORTEX_SERVER_URL"
771
+ } catch {
772
+ Write-Dbg "Failed to update serverUrl: $_"
773
+ }
774
+ }
775
+
776
+ Write-Dbg "Config existente preservada (mode=$($existingConfig.mode))"
777
+ return
778
+ }
779
+ } catch { }
780
+ }
781
+
782
+ $config = @{
783
+ configVersion = 1
784
+ mode = "pending-activation"
785
+ serverUrl = $NEOCORTEX_SERVER_URL
786
+ resilience = @{
787
+ circuitBreaker = $true
788
+ maxRetries = 3
789
+ timeoutMs = 5000
790
+ }
791
+ installedAt = (Get-Date -Format "o")
792
+ installerVersion = $VERSION
793
+ }
794
+
795
+ Write-Utf8NoBom -Path $configFile -Content ($config | ConvertTo-Json -Depth 5)
796
+ # Story 66.1 AC4: Apply ACL on config.json
797
+ Set-FileAcl $configFile
798
+ Write-Dbg "Thin client config criada: $configFile"
799
+ }
800
+
801
+ # Remove-LegacyIPProject substituida por Invoke-AutoCleanupLegacyProject
802
+ # (definida na secao de limpeza automatica acima)
803
+
804
+ # =============================================================================
805
+ # INSTALACAO CORE
806
+ # =============================================================================
807
+
808
+ function Install-Core {
809
+ $script:ClaudeDir = "$env:USERPROFILE\.claude"
810
+ $script:AgentsDir = "$script:ClaudeDir\agents"
811
+ $script:DestDir = "$script:AgentsDir\neocortex"
812
+
813
+ Write-Dbg "DEST=$script:DestDir"
814
+
815
+ # Create directories with verification (Epic 65)
816
+ if (-not (Test-Path $script:ClaudeDir)) {
817
+ try { New-Item -ItemType Directory -Path $script:ClaudeDir -Force -ErrorAction Stop | Out-Null }
818
+ catch { Write-Fail "Falha ao criar $script:ClaudeDir`: $_"; return $false }
819
+ }
820
+ try { New-Item -ItemType Directory -Path $script:AgentsDir -Force -ErrorAction Stop | Out-Null }
821
+ catch { Write-Fail "Falha ao criar $script:AgentsDir`: $_"; return $false }
822
+
823
+ # Clean previous
824
+ if (Test-Path $script:DestDir) {
825
+ try {
826
+ Remove-Item -Path $script:DestDir -Recurse -Force -ErrorAction Stop
827
+ } catch {
828
+ Write-Warn "Falha ao remover instalacao anterior: $_ (tentando continuar)"
829
+ }
830
+ }
831
+ try { New-Item -ItemType Directory -Path $script:DestDir -Force -ErrorAction Stop | Out-Null }
832
+ catch { Write-Fail "Falha ao criar $script:DestDir`: $_"; return $false }
833
+
834
+ # Verify directory was actually created (Epic 65: anti-silent-failure)
835
+ if (-not (Test-Path $script:DestDir -PathType Container)) {
836
+ Write-Fail "Diretorio $script:DestDir nao existe apos criacao"
837
+ return $false
838
+ }
839
+
840
+ if ($LOCAL_MODE) {
841
+ # Modo local: copiar IP completa (comportamento legado para devs)
842
+ $coreSource = Join-Path $script:SourceDir "core"
843
+ if (Test-Path $coreSource -PathType Container) {
844
+ Copy-Item -Path $coreSource -Destination "$script:DestDir\" -Recurse -Force -ErrorAction SilentlyContinue
845
+ }
846
+ $r = Copy-Silent "$($script:SourceDir)\package.json" "$script:DestDir\"
847
+ if (-not $r) { Write-Fail "Falha ao copiar package.json (Install-Core)" }
848
+ $r = Copy-Silent "$($script:SourceDir)\README.md" "$script:DestDir\"
849
+ if (-not $r) { Write-Fail "Falha ao copiar README.md (Install-Core)" }
850
+ } else {
851
+ # Tier 3 Remote Mode: NAO copiar IP
852
+ # Nota: Invoke-AutoCleanupLegacy ja rodou no inicio - aqui apenas config
853
+ Set-ThinClientConfig
854
+ }
855
+
856
+ # --- Version-aware cache purge on upgrade (Epic 62 - GAP 2+3) ---
857
+ $pkgJsonPath = Join-Path $script:SourceDir "package.json"
858
+ $pkgVersion = $null
859
+ if (Test-Path $pkgJsonPath) {
860
+ $pkgJson = Get-Content $pkgJsonPath -Raw | ConvertFrom-Json -ErrorAction SilentlyContinue
861
+ $pkgVersion = $pkgJson.version
862
+ }
863
+
864
+ if ($pkgVersion) {
865
+ $oldVersion = $null
866
+ # Read existing .version from either location
867
+ $versionPaths = @("$script:DestDir\.version", "$env:USERPROFILE\.neocortex\.version")
868
+ foreach ($vp in $versionPaths) {
869
+ if (Test-Path $vp -PathType Leaf) {
870
+ $oldVersion = (Get-Content $vp -Raw -ErrorAction SilentlyContinue).Trim()
871
+ if ($oldVersion) { break }
872
+ }
873
+ }
874
+
875
+ # If version changed, purge all cache files
876
+ if ($oldVersion -and $oldVersion -ne $pkgVersion) {
877
+ $cachePurgeDir = "$env:USERPROFILE\.neocortex\cache"
878
+ if (Test-Path $cachePurgeDir -PathType Container) {
879
+ $purged = 0
880
+ Get-ChildItem -Path $cachePurgeDir -File -ErrorAction SilentlyContinue | ForEach-Object {
881
+ Remove-Item $_.FullName -Force -ErrorAction SilentlyContinue
882
+ $purged++
883
+ }
884
+ if ($purged -gt 0) {
885
+ Write-Info "Cache purgado: versao alterada de $oldVersion para $pkgVersion ($purged arquivo(s))"
886
+ }
887
+ }
888
+ }
889
+
890
+ # Write version file
891
+ Write-Utf8NoBom -Path "$script:DestDir\.version" -Content $pkgVersion
892
+ }
893
+
894
+ if ($LOCAL_MODE) {
895
+ Write-Ok "Core instalado (standards, templates, scripts) [modo local]"
896
+ } else {
897
+ Write-Ok "Remote mode configured (thin client ready)"
898
+ }
899
+ return $true
900
+ }
901
+
902
+ # =============================================================================
903
+ # INSTALACAO DE SKILLS
904
+ # =============================================================================
905
+
906
+ function Install-Skills {
907
+ $script:SkillsDir = "$script:ClaudeDir\skills"
908
+ $script:SkillsDest = "$script:SkillsDir\neocortex"
909
+ $skillsSource = "$script:SourceDir\core\skills"
910
+
911
+ # Tier 3 Remote Mode: skills vem do server, nao copiar
912
+ if (-not $LOCAL_MODE) {
913
+ Write-Ok "Skills: delivered by remote server"
914
+ return $true
915
+ }
916
+
917
+ if (-not (Test-Path $skillsSource -PathType Container)) { return $true }
918
+
919
+ New-Item -ItemType Directory -Path $script:SkillsDir -Force | Out-Null
920
+
921
+ if (Test-Path $script:SkillsDest) {
922
+ Remove-Item -Path $script:SkillsDest -Recurse -Force -ErrorAction SilentlyContinue
923
+ }
924
+
925
+ try {
926
+ Copy-Item -Path $skillsSource -Destination $script:SkillsDest -Recurse -Force
927
+
928
+ # Count skills
929
+ $skillCount = 0
930
+ Get-ChildItem "$script:SkillsDest\step-skills\*\*.md", "$script:SkillsDest\domain-skills\*\*.md" -File -ErrorAction SilentlyContinue |
931
+ Where-Object { $_.Name -ne "_template.md" } | ForEach-Object { $skillCount++ }
932
+
933
+ Write-Ok "Skills instaladas ($skillCount skills) [modo local]"
934
+ return $true
935
+ } catch {
936
+ Write-Fail "Falha ao copiar skills"
937
+ return $false
938
+ }
939
+ }
940
+
941
+ # =============================================================================
942
+ # INSTALACAO DE AGENT (Claude Code)
943
+ # =============================================================================
944
+
945
+ function Install-Agent {
946
+ $claudeTargetDir = Join-Path $script:SourceDir "targets\claude-code"
947
+ if (-not (Test-Path $claudeTargetDir)) {
948
+ $claudeTargetDir = Join-Path $script:SourceDir "targets-stubs\claude-code"
949
+ }
950
+ if (-not (Test-Path $claudeTargetDir)) {
951
+ $claudeTargetDir = $script:SourceDir
952
+ }
953
+
954
+ # Epic 64 (Story 64.6): Debug diagnostics for Install-Agent
955
+ Write-Dbg "Install-Agent: SourceDir=$($script:SourceDir)"
956
+ Write-Dbg "Install-Agent: DestDir=$($script:DestDir)"
957
+ Write-Dbg "Install-Agent: claudeTargetDir=$claudeTargetDir"
958
+ $srcMdExists = Test-Path "$claudeTargetDir\neocortex.md"
959
+ $srcYamlExists = Test-Path "$claudeTargetDir\neocortex.agent.yaml"
960
+ Write-Dbg "Install-Agent: neocortex.md exists=$srcMdExists"
961
+ Write-Dbg "Install-Agent: neocortex.agent.yaml exists=$srcYamlExists"
962
+
963
+ # Epic 65: Early validation -- if NEITHER source file exists, emit clear error
964
+ if (-not $srcMdExists -and -not $srcYamlExists) {
965
+ Write-Fail "Arquivos fonte nao encontrados em: $claudeTargetDir"
966
+ Write-Fail "Diretorio de origem ($($script:SourceDir)) pode estar incompleto"
967
+ Write-Fail "Tente reinstalar: npm install -g @ornexus/neocortex"
968
+ $script:Errors += 2
969
+ return $false
970
+ }
971
+
972
+ # Tier 3: Copy only 2 stub files
973
+ # Epic 64 (Story 64.2): Capture Copy-Silent return and check for errors
974
+ $stubResult1 = Copy-Silent "$claudeTargetDir\neocortex.md" "$script:DestDir\"
975
+ if (-not $stubResult1) { Write-Fail "Falha ao copiar neocortex.md de $claudeTargetDir" }
976
+ Write-Dbg "Install-Agent: Copy neocortex.md result=$stubResult1"
977
+ $stubResult2 = Copy-Silent "$claudeTargetDir\neocortex.agent.yaml" "$script:DestDir\"
978
+ if (-not $stubResult2) { Write-Fail "Falha ao copiar neocortex.agent.yaml de $claudeTargetDir" }
979
+ Write-Dbg "Install-Agent: Copy neocortex.agent.yaml result=$stubResult2"
980
+
981
+ # Epic 65: Post-copy verification -- belt and suspenders
982
+ $destMd = Join-Path $script:DestDir "neocortex.md"
983
+ $destYaml = Join-Path $script:DestDir "neocortex.agent.yaml"
984
+ if (-not (Test-Path $destMd -PathType Leaf)) {
985
+ Write-Fail "neocortex.md nao encontrado no destino apos copia: $destMd"
986
+ if (-not $stubResult1) {} else { $script:Errors++ }
987
+ }
988
+ if (-not (Test-Path $destYaml -PathType Leaf)) {
989
+ Write-Fail "neocortex.agent.yaml nao encontrado no destino apos copia: $destYaml"
990
+ if (-not $stubResult2) {} else { $script:Errors++ }
991
+ }
992
+
993
+ # Cleanup workflow.md from previous versions
994
+ if (Test-Path "$script:DestDir\workflow.md") {
995
+ Remove-Item "$script:DestDir\workflow.md" -Force -ErrorAction SilentlyContinue
996
+ }
997
+
998
+ if ($LOCAL_MODE) {
999
+ # Modo local: copiar IP completa (comportamento legado para devs)
1000
+ $r = Copy-Silent "$($script:SourceDir)\package.json" "$script:DestDir\"
1001
+ if (-not $r) { Write-Fail "Falha ao copiar package.json" }
1002
+ $r = Copy-Silent "$($script:SourceDir)\README.md" "$script:DestDir\"
1003
+ if (-not $r) { Write-Fail "Falha ao copiar README.md" }
1004
+
1005
+ $coreSource = Join-Path $script:SourceDir "core"
1006
+ if (Test-Path $coreSource -PathType Container) {
1007
+ Copy-Item -Path $coreSource -Destination "$script:DestDir\" -Recurse -Force -ErrorAction SilentlyContinue
1008
+ }
1009
+
1010
+ foreach ($folder in @("steps-c", "steps-e", "steps-p", "steps-r", "steps-u")) {
1011
+ $stepSrc = "$($script:SourceDir)\core\steps\$folder"
1012
+ if (Test-Path $stepSrc -PathType Container) {
1013
+ Copy-Item -Path $stepSrc -Destination "$script:DestDir\" -Recurse -Force -ErrorAction SilentlyContinue
1014
+ }
1015
+ }
1016
+ }
1017
+ # Tier 3 Remote Mode: apenas 2 arquivos de interface (stubs)
1018
+
1019
+ return ($script:Errors -eq 0)
1020
+ }
1021
+
1022
+ # =============================================================================
1023
+ # CARREGAMENTO DE .ENV
1024
+ # =============================================================================
1025
+
1026
+ function Import-EnvFile {
1027
+ $envFile = $null
1028
+ @(".\.env", "$script:SourceDir\.env") | ForEach-Object {
1029
+ if ((Test-Path $_ -PathType Leaf) -and -not $envFile) { $envFile = $_ }
1030
+ }
1031
+ if (-not $envFile) { return $false }
1032
+
1033
+ $loaded = 0
1034
+ Get-Content $envFile | ForEach-Object {
1035
+ $line = $_.Trim()
1036
+ if (-not $line -or $line.StartsWith("#")) { return }
1037
+ if ($line -match "^([^=]+)=(.*)$") {
1038
+ $key = $matches[1].Trim()
1039
+ $value = $matches[2].Trim() -replace '^["'']|["'']$', ''
1040
+ if ($value -and -not [Environment]::GetEnvironmentVariable($key)) {
1041
+ [Environment]::SetEnvironmentVariable($key, $value, "Process")
1042
+ Set-Item -Path "env:$key" -Value $value -ErrorAction SilentlyContinue
1043
+ $loaded++
1044
+ }
1045
+ }
1046
+ }
1047
+ if ($loaded -gt 0) { Write-Info "$loaded variavel(eis) carregada(s) do .env" }
1048
+ return $true
1049
+ }
1050
+
1051
+ # =============================================================================
1052
+ # CONFIGURACAO DE TOKENS
1053
+ # =============================================================================
1054
+
1055
+ function Request-Tokens {
1056
+ if ($QUIET_MODE -or $AUTO_YES -or $env:CONTEXT7_API_KEY) { return }
1057
+
1058
+ Write-Host ""
1059
+ Write-Info "MCP Context7 nao configurado (opcional)"
1060
+ Write-Host " Configurar agora? [s/N]: " -NoNewline -ForegroundColor White
1061
+ $response = Read-HostWithTimeout -TimeoutSeconds 15 -Default "n"
1062
+
1063
+ if ($response -match "^[sS]([iI][mM]?)?$|^[yY]([eE][sS]?)?$") {
1064
+ Write-Host ""
1065
+ Write-Info "Obtenha sua API Key em: https://context7.com"
1066
+ Write-Host " Cole sua CONTEXT7_API_KEY: " -NoNewline -ForegroundColor White
1067
+ try {
1068
+ $apiKey = Read-Host
1069
+ if ($apiKey -match "^ctx7sk-") {
1070
+ $env:CONTEXT7_API_KEY = $apiKey
1071
+ Write-Ok "CONTEXT7_API_KEY configurada"
1072
+ Write-Info "Para persistir: `$env:CONTEXT7_API_KEY = `"$apiKey`" em `$PROFILE"
1073
+ } elseif ($apiKey) {
1074
+ Write-Warn "Formato invalido (esperado: ctx7sk-...)"
1075
+ }
1076
+ } catch {}
1077
+ }
1078
+ }
1079
+
1080
+ # =============================================================================
1081
+ # INSTALACAO DE MCP SERVERS
1082
+ # =============================================================================
1083
+
1084
+ function Install-MCPs {
1085
+ $claudeCmd = Get-Command claude -ErrorAction SilentlyContinue
1086
+ if (-not $claudeCmd) {
1087
+ Write-Info "Claude CLI nao encontrado (MCPs serao instalados depois)"
1088
+ return
1089
+ }
1090
+
1091
+ $existingMcps = ""
1092
+ try { $existingMcps = & claude mcp list 2>$null } catch {}
1093
+
1094
+ $mcpOk = @()
1095
+ $mcpSkip = @()
1096
+
1097
+ # Playwright
1098
+ if ($existingMcps -match "playwright") {
1099
+ $mcpOk += "playwright"
1100
+ } else {
1101
+ try {
1102
+ & claude mcp add playwright npx @playwright/mcp@latest 2>$null
1103
+ if ($LASTEXITCODE -eq 0) { $mcpOk += "playwright" }
1104
+ } catch {}
1105
+ }
1106
+
1107
+ # Context7
1108
+ if ($existingMcps -match "context7") {
1109
+ $mcpOk += "context7"
1110
+ } elseif ($env:CONTEXT7_API_KEY) {
1111
+ try {
1112
+ & claude mcp add --transport http context7 https://mcp.context7.com/mcp --header "CONTEXT7_API_KEY: $env:CONTEXT7_API_KEY" 2>$null
1113
+ if ($LASTEXITCODE -eq 0) { $mcpOk += "context7" }
1114
+ } catch {}
1115
+ } else {
1116
+ $mcpSkip += "context7"
1117
+ }
1118
+
1119
+ if ($mcpOk.Count -gt 0) { Write-Ok "MCPs: $($mcpOk -join ', ')" }
1120
+ if ($mcpSkip.Count -gt 0) { Write-Info "MCPs pendentes: $($mcpSkip -join ', ')" }
1121
+ }
1122
+
1123
+ # =============================================================================
1124
+ # INSTALACAO DO CODERABBIT CLI
1125
+ # =============================================================================
1126
+
1127
+ function Install-CodeRabbit {
1128
+ $coderabbitCmd = Get-Command coderabbit -ErrorAction SilentlyContinue
1129
+ if ($coderabbitCmd) {
1130
+ Write-Ok "CodeRabbit CLI"
1131
+ $script:CodeRabbitInstalled = $true
1132
+ return
1133
+ }
1134
+
1135
+ # Try curl via sh
1136
+ try {
1137
+ $shCmd = Get-Command sh -ErrorAction SilentlyContinue
1138
+ if ($shCmd) {
1139
+ $installScript = Invoke-WebRequest -Uri "https://cli.coderabbit.ai/install.sh" -UseBasicParsing -TimeoutSec 30 -ErrorAction Stop
1140
+ $installScript.Content | & sh 2>$null
1141
+ if ($LASTEXITCODE -eq 0) {
1142
+ Write-Ok "CodeRabbit CLI (instalado)"
1143
+ $script:CodeRabbitInstalled = $true
1144
+ return
1145
+ }
1146
+ }
1147
+ } catch {}
1148
+
1149
+ # Try npm
1150
+ $npmCmd = Get-Command npm -ErrorAction SilentlyContinue
1151
+ if ($npmCmd) {
1152
+ try {
1153
+ & npm install -g coderabbit 2>$null
1154
+ if ($LASTEXITCODE -eq 0) {
1155
+ Write-Ok "CodeRabbit CLI (via npm)"
1156
+ $script:CodeRabbitInstalled = $true
1157
+ return
1158
+ }
1159
+ } catch {}
1160
+ }
1161
+
1162
+ Write-Info "CodeRabbit CLI (instale depois: curl -fsSL https://cli.coderabbit.ai/install.sh | sh)"
1163
+ $script:CodeRabbitInstalled = $false
1164
+ }
1165
+
1166
+ # =============================================================================
1167
+ # MULTI-TARGET SUPPORT
1168
+ # =============================================================================
1169
+
1170
+ $script:ValidTargets = @("claude-code", "cursor", "vscode", "gemini-cli", "codex", "antigravity")
1171
+ $script:SelectedTargets = @()
1172
+ $script:TargetResults = @()
1173
+ $script:TargetCount = 0
1174
+
1175
+ function Install-Targets {
1176
+ param([string[]]$TargetList)
1177
+
1178
+ $homeDir = $env:USERPROFILE
1179
+
1180
+ foreach ($target in $TargetList) {
1181
+ switch ($target) {
1182
+ "claude-code" {
1183
+ $success = Install-Agent
1184
+ if ($success) {
1185
+ $script:TargetResults += "$target`:OK"
1186
+ $script:TargetCount++
1187
+ Write-Ok "claude-code (thin client)"
1188
+ } else {
1189
+ $script:TargetResults += "$target`:FAIL"
1190
+ Write-Fail "claude-code"
1191
+ }
1192
+ }
1193
+ "cursor" {
1194
+ $cursorTargetDir = Join-Path $script:SourceDir "targets\cursor"
1195
+ if (Test-Path $cursorTargetDir -PathType Container) {
1196
+ # Clean previous
1197
+ Remove-Item -Path "$homeDir\.cursor\agents\neocortex.md" -Force -ErrorAction SilentlyContinue
1198
+ Remove-Item -Path "$homeDir\.cursor\mcp.json" -Force -ErrorAction SilentlyContinue
1199
+ if (Test-Path "$homeDir\.cursor\skills") { Remove-Item -Path "$homeDir\.cursor\skills" -Recurse -Force -ErrorAction SilentlyContinue }
1200
+
1201
+ # Agent
1202
+ if (Test-Path "$cursorTargetDir\agent.md") {
1203
+ New-Item -ItemType Directory -Path "$homeDir\.cursor\agents" -Force | Out-Null
1204
+ Copy-Item -Path "$cursorTargetDir\agent.md" -Destination "$homeDir\.cursor\agents\neocortex.md" -Force
1205
+ }
1206
+ # Rules
1207
+ if (Test-Path "$cursorTargetDir\rules" -PathType Container) {
1208
+ New-Item -ItemType Directory -Path "$homeDir\.cursor\rules" -Force | Out-Null
1209
+ Copy-Item -Path "$cursorTargetDir\rules\*.mdc" -Destination "$homeDir\.cursor\rules\" -Force -ErrorAction SilentlyContinue
1210
+ }
1211
+ # Commands
1212
+ if (Test-Path "$cursorTargetDir\commands" -PathType Container) {
1213
+ New-Item -ItemType Directory -Path "$homeDir\.cursor\commands" -Force | Out-Null
1214
+ Copy-Item -Path "$cursorTargetDir\commands\*.md" -Destination "$homeDir\.cursor\commands\" -Force -ErrorAction SilentlyContinue
1215
+ }
1216
+ # MCP config
1217
+ if (Test-Path "$cursorTargetDir\mcp.json") {
1218
+ Copy-Item -Path "$cursorTargetDir\mcp.json" -Destination "$homeDir\.cursor\mcp.json" -Force
1219
+ }
1220
+ # Skills
1221
+ $skillsSource = Join-Path $script:SourceDir "core\skills"
1222
+ if (Test-Path $skillsSource -PathType Container) {
1223
+ New-Item -ItemType Directory -Path "$homeDir\.cursor\skills" -Force | Out-Null
1224
+ Copy-Item -Path "$skillsSource\*" -Destination "$homeDir\.cursor\skills\" -Recurse -Force -ErrorAction SilentlyContinue
1225
+ }
1226
+
1227
+ Write-Ok "cursor"
1228
+ $script:TargetResults += "$target`:OK"
1229
+ $script:TargetCount++
1230
+ } else {
1231
+ Write-Warn "cursor (adapter nao encontrado)"
1232
+ $script:TargetResults += "$target`:SKIP"
1233
+ }
1234
+ }
1235
+ "vscode" {
1236
+ $vscodeTargetDir = Join-Path $script:SourceDir "targets\vscode"
1237
+ if (Test-Path $vscodeTargetDir -PathType Container) {
1238
+ # Clean previous
1239
+ Remove-Item -Path "$homeDir\.github\agents\neocortex.md" -Force -ErrorAction SilentlyContinue
1240
+ Remove-Item -Path "$homeDir\.github\copilot-instructions.md" -Force -ErrorAction SilentlyContinue
1241
+ if (Test-Path "$homeDir\.github\skills") { Remove-Item -Path "$homeDir\.github\skills" -Recurse -Force -ErrorAction SilentlyContinue }
1242
+
1243
+ if (Test-Path "$vscodeTargetDir\agent.md") {
1244
+ New-Item -ItemType Directory -Path "$homeDir\.github\agents" -Force | Out-Null
1245
+ Copy-Item -Path "$vscodeTargetDir\agent.md" -Destination "$homeDir\.github\agents\neocortex.md" -Force
1246
+ }
1247
+ if (Test-Path "$vscodeTargetDir\instructions" -PathType Container) {
1248
+ New-Item -ItemType Directory -Path "$homeDir\.github\instructions" -Force | Out-Null
1249
+ Copy-Item -Path "$vscodeTargetDir\instructions\*.instructions.md" -Destination "$homeDir\.github\instructions\" -Force -ErrorAction SilentlyContinue
1250
+ }
1251
+ if (Test-Path "$vscodeTargetDir\prompts" -PathType Container) {
1252
+ New-Item -ItemType Directory -Path "$homeDir\.github\prompts" -Force | Out-Null
1253
+ Copy-Item -Path "$vscodeTargetDir\prompts\*.prompt.md" -Destination "$homeDir\.github\prompts\" -Force -ErrorAction SilentlyContinue
1254
+ }
1255
+ if (Test-Path "$vscodeTargetDir\mcp.json") {
1256
+ New-Item -ItemType Directory -Path "$homeDir\.vscode" -Force | Out-Null
1257
+ Copy-Item -Path "$vscodeTargetDir\mcp.json" -Destination "$homeDir\.vscode\mcp.json" -Force
1258
+ }
1259
+ if (Test-Path "$vscodeTargetDir\copilot-instructions.md") {
1260
+ Copy-Item -Path "$vscodeTargetDir\copilot-instructions.md" -Destination "$homeDir\.github\copilot-instructions.md" -Force
1261
+ }
1262
+ $skillsSource = Join-Path $script:SourceDir "core\skills"
1263
+ if (Test-Path $skillsSource -PathType Container) {
1264
+ New-Item -ItemType Directory -Path "$homeDir\.github\skills" -Force | Out-Null
1265
+ Copy-Item -Path "$skillsSource\*" -Destination "$homeDir\.github\skills\" -Recurse -Force -ErrorAction SilentlyContinue
1266
+ }
1267
+
1268
+ Write-Ok "vscode"
1269
+ $script:TargetResults += "$target`:OK"
1270
+ $script:TargetCount++
1271
+ } else {
1272
+ Write-Warn "vscode (adapter nao encontrado)"
1273
+ $script:TargetResults += "$target`:SKIP"
1274
+ }
1275
+ }
1276
+ "gemini-cli" {
1277
+ $geminiTargetDir = Join-Path $script:SourceDir "targets\gemini-cli"
1278
+ $geminiHome = if ($env:GEMINI_HOME) { $env:GEMINI_HOME } else { "$homeDir\.gemini" }
1279
+ if (Test-Path $geminiTargetDir -PathType Container) {
1280
+ Remove-Item -Path "$geminiHome\agents\neocortex.md" -Force -ErrorAction SilentlyContinue
1281
+ if (Test-Path "$geminiHome\skills") { Remove-Item -Path "$geminiHome\skills" -Recurse -Force -ErrorAction SilentlyContinue }
1282
+
1283
+ if (Test-Path "$geminiTargetDir\agent.md") {
1284
+ New-Item -ItemType Directory -Path "$geminiHome\agents" -Force | Out-Null
1285
+ Copy-Item -Path "$geminiTargetDir\agent.md" -Destination "$geminiHome\agents\neocortex.md" -Force
1286
+ }
1287
+ if (Test-Path "$geminiTargetDir\gemini.md") {
1288
+ Copy-Item -Path "$geminiTargetDir\gemini.md" -Destination "$homeDir\GEMINI.md" -Force
1289
+ }
1290
+ if (Test-Path "$geminiTargetDir\commands" -PathType Container) {
1291
+ New-Item -ItemType Directory -Path "$geminiHome\commands" -Force | Out-Null
1292
+ Copy-Item -Path "$geminiTargetDir\commands\*.toml" -Destination "$geminiHome\commands\" -Force -ErrorAction SilentlyContinue
1293
+ }
1294
+ if (Test-Path "$geminiTargetDir\settings-mcp.json") {
1295
+ $settingsFile = "$geminiHome\settings.json"
1296
+ if (Test-Path $settingsFile) {
1297
+ try {
1298
+ $existingSettings = Get-Content $settingsFile -Raw | ConvertFrom-Json
1299
+ $mcpFragment = Get-Content "$geminiTargetDir\settings-mcp.json" -Raw | ConvertFrom-Json
1300
+ if ($mcpFragment.mcpServers) {
1301
+ if (-not $existingSettings.mcpServers) {
1302
+ $existingSettings | Add-Member -NotePropertyName "mcpServers" -NotePropertyValue $mcpFragment.mcpServers -Force
1303
+ } else {
1304
+ $mcpFragment.mcpServers.PSObject.Properties | ForEach-Object {
1305
+ $existingSettings.mcpServers | Add-Member -NotePropertyName $_.Name -NotePropertyValue $_.Value -Force
1306
+ }
1307
+ }
1308
+ }
1309
+ Write-Utf8NoBom -Path $settingsFile -Content ($existingSettings | ConvertTo-Json -Depth 10)
1310
+ } catch {
1311
+ Copy-Item -Path "$geminiTargetDir\settings-mcp.json" -Destination "$geminiHome\settings-mcp.json" -Force
1312
+ }
1313
+ } else {
1314
+ Copy-Item -Path "$geminiTargetDir\settings-mcp.json" -Destination $settingsFile -Force
1315
+ }
1316
+ }
1317
+ $skillsSource = Join-Path $script:SourceDir "core\skills"
1318
+ if (Test-Path $skillsSource -PathType Container) {
1319
+ New-Item -ItemType Directory -Path "$geminiHome\skills" -Force | Out-Null
1320
+ Copy-Item -Path "$skillsSource\*" -Destination "$geminiHome\skills\" -Recurse -Force -ErrorAction SilentlyContinue
1321
+ }
1322
+
1323
+ Write-Ok "gemini-cli"
1324
+ $script:TargetResults += "$target`:OK"
1325
+ $script:TargetCount++
1326
+ } else {
1327
+ Write-Warn "gemini-cli (adapter nao encontrado)"
1328
+ $script:TargetResults += "$target`:SKIP"
1329
+ }
1330
+ }
1331
+ "codex" {
1332
+ $codexTargetDir = Join-Path $script:SourceDir "targets\codex"
1333
+ $codexHome = if ($env:CODEX_HOME) { $env:CODEX_HOME } else { "$homeDir\.codex" }
1334
+ if (Test-Path $codexTargetDir -PathType Container) {
1335
+ Remove-Item -Path "$codexHome\AGENTS.md" -Force -ErrorAction SilentlyContinue
1336
+ New-Item -ItemType Directory -Path $codexHome -Force | Out-Null
1337
+
1338
+ if (Test-Path "$codexTargetDir\agents.md") {
1339
+ Copy-Item -Path "$codexTargetDir\agents.md" -Destination "$codexHome\AGENTS.md" -Force
1340
+ }
1341
+ if (Test-Path "$codexTargetDir\config-mcp.toml") {
1342
+ $configFile = "$codexHome\config.toml"
1343
+ if (Test-Path $configFile) {
1344
+ $configContent = Get-Content $configFile -Raw
1345
+ $mcpContent = Get-Content "$codexTargetDir\config-mcp.toml" -Raw
1346
+ if ($configContent -match "# Neocortex MCP Servers") {
1347
+ $lines = Get-Content $configFile
1348
+ $markerIndex = ($lines | Select-String "# Neocortex MCP Servers" | Select-Object -First 1).LineNumber - 1
1349
+ $beforeSection = $lines[0..($markerIndex - 1)] -join "`n"
1350
+ Write-Utf8NoBom -Path $configFile -Content "$($beforeSection.TrimEnd())`n`n# Neocortex MCP Servers`n$mcpContent"
1351
+ } else {
1352
+ $existingContent = [System.IO.File]::ReadAllText($configFile, [System.Text.UTF8Encoding]::new($false))
1353
+ Write-Utf8NoBom -Path $configFile -Content "$existingContent`n# Neocortex MCP Servers`n$mcpContent"
1354
+ }
1355
+ } else {
1356
+ Write-Utf8NoBom -Path $configFile -Content "# Neocortex MCP Servers`n$mcpContent"
1357
+ }
1358
+ }
1359
+
1360
+ Write-Ok "codex"
1361
+ $script:TargetResults += "$target`:OK"
1362
+ $script:TargetCount++
1363
+ } else {
1364
+ Write-Warn "codex (adapter nao encontrado)"
1365
+ $script:TargetResults += "$target`:SKIP"
1366
+ }
1367
+ }
1368
+ "antigravity" {
1369
+ $antiTargetDir = Join-Path $script:SourceDir "targets\antigravity"
1370
+ $geminiHome = if ($env:GEMINI_HOME) { $env:GEMINI_HOME } else { "$homeDir\.gemini" }
1371
+ if (Test-Path $antiTargetDir -PathType Container) {
1372
+ if (Test-Path "$geminiHome\antigravity") { Remove-Item -Path "$geminiHome\antigravity" -Recurse -Force -ErrorAction SilentlyContinue }
1373
+
1374
+ if (Test-Path "$antiTargetDir\skill\SKILL.md") {
1375
+ New-Item -ItemType Directory -Path "$homeDir\.agent\skills\neocortex" -Force | Out-Null
1376
+ Copy-Item -Path "$antiTargetDir\skill\SKILL.md" -Destination "$homeDir\.agent\skills\neocortex\SKILL.md" -Force
1377
+ }
1378
+ if (Test-Path "$antiTargetDir\rules" -PathType Container) {
1379
+ New-Item -ItemType Directory -Path "$homeDir\.agent\rules" -Force | Out-Null
1380
+ Copy-Item -Path "$antiTargetDir\rules\*.md" -Destination "$homeDir\.agent\rules\" -Force -ErrorAction SilentlyContinue
1381
+ }
1382
+ if (Test-Path "$antiTargetDir\workflows" -PathType Container) {
1383
+ New-Item -ItemType Directory -Path "$homeDir\.agent\workflows" -Force | Out-Null
1384
+ Copy-Item -Path "$antiTargetDir\workflows\*.md" -Destination "$homeDir\.agent\workflows\" -Force -ErrorAction SilentlyContinue
1385
+ }
1386
+ if (Test-Path "$antiTargetDir\mcp-config.json") {
1387
+ New-Item -ItemType Directory -Path "$geminiHome\antigravity" -Force | Out-Null
1388
+ Copy-Item -Path "$antiTargetDir\mcp-config.json" -Destination "$geminiHome\antigravity\mcp_config.json" -Force
1389
+ }
1390
+ if (Test-Path "$antiTargetDir\gemini.md") {
1391
+ Copy-Item -Path "$antiTargetDir\gemini.md" -Destination "$homeDir\GEMINI.md" -Force
1392
+ }
1393
+ $skillsSource = Join-Path $script:SourceDir "core\skills"
1394
+ if (Test-Path $skillsSource -PathType Container) {
1395
+ $skillsDest = "$homeDir\.agent\skills\neocortex\skills"
1396
+ New-Item -ItemType Directory -Path $skillsDest -Force | Out-Null
1397
+ Copy-Item -Path "$skillsSource\*" -Destination "$skillsDest\" -Recurse -Force -ErrorAction SilentlyContinue
1398
+ }
1399
+
1400
+ Write-Ok "antigravity"
1401
+ $script:TargetResults += "$target`:OK"
1402
+ $script:TargetCount++
1403
+ } else {
1404
+ Write-Warn "antigravity (adapter nao encontrado)"
1405
+ $script:TargetResults += "$target`:SKIP"
1406
+ }
1407
+ }
1408
+ default {
1409
+ Write-Warn "'$target' nao reconhecido"
1410
+ $script:TargetResults += "$target`:SKIP"
1411
+ }
1412
+ }
1413
+ }
1414
+ }
1415
+
1416
+ # =============================================================================
1417
+ # CRIACAO DE DIRETORIOS DO PROJETO
1418
+ # =============================================================================
1419
+
1420
+ function New-ProjectDirectories {
1421
+ if ($QUIET_MODE -or $SKIP_PROJECT_DIRS) { return }
1422
+
1423
+ $shouldCreate = $false
1424
+
1425
+ if ($CreateProject -or $AUTO_YES) {
1426
+ $shouldCreate = $true
1427
+ } else {
1428
+ Write-Host " Instalar estrutura no projeto atual? [s/N]: " -NoNewline -ForegroundColor White
1429
+ $response = Read-HostWithTimeout -TimeoutSeconds 30 -Default "n"
1430
+ if ($response -match "^[sS]([iI][mM]?)?$|^[yY]([eE][sS]?)?$") { $shouldCreate = $true }
1431
+ }
1432
+
1433
+ if (-not $shouldCreate) { return }
1434
+
1435
+ $projectDir = Get-Location
1436
+
1437
+ # Clean previous
1438
+ @("$projectDir\core", "$projectDir\targets\claude-code", "$projectDir\.cursor\skills",
1439
+ "$projectDir\.github\skills", "$projectDir\.agent\skills\neocortex",
1440
+ "$projectDir\.agents\skills", "$projectDir\.claude\agents\neocortex",
1441
+ "$projectDir\.claude\skills\neocortex") | ForEach-Object {
1442
+ if (Test-Path $_) { Remove-Item -Path $_ -Recurse -Force -ErrorAction SilentlyContinue }
1443
+ }
1444
+ @("$projectDir\.cursor\agents\neocortex.md", "$projectDir\.github\agents\neocortex.md",
1445
+ "$projectDir\.github\copilot-instructions.md", "$projectDir\AGENTS.md",
1446
+ "$projectDir\GEMINI.md") | ForEach-Object {
1447
+ if (Test-Path $_) { Remove-Item -Path $_ -Force -ErrorAction SilentlyContinue }
1448
+ }
1449
+
1450
+ # Create base dirs
1451
+ @("$projectDir\.neocortex\specs", "$projectDir\.neocortex\planning",
1452
+ "$projectDir\docs\stories", "$projectDir\docs\epics", "$projectDir\docs\proposals") | ForEach-Object {
1453
+ New-Item -ItemType Directory -Path $_ -Force | Out-Null
1454
+ }
1455
+
1456
+ # State template
1457
+ $stateTemplate = Join-Path $script:SourceDir "core\data\state-template.json"
1458
+ $stateTarget = "$projectDir\.neocortex\state.json"
1459
+ if (-not (Test-Path $stateTarget) -and (Test-Path $stateTemplate)) {
1460
+ Copy-Item -Path $stateTemplate -Destination $stateTarget -Force
1461
+ }
1462
+
1463
+ # Core (ONLY in local mode)
1464
+ $coreSource = Join-Path $script:SourceDir "core"
1465
+ if ($LOCAL_MODE -and (Test-Path $coreSource -PathType Container)) {
1466
+ New-Item -ItemType Directory -Path "$projectDir\core" -Force | Out-Null
1467
+ Copy-Item -Path "$coreSource\*" -Destination "$projectDir\core\" -Recurse -Force
1468
+ }
1469
+
1470
+ # Target-specific files
1471
+ $targetSummary = @()
1472
+ foreach ($target in $script:SelectedTargets) {
1473
+ switch ($target) {
1474
+ "claude-code" {
1475
+ $claudeTargetDir = Join-Path $script:SourceDir "targets\claude-code"
1476
+ if (Test-Path $claudeTargetDir -PathType Container) {
1477
+ $agentDest = "$projectDir\.claude\agents\neocortex"
1478
+ New-Item -ItemType Directory -Path $agentDest -Force | Out-Null
1479
+
1480
+ # SEMPRE copiar os 3 arquivos de interface
1481
+ # Tier 3: Copy only 2 stub files
1482
+ # Epic 64 (Story 64.2): Capture Copy-Silent return
1483
+ $r = Copy-Silent "$claudeTargetDir\neocortex.md" "$agentDest\"
1484
+ if (-not $r) { Write-Fail "Falha ao copiar neocortex.md (projeto)" }
1485
+ $r = Copy-Silent "$claudeTargetDir\neocortex.agent.yaml" "$agentDest\"
1486
+ if (-not $r) { Write-Fail "Falha ao copiar neocortex.agent.yaml (projeto)" }
1487
+ # Cleanup workflow.md from previous versions
1488
+ if (Test-Path "$agentDest\workflow.md") {
1489
+ Remove-Item "$agentDest\workflow.md" -Force -ErrorAction SilentlyContinue
1490
+ }
1491
+
1492
+ if ($LOCAL_MODE) {
1493
+ # Modo local: copiar IP completa (comportamento legado)
1494
+ $r = Copy-Silent "$($script:SourceDir)\package.json" "$agentDest\"
1495
+ if (-not $r) { Write-Fail "Falha ao copiar package.json (projeto)" }
1496
+ $r = Copy-Silent "$($script:SourceDir)\README.md" "$agentDest\"
1497
+ if (-not $r) { Write-Fail "Falha ao copiar README.md (projeto)" }
1498
+ New-Item -ItemType Directory -Path "$agentDest\core" -Force | Out-Null
1499
+ Copy-Item -Path "$coreSource\*" -Destination "$agentDest\core\" -Recurse -Force -ErrorAction SilentlyContinue
1500
+ foreach ($folder in @("steps-c", "steps-e", "steps-p", "steps-r", "steps-u")) {
1501
+ $stepSrc = "$($script:SourceDir)\core\steps\$folder"
1502
+ if (Test-Path $stepSrc -PathType Container) {
1503
+ New-Item -ItemType Directory -Path "$agentDest\$folder" -Force | Out-Null
1504
+ Copy-Item -Path "$stepSrc\*" -Destination "$agentDest\$folder\" -Recurse -Force -ErrorAction SilentlyContinue
1505
+ }
1506
+ }
1507
+ $skillsSource = Join-Path $script:SourceDir "core\skills"
1508
+ if (Test-Path $skillsSource -PathType Container) {
1509
+ New-Item -ItemType Directory -Path "$projectDir\.claude\skills\neocortex" -Force | Out-Null
1510
+ Copy-Item -Path "$skillsSource\*" -Destination "$projectDir\.claude\skills\neocortex\" -Recurse -Force -ErrorAction SilentlyContinue
1511
+ }
1512
+ } else {
1513
+ # Tier 3 Remote Mode: limpar IP de versoes anteriores no projeto
1514
+ Invoke-AutoCleanupLegacyProject -ProjectDir $projectDir
1515
+ }
1516
+ $targetSummary += "claude-code"
1517
+ }
1518
+ }
1519
+ "cursor" {
1520
+ $cursorTargetDir = Join-Path $script:SourceDir "targets\cursor"
1521
+ if (Test-Path $cursorTargetDir -PathType Container) {
1522
+ if (Test-Path "$cursorTargetDir\agent.md") {
1523
+ New-Item -ItemType Directory -Path "$projectDir\.cursor\agents" -Force | Out-Null
1524
+ Copy-Item -Path "$cursorTargetDir\agent.md" -Destination "$projectDir\.cursor\agents\neocortex.md" -Force
1525
+ }
1526
+ if (Test-Path "$cursorTargetDir\rules" -PathType Container) {
1527
+ New-Item -ItemType Directory -Path "$projectDir\.cursor\rules" -Force | Out-Null
1528
+ Copy-Item -Path "$cursorTargetDir\rules\*.mdc" -Destination "$projectDir\.cursor\rules\" -Force -ErrorAction SilentlyContinue
1529
+ }
1530
+ if (Test-Path "$cursorTargetDir\commands" -PathType Container) {
1531
+ New-Item -ItemType Directory -Path "$projectDir\.cursor\commands" -Force | Out-Null
1532
+ Copy-Item -Path "$cursorTargetDir\commands\*.md" -Destination "$projectDir\.cursor\commands\" -Force -ErrorAction SilentlyContinue
1533
+ }
1534
+ if (Test-Path "$cursorTargetDir\mcp.json") {
1535
+ Copy-Item -Path "$cursorTargetDir\mcp.json" -Destination "$projectDir\.cursor\mcp.json" -Force
1536
+ }
1537
+ $skillsSource = Join-Path $script:SourceDir "core\skills"
1538
+ if (Test-Path $skillsSource -PathType Container) {
1539
+ New-Item -ItemType Directory -Path "$projectDir\.cursor\skills" -Force | Out-Null
1540
+ Copy-Item -Path "$skillsSource\*" -Destination "$projectDir\.cursor\skills\" -Recurse -Force -ErrorAction SilentlyContinue
1541
+ }
1542
+ $targetSummary += "cursor"
1543
+ }
1544
+ }
1545
+ "vscode" {
1546
+ $vscodeTargetDir = Join-Path $script:SourceDir "targets\vscode"
1547
+ if (Test-Path $vscodeTargetDir -PathType Container) {
1548
+ if (Test-Path "$vscodeTargetDir\agent.md") {
1549
+ New-Item -ItemType Directory -Path "$projectDir\.github\agents" -Force | Out-Null
1550
+ Copy-Item -Path "$vscodeTargetDir\agent.md" -Destination "$projectDir\.github\agents\neocortex.md" -Force
1551
+ }
1552
+ if (Test-Path "$vscodeTargetDir\instructions" -PathType Container) {
1553
+ New-Item -ItemType Directory -Path "$projectDir\.github\instructions" -Force | Out-Null
1554
+ Copy-Item -Path "$vscodeTargetDir\instructions\*.instructions.md" -Destination "$projectDir\.github\instructions\" -Force -ErrorAction SilentlyContinue
1555
+ }
1556
+ if (Test-Path "$vscodeTargetDir\prompts" -PathType Container) {
1557
+ New-Item -ItemType Directory -Path "$projectDir\.github\prompts" -Force | Out-Null
1558
+ Copy-Item -Path "$vscodeTargetDir\prompts\*.prompt.md" -Destination "$projectDir\.github\prompts\" -Force -ErrorAction SilentlyContinue
1559
+ }
1560
+ if (Test-Path "$vscodeTargetDir\mcp.json") {
1561
+ New-Item -ItemType Directory -Path "$projectDir\.vscode" -Force | Out-Null
1562
+ Copy-Item -Path "$vscodeTargetDir\mcp.json" -Destination "$projectDir\.vscode\mcp.json" -Force
1563
+ }
1564
+ if (Test-Path "$vscodeTargetDir\copilot-instructions.md") {
1565
+ Copy-Item -Path "$vscodeTargetDir\copilot-instructions.md" -Destination "$projectDir\.github\copilot-instructions.md" -Force
1566
+ }
1567
+ $skillsSource = Join-Path $script:SourceDir "core\skills"
1568
+ if (Test-Path $skillsSource -PathType Container) {
1569
+ New-Item -ItemType Directory -Path "$projectDir\.github\skills" -Force | Out-Null
1570
+ Copy-Item -Path "$skillsSource\*" -Destination "$projectDir\.github\skills\" -Recurse -Force -ErrorAction SilentlyContinue
1571
+ }
1572
+ $targetSummary += "vscode"
1573
+ }
1574
+ }
1575
+ "gemini-cli" {
1576
+ $geminiTargetDir = Join-Path $script:SourceDir "targets\gemini-cli"
1577
+ if (Test-Path $geminiTargetDir -PathType Container) {
1578
+ if (Test-Path "$geminiTargetDir\gemini.md") { Copy-Item -Path "$geminiTargetDir\gemini.md" -Destination "$projectDir\GEMINI.md" -Force }
1579
+ if (Test-Path "$geminiTargetDir\commands" -PathType Container) {
1580
+ New-Item -ItemType Directory -Path "$projectDir\.gemini\commands" -Force | Out-Null
1581
+ Copy-Item -Path "$geminiTargetDir\commands\*.toml" -Destination "$projectDir\.gemini\commands\" -Force -ErrorAction SilentlyContinue
1582
+ }
1583
+ if (Test-Path "$geminiTargetDir\agent.md") {
1584
+ New-Item -ItemType Directory -Path "$projectDir\.gemini\agents" -Force | Out-Null
1585
+ Copy-Item -Path "$geminiTargetDir\agent.md" -Destination "$projectDir\.gemini\agents\neocortex.md" -Force
1586
+ }
1587
+ if (Test-Path "$geminiTargetDir\settings-mcp.json") {
1588
+ Copy-Item -Path "$geminiTargetDir\settings-mcp.json" -Destination "$projectDir\.gemini\settings-mcp.json" -Force
1589
+ }
1590
+ $targetSummary += "gemini-cli"
1591
+ }
1592
+ }
1593
+ "codex" {
1594
+ $codexTargetDir = Join-Path $script:SourceDir "targets\codex"
1595
+ if (Test-Path $codexTargetDir -PathType Container) {
1596
+ if (Test-Path "$codexTargetDir\agents.md") { Copy-Item -Path "$codexTargetDir\agents.md" -Destination "$projectDir\AGENTS.md" -Force }
1597
+ $skillsSource = Join-Path $script:SourceDir "core\skills"
1598
+ if (Test-Path $skillsSource -PathType Container) {
1599
+ New-Item -ItemType Directory -Path "$projectDir\.agents\skills" -Force | Out-Null
1600
+ Copy-Item -Path "$skillsSource\*" -Destination "$projectDir\.agents\skills\" -Recurse -Force -ErrorAction SilentlyContinue
1601
+ }
1602
+ $targetSummary += "codex"
1603
+ }
1604
+ }
1605
+ "antigravity" {
1606
+ $antiTargetDir = Join-Path $script:SourceDir "targets\antigravity"
1607
+ if (Test-Path $antiTargetDir -PathType Container) {
1608
+ if (Test-Path "$antiTargetDir\skill\SKILL.md") {
1609
+ New-Item -ItemType Directory -Path "$projectDir\.agent\skills\neocortex" -Force | Out-Null
1610
+ Copy-Item -Path "$antiTargetDir\skill\SKILL.md" -Destination "$projectDir\.agent\skills\neocortex\SKILL.md" -Force
1611
+ }
1612
+ if (Test-Path "$antiTargetDir\rules" -PathType Container) {
1613
+ New-Item -ItemType Directory -Path "$projectDir\.agent\rules" -Force | Out-Null
1614
+ Copy-Item -Path "$antiTargetDir\rules\*.md" -Destination "$projectDir\.agent\rules\" -Force -ErrorAction SilentlyContinue
1615
+ }
1616
+ if (Test-Path "$antiTargetDir\workflows" -PathType Container) {
1617
+ New-Item -ItemType Directory -Path "$projectDir\.agent\workflows" -Force | Out-Null
1618
+ Copy-Item -Path "$antiTargetDir\workflows\*.md" -Destination "$projectDir\.agent\workflows\" -Force -ErrorAction SilentlyContinue
1619
+ }
1620
+ if (Test-Path "$antiTargetDir\gemini.md") { Copy-Item -Path "$antiTargetDir\gemini.md" -Destination "$projectDir\GEMINI.md" -Force }
1621
+ $skillsSource = Join-Path $script:SourceDir "core\skills"
1622
+ if (Test-Path $skillsSource -PathType Container) {
1623
+ $skillsDest = "$projectDir\.agent\skills\neocortex\skills"
1624
+ New-Item -ItemType Directory -Path $skillsDest -Force | Out-Null
1625
+ Copy-Item -Path "$skillsSource\*" -Destination "$skillsDest\" -Recurse -Force -ErrorAction SilentlyContinue
1626
+ }
1627
+ $targetSummary += "antigravity"
1628
+ }
1629
+ }
1630
+ }
1631
+ }
1632
+
1633
+ Write-Host ""
1634
+ Write-Ok "Estrutura do projeto instalada ($($targetSummary -join ', '))"
1635
+ Write-Host ""
1636
+ Write-Info "Proximo passo: @neocortex *init @docs/epics.md"
1637
+ }
1638
+
1639
+ # =============================================================================
1640
+ # RESULTADO
1641
+ # =============================================================================
1642
+
1643
+ function Show-Result {
1644
+ param([bool]$Success)
1645
+ if ($QUIET_MODE) { return $Success }
1646
+
1647
+ Write-Host ""
1648
+ Write-Host " ----------------------------------------" -ForegroundColor DarkGray
1649
+
1650
+ if ($Success) {
1651
+ Write-Host ""
1652
+
1653
+ # Success logo (brain/cortex shape, text centered vertically)
1654
+ Write-Host " #######" -ForegroundColor Cyan
1655
+ Write-Host " ### ########" -ForegroundColor Cyan
1656
+ Write-Host " ######### #####" -ForegroundColor Cyan
1657
+ Write-Host -NoNewline " ## ############## " -ForegroundColor Cyan
1658
+ Write-Host "N E O C O R T E X" -ForegroundColor White
1659
+ Write-Host -NoNewline " ## ### ###### ## " -ForegroundColor Cyan
1660
+ Write-Host "v$VERSION" -ForegroundColor White
1661
+ Write-Host " ## ### ### ##" -ForegroundColor Cyan
1662
+ Write-Host -NoNewline " ## ###### ### ## " -ForegroundColor Cyan
1663
+ Write-Host "Installation complete!" -ForegroundColor Green
1664
+ Write-Host -NoNewline " ############### ## " -ForegroundColor Cyan
1665
+ Write-Host "OrNexus Team" -ForegroundColor DarkGray
1666
+ Write-Host " ##### ########" -ForegroundColor Cyan
1667
+ Write-Host " ######## ##" -ForegroundColor Cyan
1668
+ Write-Host " #######" -ForegroundColor Cyan
1669
+ Write-Host ""
1670
+
1671
+ # Story 66.4 AC6: Target count
1672
+ $okTargets = ($script:TargetResults | Where-Object { $_ -match ":OK$" }).Count
1673
+ if ($okTargets -gt 0) {
1674
+ Write-Host " $okTargets plataforma(s) instalada(s)" -ForegroundColor DarkGray
1675
+ }
1676
+
1677
+ if ($LOCAL_MODE) {
1678
+ Write-Host " Modo: Local (IP completa copiada)" -ForegroundColor DarkGray
1679
+ Write-Host " Locais:" -ForegroundColor DarkGray
1680
+ Write-Host " Agente: ~\.claude\agents\neocortex\" -ForegroundColor DarkGray
1681
+ Write-Host " Skills: ~\.claude\skills\neocortex\" -ForegroundColor DarkGray
1682
+ } else {
1683
+ Write-Host " Mode: Remote (thin client)" -ForegroundColor DarkGray
1684
+ Write-Host " Status: Ready to activate" -ForegroundColor DarkGray
1685
+ Write-Host ""
1686
+ Write-Host " Activate your license:" -ForegroundColor DarkGray
1687
+ Write-Host " neocortex activate YOUR-LICENSE-KEY" -ForegroundColor Cyan
1688
+ Write-Host ""
1689
+ Write-Host " Get your key at: https://neocortex.ornexus.com/login" -ForegroundColor DarkGray
1690
+ Write-Host ""
1691
+ Write-Host " After activation:" -ForegroundColor DarkGray
1692
+ Write-Host " @neocortex *menu" -ForegroundColor Cyan
1693
+ }
1694
+ Write-Host ""
1695
+ Write-Host " Proximo passo:" -ForegroundColor DarkGray
1696
+ Write-Host " @neocortex *init @docs/epics.md" -ForegroundColor Cyan
1697
+ Write-Host ""
1698
+ return $true
1699
+ } else {
1700
+ Write-Host ""
1701
+ Write-Host " Instalacao com problemas" -ForegroundColor Red
1702
+ Write-Host ""
1703
+ # Story 66.4 AC5: Windows troubleshooting
1704
+ Write-Host " Execute novamente com " -NoNewline
1705
+ Write-Host "-Debug" -ForegroundColor White -NoNewline
1706
+ Write-Host " para detalhes:"
1707
+ Write-Host " npx @ornexus/neocortex -Debug" -ForegroundColor Yellow
1708
+ Write-Host ""
1709
+ return $false
1710
+ }
1711
+ }
1712
+
1713
+ # =============================================================================
1714
+ # MAIN
1715
+ # =============================================================================
1716
+
1717
+ Show-Banner
1718
+ Get-SourceDirectory
1719
+ Test-OldInstallation
1720
+
1721
+ # Determine targets
1722
+ if ($Targets) {
1723
+ $script:SelectedTargets = $Targets -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ }
1724
+ $invalid = $script:SelectedTargets | Where-Object { $_ -notin $script:ValidTargets }
1725
+ if ($invalid) {
1726
+ Write-Fail "Plataformas invalidas: $($invalid -join ', ')"
1727
+ Write-Host " Validas: $($script:ValidTargets -join ', ')"
1728
+ exit 1
1729
+ }
1730
+ } elseif ($Yes) {
1731
+ $script:SelectedTargets = @("claude-code")
1732
+ } else {
1733
+ $script:SelectedTargets = @("claude-code")
1734
+ }
1735
+
1736
+ Write-Dbg "Targets: $($script:SelectedTargets -join ', ')"
1737
+
1738
+ $totalSteps = 4
1739
+ if ($script:SelectedTargets -contains "claude-code") { $totalSteps = 6 }
1740
+
1741
+ # Step 1: Limpeza automatica de versoes anteriores
1742
+ Write-Step 1 $totalSteps "Limpeza de versoes anteriores"
1743
+ Invoke-AutoCleanupLegacy
1744
+
1745
+ # Step 2: Core
1746
+ Write-Step 2 $totalSteps "Instalando core"
1747
+ $coreSuccess = Install-Core
1748
+
1749
+ if (-not $coreSuccess) {
1750
+ Write-Fail "Falha na instalacao do core"
1751
+ exit 1
1752
+ }
1753
+
1754
+ # Step 3: Skills
1755
+ Write-Step 3 $totalSteps "Instalando skills"
1756
+ Install-Skills | Out-Null
1757
+
1758
+ # Step 4: Targets
1759
+ Write-Step 4 $totalSteps "Instalando $($script:SelectedTargets.Count) plataforma(s)"
1760
+ Install-Targets -TargetList $script:SelectedTargets
1761
+
1762
+ # Step 5-6: Claude Code extras
1763
+ if ($script:SelectedTargets -contains "claude-code") {
1764
+ Import-EnvFile | Out-Null
1765
+ Request-Tokens
1766
+
1767
+ Write-Step 5 $totalSteps "Configurando MCPs"
1768
+ Install-MCPs
1769
+
1770
+ Write-Step 6 $totalSteps "Verificando ferramentas"
1771
+ Install-CodeRabbit
1772
+ }
1773
+
1774
+ $installSuccess = ($script:TargetResults | Where-Object { $_ -match ":FAIL$" }).Count -eq 0
1775
+ $verifySuccess = Verify-Installation
1776
+ $installSuccess = $installSuccess -and $verifySuccess
1777
+
1778
+ if (Show-Result $installSuccess) {
1779
+ $projectSources = Test-ProjectMigrationNeeds
1780
+ if ($projectSources) {
1781
+ Write-Warn "Migracao detectada"
1782
+ Write-Info "Execute: @neocortex *init @docs/epics.md para migrar"
1783
+ }
1784
+ New-ProjectDirectories
1785
+ Write-Host " Desenvolvido por OrNexus Team" -ForegroundColor DarkGray
1786
+ Write-Host ""
1787
+ exit 0
1788
+ } else {
1789
+ exit 1
1790
+ }