patchwork-os 0.2.0-beta.1 → 0.2.0-beta.3
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/README.bridge.md +5 -5
- package/README.md +156 -12
- package/deploy/deploy-dashboard.sh +25 -1
- package/deploy/macos/README.md +153 -0
- package/deploy/macos/com.patchwork.bridge.plist.template +54 -0
- package/deploy/macos/com.patchwork.tunnel.plist.template +76 -0
- package/deploy/macos/install-mac-bridge.sh +244 -0
- package/deploy/macos/uninstall-mac-bridge.sh +22 -0
- package/dist/activityLog.d.ts +6 -0
- package/dist/activityLog.js +8 -0
- package/dist/activityLog.js.map +1 -1
- package/dist/analyticsPrefs.d.ts +35 -2
- package/dist/analyticsPrefs.js +120 -21
- package/dist/analyticsPrefs.js.map +1 -1
- package/dist/analyticsSend.js +5 -1
- package/dist/analyticsSend.js.map +1 -1
- package/dist/approvalHttp.d.ts +14 -0
- package/dist/approvalHttp.js +172 -1
- package/dist/approvalHttp.js.map +1 -1
- package/dist/approvalQueue.d.ts +27 -2
- package/dist/approvalQueue.js +44 -7
- package/dist/approvalQueue.js.map +1 -1
- package/dist/automation.d.ts +34 -3
- package/dist/automation.js +85 -10
- package/dist/automation.js.map +1 -1
- package/dist/bridge.d.ts +2 -0
- package/dist/bridge.js +114 -8
- package/dist/bridge.js.map +1 -1
- package/dist/bridgeLockDiscovery.d.ts +27 -1
- package/dist/bridgeLockDiscovery.js +37 -11
- package/dist/bridgeLockDiscovery.js.map +1 -1
- package/dist/claudeOrchestrator.js +5 -2
- package/dist/claudeOrchestrator.js.map +1 -1
- package/dist/commands/patchworkInit.d.ts +5 -0
- package/dist/commands/patchworkInit.js +86 -7
- package/dist/commands/patchworkInit.js.map +1 -1
- package/dist/commands/recipe.d.ts +51 -0
- package/dist/commands/recipe.js +363 -3
- package/dist/commands/recipe.js.map +1 -1
- package/dist/commands/recipeInstall.js +6 -3
- package/dist/commands/recipeInstall.js.map +1 -1
- package/dist/commands/task.js +2 -2
- package/dist/commands/task.js.map +1 -1
- package/dist/config.d.ts +17 -2
- package/dist/config.js +54 -17
- package/dist/config.js.map +1 -1
- package/dist/connectors/baseConnector.js +25 -3
- package/dist/connectors/baseConnector.js.map +1 -1
- package/dist/connectors/tokenStorage.js +46 -10
- package/dist/connectors/tokenStorage.js.map +1 -1
- package/dist/drivers/gemini/index.d.ts +22 -0
- package/dist/drivers/gemini/index.js +240 -129
- package/dist/drivers/gemini/index.js.map +1 -1
- package/dist/drivers/local/index.d.ts +17 -0
- package/dist/drivers/local/index.js +99 -0
- package/dist/drivers/local/index.js.map +1 -1
- package/dist/drivers/openai/index.js +30 -2
- package/dist/drivers/openai/index.js.map +1 -1
- package/dist/extensionClient.d.ts +8 -0
- package/dist/extensionClient.js +24 -2
- package/dist/extensionClient.js.map +1 -1
- package/dist/featureFlags.d.ts +76 -0
- package/dist/featureFlags.js +166 -2
- package/dist/featureFlags.js.map +1 -1
- package/dist/fp/automationInterpreter.d.ts +9 -1
- package/dist/fp/automationInterpreter.js +151 -34
- package/dist/fp/automationInterpreter.js.map +1 -1
- package/dist/fp/automationProgram.d.ts +30 -0
- package/dist/fp/automationProgram.js.map +1 -1
- package/dist/fp/automationState.d.ts +23 -4
- package/dist/fp/automationState.js +28 -4
- package/dist/fp/automationState.js.map +1 -1
- package/dist/fp/interpreterContext.d.ts +66 -1
- package/dist/fp/interpreterContext.js +140 -1
- package/dist/fp/interpreterContext.js.map +1 -1
- package/dist/fp/policyParser.js +29 -1
- package/dist/fp/policyParser.js.map +1 -1
- package/dist/index.js +765 -69
- package/dist/index.js.map +1 -1
- package/dist/lockfile.js +4 -1
- package/dist/lockfile.js.map +1 -1
- package/dist/oauth.d.ts +9 -0
- package/dist/oauth.js +33 -0
- package/dist/oauth.js.map +1 -1
- package/dist/patchworkConfig.d.ts +16 -0
- package/dist/patchworkConfig.js +5 -0
- package/dist/patchworkConfig.js.map +1 -1
- package/dist/recipeOrchestration.js +35 -1
- package/dist/recipeOrchestration.js.map +1 -1
- package/dist/recipeRoutes.d.ts +36 -0
- package/dist/recipeRoutes.js +231 -32
- package/dist/recipeRoutes.js.map +1 -1
- package/dist/recipes/agentExecutor.d.ts +25 -5
- package/dist/recipes/agentExecutor.js.map +1 -1
- package/dist/recipes/chainedRunner.js +16 -2
- package/dist/recipes/chainedRunner.js.map +1 -1
- package/dist/recipes/connectorPreflight.d.ts +53 -0
- package/dist/recipes/connectorPreflight.js +79 -0
- package/dist/recipes/connectorPreflight.js.map +1 -0
- package/dist/recipes/githubInstallSource.d.ts +62 -0
- package/dist/recipes/githubInstallSource.js +125 -0
- package/dist/recipes/githubInstallSource.js.map +1 -0
- package/dist/recipes/haltCategory.d.ts +80 -0
- package/dist/recipes/haltCategory.js +125 -0
- package/dist/recipes/haltCategory.js.map +1 -0
- package/dist/recipes/idempotencyKey.d.ts +126 -0
- package/dist/recipes/idempotencyKey.js +298 -0
- package/dist/recipes/idempotencyKey.js.map +1 -0
- package/dist/recipes/judgeSummary.d.ts +50 -0
- package/dist/recipes/judgeSummary.js +47 -0
- package/dist/recipes/judgeSummary.js.map +1 -0
- package/dist/recipes/judgeVerdict.d.ts +48 -0
- package/dist/recipes/judgeVerdict.js +174 -0
- package/dist/recipes/judgeVerdict.js.map +1 -0
- package/dist/recipes/migrations/index.d.ts +9 -0
- package/dist/recipes/migrations/index.js +133 -0
- package/dist/recipes/migrations/index.js.map +1 -1
- package/dist/recipes/runBudget.d.ts +70 -0
- package/dist/recipes/runBudget.js +109 -0
- package/dist/recipes/runBudget.js.map +1 -0
- package/dist/recipes/scheduler.d.ts +7 -0
- package/dist/recipes/scheduler.js +31 -14
- package/dist/recipes/scheduler.js.map +1 -1
- package/dist/recipes/schema.d.ts +36 -0
- package/dist/recipes/toolRegistry.js +19 -0
- package/dist/recipes/toolRegistry.js.map +1 -1
- package/dist/recipes/tools/file.js +5 -2
- package/dist/recipes/tools/file.js.map +1 -1
- package/dist/recipes/tools/http.d.ts +10 -0
- package/dist/recipes/tools/http.js +176 -0
- package/dist/recipes/tools/http.js.map +1 -0
- package/dist/recipes/tools/index.d.ts +1 -0
- package/dist/recipes/tools/index.js +1 -0
- package/dist/recipes/tools/index.js.map +1 -1
- package/dist/recipes/validation.js +1 -1
- package/dist/recipes/validation.js.map +1 -1
- package/dist/recipes/yamlRunner.d.ts +88 -7
- package/dist/recipes/yamlRunner.js +216 -25
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/recipesHttp.d.ts +3 -1
- package/dist/recipesHttp.js +9 -3
- package/dist/recipesHttp.js.map +1 -1
- package/dist/runLog.d.ts +28 -0
- package/dist/runLog.js +5 -0
- package/dist/runLog.js.map +1 -1
- package/dist/server.d.ts +111 -1
- package/dist/server.js +480 -6
- package/dist/server.js.map +1 -1
- package/dist/streamableHttp.d.ts +9 -4
- package/dist/streamableHttp.js +34 -15
- package/dist/streamableHttp.js.map +1 -1
- package/dist/tools/bridgeDoctor.js +6 -2
- package/dist/tools/bridgeDoctor.js.map +1 -1
- package/dist/tools/ccRoutines.d.ts +221 -0
- package/dist/tools/ccRoutines.js +264 -0
- package/dist/tools/ccRoutines.js.map +1 -0
- package/dist/tools/getCodeCoverage.js +7 -3
- package/dist/tools/getCodeCoverage.js.map +1 -1
- package/dist/tools/index.js +6 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/openInBrowser.js +6 -1
- package/dist/tools/openInBrowser.js.map +1 -1
- package/dist/tools/recentTracesDigest.js +56 -11
- package/dist/tools/recentTracesDigest.js.map +1 -1
- package/dist/tools/testRunners/vitestJest.js +3 -1
- package/dist/tools/testRunners/vitestJest.js.map +1 -1
- package/dist/tools/utils.js +13 -7
- package/dist/tools/utils.js.map +1 -1
- package/package.json +16 -5
- package/scripts/postinstall.mjs +27 -0
- package/scripts/smoke/run-all.mjs +162 -0
- package/scripts/start-all.mjs +513 -0
- package/scripts/start-all.ps1 +209 -0
- package/scripts/start-all.sh +73 -17
- package/scripts/start-orchestrator.ps1 +158 -0
- package/scripts/start-remote.mjs +122 -0
- package/templates/automation-policies/recipe-authoring.json +1 -1
- package/templates/automation-policies/security-first.json +1 -1
- package/templates/automation-policies/strict-lint.json +1 -1
- package/templates/automation-policies/test-driven.json +1 -1
- package/templates/automation-policy.example.json +1 -1
- package/templates/co.patchwork-os.bridge.plist +1 -1
- package/templates/recipes/approval-queue-ui-test.yaml +1 -1
- package/templates/recipes/ctx-loop-test.yaml +1 -1
- package/templates/recipes/webhook/apple-watch-health-log.yaml +145 -0
- package/dist/commands/marketplace.d.ts +0 -16
- package/dist/commands/marketplace.js +0 -32
- package/dist/commands/marketplace.js.map +0 -1
- package/dist/recipes/legacyRecipeCompat.d.ts +0 -10
- package/dist/recipes/legacyRecipeCompat.js +0 -131
- package/dist/recipes/legacyRecipeCompat.js.map +0 -1
package/README.bridge.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
[](https://github.com/Oolab-labs/claude-ide-bridge/pkgs/container/claude-ide-bridge)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
|
-
**MCP bridge giving Claude Code IDE superpowers
|
|
8
|
+
**MCP bridge giving Claude Code IDE superpowers — 170+ tools for LSP, debugging, git, GitHub, terminals, and more (see [platform-docs](documents/platform-docs.md) for the full list).**
|
|
9
9
|
|
|
10
10
|
A WebSocket bridge between Claude Code CLI and your VS Code extension. Claude sees what your IDE sees — live diagnostics, go-to-definition, call hierarchies, hover types, breakpoints, debugger state — and can act on it: edit files, run tests, commit, open PRs, all without you copy-pasting anything.
|
|
11
11
|
|
|
@@ -192,7 +192,7 @@ claude-ide-bridge start-task "Refactor the auth module for clarity, keep behavio
|
|
|
192
192
|
claude-ide-bridge continue-handoff
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
-
Requires `--
|
|
195
|
+
Requires `--driver subprocess` on the running bridge. All three subcommands accept `--json`, `--port`, `--source`. Enforces a 5s bridge-global cooldown per preset (shared with the sidebar).
|
|
196
196
|
|
|
197
197
|
---
|
|
198
198
|
|
|
@@ -223,7 +223,7 @@ Event-driven hooks that trigger Claude tasks automatically — no polling, no ma
|
|
|
223
223
|
|
|
224
224
|
Start with:
|
|
225
225
|
```bash
|
|
226
|
-
claude-ide-bridge --watch --automation --automation-policy ./policy.json --
|
|
226
|
+
claude-ide-bridge --watch --automation --automation-policy ./policy.json --driver subprocess
|
|
227
227
|
```
|
|
228
228
|
|
|
229
229
|
**18 hook events:** `onFileSave`, `onFileChanged`, `onDiagnosticsError`, `onDiagnosticsCleared`, `onGitCommit`, `onGitPush`, `onGitPull`, `onBranchCheckout`, `onPullRequest`, `onTestRun`, `onTestPassAfterFailure`, `onPostCompact`, `onInstructionsLoaded`, `onTaskCreated`, `onTaskSuccess`, `onPermissionDenied`, `onCwdChanged`, `onDebugSessionEnd`
|
|
@@ -299,7 +299,7 @@ claude-ide-bridge install claude-mem
|
|
|
299
299
|
| `--fixed-token <uuid>` | — | Stable auth token across restarts |
|
|
300
300
|
| `--automation` | off | Enable automation hooks |
|
|
301
301
|
| `--automation-policy <path>` | — | Path to policy JSON |
|
|
302
|
-
| `--
|
|
302
|
+
| `--driver subprocess` | none | Enable Claude subprocess orchestration |
|
|
303
303
|
| `--plugin <path>` | — | Load a plugin (repeatable) |
|
|
304
304
|
| `--plugin-watch` | off | Hot-reload plugins on change |
|
|
305
305
|
| `--issuer-url <url>` | — | Activate OAuth 2.0 mode |
|
|
@@ -314,7 +314,7 @@ claude-ide-bridge install claude-mem
|
|
|
314
314
|
| File | Description |
|
|
315
315
|
|---|---|
|
|
316
316
|
| [ARCHITECTURE.md](ARCHITECTURE.md) | System topology, request lifecycle, component map, design decisions |
|
|
317
|
-
| [documents/platform-docs.md](documents/platform-docs.md) | Full tool reference — all
|
|
317
|
+
| [documents/platform-docs.md](documents/platform-docs.md) | Full tool reference — all 170+ tools with parameters and examples |
|
|
318
318
|
| [documents/prompts-reference.md](documents/prompts-reference.md) | All MCP prompts (31 prompts, 12 plugin skills, 4 subagents) |
|
|
319
319
|
| [docs/automation.md](docs/automation.md) | Automation hooks reference — all 18 events, policy schema, condition filters |
|
|
320
320
|
| [docs/troubleshooting.md](docs/troubleshooting.md) | Diagnostics, common errors, and fixes |
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
> Patchwork OS is a local-first personal AI runtime: pluggable model providers, hot-reloadable tools, YAML recipes, a delegation policy with approval queue, and a durable trace memory — all running on your machine, all under your policy.
|
|
6
6
|
|
|
7
|
-
You decide which model. You decide which actions need a human nod. You own the credentials, the logs, and the deployment. Nothing phones home.
|
|
7
|
+
You decide which model. You decide which actions need a human nod. You own the credentials, the logs, and the deployment. Nothing phones home unless you [opt in to anonymous analytics](#telemetry).
|
|
8
8
|
|
|
9
9
|
**Five primitives, one runtime:**
|
|
10
10
|
|
|
@@ -25,14 +25,38 @@ The same codebase ships **two ways to use it.** Pick the layer you need.
|
|
|
25
25
|
| | What you get | Install | Best for |
|
|
26
26
|
|---|---|---|---|
|
|
27
27
|
| **🔌 Claude IDE Bridge** | MCP bridge connecting Claude Code to your IDE. 170+ tools — diagnostics, LSP, debugger, terminal, git, GitHub, file ops. | `npm i -g patchwork-os` then run `claude-ide-bridge` | Anyone who wants Claude Code to see and act on their editor state |
|
|
28
|
-
| **🤖 Patchwork OS** | Everything in the bridge **plus** YAML recipes, approval queue, oversight dashboard, mobile push approvals, multi-model providers, JetBrains companion. | Same package, run `patchwork
|
|
28
|
+
| **🤖 Patchwork OS** | Everything in the bridge **plus** YAML recipes, approval queue, oversight dashboard, mobile push approvals, multi-model providers, JetBrains companion. | Same package, run `patchwork init` | Power users running automation, agent workflows, or background tasks |
|
|
29
29
|
|
|
30
30
|
Same codebase. Bridge is the foundation; Patchwork OS is the optional layer on top. **No vendor lock-in. Runs on your machine.**
|
|
31
31
|
|
|
32
32
|
---
|
|
33
33
|
|
|
34
|
+
## Dashboard Only — No Code Editor Required
|
|
35
|
+
|
|
36
|
+
> You do not need VS Code, Windsurf, Cursor, or Claude Code CLI to use the Patchwork dashboard.
|
|
37
|
+
|
|
38
|
+
The dashboard is a standalone Next.js app that communicates with the bridge over HTTP. No editor extension required.
|
|
39
|
+
|
|
40
|
+
**Prereqs:** [Node.js 20+](https://nodejs.org) · tmux on macOS/Linux (`brew install tmux` / `apt install tmux`) — auto-detected, falls back to background mode if absent. **Windows:** natively supported — no WSL required.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install -g patchwork-os
|
|
44
|
+
patchwork-os init # scaffolds ~/.patchwork and generates a dashboard login
|
|
45
|
+
patchwork start # launches bridge + dashboard (auto-detects tmux; falls back to background mode if absent)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Open **http://localhost:3200** — that's it. `patchwork-os init` auto-generates a dashboard password and saves it to `~/.patchwork/.env` — it prints the password at the end of setup, save it for your first login.
|
|
49
|
+
|
|
50
|
+
**What you get:** run and schedule YAML recipes, connect external services (Gmail, Calendar, Slack), review AI drafts in the approval queue, read your AI inbox — all from the browser. No coding required.
|
|
51
|
+
|
|
52
|
+
> **Want IDE features too?** See [Claude IDE Bridge — Quick Start](#-claude-ide-bridge--quick-start) below to add LSP, debugger, and editor tools on top.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
34
56
|
## 🔌 Claude IDE Bridge — Quick Start
|
|
35
57
|
|
|
58
|
+
> Developers only — skip to [Dashboard Only](#dashboard-only--no-code-editor-required) above if you just want the web dashboard.
|
|
59
|
+
|
|
36
60
|
**Prerequisites:** a supported code editor — **VS Code, Cursor, Windsurf, or Google Antigravity** (or JetBrains via the [companion plugin](#jetbrains-plugin)) — plus Node.js 20+ and the [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code). The bridge's LSP, debugger, and editor-state tools run through the editor extension; without one you're limited to the headless CLI subset.
|
|
37
61
|
|
|
38
62
|
```bash
|
|
@@ -72,7 +96,20 @@ The bridge runs without any flags. No recipes, no automation, no dashboard — j
|
|
|
72
96
|
|---|---|
|
|
73
97
|
| Claude Code CLI | WebSocket `ws://127.0.0.1:<port>` |
|
|
74
98
|
| Claude Desktop | stdio shim → WebSocket |
|
|
75
|
-
|
|
|
99
|
+
| Gemini CLI, Codex CLI, claude.ai | Streamable HTTP + Bearer token |
|
|
100
|
+
|
|
101
|
+
**Connecting Gemini CLI:**
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Get the auth token from the bridge's lock file
|
|
105
|
+
patchwork-os print-token
|
|
106
|
+
|
|
107
|
+
# Add the bridge as an MCP server
|
|
108
|
+
gemini mcp add patchwork http://127.0.0.1:<port>/mcp \
|
|
109
|
+
--header "Authorization: Bearer <token>"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The bridge auto-responds to the GET probe Gemini sends before initializing, so it shows as **Connected** immediately.
|
|
76
113
|
|
|
77
114
|
**Tool modes:**
|
|
78
115
|
|
|
@@ -85,10 +122,89 @@ Bridge-only docs: [documents/platform-docs.md](documents/platform-docs.md)
|
|
|
85
122
|
|
|
86
123
|
---
|
|
87
124
|
|
|
125
|
+
## 🪟 Windows Quick Start
|
|
126
|
+
|
|
127
|
+
The bridge, VS Code extension, and full Patchwork OS orchestrator (`patchwork start`) all work natively on Windows — no WSL required. A PowerShell-native orchestrator is also available as `npm run start-all:win`.
|
|
128
|
+
|
|
129
|
+
### Prerequisites
|
|
130
|
+
|
|
131
|
+
- Node.js 20+ (from [nodejs.org](https://nodejs.org))
|
|
132
|
+
- VS Code, Cursor, or Windsurf
|
|
133
|
+
- [Claude Code CLI](https://docs.anthropic.com/en/docs/claude-code)
|
|
134
|
+
- PowerShell 5.1+ (built into Windows 10/11) or PowerShell 7+ (`pwsh`)
|
|
135
|
+
|
|
136
|
+
### Bridge-only (recommended starting point)
|
|
137
|
+
|
|
138
|
+
Open **PowerShell** or **cmd.exe**:
|
|
139
|
+
|
|
140
|
+
```powershell
|
|
141
|
+
# 1. Install
|
|
142
|
+
npm install -g patchwork-os
|
|
143
|
+
|
|
144
|
+
# 2. Install the VS Code extension
|
|
145
|
+
claude-ide-bridge install-extension
|
|
146
|
+
|
|
147
|
+
# 3. Start the bridge (bash-free entry point)
|
|
148
|
+
npm run start:bridge
|
|
149
|
+
# or equivalently:
|
|
150
|
+
node "$(npm root -g)/patchwork-os/dist/index.js" --workspace .
|
|
151
|
+
|
|
152
|
+
# 4. Connect Claude Code (new terminal)
|
|
153
|
+
claude --ide
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Type `/ide` in Claude Code to confirm the connection.
|
|
157
|
+
|
|
158
|
+
### Full orchestrator (bridge + Claude + dashboard)
|
|
159
|
+
|
|
160
|
+
Two options — both work on Windows, macOS, and Linux:
|
|
161
|
+
|
|
162
|
+
```powershell
|
|
163
|
+
# Option A: cross-platform Node.js orchestrator (recommended)
|
|
164
|
+
npm run start-all:node
|
|
165
|
+
npm run start-all:node -- --workspace C:\myproj --full --no-dashboard
|
|
166
|
+
|
|
167
|
+
# Option B: PowerShell-native orchestrator (Windows only, no Node wrapper overhead)
|
|
168
|
+
npm run start-all:win
|
|
169
|
+
npm run start-all:win -- -NoDashboard -Workspace C:\myproj -Full
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Both start the bridge, wait for the lock file, launch `claude --ide` and `remote-control`, start the Next.js dashboard on `http://localhost:3200`, poll until it's ready, then open it in your default browser. The health monitor restarts the bridge automatically if it crashes, with exponential backoff.
|
|
173
|
+
|
|
174
|
+
```powershell
|
|
175
|
+
# Node orchestrator options (--key value form)
|
|
176
|
+
npm run start-all:node -- --full # all ~170 tools
|
|
177
|
+
npm run start-all:node -- --no-dashboard # skip dashboard
|
|
178
|
+
npm run start-all:node -- --dashboard-port 3300
|
|
179
|
+
npm run start-all:node -- --no-remote # skip remote-control
|
|
180
|
+
npm run start-all:node -- --notify my-topic # ntfy.sh push notifications
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Known limitations on native Windows
|
|
184
|
+
|
|
185
|
+
| Feature | Status |
|
|
186
|
+
|---|---|
|
|
187
|
+
| Bridge + extension (LSP, debugger, editor state) | ✅ Full support |
|
|
188
|
+
| `npm run start:bridge` | ✅ Supported |
|
|
189
|
+
| `npm run start-all:node` (Node.js orchestrator) | ✅ Supported — cross-platform |
|
|
190
|
+
| `npm run start-all:win` (PS1 orchestrator) | ✅ Supported — Windows-native |
|
|
191
|
+
| Dashboard (`http://localhost:3200`) | ✅ Opens automatically |
|
|
192
|
+
| `patchwork start` / `npm run start-all` | ⚠️ Requires WSL2 or Git Bash (uses bash + tmux) |
|
|
193
|
+
| `npm run remote:node` | ✅ Supported — cross-platform Node auto-restart wrapper |
|
|
194
|
+
| `npm run remote` / `npm run vps` | ⚠️ Requires WSL2 or Git Bash |
|
|
195
|
+
| Screenshot capture (standalone bridge) | ⚠️ Not yet supported; extension screenshot works via VS Code |
|
|
196
|
+
| Credential storage | ✅ Uses DPAPI (Windows Data Protection API) via PowerShell |
|
|
197
|
+
|
|
198
|
+
### WSL2 alternative
|
|
199
|
+
|
|
200
|
+
For full Patchwork OS functionality including orchestrator, recipes, and morning-brief, run everything inside WSL2 and install the VS Code Remote-WSL extension. The bridge extension loads on the WSL side automatically (`extensionKind: ["workspace"]`), giving full tool coverage.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
88
204
|
## 🤖 Patchwork OS — Quick Start
|
|
89
205
|
|
|
90
206
|
```bash
|
|
91
|
-
npx patchwork-os@beta
|
|
207
|
+
npx patchwork-os@beta init
|
|
92
208
|
```
|
|
93
209
|
|
|
94
210
|
Sets up 5 local recipes, detects Ollama, and opens a terminal dashboard — under 90 seconds.
|
|
@@ -99,7 +215,7 @@ Get an AI digest of your Gmail, calendar, and tasks every morning — or on dema
|
|
|
99
215
|
|
|
100
216
|
```bash
|
|
101
217
|
# First-time setup (connect Gmail + Google Calendar)
|
|
102
|
-
patchwork-os
|
|
218
|
+
patchwork-os init
|
|
103
219
|
patchwork-os connections connect gmail
|
|
104
220
|
patchwork-os connections connect google-calendar
|
|
105
221
|
|
|
@@ -125,15 +241,15 @@ Think of it as a background agent that acts on your behalf — but asks before s
|
|
|
125
241
|
|
|
126
242
|
**Recipes** are plain YAML files. They declare a trigger (cron, file save, git commit, test run, webhook) and an action (run a prompt, write to inbox, call a connector). No code required. Share them like dotfiles.
|
|
127
243
|
|
|
128
|
-
**Models** are yours. Claude, GPT, Gemini, Grok, or local Ollama. Swap at any time. Nothing phones home.
|
|
244
|
+
**Models** are yours. Claude, GPT, Gemini, Grok, or local Ollama. Swap at any time. Nothing phones home unless you opt in (see [Telemetry](#telemetry)).
|
|
129
245
|
|
|
130
|
-
**Oversight** is non-negotiable. Every write or external action lands in `~/.patchwork/inbox/` for approval. The web UI at `http://localhost:3200` shows pending approvals, live sessions, recipe run history, and analytics.
|
|
246
|
+
**Oversight** is non-negotiable. Every write or external action lands in `~/.patchwork/inbox/` for approval. The web UI at `http://localhost:3200` shows pending approvals, live sessions, recipe run history, and local analytics (the dashboard's analytics panel is computed entirely from on-disk logs — it does not transmit anything).
|
|
131
247
|
|
|
132
248
|
### Patchwork commands
|
|
133
249
|
|
|
134
250
|
```bash
|
|
135
251
|
# One-command setup: extension + CLAUDE.md + starter recipes
|
|
136
|
-
patchwork
|
|
252
|
+
patchwork init
|
|
137
253
|
|
|
138
254
|
# Explore
|
|
139
255
|
patchwork recipe list # installed recipes
|
|
@@ -173,7 +289,7 @@ The package ships these in `templates/recipes/`. Recipes that need API keys are
|
|
|
173
289
|
|
|
174
290
|
### Automation hooks
|
|
175
291
|
|
|
176
|
-
Event-driven hooks trigger Claude tasks automatically. Activate with `--automation --automation-policy <path.json> --
|
|
292
|
+
Event-driven hooks trigger Claude tasks automatically. Activate with `--automation --automation-policy <path.json> --driver subprocess`.
|
|
177
293
|
|
|
178
294
|
Key hooks:
|
|
179
295
|
|
|
@@ -225,7 +341,7 @@ Use whichever fits your mental model.
|
|
|
225
341
|
|
|
226
342
|
---
|
|
227
343
|
|
|
228
|
-
## Tool surface
|
|
344
|
+
## Tool surface
|
|
229
345
|
|
|
230
346
|
170+ MCP tools across 15 categories. Highlights:
|
|
231
347
|
|
|
@@ -296,7 +412,7 @@ Systemd service and deploy scripts in [`deploy/`](deploy/). Full guide: [docs/re
|
|
|
296
412
|
| 170+ MCP tools (LSP, git, tests, debugger, diagnostics) | **shipped** |
|
|
297
413
|
| VS Code / Cursor / Windsurf / Antigravity extension | **shipped** |
|
|
298
414
|
| JetBrains plugin (49 handlers) | **shipped** |
|
|
299
|
-
| `patchwork
|
|
415
|
+
| `patchwork init` — one-command setup | **shipped** |
|
|
300
416
|
| Terminal dashboard | **shipped** |
|
|
301
417
|
| Web oversight UI (approvals, sessions, recipes) | **shipped** |
|
|
302
418
|
| Recipe runner (YAML, cron, manual, webhook) | **shipped** |
|
|
@@ -320,11 +436,32 @@ npm install && npm run build
|
|
|
320
436
|
# Symlink installs break the macOS LaunchAgent (EPERM at startup)
|
|
321
437
|
npm pack
|
|
322
438
|
npm install -g patchwork-os-*.tgz
|
|
323
|
-
patchwork
|
|
439
|
+
patchwork init
|
|
324
440
|
```
|
|
325
441
|
|
|
326
442
|
---
|
|
327
443
|
|
|
444
|
+
## Telemetry
|
|
445
|
+
|
|
446
|
+
Patchwork ships an **opt-in** anonymous usage summary. It is **disabled by default** — the bridge sends nothing unless you explicitly turn it on.
|
|
447
|
+
|
|
448
|
+
**If you opt in**, on bridge shutdown an aggregate summary is POSTed to `https://analytics.claude-ide-bridge.dev/v1/usage`:
|
|
449
|
+
|
|
450
|
+
- Total session count and total tool-call count (no per-call payloads)
|
|
451
|
+
- Tool name → call count + median/p95 latency, capped at the top-N tools
|
|
452
|
+
- Bridge version, Node version, OS family (`darwin` / `linux` / `win32`)
|
|
453
|
+
- A per-install random salt (regenerated at any time by deleting `~/.claude/ide/analytics-salt`) used to coalesce repeated installs from the same machine without sending machine identifiers
|
|
454
|
+
|
|
455
|
+
**What is never sent:** workspace paths, file contents, prompts, tool arguments, tool output, project names, git history, credentials, IPs (transport-level only, dropped server-side), or anything from `~/.patchwork/`.
|
|
456
|
+
|
|
457
|
+
**How to opt in:** set `analyticsEnabled: true` in the dashboard's Settings panel, or write `{"enabled": true, "decidedAt": "<iso>"}` to `~/.claude/ide/analytics.json` (mode 0600).
|
|
458
|
+
|
|
459
|
+
**How to opt out / stay out:** do nothing. Default state is `null` (no preference) which behaves as opt-out. To explicitly opt out and silence future prompts, write `{"enabled": false, ...}` to the same file.
|
|
460
|
+
|
|
461
|
+
**Source:** [src/analyticsSend.ts](src/analyticsSend.ts), [src/analyticsAggregator.ts](src/analyticsAggregator.ts), [src/analyticsPrefs.ts](src/analyticsPrefs.ts) — endpoint is hardcoded (not runtime-configurable, by design, to prevent redirect attacks).
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
328
465
|
## Documentation
|
|
329
466
|
|
|
330
467
|
| Doc | Contents |
|
|
@@ -345,6 +482,13 @@ patchwork patchwork-init
|
|
|
345
482
|
|
|
346
483
|
---
|
|
347
484
|
|
|
485
|
+
## Support
|
|
486
|
+
|
|
487
|
+
- **Bugs & feature requests:** [GitHub Issues](https://github.com/Oolab-labs/patchwork-os/issues)
|
|
488
|
+
- **Questions & community:** [GitHub Discussions](https://github.com/Oolab-labs/patchwork-os/discussions)
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
348
492
|
## License
|
|
349
493
|
|
|
350
494
|
MIT © Oolab Labs
|
|
@@ -39,9 +39,17 @@ echo "==> Copying tarball to VPS..."
|
|
|
39
39
|
scp "$TARBALL" "$VPS:/tmp/patchwork-dashboard.tar.gz"
|
|
40
40
|
|
|
41
41
|
echo "==> Deploying on VPS..."
|
|
42
|
+
# Pass secrets as positional args (NOT inside the heredoc body) so the
|
|
43
|
+
# single-quoted heredoc still preserves remote-shell `$X` references but
|
|
44
|
+
# the operator's local env reaches the VPS. Without this, the previous
|
|
45
|
+
# `${PATCHWORK_BRIDGE_TOKEN:-REPLACE_ME}` inside the heredoc evaluated on
|
|
46
|
+
# the remote, where the var doesn't exist, and always wrote REPLACE_ME.
|
|
42
47
|
# shellcheck disable=SC2087
|
|
43
|
-
ssh "$VPS" bash <<'REMOTE'
|
|
48
|
+
ssh "$VPS" bash -s -- "${PATCHWORK_BRIDGE_TOKEN:-REPLACE_ME}" "${DASHBOARD_PASSWORD:-}" <<'REMOTE'
|
|
44
49
|
set -euo pipefail
|
|
50
|
+
# `${N:-}` so an empty/missing positional arg doesn't trip `set -u`.
|
|
51
|
+
PATCHWORK_BRIDGE_TOKEN="${1:-REPLACE_ME}"
|
|
52
|
+
DASHBOARD_PASSWORD="${2:-}"
|
|
45
53
|
REMOTE_DIR="/opt/patchwork-dashboard"
|
|
46
54
|
PM2_NAME="patchwork-dashboard"
|
|
47
55
|
PORT=3200
|
|
@@ -52,10 +60,26 @@ if pm2 list | grep -q "$PM2_NAME"; then
|
|
|
52
60
|
pm2 delete "$PM2_NAME" || true
|
|
53
61
|
fi
|
|
54
62
|
|
|
63
|
+
# Preserve .env.local across the deploy. Without this stash/restore, the
|
|
64
|
+
# `rm -rf "$REMOTE_DIR"` below blows away every secret the operator pasted
|
|
65
|
+
# (VAPID, PATCHWORK_PUSH_TOKEN, custom DASHBOARD_PASSWORD), and the "if
|
|
66
|
+
# already exists, preserve" branch later in this script never fires —
|
|
67
|
+
# the file no longer exists by then.
|
|
68
|
+
ENV_BACKUP=""
|
|
69
|
+
if [ -f "$REMOTE_DIR/.env.local" ]; then
|
|
70
|
+
ENV_BACKUP="$(mktemp /tmp/patchwork-env.XXXXXX)"
|
|
71
|
+
cp -p "$REMOTE_DIR/.env.local" "$ENV_BACKUP"
|
|
72
|
+
fi
|
|
73
|
+
|
|
55
74
|
# Wipe and recreate deploy dir
|
|
56
75
|
rm -rf "$REMOTE_DIR"
|
|
57
76
|
mkdir -p "$REMOTE_DIR"
|
|
58
77
|
|
|
78
|
+
if [ -n "$ENV_BACKUP" ] && [ -f "$ENV_BACKUP" ]; then
|
|
79
|
+
cp -p "$ENV_BACKUP" "$REMOTE_DIR/.env.local"
|
|
80
|
+
rm -f "$ENV_BACKUP"
|
|
81
|
+
fi
|
|
82
|
+
|
|
59
83
|
# Extract
|
|
60
84
|
tar -xzf /tmp/patchwork-dashboard.tar.gz -C "$REMOTE_DIR"
|
|
61
85
|
rm /tmp/patchwork-dashboard.tar.gz
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# macOS launchd setup for the bridge
|
|
2
|
+
|
|
3
|
+
Make the local `claude-ide-bridge` and the SSH reverse tunnel to your
|
|
4
|
+
self-hosted dashboard persistent on your Mac:
|
|
5
|
+
|
|
6
|
+
- Auto-start at login
|
|
7
|
+
- Auto-restart on crash (bridge has its own `--watch` supervisor; launchd
|
|
8
|
+
is the supervisor of the supervisor)
|
|
9
|
+
- Auto-reconnect on network change / sleep / wake (autossh)
|
|
10
|
+
- No tmux session to keep alive, no terminal to leave open
|
|
11
|
+
|
|
12
|
+
## One-time setup
|
|
13
|
+
|
|
14
|
+
1. **Install the patchwork CLI globally** (not via `npm link`). LaunchAgents
|
|
15
|
+
run in a tighter sandbox; symlinked installs into `~/Documents` /
|
|
16
|
+
`~/Desktop` / `~/Downloads` fail with `EPERM`:
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g patchwork-os
|
|
19
|
+
# or, from a local repo:
|
|
20
|
+
# npm pack && npm install -g patchwork-os-*.tgz
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
2. **Make sure you can SSH to the VPS without a password prompt.** The
|
|
24
|
+
tunnel runs unattended; if SSH would prompt for a key passphrase,
|
|
25
|
+
add the key to your agent (`ssh-add ~/.ssh/id_ed25519`) or use a
|
|
26
|
+
passphrase-less key.
|
|
27
|
+
|
|
28
|
+
3. **(Recommended) Pin the SSH target in `~/.ssh/config` first.** Using
|
|
29
|
+
the public domain as the SSH target is fragile — DNS drifts during
|
|
30
|
+
redeploys (CDN edges, transient IPs), so SSH lands on a different
|
|
31
|
+
machine and the host key changes. Add an alias once and use it
|
|
32
|
+
everywhere:
|
|
33
|
+
|
|
34
|
+
```ssh-config
|
|
35
|
+
# ~/.ssh/config
|
|
36
|
+
Host pw-bridge
|
|
37
|
+
HostName 185.167.97.141 # your VPS IP — stable across DNS shifts
|
|
38
|
+
User wesh # or root, whatever your VPS allows
|
|
39
|
+
IdentityFile ~/.ssh/id_ed25519
|
|
40
|
+
ServerAliveInterval 30
|
|
41
|
+
ServerAliveCountMax 3
|
|
42
|
+
UserKnownHostsFile ~/.ssh/known_hosts.patchwork
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Verify it works once: `ssh pw-bridge "echo ok"`. The host key is
|
|
46
|
+
accepted into the dedicated `known_hosts.patchwork` file and stays
|
|
47
|
+
there even if you `ssh-keygen -R` your global known_hosts later.
|
|
48
|
+
|
|
49
|
+
4. **Run the installer** with the alias (cleanest):
|
|
50
|
+
```bash
|
|
51
|
+
VPS_HOST=pw-bridge bash deploy/macos/install-mac-bridge.sh
|
|
52
|
+
```
|
|
53
|
+
The installer detects the alias via `ssh -G` and lets ssh_config
|
|
54
|
+
own user + identity + hostname resolution. On a VPS rebuild, you
|
|
55
|
+
only update `~/.ssh/config` — the LaunchAgents pick it up.
|
|
56
|
+
|
|
57
|
+
Without an alias (interactive, prompts for VPS host):
|
|
58
|
+
```bash
|
|
59
|
+
bash deploy/macos/install-mac-bridge.sh
|
|
60
|
+
# → prompts; recommend the IP (185.167.97.141) over the domain
|
|
61
|
+
```
|
|
62
|
+
Or fully env-driven:
|
|
63
|
+
```bash
|
|
64
|
+
VPS_HOST=185.167.97.141 VPS_USER=root \
|
|
65
|
+
BRIDGE_PORT=63906 VPS_PORT=3285 \
|
|
66
|
+
bash deploy/macos/install-mac-bridge.sh
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
5. **Sync the bridge token to the VPS** (the installer prints the exact
|
|
70
|
+
`ssh … sed … pm2 restart` command — copy-paste).
|
|
71
|
+
|
|
72
|
+
## What runs after install
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
~/Library/LaunchAgents/com.patchwork.bridge.plist
|
|
76
|
+
~/Library/LaunchAgents/com.patchwork.tunnel.plist
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Both are loaded into the per-user `gui/$UID` launchd domain at install
|
|
80
|
+
time and at every login.
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
[claude-ide-bridge --port 63906 --fixed-token <…> --watch]
|
|
84
|
+
│
|
|
85
|
+
│ 127.0.0.1:63906
|
|
86
|
+
▼
|
|
87
|
+
[autossh -R 127.0.0.1:3285:localhost:63906]
|
|
88
|
+
│
|
|
89
|
+
│ encrypted SSH reverse tunnel
|
|
90
|
+
▼
|
|
91
|
+
VPS:3285 ──── nginx ──── dashboard `/api/bridge/*`
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Logs
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
tail -f ~/Library/Logs/patchwork-bridge.log
|
|
98
|
+
tail -f ~/Library/Logs/patchwork-tunnel.log
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Status
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
launchctl print gui/$UID/com.patchwork.bridge
|
|
105
|
+
launchctl print gui/$UID/com.patchwork.tunnel
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Restart manually
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
launchctl kickstart -k gui/$UID/com.patchwork.bridge
|
|
112
|
+
launchctl kickstart -k gui/$UID/com.patchwork.tunnel
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Uninstall
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
bash deploy/macos/uninstall-mac-bridge.sh
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Troubleshooting
|
|
122
|
+
|
|
123
|
+
- **`com.patchwork.bridge` exits with status 78 / `EPERM`** — the bridge
|
|
124
|
+
CLI is installed via `npm link` and points into `~/Documents`. The
|
|
125
|
+
macOS sandbox blocks LaunchAgents from reading that tree. Reinstall
|
|
126
|
+
globally as a real package (see step 1).
|
|
127
|
+
- **`com.patchwork.tunnel` keeps respawning** — check the SSH key is
|
|
128
|
+
added to `ssh-agent` (`ssh-add -l`). LaunchAgents run before the
|
|
129
|
+
user's shell rc, so an interactive `ssh-add` from `.zshrc` doesn't
|
|
130
|
+
apply. Use a passphrase-less key, or store the key in macOS Keychain
|
|
131
|
+
with `ssh-add --apple-use-keychain`.
|
|
132
|
+
- **Tunnel succeeds but dashboard says offline** — VPS port already in
|
|
133
|
+
use by an old leftover bridge. SSH to the VPS and `pkill -f "autossh\|sshd: .*\@notty"`,
|
|
134
|
+
or pick a different `VPS_PORT`.
|
|
135
|
+
- **Dashboard 401s on every bridge call** — `PATCHWORK_BRIDGE_TOKEN`
|
|
136
|
+
on the VPS doesn't match the `--fixed-token` value the bridge is
|
|
137
|
+
using. Re-run the install script's printed `sed … pm2 restart`
|
|
138
|
+
command.
|
|
139
|
+
- **`Host key for X has changed and you have requested strict
|
|
140
|
+
checking`** every now and then — the SSH target is moving. Two
|
|
141
|
+
causes:
|
|
142
|
+
1. **DNS drift.** The public domain resolves to a different IP than
|
|
143
|
+
it did last time (CDN edge, redeploy churn). `dig +short
|
|
144
|
+
bridge.your.tld` vs your known VPS IP — if those differ, switch
|
|
145
|
+
the `VPS_HOST` to the IP or a `~/.ssh/config` alias and re-run
|
|
146
|
+
the installer.
|
|
147
|
+
2. **VPS rebuild.** A reimage regenerates `/etc/ssh/ssh_host_*_key`
|
|
148
|
+
files. Either back them up before the rebuild and restore after,
|
|
149
|
+
or accept the new key once with `ssh-keygen -R <host> && ssh
|
|
150
|
+
<host>`. The launchd tunnel uses `StrictHostKeyChecking=accept-new`
|
|
151
|
+
(only auto-trusts on first connect, not after change), so you'll
|
|
152
|
+
see the warning, accept the new key interactively once, and the
|
|
153
|
+
tunnel resumes.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string>com.patchwork.bridge</string>
|
|
7
|
+
|
|
8
|
+
<key>ProgramArguments</key>
|
|
9
|
+
<array>
|
|
10
|
+
<string>{{BRIDGE_BIN}}</string>
|
|
11
|
+
<string>--port</string>
|
|
12
|
+
<string>{{BRIDGE_PORT}}</string>
|
|
13
|
+
<string>--fixed-token</string>
|
|
14
|
+
<string>{{BRIDGE_TOKEN}}</string>
|
|
15
|
+
<string>--watch</string>
|
|
16
|
+
<string>--workspace</string>
|
|
17
|
+
<string>{{WORKSPACE}}</string>
|
|
18
|
+
</array>
|
|
19
|
+
|
|
20
|
+
<key>RunAtLoad</key>
|
|
21
|
+
<true/>
|
|
22
|
+
<!-- KeepAlive is redundant with `--watch` (which has its own
|
|
23
|
+
exponential-backoff supervisor and recovers from crashes faster
|
|
24
|
+
than launchd's per-second relaunch). Leave it true as belt-and-
|
|
25
|
+
suspenders in case `--watch` itself dies (its supervisor process
|
|
26
|
+
is a single Node, and that's the one launchd is keeping alive). -->
|
|
27
|
+
<key>KeepAlive</key>
|
|
28
|
+
<true/>
|
|
29
|
+
|
|
30
|
+
<key>StandardOutPath</key>
|
|
31
|
+
<string>{{HOME}}/Library/Logs/patchwork-bridge.log</string>
|
|
32
|
+
<key>StandardErrorPath</key>
|
|
33
|
+
<string>{{HOME}}/Library/Logs/patchwork-bridge.log</string>
|
|
34
|
+
|
|
35
|
+
<key>WorkingDirectory</key>
|
|
36
|
+
<string>{{WORKSPACE}}</string>
|
|
37
|
+
|
|
38
|
+
<key>EnvironmentVariables</key>
|
|
39
|
+
<dict>
|
|
40
|
+
<!-- launchd's default PATH doesn't include Homebrew. Bridge spawns
|
|
41
|
+
child processes (claude CLI, git, npm) via PATH lookup, so
|
|
42
|
+
missing /opt/homebrew/bin breaks half the tools. -->
|
|
43
|
+
<key>PATH</key>
|
|
44
|
+
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
|
|
45
|
+
<key>HOME</key>
|
|
46
|
+
<string>{{HOME}}</string>
|
|
47
|
+
</dict>
|
|
48
|
+
|
|
49
|
+
<!-- Throttle: don't relaunch faster than every 10 s on rapid crash
|
|
50
|
+
loops, prevents spinning up if the binary is broken. -->
|
|
51
|
+
<key>ThrottleInterval</key>
|
|
52
|
+
<integer>10</integer>
|
|
53
|
+
</dict>
|
|
54
|
+
</plist>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>Label</key>
|
|
6
|
+
<string>com.patchwork.tunnel</string>
|
|
7
|
+
|
|
8
|
+
<key>ProgramArguments</key>
|
|
9
|
+
<array>
|
|
10
|
+
<string>{{AUTOSSH_BIN}}</string>
|
|
11
|
+
<!-- AUTOSSH_PORT=0 disables the legacy monitoring-port heartbeat in
|
|
12
|
+
favor of SSH's own ServerAliveInterval/CountMax. Modern autossh
|
|
13
|
+
docs recommend this; the monitoring port is unreliable behind
|
|
14
|
+
NAT and consumes another tunnel slot. -->
|
|
15
|
+
<string>-M</string>
|
|
16
|
+
<string>0</string>
|
|
17
|
+
<!-- -N: no remote command -T: no pseudo-tty -->
|
|
18
|
+
<string>-N</string>
|
|
19
|
+
<string>-T</string>
|
|
20
|
+
<string>-R</string>
|
|
21
|
+
<string>127.0.0.1:{{VPS_PORT}}:localhost:{{BRIDGE_PORT}}</string>
|
|
22
|
+
<!-- ServerAliveInterval=30 + CountMax=3 = ssh kills the link if
|
|
23
|
+
the server doesn't respond for 90 s, autossh restarts. Critical
|
|
24
|
+
for laptop sleep/wake and Wi-Fi switches. -->
|
|
25
|
+
<string>-o</string>
|
|
26
|
+
<string>ServerAliveInterval=30</string>
|
|
27
|
+
<string>-o</string>
|
|
28
|
+
<string>ServerAliveCountMax=3</string>
|
|
29
|
+
<!-- ExitOnForwardFailure=yes makes autossh exit + retry if the
|
|
30
|
+
remote port is already bound. Otherwise the tunnel "succeeds"
|
|
31
|
+
but no traffic flows. -->
|
|
32
|
+
<string>-o</string>
|
|
33
|
+
<string>ExitOnForwardFailure=yes</string>
|
|
34
|
+
<!-- Don't auto-add new host keys (security: surface key changes
|
|
35
|
+
instead of silently trusting). Initial setup expects the user
|
|
36
|
+
to have already SSH'd at least once and accepted the key. -->
|
|
37
|
+
<string>-o</string>
|
|
38
|
+
<string>StrictHostKeyChecking=accept-new</string>
|
|
39
|
+
<string>-i</string>
|
|
40
|
+
<string>{{SSH_KEY}}</string>
|
|
41
|
+
<!-- SSH_TARGET is rendered by install-mac-bridge.sh:
|
|
42
|
+
- "user@host" form when host is an IP or hostname
|
|
43
|
+
- bare alias when host matches a `~/.ssh/config` Host entry
|
|
44
|
+
(so ssh_config's User + HostName + IdentityFile resolution
|
|
45
|
+
works as designed; passing user@alias would override the
|
|
46
|
+
config's User directive and confuse the alias case). -->
|
|
47
|
+
<string>{{SSH_TARGET}}</string>
|
|
48
|
+
</array>
|
|
49
|
+
|
|
50
|
+
<key>RunAtLoad</key>
|
|
51
|
+
<true/>
|
|
52
|
+
<key>KeepAlive</key>
|
|
53
|
+
<true/>
|
|
54
|
+
|
|
55
|
+
<key>StandardOutPath</key>
|
|
56
|
+
<string>{{HOME}}/Library/Logs/patchwork-tunnel.log</string>
|
|
57
|
+
<key>StandardErrorPath</key>
|
|
58
|
+
<string>{{HOME}}/Library/Logs/patchwork-tunnel.log</string>
|
|
59
|
+
|
|
60
|
+
<key>EnvironmentVariables</key>
|
|
61
|
+
<dict>
|
|
62
|
+
<key>PATH</key>
|
|
63
|
+
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
|
|
64
|
+
<key>HOME</key>
|
|
65
|
+
<string>{{HOME}}</string>
|
|
66
|
+
<!-- AUTOSSH_GATETIME=0: don't require a "stable" connection time
|
|
67
|
+
before counting reconnect attempts. Default 30 s makes startup
|
|
68
|
+
after a long sleep slower than necessary. -->
|
|
69
|
+
<key>AUTOSSH_GATETIME</key>
|
|
70
|
+
<string>0</string>
|
|
71
|
+
</dict>
|
|
72
|
+
|
|
73
|
+
<key>ThrottleInterval</key>
|
|
74
|
+
<integer>10</integer>
|
|
75
|
+
</dict>
|
|
76
|
+
</plist>
|