@ornexus/neocortex 4.60.43 → 4.60.45

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.
Files changed (37) hide show
  1. package/dist/sbom.cdx.json +23 -23
  2. package/install.js +16 -1
  3. package/install.ps1 +57 -401
  4. package/install.sh +30 -37
  5. package/package.json +2 -2
  6. package/packages/client/dist/commands/invoke.js +39 -39
  7. package/packages/client/dist/errors/error-messages.js +2 -2
  8. package/packages/client/dist/evidence/collector.d.ts +2 -0
  9. package/packages/client/dist/evidence/collector.js +1 -1
  10. package/packages/client/dist/license/license-client.d.ts +11 -0
  11. package/packages/client/dist/license/license-client.js +1 -1
  12. package/packages/client/dist/runner/headless/run-yoloop.d.ts +9 -0
  13. package/packages/client/dist/runner/headless/run-yoloop.js +5 -3
  14. package/packages/client/dist/yoloop/index.d.ts +1 -1
  15. package/packages/client/dist/yoloop/invoke-hooks.js +10 -8
  16. package/packages/client/dist/yoloop/shared-yoloop-types.d.ts +61 -0
  17. package/packages/client/dist/yoloop/yoloop-client-state-store.d.ts +23 -0
  18. package/packages/client/dist/yoloop/yoloop-client-state-store.js +1 -1
  19. package/packages/shared/dist/invocation/index.js +9 -2
  20. package/targets-stubs/antigravity/gemini.md +1 -1
  21. package/targets-stubs/antigravity/install-antigravity.sh +10 -101
  22. package/targets-stubs/antigravity/skill/SKILL.md +1 -1
  23. package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
  24. package/targets-stubs/claude-code/neocortex-root.md +2 -2
  25. package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
  26. package/targets-stubs/claude-code/neocortex.md +2 -2
  27. package/targets-stubs/codex/AGENTS.md +1 -1
  28. package/targets-stubs/codex/install-codex.sh +4 -1
  29. package/targets-stubs/cursor/agent.md +2 -2
  30. package/targets-stubs/cursor/install-cursor.sh +4 -1
  31. package/targets-stubs/gemini-cli/agent.md +2 -2
  32. package/targets-stubs/gemini-cli/install-gemini.sh +4 -1
  33. package/targets-stubs/grok/install-grok.sh +4 -1
  34. package/targets-stubs/lib/mcp-merge.js +220 -20
  35. package/targets-stubs/opencode/neocortex-root.md +1 -1
  36. package/targets-stubs/vscode/install-vscode.sh +4 -1
  37. package/targets-stubs/vscode/neocortex.agent.md +2 -2
package/install.ps1 CHANGED
@@ -17,7 +17,7 @@ param(
17
17
  [string]$ServerUrl = ('https://{0}.{1}.{2}' -f 'api','neocortex','sh')
18
18
  )
19
19
 
20
- $VERSION = "4.60.43"
20
+ $VERSION = "4.60.45"
21
21
 
22
22
  # =============================================================================
23
23
  # CONFIGURACOES
@@ -35,8 +35,6 @@ $DEBUG_MODE = $Debug
35
35
  $SKIP_PROJECT_DIRS = $SkipProject
36
36
  $QUIET_MODE = $Quiet
37
37
  $NO_BANNER = $NoBanner
38
- # LOCAL_MODE removed (Epic 50): thin-client ALWAYS, zero IP on client
39
- $LOCAL_MODE = $false
40
38
  $NEOCORTEX_SERVER_URL = $ServerUrl
41
39
 
