@ijfw/install 1.2.8 → 1.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ijfw.js CHANGED
@@ -2516,14 +2516,19 @@ async function main() {
2516
2516
  case "dashboard": {
2517
2517
  const dashSub = argv[3];
2518
2518
  const root = repoRoot();
2519
+ const ijfwHome = join9(homedir(), ".ijfw");
2520
+ const findInTree = (...rel) => {
2521
+ const candidates = [join9(root, ...rel), join9(ijfwHome, ...rel)];
2522
+ return candidates.find((p) => existsSync3(p)) || null;
2523
+ };
2519
2524
  if (dashSub === "start" || dashSub === "stop" || dashSub === "status") {
2520
- const dashBin = join9(root, "mcp-server", "bin", "ijfw-dashboard");
2521
- if (existsSync3(dashBin)) {
2525
+ const dashBin = findInTree("mcp-server", "bin", "ijfw-dashboard");
2526
+ if (dashBin) {
2522
2527
  const r = spawnSync12("node", [dashBin, dashSub, ...argv.slice(4)], { stdio: "inherit" });
2523
2528
  process.exit(r.status ?? 0);
2524
2529
  } else {
2525
- const serverJs = join9(root, "mcp-server", "src", "dashboard-server.js");
2526
- if (dashSub === "start" && existsSync3(serverJs)) {
2530
+ const serverJs = findInTree("mcp-server", "src", "dashboard-server.js");
2531
+ if (dashSub === "start" && serverJs) {
2527
2532
  const { spawn } = await import("node:child_process");
2528
2533
  const child = spawn(process.execPath, [serverJs, "--daemon"], {
2529
2534
  detached: true,
@@ -2533,12 +2538,12 @@ async function main() {
2533
2538
  console.log("Dashboard starting... (check: ijfw dashboard status)");
2534
2539
  process.exit(0);
2535
2540
  }
2536
- console.log("[ijfw] Dashboard bin not found. Run from the IJFW repo root.");
2541
+ console.log("[ijfw] Dashboard not found. Try `ijfw-install` to deploy ~/.ijfw/, or run from the IJFW repo root.");
2537
2542
  process.exit(1);
2538
2543
  }
2539
2544
  } else if (dashSub === "render" || !dashSub) {
2540
- const binJs = join9(root, "scripts", "dashboard", "bin.js");
2541
- if (existsSync3(binJs)) {
2545
+ const binJs = findInTree("scripts", "dashboard", "bin.js");
2546
+ if (binJs) {
2542
2547
  const r = spawnSync12("node", [binJs, ...argv.slice(dashSub ? 4 : 3)], { stdio: "inherit" });
2543
2548
  process.exit(r.status ?? 0);
2544
2549
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ijfw/install",
3
- "version": "1.2.8",
3
+ "version": "1.2.9",
4
4
  "description": "One-command installer for IJFW -- the AI efficiency layer. One install, every AI coding agent, zero config.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/install.ps1 CHANGED
@@ -83,8 +83,15 @@ function Invoke-CloneOrPull($target, $branch) {
83
83
  # Upgrade path.
84
84
  $hasGit = Test-Path (Join-Path $target ".git")
85
85
  if ($hasGit) {
86
- & git -C $target remote get-url origin 2>$null | Out-Null
86
+ $currentOriginRaw = & git -C $target remote get-url origin 2>$null
87
87
  if ($LASTEXITCODE -eq 0) {
88
+ # Self-heal stale origin URLs across host migrations (1.2.9 parity with install.js).
89
+ # Without this, Windows users on the pre-GitLab origin still 404 on every upgrade.
90
+ $currentOrigin = ($currentOriginRaw | Out-String).Trim()
91
+ if ($currentOrigin -and $currentOrigin -ne $DEFAULT_REPO) {
92
+ Write-Host " origin migration: $currentOrigin -> $DEFAULT_REPO"
93
+ & git -C $target remote set-url origin $DEFAULT_REPO
94
+ }
88
95
  # fetch + hard checkout avoids ff-only failures from local divergence.
89
96
  & git -C $target fetch --depth 1 origin $branch
90
97
  if ($LASTEXITCODE -ne 0) { throw "Could not reach the IJFW repo (exit $LASTEXITCODE). Check your network connection and retry." }
@@ -95,9 +102,12 @@ function Invoke-CloneOrPull($target, $branch) {
95
102
  }
96
103
 
97
104
  # Broken repo or no origin: backup user data, re-clone, restore.
105
+ # Rename-Item -NewName requires a leaf name; Move-Item -Destination accepts an
106
+ # absolute path. Using Rename-Item with an absolute path silently lost user data
107
+ # on Windows pre-1.2.9 because PowerShell rejected the call.
98
108
  $ts = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
99
109
  $backupDir = "$target.bak.$ts"
100
- Rename-Item -LiteralPath $target -NewName $backupDir
110
+ Move-Item -LiteralPath $target -Destination $backupDir -Force
101
111
  try {
102
112
  & git clone --depth 1 --branch $branch $DEFAULT_REPO $target
103
113
  if ($LASTEXITCODE -ne 0) { throw "Could not reach the IJFW repo (exit $LASTEXITCODE). Check your network connection and retry." }
@@ -106,14 +116,14 @@ function Invoke-CloneOrPull($target, $branch) {
106
116
  if (Test-Path $src) {
107
117
  $dst = Join-Path $target $item
108
118
  if (Test-Path $dst) { Remove-Item -Recurse -Force -LiteralPath $dst }
109
- Move-Item -LiteralPath $src -Destination $dst
119
+ Move-Item -LiteralPath $src -Destination $dst -Force
110
120
  }
111
121
  }
112
122
  Remove-Item -Recurse -Force -LiteralPath $backupDir
113
123
  return "updated"
114
124
  } catch {
115
125
  if (Test-Path $target) { Remove-Item -Recurse -Force -LiteralPath $target }
116
- Rename-Item -LiteralPath $backupDir -NewName $target
126
+ Move-Item -LiteralPath $backupDir -Destination $target -Force
117
127
  throw
118
128
  }
119
129
  }
@@ -123,6 +133,13 @@ function Invoke-InstallScript($target) {
123
133
  if (-not (Test-Path $script)) { throw "The installer script is not at $script yet. Run the full install from a fresh clone." }
124
134
  $gitBash = Resolve-GitBash
125
135
  if (-not $gitBash) { throw "IJFW needs Git Bash to complete setup. Install Git for Windows (includes bash.exe) and rerun." }
136
+ # Propagate IJFW_HOME into the bash sub-call so a custom -Dir target lands
137
+ # platform configs / sentinels under the user's chosen tree instead of the
138
+ # default ~/.ijfw. Without this, .\install.ps1 -Dir D:\custom would scribble
139
+ # MCP entries into the user's real ~/.codex / ~/.gemini / ~/.claude pointing
140
+ # at the scratch dir.
141
+ $priorIjfwHome = $env:IJFW_HOME
142
+ $env:IJFW_HOME = $target
126
143
  Push-Location $target
127
144
  try {
128
145
  $env:IJFW_NONINTERACTIVE = if ($env:CI -or $Yes) { "1" } else { "" }
@@ -134,6 +151,7 @@ function Invoke-InstallScript($target) {
134
151
  } finally {
135
152
  Pop-Location
136
153
  Remove-Item Env:\IJFW_SKIP_CLOSER -ErrorAction SilentlyContinue
154
+ if ($priorIjfwHome) { $env:IJFW_HOME = $priorIjfwHome } else { Remove-Item Env:\IJFW_HOME -ErrorAction SilentlyContinue }
137
155
  }
138
156
  }
139
157