patchwork-os 0.2.0-beta.4 → 0.2.0-beta.5.canary.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.
@@ -1,209 +1,209 @@
1
- #Requires -Version 5.1
2
- <#
3
- .SYNOPSIS
4
- Windows orchestrator for bridge + Claude + Patchwork dashboard.
5
-
6
- .DESCRIPTION
7
- Cross-platform alternative to start-all.sh for native Windows (PowerShell/cmd).
8
- Starts the bridge, waits for the lock file, launches Claude --ide, and
9
- optionally starts the Patchwork dashboard dev server and opens it in the browser.
10
-
11
- Run via npm:
12
- npm run start:bridge # bridge only (simplest)
13
- npm run start-all:win # full orchestrator (bridge + claude + dashboard)
14
-
15
- Or directly:
16
- pwsh -File scripts\start-all.ps1
17
- pwsh -File scripts\start-all.ps1 --no-dashboard
18
- pwsh -File scripts\start-all.ps1 --workspace C:\my\project --dashboard-port 3200
19
-
20
- .PARAMETER Workspace
21
- Directory to open in Claude (default: current directory).
22
-
23
- .PARAMETER Full
24
- Pass --full to the bridge, registering all ~95 tools including git/terminal/file ops.
25
- Default is slim mode (27 IDE-exclusive tools).
26
-
27
- .PARAMETER NoDashboard
28
- Skip starting the Patchwork dashboard.
29
-
30
- .PARAMETER DashboardPort
31
- Port for the Next.js dashboard dev server (default: 3200).
32
-
33
- .PARAMETER BridgePort
34
- Port for the bridge (default: auto-assigned via lock file).
35
-
36
- .PARAMETER Notify
37
- ntfy.sh topic for push notifications (optional).
38
- #>
39
- [CmdletBinding()]
40
- param(
41
- [string]$Workspace = ".",
42
- [switch]$Full,
43
- [switch]$NoDashboard,
44
- [int] $DashboardPort = 3200,
45
- [int] $BridgePort = 0,
46
- [string]$Notify = ""
47
- )
48
-
49
- Set-StrictMode -Version Latest
50
- $ErrorActionPreference = "Stop"
51
-
52
- # ── Resolve paths ─────────────────────────────────────────────────────────────
53
- $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
54
- $BridgeDir = Split-Path -Parent $ScriptDir
55
- $DashboardDir = Join-Path $BridgeDir "dashboard"
56
-
57
- try {
58
- $Workspace = (Resolve-Path $Workspace).Path
59
- } catch {
60
- Write-Error "Workspace directory not found: $Workspace"
61
- exit 1
62
- }
63
-
64
- # ── Helpers ───────────────────────────────────────────────────────────────────
65
- function Write-Status($msg) { Write-Host "[orchestrator] $msg" -ForegroundColor Cyan }
66
- function Write-Ok($msg) { Write-Host "[ok] $msg" -ForegroundColor Green }
67
- function Write-Warn($msg) { Write-Host "[warn] $msg" -ForegroundColor Yellow }
68
-
69
- function Send-Notify($msg) {
70
- if (-not $Notify) { return }
71
- try {
72
- Invoke-RestMethod -Uri "https://ntfy.sh/$Notify" -Method Post -Body $msg -TimeoutSec 5 | Out-Null
73
- } catch { Write-Warn "ntfy notification failed: $_" }
74
- }
75
-
76
- # ── Track child processes for cleanup ─────────────────────────────────────────
77
- $Jobs = [System.Collections.Generic.List[System.Diagnostics.Process]]::new()
78
-
79
- function Stop-AllJobs {
80
- foreach ($p in $Jobs) {
81
- if (-not $p.HasExited) {
82
- try { $p.Kill($true) } catch { }
83
- }
84
- }
85
- }
86
-
87
- # Clean up on Ctrl+C or exit
88
- $null = Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action { Stop-AllJobs }
89
- try { [Console]::TreatControlCAsInput = $false } catch { }
90
-
91
- # ── Build bridge args ─────────────────────────────────────────────────────────
92
- $BridgeArgs = @("--workspace", $Workspace)
93
- if ($BridgePort -gt 0) { $BridgeArgs += @("--port", $BridgePort) }
94
- if ($Full) { $BridgeArgs += "--full" }
95
-
96
- # ── Start bridge ──────────────────────────────────────────────────────────────
97
- Write-Status "Starting bridge (workspace: $Workspace)..."
98
-
99
- $BridgeInfo = New-Object System.Diagnostics.ProcessStartInfo
100
- $BridgeInfo.UseShellExecute = $false
101
- # On Windows, npm global bins are .cmd wrappers — must invoke via cmd.exe.
102
- # Quote each argument so workspace paths with spaces (e.g. "C:\Users\Jane Doe\...") survive.
103
- $BridgeInfo.FileName = "cmd.exe"
104
- $quotedArgs = $BridgeArgs | ForEach-Object { if ($_ -match '\s') { "`"$_`"" } else { $_ } }
105
- $BridgeInfo.Arguments = "/c claude-ide-bridge " + ($quotedArgs -join " ")
106
-
107
- $BridgeProc = [System.Diagnostics.Process]::Start($BridgeInfo)
108
- $Jobs.Add($BridgeProc)
109
-
110
- # ── Wait for lock file ────────────────────────────────────────────────────────
111
- Write-Status "Waiting for bridge lock file..."
112
- $ClaudeBase = if ($env:CLAUDE_CONFIG_DIR) { $env:CLAUDE_CONFIG_DIR } else { Join-Path $env:USERPROFILE ".claude" }
113
- $IdeDir = Join-Path $ClaudeBase "ide"
114
- $Deadline = (Get-Date).AddSeconds(30)
115
- $LockFile = $null
116
-
117
- while ((Get-Date) -lt $Deadline) {
118
- $locks = Get-ChildItem -Path $IdeDir -Filter "*.lock" -ErrorAction SilentlyContinue |
119
- Where-Object { $_.LastWriteTime -gt (Get-Date).AddSeconds(-60) }
120
- if ($locks) {
121
- # Find the lock that matches our workspace
122
- foreach ($lf in $locks) {
123
- try {
124
- $content = Get-Content $lf.FullName -Raw | ConvertFrom-Json
125
- if ($content.isBridge -and
126
- ($content.workspace -replace '\\','/' ) -eq ($Workspace -replace '\\','/')) {
127
- $LockFile = $lf
128
- $DetectedPort = [int][System.IO.Path]::GetFileNameWithoutExtension($lf.Name)
129
- break
130
- }
131
- } catch { }
132
- }
133
- if ($LockFile) { break }
134
- }
135
- Start-Sleep -Milliseconds 200
136
- }
137
-
138
- if (-not $LockFile) {
139
- Write-Error "Bridge lock file not written after 30s. Bridge may have failed to start."
140
- Stop-AllJobs
141
- exit 1
142
- }
143
-
144
- Write-Ok "Bridge ready on port $DetectedPort"
145
- Send-Notify "Bridge started on port $DetectedPort"
146
-
147
- # ── Start Claude --ide ────────────────────────────────────────────────────────
148
- Write-Status "Starting claude --ide..."
149
- $ClaudeInfo = New-Object System.Diagnostics.ProcessStartInfo
150
- $ClaudeInfo.FileName = "cmd.exe"
151
- $ClaudeInfo.Arguments = "/c claude --ide"
152
- $ClaudeInfo.UseShellExecute = $false
153
- $ClaudeProc = [System.Diagnostics.Process]::Start($ClaudeInfo)
154
- $Jobs.Add($ClaudeProc)
155
-
156
- # ── Start dashboard ───────────────────────────────────────────────────────────
157
- $DashProc = $null
158
- if (-not $NoDashboard) {
159
- if (-not (Test-Path (Join-Path $DashboardDir "node_modules"))) {
160
- Write-Warn "dashboard/node_modules not found. Run 'npm ci' in the dashboard directory first, or pass -NoDashboard."
161
- } else {
162
- Write-Status "Starting dashboard on http://localhost:$DashboardPort ..."
163
-
164
- $env:PATCHWORK_BRIDGE_PORT = $DetectedPort
165
- $DashInfo = New-Object System.Diagnostics.ProcessStartInfo
166
- $DashInfo.FileName = "cmd.exe"
167
- $DashInfo.Arguments = "/c npx next dev -p $DashboardPort"
168
- $DashInfo.WorkingDirectory = $DashboardDir
169
- $DashInfo.UseShellExecute = $false
170
- $DashProc = [System.Diagnostics.Process]::Start($DashInfo)
171
- $Jobs.Add($DashProc)
172
-
173
- # Poll until Next.js answers, then open the browser
174
- $DashUrl = "http://localhost:$DashboardPort"
175
- $DashDeadline = (Get-Date).AddSeconds(60)
176
- $Opened = $false
177
- while ((Get-Date) -lt $DashDeadline) {
178
- try {
179
- $r = Invoke-WebRequest -Uri $DashUrl -UseBasicParsing -TimeoutSec 1 -ErrorAction Stop
180
- if ($r.StatusCode -lt 500) {
181
- Write-Ok "Dashboard ready — opening $DashUrl"
182
- Start-Process $DashUrl # opens default browser on Windows
183
- $Opened = $true
184
- break
185
- }
186
- } catch { }
187
- Start-Sleep -Milliseconds 1000
188
- }
189
- if (-not $Opened) {
190
- Write-Warn "Dashboard did not respond within 60s — open $DashUrl manually."
191
- }
192
- }
193
- }
194
-
195
- # ── Wait ──────────────────────────────────────────────────────────────────────
196
- Write-Host ""
197
- Write-Ok "All processes started. Press Ctrl+C to stop."
198
- Write-Host " Bridge PID : $($BridgeProc.Id)"
199
- Write-Host " Claude PID : $($ClaudeProc.Id)"
200
- if ($DashProc) { Write-Host " Dashboard : http://localhost:$DashboardPort (PID $($DashProc.Id))" }
201
- Write-Host ""
202
-
203
- try {
204
- # Block until the bridge exits (primary process)
205
- $BridgeProc.WaitForExit()
206
- } finally {
207
- Write-Status "Bridge exited — stopping all processes..."
208
- Stop-AllJobs
209
- }
1
+ #Requires -Version 5.1
2
+ <#
3
+ .SYNOPSIS
4
+ Windows orchestrator for bridge + Claude + Patchwork dashboard.
5
+
6
+ .DESCRIPTION
7
+ Cross-platform alternative to start-all.sh for native Windows (PowerShell/cmd).
8
+ Starts the bridge, waits for the lock file, launches Claude --ide, and
9
+ optionally starts the Patchwork dashboard dev server and opens it in the browser.
10
+
11
+ Run via npm:
12
+ npm run start:bridge # bridge only (simplest)
13
+ npm run start-all:win # full orchestrator (bridge + claude + dashboard)
14
+
15
+ Or directly:
16
+ pwsh -File scripts\start-all.ps1
17
+ pwsh -File scripts\start-all.ps1 --no-dashboard
18
+ pwsh -File scripts\start-all.ps1 --workspace C:\my\project --dashboard-port 3200
19
+
20
+ .PARAMETER Workspace
21
+ Directory to open in Claude (default: current directory).
22
+
23
+ .PARAMETER Full
24
+ Pass --full to the bridge, registering all ~95 tools including git/terminal/file ops.
25
+ Default is slim mode (27 IDE-exclusive tools).
26
+
27
+ .PARAMETER NoDashboard
28
+ Skip starting the Patchwork dashboard.
29
+
30
+ .PARAMETER DashboardPort
31
+ Port for the Next.js dashboard dev server (default: 3200).
32
+
33
+ .PARAMETER BridgePort
34
+ Port for the bridge (default: auto-assigned via lock file).
35
+
36
+ .PARAMETER Notify
37
+ ntfy.sh topic for push notifications (optional).
38
+ #>
39
+ [CmdletBinding()]
40
+ param(
41
+ [string]$Workspace = ".",
42
+ [switch]$Full,
43
+ [switch]$NoDashboard,
44
+ [int] $DashboardPort = 3200,
45
+ [int] $BridgePort = 0,
46
+ [string]$Notify = ""
47
+ )
48
+
49
+ Set-StrictMode -Version Latest
50
+ $ErrorActionPreference = "Stop"
51
+
52
+ # ── Resolve paths ─────────────────────────────────────────────────────────────
53
+ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
54
+ $BridgeDir = Split-Path -Parent $ScriptDir
55
+ $DashboardDir = Join-Path $BridgeDir "dashboard"
56
+
57
+ try {
58
+ $Workspace = (Resolve-Path $Workspace).Path
59
+ } catch {
60
+ Write-Error "Workspace directory not found: $Workspace"
61
+ exit 1
62
+ }
63
+
64
+ # ── Helpers ───────────────────────────────────────────────────────────────────
65
+ function Write-Status($msg) { Write-Host "[orchestrator] $msg" -ForegroundColor Cyan }
66
+ function Write-Ok($msg) { Write-Host "[ok] $msg" -ForegroundColor Green }
67
+ function Write-Warn($msg) { Write-Host "[warn] $msg" -ForegroundColor Yellow }
68
+
69
+ function Send-Notify($msg) {
70
+ if (-not $Notify) { return }
71
+ try {
72
+ Invoke-RestMethod -Uri "https://ntfy.sh/$Notify" -Method Post -Body $msg -TimeoutSec 5 | Out-Null
73
+ } catch { Write-Warn "ntfy notification failed: $_" }
74
+ }
75
+
76
+ # ── Track child processes for cleanup ─────────────────────────────────────────
77
+ $Jobs = [System.Collections.Generic.List[System.Diagnostics.Process]]::new()
78
+
79
+ function Stop-AllJobs {
80
+ foreach ($p in $Jobs) {
81
+ if (-not $p.HasExited) {
82
+ try { $p.Kill($true) } catch { }
83
+ }
84
+ }
85
+ }
86
+
87
+ # Clean up on Ctrl+C or exit
88
+ $null = Register-EngineEvent -SourceIdentifier PowerShell.Exiting -Action { Stop-AllJobs }
89
+ try { [Console]::TreatControlCAsInput = $false } catch { }
90
+
91
+ # ── Build bridge args ─────────────────────────────────────────────────────────
92
+ $BridgeArgs = @("--workspace", $Workspace)
93
+ if ($BridgePort -gt 0) { $BridgeArgs += @("--port", $BridgePort) }
94
+ if ($Full) { $BridgeArgs += "--full" }
95
+
96
+ # ── Start bridge ──────────────────────────────────────────────────────────────
97
+ Write-Status "Starting bridge (workspace: $Workspace)..."
98
+
99
+ $BridgeInfo = New-Object System.Diagnostics.ProcessStartInfo
100
+ $BridgeInfo.UseShellExecute = $false
101
+ # On Windows, npm global bins are .cmd wrappers — must invoke via cmd.exe.
102
+ # Quote each argument so workspace paths with spaces (e.g. "C:\Users\Jane Doe\...") survive.
103
+ $BridgeInfo.FileName = "cmd.exe"
104
+ $quotedArgs = $BridgeArgs | ForEach-Object { if ($_ -match '\s') { "`"$_`"" } else { $_ } }
105
+ $BridgeInfo.Arguments = "/c claude-ide-bridge " + ($quotedArgs -join " ")
106
+
107
+ $BridgeProc = [System.Diagnostics.Process]::Start($BridgeInfo)
108
+ $Jobs.Add($BridgeProc)
109
+
110
+ # ── Wait for lock file ────────────────────────────────────────────────────────
111
+ Write-Status "Waiting for bridge lock file..."
112
+ $ClaudeBase = if ($env:CLAUDE_CONFIG_DIR) { $env:CLAUDE_CONFIG_DIR } else { Join-Path $env:USERPROFILE ".claude" }
113
+ $IdeDir = Join-Path $ClaudeBase "ide"
114
+ $Deadline = (Get-Date).AddSeconds(30)
115
+ $LockFile = $null
116
+
117
+ while ((Get-Date) -lt $Deadline) {
118
+ $locks = Get-ChildItem -Path $IdeDir -Filter "*.lock" -ErrorAction SilentlyContinue |
119
+ Where-Object { $_.LastWriteTime -gt (Get-Date).AddSeconds(-60) }
120
+ if ($locks) {
121
+ # Find the lock that matches our workspace
122
+ foreach ($lf in $locks) {
123
+ try {
124
+ $content = Get-Content $lf.FullName -Raw | ConvertFrom-Json
125
+ if ($content.isBridge -and
126
+ ($content.workspace -replace '\\','/' ) -eq ($Workspace -replace '\\','/')) {
127
+ $LockFile = $lf
128
+ $DetectedPort = [int][System.IO.Path]::GetFileNameWithoutExtension($lf.Name)
129
+ break
130
+ }
131
+ } catch { }
132
+ }
133
+ if ($LockFile) { break }
134
+ }
135
+ Start-Sleep -Milliseconds 200
136
+ }
137
+
138
+ if (-not $LockFile) {
139
+ Write-Error "Bridge lock file not written after 30s. Bridge may have failed to start."
140
+ Stop-AllJobs
141
+ exit 1
142
+ }
143
+
144
+ Write-Ok "Bridge ready on port $DetectedPort"
145
+ Send-Notify "Bridge started on port $DetectedPort"
146
+
147
+ # ── Start Claude --ide ────────────────────────────────────────────────────────
148
+ Write-Status "Starting claude --ide..."
149
+ $ClaudeInfo = New-Object System.Diagnostics.ProcessStartInfo
150
+ $ClaudeInfo.FileName = "cmd.exe"
151
+ $ClaudeInfo.Arguments = "/c claude --ide"
152
+ $ClaudeInfo.UseShellExecute = $false
153
+ $ClaudeProc = [System.Diagnostics.Process]::Start($ClaudeInfo)
154
+ $Jobs.Add($ClaudeProc)
155
+
156
+ # ── Start dashboard ───────────────────────────────────────────────────────────
157
+ $DashProc = $null
158
+ if (-not $NoDashboard) {
159
+ if (-not (Test-Path (Join-Path $DashboardDir "node_modules"))) {
160
+ Write-Warn "dashboard/node_modules not found. Run 'npm ci' in the dashboard directory first, or pass -NoDashboard."
161
+ } else {
162
+ Write-Status "Starting dashboard on http://localhost:$DashboardPort ..."
163
+
164
+ $env:PATCHWORK_BRIDGE_PORT = $DetectedPort
165
+ $DashInfo = New-Object System.Diagnostics.ProcessStartInfo
166
+ $DashInfo.FileName = "cmd.exe"
167
+ $DashInfo.Arguments = "/c npx next dev -p $DashboardPort"
168
+ $DashInfo.WorkingDirectory = $DashboardDir
169
+ $DashInfo.UseShellExecute = $false
170
+ $DashProc = [System.Diagnostics.Process]::Start($DashInfo)
171
+ $Jobs.Add($DashProc)
172
+
173
+ # Poll until Next.js answers, then open the browser
174
+ $DashUrl = "http://localhost:$DashboardPort"
175
+ $DashDeadline = (Get-Date).AddSeconds(60)
176
+ $Opened = $false
177
+ while ((Get-Date) -lt $DashDeadline) {
178
+ try {
179
+ $r = Invoke-WebRequest -Uri $DashUrl -UseBasicParsing -TimeoutSec 1 -ErrorAction Stop
180
+ if ($r.StatusCode -lt 500) {
181
+ Write-Ok "Dashboard ready — opening $DashUrl"
182
+ Start-Process $DashUrl # opens default browser on Windows
183
+ $Opened = $true
184
+ break
185
+ }
186
+ } catch { }
187
+ Start-Sleep -Milliseconds 1000
188
+ }
189
+ if (-not $Opened) {
190
+ Write-Warn "Dashboard did not respond within 60s — open $DashUrl manually."
191
+ }
192
+ }
193
+ }
194
+
195
+ # ── Wait ──────────────────────────────────────────────────────────────────────
196
+ Write-Host ""
197
+ Write-Ok "All processes started. Press Ctrl+C to stop."
198
+ Write-Host " Bridge PID : $($BridgeProc.Id)"
199
+ Write-Host " Claude PID : $($ClaudeProc.Id)"
200
+ if ($DashProc) { Write-Host " Dashboard : http://localhost:$DashboardPort (PID $($DashProc.Id))" }
201
+ Write-Host ""
202
+
203
+ try {
204
+ # Block until the bridge exits (primary process)
205
+ $BridgeProc.WaitForExit()
206
+ } finally {
207
+ Write-Status "Bridge exited — stopping all processes..."
208
+ Stop-AllJobs
209
+ }