42
40
  function Test-Interactive {
@@ -362,59 +360,14 @@ function Set-DirAcl {
362
360
  }
363
361
 
364
362
  # =============================================================================
365
- # MCP JSON CONFIG MERGE HELPER (additive, preserves user-defined servers)
366
- # Fail-open: on error, leaves existing file untouched.
363
+ # MCP CONFIG MERGE HELPER (semantic, additive, preserves user-defined servers)
364
+ # Fail-closed: ambiguity/conflicts leave the existing file untouched.
367
365
  # $RootKey: top-level key containing the servers map.
368
366
  # - "mcpServers" for Cursor and Gemini CLI settings
369
367
  # - "servers" for VS Code
370
- # - "" for Antigravity (flat JSON: keys are server names)
368
+ # - "mcp" for OpenCode
371
369
  # =============================================================================
372
370
 
373
- function Remove-DisabledOptionalMcpServers {
374
- param(
375
- [object]$Config,
376
- [string]$RootKey = "mcpServers"
377
- )
378
-
379
- $optionalServers = @{
380
- "storybook" = $env:NEOCORTEX_ENABLE_STORYBOOK_MCP
381
- }
382
-
383
- $container = $Config
384
- if ($RootKey -ne "") {
385
- $container = $Config.$RootKey
386
- }
387
- if (-not $container) { return $Config }
388
-
389
- foreach ($name in $optionalServers.Keys) {
390
- if ($optionalServers[$name] -ne "1" -and ($container.PSObject.Properties.Name -contains $name)) {
391
- $container.PSObject.Properties.Remove($name)
392
- }
393
- }
394
-
395
- return $Config
396
- }
397
-
398
- function Select-EnabledMcpToml {
399
- param([string]$Content)
400
-
401
- $enabled = @{
402
- "storybook" = $env:NEOCORTEX_ENABLE_STORYBOOK_MCP
403
- }
404
- $out = New-Object System.Collections.Generic.List[string]
405
- $include = $true
406
-
407
- foreach ($line in ($Content -split "`r?`n")) {
408
- if ($line -match '^\[mcp_servers\.([^\]]+)\]$') {
409
- $name = $Matches[1]
410
- $include = -not $enabled.ContainsKey($name) -or $enabled[$name] -eq "1"
411
- }
412
- if ($include) { $out.Add($line) }
413
- }
414
-
415
- return (($out -join "`n").TrimEnd() + "`n")
416
- }
417
-
418
371
  function Merge-JsonMcpConfig {
419
372
  param(
420
373
  [string]$StubFile,
@@ -424,83 +377,14 @@ function Merge-JsonMcpConfig {
424
377
  )
425
378
 
426
379
  if (-not (Test-Path $StubFile)) { return }
427
-
428
- if (-not (Test-Path $DestFile)) {
429
- $destDir = Split-Path -Parent $DestFile
430
- if ($destDir -and -not (Test-Path $destDir)) {
431
- New-Item -ItemType Directory -Path $destDir -Force -ErrorAction SilentlyContinue | Out-Null
432
- Set-DirAcl -Path $destDir
433
- }
434
- try {
435
- $stub = Get-Content $StubFile -Raw -ErrorAction Stop | ConvertFrom-Json
436
- $stub = Remove-DisabledOptionalMcpServers -Config $stub -RootKey $RootKey
437
- Write-Utf8NoBom -Path $DestFile -Content ($stub | ConvertTo-Json -Depth 20)
438
- } catch { }
439
- return
440
- }
441
-
442
- try {
443
- $existing = Get-Content $DestFile -Raw -ErrorAction Stop | ConvertFrom-Json
444
- $stub = Get-Content $StubFile -Raw -ErrorAction Stop | ConvertFrom-Json
445
- $stub = Remove-DisabledOptionalMcpServers -Config $stub -RootKey $RootKey
446
-
447
- if ($RootKey -eq "") {
448
- # Flat JSON: iterate over stub top-level properties
449
- foreach ($prop in $stub.PSObject.Properties) {
450
- if ($existing.PSObject.Properties.Name -contains $prop.Name) {
451
- $existing.$($prop.Name) = $prop.Value
452
- } else {
453
- $existing | Add-Member -NotePropertyName $prop.Name -NotePropertyValue $prop.Value -Force
454
- }
455
- }
456
- } else {
457
- if (-not $stub.$RootKey) { return }
458
- if (-not $existing.$RootKey) {
459
- $existing | Add-Member -NotePropertyName $RootKey -NotePropertyValue ([pscustomobject]@{}) -Force
460
- }
461
-
462
- $antigravityMigrated = $false
463
- foreach ($managedName in $ManagedTopLevelNames) {
464
- if ($existing.PSObject.Properties.Name -contains $managedName) {
465
- $value = $existing.$managedName
466
- if ($value -and ($value.PSObject.Properties.Name -contains "httpUrl") -and -not ($value.PSObject.Properties.Name -contains "serverUrl")) {
467
- $value | Add-Member -NotePropertyName "serverUrl" -NotePropertyValue $value.httpUrl -Force
468
- $value.PSObject.Properties.Remove("httpUrl")
469
- }
470
- $existing.$RootKey | Add-Member -NotePropertyName $managedName -NotePropertyValue $value -Force
471
- $existing.PSObject.Properties.Remove($managedName)
472
- $antigravityMigrated = $true
473
- }
474
- }
475
-
476
- foreach ($prop in $stub.$RootKey.PSObject.Properties) {
477
- if ($existing.$RootKey.PSObject.Properties.Name -contains $prop.Name) {
478
- $existing.$RootKey.$($prop.Name) = $prop.Value
479
- } else {
480
- $existing.$RootKey | Add-Member -NotePropertyName $prop.Name -NotePropertyValue $prop.Value -Force
481
- }
482
- }
483
-
484
- if ($ManagedTopLevelNames.Count -gt 0) {
485
- if ($antigravityMigrated) {
486
- $stamp = (Get-Date).ToString("yyyyMMddTHHmmss")
487
- $backup = "$DestFile.neocortex-backup-structural-$stamp"
488
- Copy-Item -Path $DestFile -Destination $backup -Force -ErrorAction SilentlyContinue
489
- Write-Info "Antigravity MCP backupCreated=$backup"
490
- }
491
- Write-Info "Antigravity MCP merge: managed entries migrated/updated under mcpServers; custom top-level entries preserved."
492
- }
493
- }
494
-
495
- Write-Utf8NoBom -Path $DestFile -Content ($existing | ConvertTo-Json -Depth 20)
496
- } catch {
497
- try {
498
- $stamp = (Get-Date).ToString("yyyyMMddTHHmmss")
499
- $backup = "$DestFile.neocortex-backup-$stamp"
500
- Copy-Item -Path $DestFile -Destination $backup -Force -ErrorAction Stop
501
- Write-Warn "MCP config invalido: $DestFile; backup criado em $backup; corrija a sintaxe e execute novamente. Original preservado."
502
- } catch { }
503
- }
380
+ $helper = Join-Path $script:SourceDir "targets-stubs\lib\mcp-merge.js"
381
+ $node = Get-Command node -ErrorAction SilentlyContinue
382
+ if (-not $node -or -not (Test-Path $helper -PathType Leaf)) {
383
+ throw "MCP_MERGE_HELPER_UNAVAILABLE"
384
+ }
385
+ $legacyNames = $ManagedTopLevelNames -join ','
386
+ & $node.Source $helper json $StubFile $DestFile $RootKey WINDOWS $legacyNames
387
+ if ($LASTEXITCODE -ne 0) { throw "MCP_MERGE_BLOCKED_$LASTEXITCODE" }
504
388
  }
505
389
 
506
390
  function Get-VsCodeUserMcpPath {
@@ -524,48 +408,13 @@ function Merge-CodexMcpToml {
524
408
  param([string]$StubFile, [string]$DestFile, [string]$TargetName = "Codex")
525
409
 
526
410
  if (-not (Test-Path $StubFile)) { return }
527
- $managed = @("playwright", "context7", "browser_use", "figma", "shadcn", "chrome-devtools")
528
- $destDir = Split-Path -Parent $DestFile
529
- if ($destDir -and -not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir -Force -ErrorAction SilentlyContinue | Out-Null }
530
- $stub = Get-Content $StubFile -Raw
531
-
532
- $sections = New-Object System.Collections.Generic.List[string]
533
- foreach ($name in $managed) {
534
- $pattern = "(?ms)^\[mcp_servers\." + [regex]::Escape($name) + "\].*?(?=^\[|\z)"
535
- $match = [regex]::Match($stub, $pattern)
536
- if ($match.Success) { $sections.Add($match.Value.Trim()) }
537
- }
538
- $block = ($sections -join "`n`n")
539
-
540
- if (-not (Test-Path $DestFile)) {
541
- Write-Utf8NoBom -Path $DestFile -Content ("# Neocortex MCP Servers`n$block`n")
542
- return
543
- }
544
-
545
- try {
546
- $existing = Get-Content $DestFile -Raw -ErrorAction Stop
547
- foreach ($line in ($existing -split "`r?`n")) {
548
- $trimmed = $line.Trim()
549
- if ($trimmed.StartsWith("[") -and ($trimmed -notmatch '^\[[^\]]+\]$')) { throw "invalid table header: $trimmed" }
550
- $quoteCount = ([regex]::Matches($trimmed, '(?<!\\)"')).Count
551
- if (($quoteCount % 2) -ne 0) { throw "unbalanced quote: $trimmed" }
552
- }
553
-
554
- foreach ($name in $managed) {
555
- $pattern = "(?ms)^\[mcp_servers\." + [regex]::Escape($name) + "\].*?(?=^\[|\z)"
556
- $existing = [regex]::Replace($existing, $pattern, "")
557
- }
558
- $existing = ($existing -replace '(?ms)\n*# Neocortex MCP Servers\s*\z', '').TrimEnd()
559
- $next = "$existing`n`n# Neocortex MCP Servers`n$block`n"
560
- if ($next -ne (Get-Content $DestFile -Raw)) { Write-Utf8NoBom -Path $DestFile -Content $next }
561
- } catch {
562
- try {
563
- $stamp = (Get-Date).ToString("yyyyMMddTHHmmss")
564
- $backup = "$DestFile.neocortex-backup-$stamp"
565
- Copy-Item -Path $DestFile -Destination $backup -Force -ErrorAction Stop
566
- Write-Warn "$TargetName config.toml invalido: $DestFile; backup criado em $backup; corrija a sintaxe e execute novamente. Original preservado."
567
- } catch { }
411
+ $helper = Join-Path $script:SourceDir "targets-stubs\lib\mcp-merge.js"
412
+ $node = Get-Command node -ErrorAction SilentlyContinue
413
+ if (-not $node -or -not (Test-Path $helper -PathType Leaf)) {
414
+ throw "MCP_MERGE_HELPER_UNAVAILABLE"
568
415
  }
416
+ & $node.Source $helper toml $StubFile $DestFile $TargetName
417
+ if ($LASTEXITCODE -ne 0) { throw "MCP_MERGE_BLOCKED_$LASTEXITCODE" }
569
418
  }
570
419
 
571
420
  function Read-HostWithTimeout {
@@ -1004,55 +853,27 @@ function Verify-Installation {
1004
853
  }
1005
854
  }
1006
855
 
1007
- if ($LOCAL_MODE) {
1008
- # --- Layer 3: Step directories (local mode only) ---
1009
- foreach ($dir in @("steps-c", "steps-e", "steps-p", "steps-r", "steps-u")) {
1010
- $dirPath = Join-Path $script:DestDir $dir
1011
- if (-not (Test-Path $dirPath -PathType Container)) {
1012
- $report += @{ Status = "FAIL"; Detail = "$dir/ (diretorio nao encontrado)" }
1013
- $fails++
1014
- } else {
1015
- $mdCount = (Get-ChildItem -Path $dirPath -Filter "*.md" -File -ErrorAction SilentlyContinue).Count
1016
- if ($mdCount -eq 0) {
1017
- $report += @{ Status = "WARN"; Detail = "$dir/ (vazio - nenhum arquivo .md)" }
1018
- $warns++
1019
- } else {
1020
- $report += @{ Status = "OK"; Detail = "$dir/ ($mdCount arquivos)" }
1021
- }
1022
- }
1023
- }
1024
-
1025
- # --- Layer 3b: Core directory (local mode only) ---
1026
- $corePath = Join-Path $script:DestDir "core"
1027
- if (-not (Test-Path $corePath -PathType Container)) {
1028
- $report += @{ Status = "FAIL"; Detail = "core/ (diretorio nao encontrado)" }
1029
- $fails++
1030
- } else {
1031
- $report += @{ Status = "OK"; Detail = "core/" }
1032
- }
856
+ # --- Layer 3: Thin client config (remote mode) ---
857
+ $configFile = "$env:USERPROFILE\.neocortex\config.json"
858
+ if (Test-Path $configFile -PathType Leaf) {
859
+ $report += @{ Status = "OK"; Detail = "~\.neocortex\config.json (thin client configured)" }
1033
860
  } else {
1034
- # --- Layer 3: Thin client config (remote mode) ---
1035
- $configFile = "$env:USERPROFILE\.neocortex\config.json"
1036
- if (Test-Path $configFile -PathType Leaf) {
1037
- $report += @{ Status = "OK"; Detail = "~\.neocortex\config.json (thin client configured)" }
1038
- } else {
1039
- $report += @{ Status = "WARN"; Detail = "~\.neocortex\config.json (nao encontrado)" }
1040
- $warns++
1041
- }
861
+ $report += @{ Status = "WARN"; Detail = "~\.neocortex\config.json (nao encontrado)" }
862
+ $warns++
863
+ }
1042
864
 
1043
- # Verify NO IP directories exist
1044
- $ipFound = $false
1045
- foreach ($dir in @("core", "steps-c", "steps-e", "steps-p", "steps-r", "steps-u")) {
1046
- if (Test-Path (Join-Path $script:DestDir $dir) -PathType Container) {
1047
- $report += @{ Status = "WARN"; Detail = "$dir/ ainda existe (deveria ter sido removido)" }
1048
- $warns++
1049
- $ipFound = $true
1050
- }
1051
- }
1052
- if (-not $ipFound) {
1053
- $report += @{ Status = "OK"; Detail = "Zero IP no filesystem (modo remoto)" }
865
+ # Verify NO IP directories exist
866
+ $ipFound = $false
867
+ foreach ($dir in @("core", "steps-c", "steps-e", "steps-p", "steps-r", "steps-u")) {
868
+ if (Test-Path (Join-Path $script:DestDir $dir) -PathType Container) {
869
+ $report += @{ Status = "WARN"; Detail = "$dir/ ainda existe (deveria ter sido removido)" }
870
+ $warns++
871
+ $ipFound = $true
1054
872
  }
1055
873
  }
874
+ if (-not $ipFound) {
875
+ $report += @{ Status = "OK"; Detail = "Zero IP no filesystem (modo remoto)" }
876
+ }
1056
877
 
1057
878
  # --- Layer 4: Tool availability (Story 66.4 AC1/AC2) ---
1058
879
  $claudeCmd = Get-Command claude -ErrorAction SilentlyContinue
@@ -1261,21 +1082,8 @@ function Install-Core {
1261
1082
  return $false
1262
1083
  }
1263
1084
 
1264
- if ($LOCAL_MODE) {
1265
- # Modo local: copiar IP completa (comportamento legado para devs)
1266
- $coreSource = Join-Path $script:SourceDir "core"
1267
- if (Test-Path $coreSource -PathType Container) {
1268
- Copy-Item -Path $coreSource -Destination "$script:DestDir\" -Recurse -Force -ErrorAction SilentlyContinue
1269
- }
1270
- $r = Copy-Silent "$($script:SourceDir)\package.json" "$script:DestDir\"
1271
- if (-not $r) { Write-Fail "Falha ao copiar package.json (Install-Core)" }
1272
- $r = Copy-Silent "$($script:SourceDir)\README.md" "$script:DestDir\"
1273
- if (-not $r) { Write-Fail "Falha ao copiar README.md (Install-Core)" }
1274
- } else {
1275
- # Tier 3 Remote Mode: NAO copiar IP
1276
- # Nota: Invoke-AutoCleanupLegacy ja rodou no inicio - aqui apenas config
1277
- if (-not (Set-ThinClientConfig)) { return $false }
1278
- }
1085
+ # Thin-client invariant: configure the remote client and never copy core/**.
1086
+ if (-not (Set-ThinClientConfig)) { return $false }
1279
1087
 
1280
1088
  # --- Version-aware cache purge on upgrade (Epic 62 - GAP 2+3) ---
1281
1089
  $pkgJsonPath = Join-Path $script:SourceDir "package.json"
@@ -1315,11 +1123,7 @@ function Install-Core {
1315
1123
  Write-Utf8NoBom -Path "$script:DestDir\.version" -Content $pkgVersion
1316
1124
  }
1317
1125
 
1318
- if ($LOCAL_MODE) {
1319
- Write-Ok "Core instalado (standards, templates, scripts) [modo local]"
1320
- } else {
1321
- Write-Ok "Remote mode configured (thin client ready)"
1322
- }
1126
+ Write-Ok "Remote mode configured (thin client ready)"
1323
1127
  return $true
1324
1128
  }
1325
1129
 
@@ -1328,38 +1132,8 @@ function Install-Core {
1328
1132
  # =============================================================================
1329
1133
 
1330
1134
  function Install-Skills {
1331
- $script:SkillsDir = "$script:ClaudeDir\skills"
1332
- $script:SkillsDest = "$script:SkillsDir\neocortex"
1333
- $skillsSource = "$script:SourceDir\core\skills"
1334
-
1335
- # Tier 3 Remote Mode: skills vem do server, nao copiar
1336
- if (-not $LOCAL_MODE) {
1337
- Write-Ok "Skills: delivered by remote server"
1338
- return $true
1339
- }
1340
-
1341
- if (-not (Test-Path $skillsSource -PathType Container)) { return $true }
1342
-
1343
- New-Item -ItemType Directory -Path $script:SkillsDir -Force | Out-Null
1344
-
1345
- if (Test-Path $script:SkillsDest) {
1346
- Remove-Item -Path $script:SkillsDest -Recurse -Force -ErrorAction SilentlyContinue
1347
- }
1348
-
1349
- try {
1350
- Copy-Item -Path $skillsSource -Destination $script:SkillsDest -Recurse -Force
1351
-
1352
- # Count skills
1353
- $skillCount = 0
1354
- Get-ChildItem "$script:SkillsDest\step-skills\*\*.md", "$script:SkillsDest\domain-skills\*\*.md" -File -ErrorAction SilentlyContinue |
1355
- Where-Object { $_.Name -ne "_template.md" } | ForEach-Object { $skillCount++ }
1356
-
1357
- Write-Ok "Skills instaladas ($skillCount skills) [modo local]"
1358
- return $true
1359
- } catch {
1360
- Write-Fail "Falha ao copiar skills"
1361
- return $false
1362
- }
1135
+ Write-Ok "Skills: delivered by remote server"
1136
+ return $true
1363
1137
  }
1364
1138
 
1365
1139
  # =============================================================================
@@ -1419,27 +1193,6 @@ function Install-Agent {
1419
1193
  Remove-Item "$script:DestDir\workflow.md" -Force -ErrorAction SilentlyContinue
1420
1194
  }
1421
1195
 
1422
- if ($LOCAL_MODE) {
1423
- # Modo local: copiar IP completa (comportamento legado para devs)
1424
- $r = Copy-Silent "$($script:SourceDir)\package.json" "$script:DestDir\"
1425
- if (-not $r) { Write-Fail "Falha ao copiar package.json" }
1426
- $r = Copy-Silent "$($script:SourceDir)\README.md" "$script:DestDir\"
1427
- if (-not $r) { Write-Fail "Falha ao copiar README.md" }
1428
-
1429
- $coreSource = Join-Path $script:SourceDir "core"
1430
- if (Test-Path $coreSource -PathType Container) {
1431
- Copy-Item -Path $coreSource -Destination "$script:DestDir\" -Recurse -Force -ErrorAction SilentlyContinue
1432
- }
1433
-
1434
- foreach ($folder in @("steps-c", "steps-e", "steps-p", "steps-r", "steps-u")) {
1435
- $stepSrc = "$($script:SourceDir)\core\steps\$folder"
1436
- if (Test-Path $stepSrc -PathType Container) {
1437
- Copy-Item -Path $stepSrc -Destination "$script:DestDir\" -Recurse -Force -ErrorAction SilentlyContinue
1438
- }
1439
- }
1440
- }
1441
- # Tier 3 Remote Mode: apenas 2 arquivos de interface (stubs)
1442
-
1443
1196
  return ($script:Errors -eq 0)
1444
1197
  }
1445
1198
 
@@ -1658,13 +1411,6 @@ function Install-Targets {
1658
1411
  if (Test-Path "$cursorTargetDir\mcp.json") {
1659
1412
  Merge-JsonMcpConfig -StubFile "$cursorTargetDir\mcp.json" -DestFile "$homeDir\.cursor\mcp.json" -RootKey "mcpServers"
1660
1413
  }
1661
- # Skills
1662
- $skillsSource = Join-Path $script:SourceDir "core\skills"
1663
- if (Test-Path $skillsSource -PathType Container) {
1664
- New-Item -ItemType Directory -Path "$homeDir\.cursor\skills" -Force | Out-Null
1665
- Copy-Item -Path "$skillsSource\*" -Destination "$homeDir\.cursor\skills\" -Recurse -Force -ErrorAction SilentlyContinue
1666
- }
1667
-
1668
1414
  Write-Ok "cursor"
1669
1415
  $script:TargetResults += "$target`:OK"
1670
1416
  $script:TargetCount++
@@ -1701,12 +1447,6 @@ function Install-Targets {
1701
1447
  if (Test-Path "$vscodeTargetDir\copilot-instructions.md") {
1702
1448
  Copy-ManagedFile -Source "$vscodeTargetDir\copilot-instructions.md" -Destination "$homeDir\.github\copilot-instructions.md" -ManagedId "profile-vscode-copilot-instructions" -BaseDir $homeDir | Out-Null
1703
1449
  }
1704
- $skillsSource = Join-Path $script:SourceDir "core\skills"
1705
- if (Test-Path $skillsSource -PathType Container) {
1706
- New-Item -ItemType Directory -Path "$homeDir\.github\skills" -Force | Out-Null
1707
- Copy-Item -Path "$skillsSource\*" -Destination "$homeDir\.github\skills\" -Recurse -Force -ErrorAction SilentlyContinue
1708
- }
1709
-
1710
1450
  Write-Ok "vscode"
1711
1451
  $script:TargetResults += "$target`:OK"
1712
1452
  $script:TargetCount++
@@ -1739,12 +1479,6 @@ function Install-Targets {
1739
1479
  # Additive merge into ~/.gemini/settings.json (root key is "mcpServers")
1740
1480
  Merge-JsonMcpConfig -StubFile "$geminiTargetDir\settings-mcp.json" -DestFile "$geminiHome\settings.json" -RootKey "mcpServers"
1741
1481
  }
1742
- $skillsSource = Join-Path $script:SourceDir "core\skills"
1743
- if (Test-Path $skillsSource -PathType Container) {
1744
- New-Item -ItemType Directory -Path "$geminiHome\skills" -Force | Out-Null
1745
- Copy-Item -Path "$skillsSource\*" -Destination "$geminiHome\skills\" -Recurse -Force -ErrorAction SilentlyContinue
1746
- }
1747
-
1748
1482
  Write-Ok "gemini"
1749
1483
  $script:TargetResults += "$target`:OK"
1750
1484
  $script:TargetCount++
@@ -1825,13 +1559,6 @@ function Install-Targets {
1825
1559
  if (Test-Path "$antiTargetDir\gemini.md") {
1826
1560
  Copy-ManagedFile -Source "$antiTargetDir\gemini.md" -Destination "$homeDir\GEMINI.md" -ManagedId "profile-antigravity-root" -BaseDir $homeDir | Out-Null
1827
1561
  }
1828
- $skillsSource = Join-Path $script:SourceDir "core\skills"
1829
- if (Test-Path $skillsSource -PathType Container) {
1830
- $skillsDest = "$homeDir\.agent\skills\neocortex\skills"
1831
- New-Item -ItemType Directory -Path $skillsDest -Force | Out-Null
1832
- Copy-Item -Path "$skillsSource\*" -Destination "$skillsDest\" -Recurse -Force -ErrorAction SilentlyContinue
1833
- }
1834
-
1835
1562
  Write-Ok "antigravity"
1836
1563
  $script:TargetResults += "$target`:OK"
1837
1564
  $script:TargetCount++
@@ -1941,20 +1668,6 @@ function New-ProjectDirectories {
1941
1668
  New-Item -ItemType Directory -Path $_ -Force | Out-Null
1942
1669
  }
1943
1670
 
1944
- # State template
1945
- $stateTemplate = Join-Path $script:SourceDir "core\data\state-template.json"
1946
- $stateTarget = "$projectDir\.neocortex\state.json"
1947
- if (-not (Test-Path $stateTarget) -and (Test-Path $stateTemplate)) {
1948
- Copy-Item -Path $stateTemplate -Destination $stateTarget -Force
1949
- }
1950
-
1951
- # Core (ONLY in local mode)
1952
- $coreSource = Join-Path $script:SourceDir "core"
1953
- if ($LOCAL_MODE -and (Test-Path $coreSource -PathType Container)) {
1954
- New-Item -ItemType Directory -Path "$projectDir\core" -Force | Out-Null
1955
- Copy-Item -Path "$coreSource\*" -Destination "$projectDir\core\" -Recurse -Force
1956
- }
1957
-
1958
1671
  # Target-specific files
1959
1672
  $targetSummary = @()
1960
1673
  foreach ($target in $script:SelectedTargets) {
@@ -1977,30 +1690,7 @@ function New-ProjectDirectories {
1977
1690
  Remove-Item "$agentDest\workflow.md" -Force -ErrorAction SilentlyContinue
1978
1691
  }
1979
1692
 
1980
- if ($LOCAL_MODE) {
1981
- # Modo local: copiar IP completa (comportamento legado)
1982
- $r = Copy-Silent "$($script:SourceDir)\package.json" "$agentDest\"
1983
- if (-not $r) { Write-Fail "Falha ao copiar package.json (projeto)" }
1984
- $r = Copy-Silent "$($script:SourceDir)\README.md" "$agentDest\"
1985
- if (-not $r) { Write-Fail "Falha ao copiar README.md (projeto)" }
1986
- New-Item -ItemType Directory -Path "$agentDest\core" -Force | Out-Null
1987
- Copy-Item -Path "$coreSource\*" -Destination "$agentDest\core\" -Recurse -Force -ErrorAction SilentlyContinue
1988
- foreach ($folder in @("steps-c", "steps-e", "steps-p", "steps-r", "steps-u")) {
1989
- $stepSrc = "$($script:SourceDir)\core\steps\$folder"
1990
- if (Test-Path $stepSrc -PathType Container) {
1991
- New-Item -ItemType Directory -Path "$agentDest\$folder" -Force | Out-Null
1992
- Copy-Item -Path "$stepSrc\*" -Destination "$agentDest\$folder\" -Recurse -Force -ErrorAction SilentlyContinue
1993
- }
1994
- }
1995
- $skillsSource = Join-Path $script:SourceDir "core\skills"
1996
- if (Test-Path $skillsSource -PathType Container) {
1997
- New-Item -ItemType Directory -Path "$projectDir\.claude\skills\neocortex" -Force | Out-Null
1998
- Copy-Item -Path "$skillsSource\*" -Destination "$projectDir\.claude\skills\neocortex\" -Recurse -Force -ErrorAction SilentlyContinue
1999
- }
2000
- } else {
2001
- # Tier 3 Remote Mode: limpar IP de versoes anteriores no projeto
2002
- Invoke-AutoCleanupLegacyProject -ProjectDir $projectDir
2003
- }
1693
+ Invoke-AutoCleanupLegacyProject -ProjectDir $projectDir
2004
1694
  $targetSummary += "claude-code"
2005
1695
  }
2006
1696
  }
@@ -2019,15 +1709,6 @@ function New-ProjectDirectories {
2019
1709
  New-Item -ItemType Directory -Path "$projectDir\.cursor\commands" -Force | Out-Null
2020
1710
  Copy-Item -Path "$cursorTargetDir\commands\*.md" -Destination "$projectDir\.cursor\commands\" -Force -ErrorAction SilentlyContinue
2021
1711
  }
2022
- if (Test-Path "$cursorTargetDir\mcp.json") {
2023
- New-Item -ItemType Directory -Path "$projectDir\.cursor" -Force | Out-Null
2024
- Merge-JsonMcpConfig -StubFile "$cursorTargetDir\mcp.json" -DestFile "$projectDir\.cursor\mcp.json" -RootKey "mcpServers"
2025
- }
2026
- $skillsSource = Join-Path $script:SourceDir "core\skills"
2027
- if (Test-Path $skillsSource -PathType Container) {
2028
- New-Item -ItemType Directory -Path "$projectDir\.cursor\skills" -Force | Out-Null
2029
- Copy-Item -Path "$skillsSource\*" -Destination "$projectDir\.cursor\skills\" -Recurse -Force -ErrorAction SilentlyContinue
2030
- }
2031
1712
  $targetSummary += "cursor"
2032
1713
  }
2033
1714
  }
@@ -2048,18 +1729,9 @@ function New-ProjectDirectories {
2048
1729
  New-Item -ItemType Directory -Path "$projectDir\.github\prompts" -Force | Out-Null
2049
1730
  Copy-Item -Path "$vscodeTargetDir\prompts\*.prompt.md" -Destination "$projectDir\.github\prompts\" -Force -ErrorAction SilentlyContinue
2050
1731
  }
2051
- if (Test-Path "$vscodeTargetDir\mcp.json") {
2052
- New-Item -ItemType Directory -Path "$projectDir\.vscode" -Force | Out-Null
2053
- Merge-JsonMcpConfig -StubFile "$vscodeTargetDir\mcp.json" -DestFile "$projectDir\.vscode\mcp.json" -RootKey "servers"
2054
- }
2055
1732
  if (Test-Path "$vscodeTargetDir\copilot-instructions.md") {
2056
1733
  Copy-ManagedFile -Source "$vscodeTargetDir\copilot-instructions.md" -Destination "$projectDir\.github\copilot-instructions.md" -ManagedId "project-vscode-copilot-instructions" -BaseDir $projectDir | Out-Null
2057
1734
  }
2058
- $skillsSource = Join-Path $script:SourceDir "core\skills"
2059
- if (Test-Path $skillsSource -PathType Container) {
2060
- New-Item -ItemType Directory -Path "$projectDir\.github\skills" -Force | Out-Null
2061
- Copy-Item -Path "$skillsSource\*" -Destination "$projectDir\.github\skills\" -Recurse -Force -ErrorAction SilentlyContinue
2062
- }
2063
1735
  $targetSummary += "vscode"
2064
1736
  }
2065
1737
  }
@@ -2078,9 +1750,6 @@ function New-ProjectDirectories {
2078
1750
  New-Item -ItemType Directory -Path "$projectDir\.gemini\agents" -Force | Out-Null
2079
1751
  Copy-ManagedFile -Source "$geminiTargetDir\agent.md" -Destination "$projectDir\.gemini\agents\neocortex.md" -ManagedId "project-gemini-neocortex" -BaseDir $projectDir | Out-Null
2080
1752
  }
2081
- if (Test-Path "$geminiTargetDir\settings-mcp.json") {
2082
- Copy-Item -Path "$geminiTargetDir\settings-mcp.json" -Destination "$projectDir\.gemini\settings-mcp.json" -Force
2083
- }
2084
1753
  $targetSummary += "gemini"
2085
1754
  }
2086
1755
  }
@@ -2092,11 +1761,6 @@ function New-ProjectDirectories {
2092
1761
  New-Item -ItemType Directory -Path "$projectDir\.codex\agents" -Force | Out-Null
2093
1762
  Copy-ManagedFile -Source "$codexTargetDir\neocortex.toml" -Destination "$projectDir\.codex\agents\neocortex.toml" -ManagedId "project-codex-neocortex" -BaseDir $projectDir | Out-Null
2094
1763
  }
2095
- $skillsSource = Join-Path $script:SourceDir "core\skills"
2096
- if (Test-Path $skillsSource -PathType Container) {
2097
- New-Item -ItemType Directory -Path "$projectDir\.agents\skills" -Force | Out-Null
2098
- Copy-Item -Path "$skillsSource\*" -Destination "$projectDir\.agents\skills\" -Recurse -Force -ErrorAction SilentlyContinue
2099
- }
2100
1764
  $targetSummary += "codex"
2101
1765
  }
