@work-bridge/work-bridge 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 jaeyoung0509
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,358 @@
1
+ # work-bridge
2
+
3
+ > **Switching between Claude Code, Gemini CLI, OpenCode, and Codex due to LLM cost?**
4
+ > Bring your session context, MCP configs, and skills with you — instantly.
5
+
6
+ `work-bridge` is a local-first portability layer for AI coding-agent workflows. It inspects your current sessions, skills, and MCP server configs across all major tools, then exports a portable bundle that any other tool can pick up from where you left off.
7
+
8
+ [![Go Version](https://img.shields.io/badge/Go-1.21+-00ADD8?style=flat&logo=go)](https://golang.org)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
10
+ [![npm](https://img.shields.io/npm/v/%40work-bridge%2Fwork-bridge?color=cb3837&logo=npm)](https://www.npmjs.com/package/@work-bridge/work-bridge)
11
+
12
+ ---
13
+
14
+ ## Why work-bridge?
15
+
16
+ Modern AI coding agents store their state in incompatible formats:
17
+
18
+ | What you lose when switching tools | What work-bridge preserves |
19
+ |------------------------------------|---------------------------|
20
+ | Current task title & goal | ✅ Task title & current goal |
21
+ | Session summary & decisions | ✅ Summary, decisions, failures |
22
+ | Project instruction files (AGENTS.md, CLAUDE.md, GEMINI.md…) | ✅ All instruction artifacts |
23
+ | MCP server configurations | ✅ Inspected & validated MCP configs |
24
+ | Portable settings (non-sensitive) | ✅ Settings snapshot (secrets stripped) |
25
+ | Touched files & tool events | ✅ File touch history & event log |
26
+
27
+ ---
28
+
29
+ ## Supported Tools
30
+
31
+ | Tool | Import | Export | MCP | Skills |
32
+ |------|:------:|:------:|:---:|:------:|
33
+ | **Claude Code** | ✅ | ✅ | ✅ | ✅ |
34
+ | **Gemini CLI** | ✅ | ✅ | ✅ | ✅ |
35
+ | **OpenCode** | ✅ | ✅ | ✅ | ✅ |
36
+ | **Codex CLI** | ✅ | ✅ | ✅ | ✅ |
37
+
38
+ ---
39
+
40
+ ## Quick Start
41
+
42
+ ### Install via npm (recommended)
43
+
44
+ ```bash
45
+ npm install -g @work-bridge/work-bridge
46
+ work-bridge
47
+ ```
48
+
49
+ ### Install via Go
50
+
51
+ ```bash
52
+ go install github.com/jaeyoung0509/work-bridge/cmd/work-bridge@latest
53
+ ```
54
+
55
+ ### Download binary
56
+
57
+ Grab the latest release binary from [GitHub Releases](https://github.com/jaeyoung0509/work-bridge/releases).
58
+
59
+ ---
60
+
61
+ ## Usage
62
+
63
+ ### TUI (Interactive Mode)
64
+
65
+ Just run `work-bridge` in your terminal for the full interactive experience:
66
+
67
+ ```bash
68
+ work-bridge
69
+ ```
70
+
71
+ The TUI provides five panels:
72
+
73
+ | Panel | What it does |
74
+ |-------|-------------|
75
+ | **Sessions** | Browse, inspect, import, doctor-check, and export sessions |
76
+ | **Projects** | Index project roots from configured workspace roots |
77
+ | **Skills** | Compare project/user/global skill coverage and sync across scopes |
78
+ | **MCP** | Inspect config locations, merge effective scope, and run runtime validation |
79
+ | **Logs** | View recent workspace actions and errors |
80
+
81
+ **Mouse support:** pane focus · list selection · preview tab switching · scroll
82
+
83
+ ### Migration Workflow
84
+
85
+ ```
86
+ You were using Claude Code → now switching to Gemini CLI
87
+ ```
88
+
89
+ ```bash
90
+ # 1. Inspect what Claude Code has
91
+ work-bridge inspect claude --limit 5
92
+
93
+ # 2. Import the latest session into a portable bundle
94
+ work-bridge import --from claude --session latest --out ./bundle.json
95
+
96
+ # 3. Check compatibility with the target tool
97
+ work-bridge doctor --from claude --session latest --target gemini
98
+
99
+ # 4. Export target-native artifacts
100
+ work-bridge export --bundle ./bundle.json --target gemini --out ./out/
101
+
102
+ # 5. Start Gemini CLI — it'll pick up GEMINI.work-bridge.md automatically
103
+ cd ./out && gemini
104
+ ```
105
+
106
+ The exported `./out/` directory contains:
107
+
108
+ - `GEMINI.work-bridge.md` — context supplement injected into Gemini CLI
109
+ - `SETTINGS_PATCH.json` — portable settings to apply
110
+ - `STARTER_PROMPT.md` — copy-paste prompt to resume your task
111
+ - `manifest.json` — export manifest with portability warnings
112
+
113
+ ### Pack / Unpack (Portable Archives)
114
+
115
+ Share your session state across machines or teammates:
116
+
117
+ ```bash
118
+ # Pack a session into a portable .spkg archive
119
+ work-bridge pack --from claude --session latest --out ./my-session.spkg
120
+
121
+ # Unpack on another machine and target a different tool
122
+ work-bridge unpack --file ./my-session.spkg --target codex --out ./out/
123
+ ```
124
+
125
+ ### Detect
126
+
127
+ ```bash
128
+ # Auto-detect all installed tools and project artifacts
129
+ work-bridge detect
130
+ ```
131
+
132
+ ### CLI Reference
133
+
134
+ ```
135
+ work-bridge [flags]
136
+ work-bridge detect
137
+ work-bridge inspect <tool> [--limit N]
138
+ work-bridge import --from <tool> [--session <id|latest>] [--out <path>]
139
+ work-bridge doctor --from <tool> [--session <id|latest>] --target <tool>
140
+ work-bridge export --bundle <path> --target <tool> [--out <dir>]
141
+ work-bridge pack --from <tool> [--session <id|latest>] --out <path>
142
+ work-bridge unpack --file <path> --target <tool> [--out <dir>]
143
+ work-bridge version
144
+ ```
145
+
146
+ **Supported tools:** `claude` · `gemini` · `codex` · `opencode`
147
+
148
+ ---
149
+
150
+ ## How It Works
151
+
152
+ ```
153
+ ┌─────────────────────────────────────────────────────────────────┐
154
+ │ work-bridge │
155
+ │ │
156
+ │ detect/ ──► inspect/ ──► importer/ ──► domain.SessionBundle │
157
+ │ │ │
158
+ │ doctor/ │
159
+ │ (compatibility check) │
160
+ │ │ │
161
+ │ exporter/ │
162
+ │ (target-native artifacts) │
163
+ └─────────────────────────────────────────────────────────────────┘
164
+
165
+ SessionBundle fields:
166
+ source_tool · source_session_id · project_root
167
+ task_title · current_goal · summary
168
+ instruction_artifacts (AGENTS.md, CLAUDE.md, GEMINI.md …)
169
+ settings_snapshot (sensitive keys redacted automatically)
170
+ tool_events · touched_files
171
+ decisions · failures · resume_hints
172
+ token_stats · provenance · redactions
173
+ ```
174
+
175
+ ### Security & Redaction
176
+
177
+ `work-bridge` automatically strips sensitive values during import:
178
+
179
+ - Key-based: `secret`, `token`, `password`, `auth`, `oauth`, `credential`, `api_key`, `apikey`
180
+ - Value-based heuristics: `sk-*`, `ghp_*`, `github_pat_*`, `AIza*` prefixes, and long random-looking strings
181
+ - Redacted fields are listed in `bundle.redactions` for transparency — nothing is silently dropped
182
+
183
+ ---
184
+
185
+ ## MCP Validation
186
+
187
+ The **MCP** panel (and `inspect` output) runs a real runtime handshake for supported transports:
188
+
189
+ 1. Spawns the server process (stdio) or connects (HTTP / SSE)
190
+ 2. Sends `initialize` → waits for capability response
191
+ 3. Sends `notifications/initialized`
192
+ 4. Counts advertised `resources`, `resourceTemplates`, `tools`, and `prompts`
193
+
194
+ This catches config problems that a static lint pass would miss.
195
+
196
+ ---
197
+
198
+ ## Configuration
199
+
200
+ Configuration is resolved in this priority order:
201
+
202
+ 1. CLI flags
203
+ 2. Environment variables (`WORK_BRIDGE_` prefix)
204
+ 3. `--config <file>`
205
+ 4. Auto-discovered config in CWD → then home directory
206
+ 5. Built-in defaults
207
+
208
+ ### Supported Config Files
209
+
210
+ - `.work-bridge.yaml` / `.work-bridge.yml`
211
+ - `.work-bridge.toml`
212
+ - `.work-bridge.json`
213
+
214
+ ### Key Config Fields
215
+
216
+ ```yaml
217
+ # .work-bridge.yaml
218
+ workspace_roots:
219
+ - ~/Projects
220
+ - ~/work
221
+
222
+ paths:
223
+ codex: ~/.local/share/codex
224
+ gemini: ~/.config/gemini
225
+ claude: ~/.claude
226
+ opencode: ~/.config/opencode
227
+
228
+ output:
229
+ export_dir: ./out/work-bridge
230
+ package_path: ./session.spkg
231
+ unpack_dir: ./out/unpacked
232
+
233
+ redaction:
234
+ detect_sensitive_values: true
235
+ additional_sensitive_keys:
236
+ - my_internal_token
237
+ ```
238
+
239
+ ### JSON Example
240
+
241
+ ```json
242
+ {
243
+ "format": "json",
244
+ "workspace_roots": ["~/Projects", "~/work"],
245
+ "paths": {
246
+ "codex": "/Users/me/.local/share/codex"
247
+ },
248
+ "output": {
249
+ "export_dir": "./out/work-bridge"
250
+ }
251
+ }
252
+ ```
253
+
254
+ ### Environment Variables
255
+
256
+ | Variable | Config Key |
257
+ |----------|-----------|
258
+ | `WORK_BRIDGE_FORMAT` | `format` |
259
+ | `WORK_BRIDGE_WORKSPACE_ROOTS` | `workspace_roots` |
260
+ | `WORK_BRIDGE_PATHS_CODEX` | `paths.codex` |
261
+ | `WORK_BRIDGE_PATHS_GEMINI` | `paths.gemini` |
262
+ | `WORK_BRIDGE_PATHS_CLAUDE` | `paths.claude` |
263
+ | `WORK_BRIDGE_PATHS_OPENCODE` | `paths.opencode` |
264
+ | `WORK_BRIDGE_OUTPUT_EXPORT_DIR` | `output.export_dir` |
265
+
266
+ ---
267
+
268
+ ## Repository Layout
269
+
270
+ ```
271
+ cmd/work-bridge/ CLI entrypoint (main.go)
272
+ internal/
273
+ cli/ Cobra/Viper root command, TUI backend wiring
274
+ app.go App struct, Run(), Config
275
+ root_tui.go TUI launch logic and Backend wiring
276
+ legacy_commands.go detect/inspect/import/doctor/export commands
277
+ package_commands.go pack/unpack commands
278
+ root_tui_backend.go All TUI backend action implementations
279
+ tui/ Bubble Tea v2 interactive workspace
280
+ domain/ Portable bundle types (SessionBundle, Tool, …)
281
+ importer/ Tool-specific session importers
282
+ claude.go / codex.go / gemini.go / opencode.go
283
+ normalizer.go Signal extraction & normalization
284
+ signals.go Decision/failure/hint signal detection
285
+ exporter/ Target-native artifact generation
286
+ detect/ Tool installation & project artifact detection
287
+ inspect/ Session listing for each tool
288
+ doctor/ Cross-tool compatibility analysis
289
+ catalog/ Skills catalog (project/user/global scopes)
290
+ capability/ MCP capability registry
291
+ packagex/ .spkg pack/unpack (zip-based)
292
+ platform/ FS, clock, archive, env, redact utilities
293
+ testdata/ Fixtures and golden outputs
294
+ scripts/
295
+ install.cjs npm postinstall binary downloader
296
+ ```
297
+
298
+ ---
299
+
300
+ ## Building from Source
301
+
302
+ ```bash
303
+ git clone https://github.com/jaeyoung0509/work-bridge.git
304
+ cd work-bridge
305
+
306
+ # Build
307
+ make build
308
+ ./bin/work-bridge
309
+
310
+ # Test
311
+ make test
312
+
313
+ # Lint
314
+ make lint
315
+
316
+ # Format
317
+ make fmt
318
+ ```
319
+
320
+ **Requirements:** Go 1.21+
321
+
322
+ ---
323
+
324
+ ## Publishing a Release
325
+
326
+ Releases use [GoReleaser](https://goreleaser.com/). A GitHub Actions workflow triggers on version tags:
327
+
328
+ ```bash
329
+ git tag v0.1.0
330
+ git push origin v0.1.0
331
+ ```
332
+
333
+ GoReleaser builds cross-platform binaries (`darwin/amd64`, `darwin/arm64`, `linux/amd64`, `linux/arm64`, `windows/amd64`, `windows/arm64`) and uploads them as `.tar.gz` / `.zip` archives to the GitHub Release.
334
+
335
+ The npm package wrapper then downloads the correct binary at install time via `scripts/install.cjs`.
336
+
337
+ ---
338
+
339
+ ## Contributing
340
+
341
+ See [CONTRIBUTING.md](./CONTRIBUTING.md).
342
+
343
+ **Good first areas:**
344
+ - Add a new tool importer under `internal/importer/`
345
+ - Extend `internal/exporter/` with a new target format
346
+ - Improve MCP runtime validation for new transport types
347
+ - Add fixture-backed tests for edge cases
348
+
349
+ Principles:
350
+ - Local-first, no network calls during normal operation
351
+ - Deterministic output for fixture-backed tests
352
+ - Sensitive data must never leave the machine unredacted
353
+
354
+ ---
355
+
356
+ ## License
357
+
358
+ MIT © [jaeyoung0509](https://github.com/jaeyoung0509)
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawnSync } = require('node:child_process');
4
+ const { existsSync } = require('node:fs');
5
+ const { join } = require('node:path');
6
+
7
+ const binary = join(__dirname, 'work-bridge');
8
+
9
+ if (!existsSync(binary)) {
10
+ console.error('work-bridge binary is not installed yet. Re-run npm install or check the release assets.');
11
+ process.exit(1);
12
+ }
13
+
14
+ const result = spawnSync(binary, process.argv.slice(2), { stdio: 'inherit' });
15
+ process.exit(result.status ?? 1);
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@work-bridge/work-bridge",
3
+ "version": "0.1.0",
4
+ "description": "Portable session migration CLI for Claude Code, Gemini CLI, OpenCode, and Codex CLI.",
5
+ "homepage": "https://github.com/jaeyoung0509/work-bridge",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/jaeyoung0509/work-bridge.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/jaeyoung0509/work-bridge/issues"
12
+ },
13
+ "keywords": [
14
+ "claude",
15
+ "gemini",
16
+ "codex",
17
+ "opencode",
18
+ "mcp",
19
+ "session",
20
+ "migration",
21
+ "ai",
22
+ "coding-agent",
23
+ "tui"
24
+ ],
25
+ "license": "MIT",
26
+ "bin": {
27
+ "work-bridge": "bin/work-bridge.js"
28
+ },
29
+ "scripts": {
30
+ "postinstall": "node scripts/install.cjs"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "files": [
36
+ "bin/work-bridge.js",
37
+ "scripts/install.cjs"
38
+ ],
39
+ "engines": {
40
+ "node": ">=20"
41
+ }
42
+ }
@@ -0,0 +1,105 @@
1
+ const fs = require('node:fs');
2
+ const os = require('node:os');
3
+ const path = require('node:path');
4
+ const https = require('node:https');
5
+ const { spawnSync } = require('node:child_process');
6
+
7
+ const pkgRoot = path.resolve(__dirname, '..');
8
+ const vendorDir = path.join(pkgRoot, 'bin');
9
+ const binaryName = process.platform === 'win32' ? 'work-bridge.exe' : 'work-bridge';
10
+
11
+ const repo =
12
+ process.env.WORK_BRIDGE_GITHUB_REPO ||
13
+ process.env.npm_package_repository_url ||
14
+ process.env.npm_package_repository ||
15
+ '';
16
+ const releaseTag = process.env.WORK_BRIDGE_VERSION || process.env.npm_package_version || 'latest';
17
+
18
+ if (!repo) {
19
+ console.warn('[work-bridge] WORK_BRIDGE_GITHUB_REPO is not set; skipping binary download.');
20
+ process.exit(0);
21
+ }
22
+
23
+ const [owner, name] = repo.replace(/^git\+https:\/\/github.com\//, '').replace(/^https:\/\/github.com\//, '').replace(/\.git$/, '').split('/').slice(-2);
24
+ if (!owner || !name) {
25
+ console.warn('[work-bridge] Could not parse GitHub repository from WORK_BRIDGE_GITHUB_REPO; skipping binary download.');
26
+ process.exit(0);
27
+ }
28
+
29
+ const platform = platformId(process.platform);
30
+ const arch = archId(process.arch);
31
+ if (!platform || !arch) {
32
+ console.warn(`[work-bridge] Unsupported platform ${process.platform}/${process.arch}; skipping binary download.`);
33
+ process.exit(0);
34
+ }
35
+
36
+ const assetName = `work-bridge_${platform}_${arch}.tar.gz`;
37
+ const url = `https://github.com/${owner}/${name}/releases/download/${releaseTag}/${assetName}`;
38
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'work-bridge-'));
39
+ const archivePath = path.join(tmpDir, assetName);
40
+
41
+ download(url, archivePath, (err) => {
42
+ if (err) {
43
+ console.warn(`[work-bridge] Download failed: ${err.message}`);
44
+ process.exit(0);
45
+ }
46
+
47
+ fs.mkdirSync(vendorDir, { recursive: true });
48
+ const extract = spawnSync('tar', ['-xzf', archivePath, '-C', vendorDir], { stdio: 'inherit' });
49
+ if (extract.status !== 0) {
50
+ console.warn('[work-bridge] Extraction failed; the wrapper will remain inert until a successful reinstall.');
51
+ process.exit(0);
52
+ }
53
+
54
+ const extractedBinary = path.join(vendorDir, binaryName);
55
+ if (process.platform !== 'win32' && fs.existsSync(extractedBinary)) {
56
+ fs.chmodSync(extractedBinary, 0o755);
57
+ }
58
+ process.exit(0);
59
+ });
60
+
61
+ function download(url, dest, done) {
62
+ const file = fs.createWriteStream(dest);
63
+ const request = https.get(url, (response) => {
64
+ if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
65
+ file.close();
66
+ return download(response.headers.location, dest, done);
67
+ }
68
+ if (response.statusCode !== 200) {
69
+ file.close();
70
+ return done(new Error(`unexpected status ${response.statusCode}`));
71
+ }
72
+ response.pipe(file);
73
+ file.on('finish', () => {
74
+ file.close(done);
75
+ });
76
+ });
77
+
78
+ request.on('error', (err) => {
79
+ file.close();
80
+ done(err);
81
+ });
82
+ }
83
+
84
+ function platformId(platform) {
85
+ switch (platform) {
86
+ case 'darwin':
87
+ case 'linux':
88
+ return platform;
89
+ case 'win32':
90
+ return 'windows';
91
+ default:
92
+ return '';
93
+ }
94
+ }
95
+
96
+ function archId(arch) {
97
+ switch (arch) {
98
+ case 'x64':
99
+ return 'amd64';
100
+ case 'arm64':
101
+ return 'arm64';
102
+ default:
103
+ return '';
104
+ }
105
+ }