2102
1766
  }
@@ -2132,12 +1796,6 @@ function New-ProjectDirectories {
2132
1796
  Copy-ManagedFile -Source "$antiTargetDir\gemini.md" -Destination "$projectDir\GEMINI.md" -ManagedId "project-antigravity-root" -BaseDir $projectDir | Out-Null
2133
1797
  Copy-ManagedFile -Source "$antiTargetDir\gemini.md" -Destination "$projectDir\.agents\AGENTS.md" -ManagedId "project-antigravity-agents-root" -BaseDir $projectDir | Out-Null
2134
1798
  }
2135
- $skillsSource = Join-Path $script:SourceDir "core\skills"
2136
- if (Test-Path $skillsSource -PathType Container) {
2137
- $skillsDest = "$projectDir\.agent\skills\neocortex\skills"
2138
- New-Item -ItemType Directory -Path $skillsDest -Force | Out-Null
2139
- Copy-Item -Path "$skillsSource\*" -Destination "$skillsDest\" -Recurse -Force -ErrorAction SilentlyContinue
2140
- }
2141
1799
  $targetSummary += "antigravity"
2142
1800
  }
2143
1801
  }
@@ -2219,23 +1877,16 @@ function Show-Result {
2219
1877
  Write-Host " $okTargets plataforma(s) instalada(s)" -ForegroundColor DarkGray
2220
1878
  }
2221
1879
 
2222
- if ($LOCAL_MODE) {
2223
- Write-Host " Modo: Local (IP completa copiada)" -ForegroundColor DarkGray
2224
- Write-Host " Locais:" -ForegroundColor DarkGray
2225
- Write-Host " Agente: ~\.claude\agents\neocortex\" -ForegroundColor DarkGray
2226
- Write-Host " Skills: ~\.claude\skills\neocortex\" -ForegroundColor DarkGray
2227
- } else {
2228
- Write-Host " Mode: Remote (thin client)" -ForegroundColor DarkGray
2229
- Write-Host " Status: Ready to activate" -ForegroundColor DarkGray
2230
- Write-Host ""
2231
- Write-Host " Activate your license:" -ForegroundColor DarkGray
2232
- Write-Host " neocortex activate YOUR-LICENSE-KEY" -ForegroundColor Cyan
2233
- Write-Host ""
2234
- Write-Host " Get your key at: https://neocortex.sh/portal/login" -ForegroundColor DarkGray
2235
- Write-Host ""
2236
- Write-Host " After activation:" -ForegroundColor DarkGray
2237
- Write-Host " @neocortex *menu" -ForegroundColor Cyan
2238
- }
1880
+ Write-Host " Mode: Remote (thin client)" -ForegroundColor DarkGray
1881
+ Write-Host " Status: Ready to activate" -ForegroundColor DarkGray
1882
+ Write-Host ""
1883
+ Write-Host " Activate your license:" -ForegroundColor DarkGray
1884
+ Write-Host " neocortex activate YOUR-LICENSE-KEY" -ForegroundColor Cyan
1885
+ Write-Host ""
1886
+ Write-Host " Get your key at: https://neocortex.sh/portal/login" -ForegroundColor DarkGray
1887
+ Write-Host ""
1888
+ Write-Host " After activation:" -ForegroundColor DarkGray
1889
+ Write-Host " @neocortex *menu" -ForegroundColor Cyan
2239
1890
  Write-Host ""
2240
1891
  Write-Host " Proximo passo:" -ForegroundColor DarkGray
2241
1892
  Write-Host " @neocortex *menu" -ForegroundColor Cyan
@@ -2265,7 +1916,12 @@ Test-OldInstallation
2265
1916
 
2266
1917
  # Determine targets
2267
1918
  if ($Targets) {
2268
- $script:SelectedTargets = $Targets -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ }
1919
+ $seenTargets = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
1920
+ $script:SelectedTargets = @($Targets -split ',' | ForEach-Object {
1921
+ $candidate = $_.Trim()
1922
+ if ($candidate -eq 'gemini-cli') { $candidate = 'gemini' }
1923
+ if ($candidate -and $seenTargets.Add($candidate)) { $candidate }
1924
+ })
2269
1925
  $invalid = $script:SelectedTargets | Where-Object { $_ -notin $script:ValidTargets }
2270
1926
  if ($invalid) {
2271
1927
  Write-Fail "Plataformas invalidas: $($invalid -join ', ')"