@openchambery/web 1.17.1-beta.7 → 1.17.1-beta.8
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.md +3 -39
- package/bin/cli-output.js +0 -16
- package/bin/cli.js +3 -66
- package/bin/cli.test.js +4 -81
- package/bin/lib/DOCUMENTATION.md +5 -19
- package/bin/lib/cli-args.js +3 -327
- package/bin/lib/cli-http.js +0 -16
- package/bin/lib/cli-lifecycle.js +2 -111
- package/bin/lib/cli-paths.js +0 -57
- package/dist/assets/{AgentAvatar-htFrIvQx.js → AgentAvatar-C6Hxu5_o.js} +1 -1
- package/dist/assets/{AssistantView-BZiJsNuI.js → AssistantView-ZlXc0xFT.js} +1 -1
- package/dist/assets/{ChatContainer-CdmcMnL3.js → ChatContainer-BXFy3Uu2.js} +5 -5
- package/dist/assets/{DiagramView-B7sq74V-.js → DiagramView-CgotrQyK.js} +1 -1
- package/dist/assets/{FadeInOnReveal-8fY7XL23.js → FadeInOnReveal-CvNA_aGD.js} +1 -1
- package/dist/assets/{Icon-B7eLbnyj.js → Icon-BPJ_quEe.js} +1 -1
- package/dist/assets/{MarkdownRendererImpl-DICju9ve.js → MarkdownRendererImpl-Cj4y0P0S.js} +1 -1
- package/dist/assets/{MobileDetailNavigation-CuxWU1yf.js → MobileDetailNavigation-5tAL5d_M.js} +1 -1
- package/dist/assets/{MobileShareBridge-CPg9Eyro.js → MobileShareBridge-BL7Ehxhd.js} +1 -1
- package/dist/assets/{MobileSurface-D7sDH_tx.js → MobileSurface-ByMnQ5rD.js} +1 -1
- package/dist/assets/{MultiRunWindow-MSO0Equt.js → MultiRunWindow-Che7L3TX.js} +1 -1
- package/dist/assets/{OnboardingScreen-C87u_MLg.js → OnboardingScreen-CdvaEBtt.js} +1 -1
- package/dist/assets/{OverlayScrollbar-Kmmybw-z.js → OverlayScrollbar-C2pEDFq-.js} +1 -1
- package/dist/assets/SettingsView-D0p-e8Px.js +25 -0
- package/dist/assets/{SettingsWindow-Bl25cfXX.js → SettingsWindow-KYhsFUrb.js} +1 -1
- package/dist/assets/{TerminalView-jR5jP1b0.js → TerminalView-Da5aLqHR.js} +1 -1
- package/dist/assets/{ToolOutputDialog-DCEZb2DZ.js → ToolOutputDialog-DZI4uxx3.js} +1 -1
- package/dist/assets/{appThemeRegistry-aiRF-s3c.js → appThemeRegistry-DAgBeFsZ.js} +2 -2
- package/dist/assets/{button-bYWkDtDI.js → button-BmNJBT13.js} +1 -1
- package/dist/assets/{clipboard-CzpzN4Um.js → clipboard-CXWbHCAk.js} +1 -1
- package/dist/assets/{collapsible-A1PFvMRp.js → collapsible-68IqWBM1.js} +1 -1
- package/dist/assets/{context-menu-CkpHn-Bm.js → context-menu-BXH0AcOc.js} +1 -1
- package/dist/assets/desktopHosts-BpjUSDz4.js +1 -0
- package/dist/assets/{desktopRelayRestore-C5vYnSTd.js → desktopRelayRestore-BzUEk1i7.js} +1 -1
- package/dist/assets/{diagram-BkwKWaTO.js → diagram-YN0GZ1Q0.js} +1 -1
- package/dist/assets/{dialog-DW7-_iqo.js → dialog-BV1ENlLf.js} +1 -1
- package/dist/assets/es-EXZUX1sB.js +15 -0
- package/dist/assets/{fileQueries-P9SX4YwC.js → fileQueries-i4oziMnC.js} +1 -1
- package/dist/assets/fr-jWNPO91J.js +13 -0
- package/dist/assets/{gitApi-CMsZ2v08.js → gitApi-BW5AFgD1.js} +1 -1
- package/dist/assets/{gitApiHttp-DvIIcDAO.js → gitApiHttp-C1DaEMKR.js} +1 -1
- package/dist/assets/{input-B9aNttqV.js → input-BLVhPvhN.js} +1 -1
- package/dist/assets/{insertionBoundaries-Di3rCXgN.js → insertionBoundaries-D4KbXFFj.js} +1 -1
- package/dist/assets/ja-Dcb0VtDE.js +15 -0
- package/dist/assets/ko-CX71xNDX.js +15 -0
- package/dist/assets/{main-DY27kMV5.js → main-CcyyPAib.js} +2 -2
- package/dist/assets/{main-Chtf300b.js → main-DzxdsF_k.js} +5 -5
- package/dist/assets/{markdown-worker-BoB1_DPo.js → markdown-worker-Cq3Twp1A.js} +1 -1
- package/dist/assets/{markdownTheme-om5XcPqq.js → markdownTheme-CCnvI6L0.js} +1 -1
- package/dist/assets/{miniChat-BWbpl5SN.js → miniChat-BsNf9y48.js} +2 -2
- package/dist/assets/mobile-CsJg2IAq.js +2 -0
- package/dist/assets/{multirun-BfPcVktg.js → multirun-qs5hZkwM.js} +1 -1
- package/dist/assets/persistence-C_KCiMcY.js +3 -0
- package/dist/assets/{pl-BSjLn4dm.js → pl-mR_3Sqr8.js} +2 -2
- package/dist/assets/{projectMeta-CiAR7MRG.js → projectMeta-1SSTNg8w.js} +1 -1
- package/dist/assets/pt-BR-D1RpVOvC.js +15 -0
- package/dist/assets/radio-DBJG9Dd1.js +1 -0
- package/dist/assets/{renderElectronMiniChatApp-CiEXAVSt.js → renderElectronMiniChatApp-DOWE0jSA.js} +2 -2
- package/dist/assets/{renderMobileApp-BHvgSVPk.js → renderMobileApp-bklJJSZi.js} +3 -3
- package/dist/assets/{runtimeConfig-49YbZaqI.js → runtimeConfig-JSaYFA5x.js} +1 -1
- package/dist/assets/{runtimeEndpointReset-CdhtjuPe.js → runtimeEndpointReset-ix1NxqYw.js} +1 -1
- package/dist/assets/{sortable-tabs-strip-XeYica3j.js → sortable-tabs-strip-DncWjNx4.js} +1 -1
- package/dist/assets/src-B8mzksNL.css +2 -0
- package/dist/assets/store-oojlrF4d.js +15 -0
- package/dist/assets/{terminalApi-DAu7xKli.js → terminalApi-BYTA045F.js} +1 -1
- package/dist/assets/{tooltip-BSlxaNrR.js → tooltip-BYGBBTc2.js} +1 -1
- package/dist/assets/uk-UvnVqWv-.js +15 -0
- package/dist/assets/{url-DjkTDrad.js → url-CGHw6D-E.js} +1 -1
- package/dist/assets/useAppFontEffects-B1EhZNex.js +7 -0
- package/dist/assets/{useDesktopWindowControlsLayout-BwYnhrEy.js → useDesktopWindowControlsLayout-Dc69l-pm.js} +1 -1
- package/dist/assets/{useEffectiveDirectory-CEmsrrEs.js → useEffectiveDirectory-dCGvvYRh.js} +1 -1
- package/dist/assets/{useFontPreferences-BxMT_kty.js → useFontPreferences-Bu4ME5hk.js} +1 -1
- package/dist/assets/{useMobileNavigationStore-DryW-QdG.js → useMobileNavigationStore-DhkIZBJw.js} +4 -4
- package/dist/assets/useSessionAutoCleanup-D-r9oDye.js +1 -0
- package/dist/assets/{useWorkerHighlightedLines-CFW2AoPL.js → useWorkerHighlightedLines-05dLFgTI.js} +1 -1
- package/dist/assets/{utils-RUACCsOs.js → utils-DyUyiLje.js} +1 -1
- package/dist/assets/zh-CN-9v-RC966.js +15 -0
- package/dist/assets/zh-TW-BZ_wZdC-.js +15 -0
- package/dist/index.html +8 -8
- package/dist/mini-chat.html +8 -8
- package/dist/mobile.html +8 -8
- package/package.json +1 -1
- package/server/index.d.ts +0 -6
- package/server/index.js +5 -153
- package/server/lib/opencode/DOCUMENTATION.md +6 -10
- package/server/lib/opencode/cli-entry-runtime.js +0 -10
- package/server/lib/opencode/cli-options.js +0 -65
- package/server/lib/opencode/core-routes.js +2 -4
- package/server/lib/opencode/routes.test.js +0 -1
- package/server/lib/opencode/server-startup-runtime.js +0 -55
- package/server/lib/opencode/settings-helpers.js +0 -55
- package/server/lib/opencode/settings-helpers.test.js +0 -20
- package/server/lib/opencode/settings-normalization-runtime.js +0 -87
- package/server/lib/opencode/settings-normalization-runtime.test.js +0 -3
- package/server/lib/opencode/settings-runtime.js +9 -102
- package/server/lib/opencode/settings-runtime.test.js +0 -10
- package/server/lib/opencode/shutdown-runtime.js +1 -9
- package/server/lib/opencode/shutdown-runtime.test.js +0 -2
- package/server/lib/opencode/startup-pipeline-runtime.js +0 -20
- package/server/lib/opencode/startup-pipeline-runtime.test.js +2 -3
- package/server/lib/opencode/tunnel-wiring-runtime.js +2 -80
- package/server/lib/relay/DOCUMENTATION.md +1 -1
- package/bin/lib/cli-tunnel-capabilities.js +0 -9
- package/bin/lib/cli-tunnel-profiles.js +0 -366
- package/bin/lib/cli-tunnel-utils.js +0 -300
- package/bin/lib/commands-tunnel.js +0 -1761
- package/dist/assets/SettingsView-5YNu54KI.js +0 -25
- package/dist/assets/desktopHosts-D5m_ggY1.js +0 -1
- package/dist/assets/es-Cei_75Jt.js +0 -15
- package/dist/assets/fr-Dn7WSHh2.js +0 -13
- package/dist/assets/ja-DFARVqVj.js +0 -15
- package/dist/assets/ko-pyLnIyDY.js +0 -15
- package/dist/assets/mobile-DEQeGskq.js +0 -2
- package/dist/assets/persistence-CHA81Od7.js +0 -3
- package/dist/assets/pt-BR-DaWvr_0A.js +0 -15
- package/dist/assets/radio-BnF4XhCC.js +0 -1
- package/dist/assets/src-BtkWqMFu.css +0 -2
- package/dist/assets/store-DIpqFVjs.js +0 -15
- package/dist/assets/uk-CHCRqRKf.js +0 -15
- package/dist/assets/useAppFontEffects-BRNICZS2.js +0 -7
- package/dist/assets/useSessionAutoCleanup-DMJ1LiW_.js +0 -1
- package/dist/assets/zh-CN-BWEQZKXk.js +0 -15
- package/dist/assets/zh-TW-BbO-gJq3.js +0 -15
- package/server/lib/cloudflare-tunnel.js +0 -618
- package/server/lib/ngrok-tunnel.js +0 -343
- package/server/lib/ngrok-tunnel.test.js +0 -50
- package/server/lib/tunnels/DOCUMENTATION.md +0 -21
- package/server/lib/tunnels/executable-search.js +0 -140
- package/server/lib/tunnels/executable-search.test.js +0 -96
- package/server/lib/tunnels/index.js +0 -179
- package/server/lib/tunnels/index.test.js +0 -93
- package/server/lib/tunnels/install-help.js +0 -56
- package/server/lib/tunnels/install-help.test.js +0 -31
- package/server/lib/tunnels/managed-config.js +0 -201
- package/server/lib/tunnels/providers/cloudflare.js +0 -266
- package/server/lib/tunnels/providers/ngrok.js +0 -123
- package/server/lib/tunnels/registry.js +0 -51
- package/server/lib/tunnels/routes.js +0 -610
- package/server/lib/tunnels/types.js +0 -245
- package/server/lib/tunnels/types.test.js +0 -34
package/README.md
CHANGED
|
@@ -29,14 +29,6 @@ openchamber startup enable # Start at login as a native service
|
|
|
29
29
|
OPENCHAMBER_UI_PASSWORD=secret openchamber startup enable # Save service password env
|
|
30
30
|
openchamber startup status # Show startup service status
|
|
31
31
|
openchamber startup disable # Remove startup service
|
|
32
|
-
openchamber tunnel help # Tunnel lifecycle commands
|
|
33
|
-
openchamber tunnel providers # Show provider capabilities
|
|
34
|
-
openchamber tunnel profile add --provider cloudflare --mode managed-remote --name prod-main --hostname app.example.com --token <token>
|
|
35
|
-
openchamber tunnel start --profile prod-main
|
|
36
|
-
openchamber tunnel start --provider cloudflare --mode quick --qr
|
|
37
|
-
openchamber tunnel start --provider cloudflare --mode managed-local --config ~/.cloudflared/config.yml
|
|
38
|
-
openchamber tunnel status --all # Show tunnel state across instances
|
|
39
|
-
openchamber tunnel stop --port 3000 # Stop tunnel only (server stays running)
|
|
40
32
|
openchamber connect-url --port 3000 # Add this server to OpenChamber Desktop
|
|
41
33
|
openchamber connect-url --server http://host:3000 --qr
|
|
42
34
|
openchamber connect-url --port 3000 --qr
|
|
@@ -80,13 +72,6 @@ The **Add a device** dialog defaults to `wss://relay.openchamber.dev/ws` and let
|
|
|
80
72
|
|
|
81
73
|
Saved pairing candidates retain their endpoint snapshot, including the Relay URL. Mobile and Desktop clients reconnect through that saved endpoint until a new pairing flow replaces it. See [OpenChamber Relay Server](https://github.com/yee94/openchamber/tree/main/packages/relay-server#readme) for bundle builds, reverse-proxy configuration, security, operations, and systemd guidance.
|
|
82
74
|
|
|
83
|
-
### Tunnel behavior notes
|
|
84
|
-
|
|
85
|
-
- One active tunnel per running OpenChamber instance (port).
|
|
86
|
-
- Starting a different tunnel mode/provider on the same instance replaces the active tunnel.
|
|
87
|
-
- Replacing or stopping a tunnel revokes existing connect links and invalidates remote tunnel sessions.
|
|
88
|
-
- Connect links are one-time tokens; generating a new link revokes the previous unused link.
|
|
89
|
-
|
|
90
75
|
### Connect other OpenChamber apps
|
|
91
76
|
|
|
92
77
|
Use `connect-url` when a web/API server should be added to OpenChamber Desktop or another OpenChamber app. If no server is running on the selected port, OpenChamber starts one first.
|
|
@@ -157,30 +142,9 @@ OPENCHAMBER_OPENCODE_HOSTNAME=0.0.0.0 openchamber --port 3000
|
|
|
157
142
|
```yaml
|
|
158
143
|
environment:
|
|
159
144
|
UI_PASSWORD: your_secure_password
|
|
160
|
-
OPENCHAMBER_TUNNEL_MODE: quick # quick | managed-remote | managed-local
|
|
161
|
-
OPENCHAMBER_TUNNEL_PROVIDER: cloudflare
|
|
162
145
|
OPENCHAMBER_UPDATE_API_URL: https://updates.example.com/v1/update/check # Primary compatible update-check service; Vercel and GitHub Releases provide fallback
|
|
163
146
|
```
|
|
164
147
|
|
|
165
|
-
For `managed-remote` mode, also set:
|
|
166
|
-
|
|
167
|
-
```yaml
|
|
168
|
-
environment:
|
|
169
|
-
OPENCHAMBER_TUNNEL_MODE: managed-remote
|
|
170
|
-
OPENCHAMBER_TUNNEL_HOSTNAME: app.example.com
|
|
171
|
-
OPENCHAMBER_TUNNEL_TOKEN: <token>
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
For `managed-local` mode, you can set:
|
|
175
|
-
|
|
176
|
-
```yaml
|
|
177
|
-
environment:
|
|
178
|
-
OPENCHAMBER_TUNNEL_MODE: managed-local
|
|
179
|
-
OPENCHAMBER_TUNNEL_CONFIG: /home/openchamber/.cloudflared/config.yml
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
Managed-local path note: `OPENCHAMBER_TUNNEL_CONFIG` must use a container path under `/home/openchamber/...`. If the config file references `credentials-file`, ensure that JSON path is also mounted and reachable inside the container.
|
|
183
|
-
|
|
184
148
|
**Data directory:** mount `data/` for persistent storage. Ensure permissions:
|
|
185
149
|
```bash
|
|
186
150
|
mkdir -p data/openchamber data/opencode/share data/opencode/config data/ssh
|
|
@@ -256,14 +220,14 @@ systemctl --user enable --now opencode openchamber
|
|
|
256
220
|
|
|
257
221
|
## What makes the web version special
|
|
258
222
|
|
|
259
|
-
- **Remote access** -
|
|
223
|
+
- **Remote access** - LAN pairing and private relay with QR onboarding. Scan from your phone, start coding.
|
|
260
224
|
- **Mobile-first PWA** - optimized chat controls, keyboard-safe layouts, drag-to-reorder projects
|
|
261
225
|
- **Background notifications** - know when your agent finishes, even from another tab
|
|
262
226
|
- **Self-update** - update and restart from the UI, server settings stay intact
|
|
263
227
|
- **Cross-tab tracking** - session activity stays in sync across browser tabs
|
|
264
228
|
|
|
265
|
-
-
|
|
266
|
-
- One-scan onboarding with
|
|
229
|
+
- LAN pairing and private relay for reaching a host that is not publicly exposed
|
|
230
|
+
- One-scan onboarding with pairing QR links
|
|
267
231
|
- Mobile-first experience: optimized chat controls, keyboard-safe layouts, and attachment-friendly UI
|
|
268
232
|
- Background notifications plus reliable cross-tab session activity tracking
|
|
269
233
|
- Built-in self-update + restart flow that keeps your server settings intact
|
package/bin/cli-output.js
CHANGED
|
@@ -21,21 +21,6 @@ import {
|
|
|
21
21
|
isCancel,
|
|
22
22
|
} from '@clack/prompts';
|
|
23
23
|
|
|
24
|
-
// ── Provider icons ──────────────────────────────────────────────
|
|
25
|
-
|
|
26
|
-
const TUNNEL_PROVIDER_ICON = {
|
|
27
|
-
cloudflare: '☁',
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
function formatProviderWithIcon(provider) {
|
|
31
|
-
if (typeof provider !== 'string' || provider.trim().length === 0) {
|
|
32
|
-
return 'unknown';
|
|
33
|
-
}
|
|
34
|
-
const normalized = provider.trim().toLowerCase();
|
|
35
|
-
const icon = TUNNEL_PROVIDER_ICON[normalized];
|
|
36
|
-
return icon ? `${icon} ${normalized}` : normalized;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
24
|
// ── Status-aware log dispatch ───────────────────────────────────
|
|
40
25
|
|
|
41
26
|
/**
|
|
@@ -135,6 +120,5 @@ export {
|
|
|
135
120
|
createSpinner,
|
|
136
121
|
createProgress,
|
|
137
122
|
printJson,
|
|
138
|
-
formatProviderWithIcon,
|
|
139
123
|
logStatus,
|
|
140
124
|
};
|
package/bin/cli.js
CHANGED
|
@@ -10,21 +10,11 @@ import {
|
|
|
10
10
|
hasUiPasswordConfigured,
|
|
11
11
|
assertAuthenticatedNetworkExposure,
|
|
12
12
|
} from './lib/cli-network.js';
|
|
13
|
-
import {
|
|
14
|
-
maskToken,
|
|
15
|
-
resolveToken,
|
|
16
|
-
redactProfileForOutput,
|
|
17
|
-
redactProfilesForOutput,
|
|
18
|
-
warnIfUnsafeFilePermissions,
|
|
19
|
-
ensureTunnelProfilesMigrated as ensureTunnelProfilesMigratedBase,
|
|
20
|
-
} from './lib/cli-tunnel-profiles.js';
|
|
21
13
|
import {
|
|
22
14
|
parseArgs,
|
|
23
15
|
showHelp,
|
|
24
16
|
showStartupHelp,
|
|
25
17
|
showConnectUrlHelp,
|
|
26
|
-
showTunnelHelp,
|
|
27
|
-
generateCompletionScript,
|
|
28
18
|
findClosestMatch,
|
|
29
19
|
} from './lib/cli-args.js';
|
|
30
20
|
import { readDesktopLocalPortFromSettings } from './lib/cli-paths.js';
|
|
@@ -36,17 +26,13 @@ import { createUpdateCommand } from './lib/commands-update.js';
|
|
|
36
26
|
import { createConnectUrlCommand } from './lib/commands-connect-url.js';
|
|
37
27
|
import { createLifecycleCommands } from './lib/commands-lifecycle.js';
|
|
38
28
|
import { createServeCommand } from './lib/commands-serve.js';
|
|
39
|
-
import { createTunnelCommand, isValidTunnelDoctorResponse, shouldDisplayTunnelQr } from './lib/commands-tunnel.js';
|
|
40
29
|
import {
|
|
41
|
-
resolveDoctorPortStatuses,
|
|
42
30
|
discoverRunningInstances,
|
|
43
31
|
discoverOpenChamberInstanceOnPort,
|
|
44
32
|
discoverLifecycleInstances,
|
|
45
33
|
discoverUnconfirmedRegistryInstanceOnPort,
|
|
46
|
-
resolveTunnelProviders,
|
|
47
34
|
} from './lib/cli-lifecycle.js';
|
|
48
35
|
import {
|
|
49
|
-
fetchTunnelProvidersFromPort,
|
|
50
36
|
fetchSystemInfoFromPort,
|
|
51
37
|
} from './lib/cli-http.js';
|
|
52
38
|
import {
|
|
@@ -60,7 +46,6 @@ import {
|
|
|
60
46
|
import {
|
|
61
47
|
intro as clackIntro, outro as clackOutro, cancel as clackCancel,
|
|
62
48
|
isJsonMode,
|
|
63
|
-
isQuietMode,
|
|
64
49
|
printJson,
|
|
65
50
|
logStatus,
|
|
66
51
|
} from './cli-output.js';
|
|
@@ -70,24 +55,10 @@ const __dirname = path.dirname(__filename);
|
|
|
70
55
|
|
|
71
56
|
const PACKAGE_JSON = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
|
|
72
57
|
|
|
73
|
-
let onCancelCleanup = null;
|
|
74
58
|
let activeCommandOptions = null;
|
|
75
59
|
let foregroundServerActive = false;
|
|
76
60
|
let foregroundShutdown = null;
|
|
77
61
|
|
|
78
|
-
function setCancelCleanup(handler) {
|
|
79
|
-
onCancelCleanup = typeof handler === 'function' ? handler : null;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function shouldWarnForTunnelProfileFile() {
|
|
83
|
-
if (!activeCommandOptions) return false;
|
|
84
|
-
return !isJsonMode(activeCommandOptions) && !isQuietMode(activeCommandOptions);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function ensureTunnelProfilesMigrated() {
|
|
88
|
-
return ensureTunnelProfilesMigratedBase({ shouldWarn: shouldWarnForTunnelProfileFile() });
|
|
89
|
-
}
|
|
90
|
-
|
|
91
62
|
const HAS_PLAIN_FLAG = process.argv.includes('--plain');
|
|
92
63
|
const STYLE_ENABLED = process.stdout.isTTY && process.env.NO_COLOR !== '1' && !HAS_PLAIN_FLAG;
|
|
93
64
|
const ANSI = {
|
|
@@ -163,14 +134,6 @@ commands.serve = createServeCommand({
|
|
|
163
134
|
commands.restart = lifecycleCommands.restart;
|
|
164
135
|
}
|
|
165
136
|
|
|
166
|
-
commands.tunnel = createTunnelCommand({
|
|
167
|
-
serveCommand: commands.serve.bind(commands),
|
|
168
|
-
stopCommand: commands.stop.bind(commands),
|
|
169
|
-
setCancelCleanup,
|
|
170
|
-
boldText,
|
|
171
|
-
ensureTunnelProfilesMigrated,
|
|
172
|
-
});
|
|
173
|
-
|
|
174
137
|
commands['connect-url'] = createConnectUrlCommand({
|
|
175
138
|
serveCommand: commands.serve.bind(commands),
|
|
176
139
|
});
|
|
@@ -183,7 +146,7 @@ commands.update = createUpdateCommand({
|
|
|
183
146
|
|
|
184
147
|
async function main() {
|
|
185
148
|
const parsed = parseArgs();
|
|
186
|
-
const { command,
|
|
149
|
+
const { command, startupAction, options, removedFlagErrors, helpRequested, versionRequested } = parsed;
|
|
187
150
|
activeCommandOptions = options;
|
|
188
151
|
|
|
189
152
|
if (versionRequested) {
|
|
@@ -213,9 +176,7 @@ async function main() {
|
|
|
213
176
|
}
|
|
214
177
|
|
|
215
178
|
if (helpRequested) {
|
|
216
|
-
if (command === '
|
|
217
|
-
showTunnelHelp();
|
|
218
|
-
} else if (command === 'startup') {
|
|
179
|
+
if (command === 'startup') {
|
|
219
180
|
showStartupHelp();
|
|
220
181
|
} else if (command === 'connect-url') {
|
|
221
182
|
showConnectUrlHelp();
|
|
@@ -225,18 +186,13 @@ async function main() {
|
|
|
225
186
|
return;
|
|
226
187
|
}
|
|
227
188
|
|
|
228
|
-
if (command === 'tunnel') {
|
|
229
|
-
await commands.tunnel(options, subcommand, tunnelAction);
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
189
|
if (command === 'startup') {
|
|
234
190
|
await commands.startup(options, startupAction);
|
|
235
191
|
return;
|
|
236
192
|
}
|
|
237
193
|
|
|
238
194
|
if (!commands[command]) {
|
|
239
|
-
const knownCommands = ['serve', 'stop', 'restart', 'status', '
|
|
195
|
+
const knownCommands = ['serve', 'stop', 'restart', 'status', 'startup', 'logs', 'connect-url', 'update'];
|
|
240
196
|
const suggestion = findClosestMatch(command, knownCommands);
|
|
241
197
|
const hint = suggestion ? ` Did you mean '${suggestion}'?` : '';
|
|
242
198
|
if (isJsonMode(options)) {
|
|
@@ -274,14 +230,6 @@ if (isCliExecution) {
|
|
|
274
230
|
isHandlingSigint = true;
|
|
275
231
|
(async () => {
|
|
276
232
|
clackCancel('Operation cancelled.');
|
|
277
|
-
if (onCancelCleanup) {
|
|
278
|
-
try {
|
|
279
|
-
await onCancelCleanup();
|
|
280
|
-
} catch {
|
|
281
|
-
} finally {
|
|
282
|
-
setCancelCleanup(null);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
233
|
process.exit(130);
|
|
286
234
|
})();
|
|
287
235
|
});
|
|
@@ -341,8 +289,6 @@ export {
|
|
|
341
289
|
assertAuthenticatedNetworkExposure,
|
|
342
290
|
resolveServeHost,
|
|
343
291
|
hasUiPasswordConfigured,
|
|
344
|
-
shouldDisplayTunnelQr,
|
|
345
|
-
isValidTunnelDoctorResponse,
|
|
346
292
|
readDesktopLocalPortFromSettings,
|
|
347
293
|
getPidFilePath,
|
|
348
294
|
getInstanceFilePath,
|
|
@@ -350,21 +296,12 @@ export {
|
|
|
350
296
|
isOpenchamberProcessRunning,
|
|
351
297
|
isOpenchamberCmdline,
|
|
352
298
|
getOpenchamberProcessState,
|
|
353
|
-
resolveTunnelProviders,
|
|
354
|
-
fetchTunnelProvidersFromPort,
|
|
355
299
|
fetchSystemInfoFromPort,
|
|
356
300
|
discoverRunningInstances,
|
|
357
301
|
discoverOpenChamberInstanceOnPort,
|
|
358
302
|
discoverLifecycleInstances,
|
|
359
303
|
discoverUnconfirmedRegistryInstanceOnPort,
|
|
360
|
-
ensureTunnelProfilesMigrated,
|
|
361
|
-
resolveToken,
|
|
362
|
-
redactProfileForOutput,
|
|
363
|
-
redactProfilesForOutput,
|
|
364
|
-
maskToken,
|
|
365
304
|
findClosestMatch,
|
|
366
|
-
generateCompletionScript,
|
|
367
305
|
TunnelCliError,
|
|
368
306
|
EXIT_CODE,
|
|
369
|
-
warnIfUnsafeFilePermissions,
|
|
370
307
|
};
|
package/bin/cli.test.js
CHANGED
|
@@ -10,11 +10,6 @@ import { pathToFileURL } from 'url';
|
|
|
10
10
|
import { isModuleCliExecution, normalizeCliEntryPath } from './cli-entry.js';
|
|
11
11
|
import { requestJson } from './lib/cli-http.js';
|
|
12
12
|
import { inspectTunnelAttachability } from './lib/cli-lifecycle.js';
|
|
13
|
-
import { DEFAULT_TUNNEL_PROVIDER_CAPABILITIES } from './lib/cli-tunnel-capabilities.js';
|
|
14
|
-
import {
|
|
15
|
-
TUNNEL_PROVIDER_CLOUDFLARE,
|
|
16
|
-
TUNNEL_PROVIDER_NGROK,
|
|
17
|
-
} from '../server/lib/tunnels/types.js';
|
|
18
13
|
import {
|
|
19
14
|
assertAuthenticatedNetworkExposure,
|
|
20
15
|
commands,
|
|
@@ -22,7 +17,6 @@ import {
|
|
|
22
17
|
discoverLifecycleInstances,
|
|
23
18
|
discoverRunningInstances,
|
|
24
19
|
discoverUnconfirmedRegistryInstanceOnPort,
|
|
25
|
-
ensureTunnelProfilesMigrated,
|
|
26
20
|
getInstanceFilePath,
|
|
27
21
|
getPidFilePath,
|
|
28
22
|
isOpenchamberCmdline,
|
|
@@ -178,13 +172,6 @@ function spawnOpenChamberLikeHungServer(port) {
|
|
|
178
172
|
}
|
|
179
173
|
|
|
180
174
|
describe('cli args', () => {
|
|
181
|
-
it('loads fallback tunnel provider capabilities for CLI startup', () => {
|
|
182
|
-
expect(DEFAULT_TUNNEL_PROVIDER_CAPABILITIES.map((provider) => provider.provider)).toEqual([
|
|
183
|
-
TUNNEL_PROVIDER_CLOUDFLARE,
|
|
184
|
-
TUNNEL_PROVIDER_NGROK,
|
|
185
|
-
]);
|
|
186
|
-
});
|
|
187
|
-
|
|
188
175
|
it('accepts legacy daemon flags as no-ops', () => {
|
|
189
176
|
expect(parseArgs(['serve', '--daemon']).removedFlagErrors).toEqual([]);
|
|
190
177
|
expect(parseArgs(['serve', '-d']).removedFlagErrors).toEqual([]);
|
|
@@ -229,17 +216,6 @@ describe('cli args', () => {
|
|
|
229
216
|
expect(parsed.options.port).toBe(3002);
|
|
230
217
|
});
|
|
231
218
|
|
|
232
|
-
it('parses tunnel auto-start server options', () => {
|
|
233
|
-
const parsed = parseArgs(['tunnel', 'start', '--port', '3002', '--api-only', '--lan', '--ui-password', 'secret']);
|
|
234
|
-
|
|
235
|
-
expect(parsed.command).toBe('tunnel');
|
|
236
|
-
expect(parsed.subcommand).toBe('start');
|
|
237
|
-
expect(parsed.options.port).toBe(3002);
|
|
238
|
-
expect(parsed.options.apiOnly).toBe(true);
|
|
239
|
-
expect(parsed.options.host).toBe('0.0.0.0');
|
|
240
|
-
expect(parsed.options.uiPassword).toBe('secret');
|
|
241
|
-
});
|
|
242
|
-
|
|
243
219
|
it('maps --lan to wildcard bind host', () => {
|
|
244
220
|
const parsed = parseArgs(['serve', '--lan', '--port', '3002']);
|
|
245
221
|
|
|
@@ -252,13 +228,6 @@ describe('cli args', () => {
|
|
|
252
228
|
|
|
253
229
|
expect(parsed.options.host).toBe('0.0.0.0');
|
|
254
230
|
});
|
|
255
|
-
|
|
256
|
-
it('keeps --hostname for tunnel commands', () => {
|
|
257
|
-
const parsed = parseArgs(['tunnel', 'start', '--hostname', 'app.example.com']);
|
|
258
|
-
|
|
259
|
-
expect(parsed.options.hostname).toBe('app.example.com');
|
|
260
|
-
expect(parsed.options.host).toBeUndefined();
|
|
261
|
-
});
|
|
262
231
|
});
|
|
263
232
|
|
|
264
233
|
describe('network-exposed auth validation', () => {
|
|
@@ -322,51 +291,6 @@ describe('serve host resolution', () => {
|
|
|
322
291
|
});
|
|
323
292
|
});
|
|
324
293
|
|
|
325
|
-
describe('compatibility exports', () => {
|
|
326
|
-
it('allows tunnel profile migration before command options are initialized', async () => {
|
|
327
|
-
await withTempOpenChamberDataDir(async () => {
|
|
328
|
-
const store = ensureTunnelProfilesMigrated();
|
|
329
|
-
|
|
330
|
-
expect(store).toEqual({ version: 1, profiles: [] });
|
|
331
|
-
});
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
it('includes ngrok in fallback tunnel providers when no server is reachable', async () => {
|
|
335
|
-
await withTempOpenChamberDataDir(async () => {
|
|
336
|
-
const output = await captureStdout(async () => {
|
|
337
|
-
await commands.tunnel({ json: true }, 'providers');
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
const body = JSON.parse(output);
|
|
341
|
-
expect(body.source).toBe('fallback');
|
|
342
|
-
expect(body.providers.map((entry) => entry.provider)).toContain('ngrok');
|
|
343
|
-
});
|
|
344
|
-
});
|
|
345
|
-
|
|
346
|
-
it('supports ngrok quick dry-run with an explicit port', async () => {
|
|
347
|
-
await withTempOpenChamberDataDir(async () => {
|
|
348
|
-
const output = await captureStdout(async () => {
|
|
349
|
-
await commands.tunnel({
|
|
350
|
-
json: true,
|
|
351
|
-
dryRun: true,
|
|
352
|
-
explicitPort: true,
|
|
353
|
-
port: 3003,
|
|
354
|
-
provider: 'ngrok',
|
|
355
|
-
mode: 'quick',
|
|
356
|
-
}, 'start');
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
const body = JSON.parse(output);
|
|
360
|
-
expect(body).toEqual(expect.objectContaining({
|
|
361
|
-
ok: true,
|
|
362
|
-
dryRun: true,
|
|
363
|
-
provider: 'ngrok',
|
|
364
|
-
mode: 'quick',
|
|
365
|
-
}));
|
|
366
|
-
});
|
|
367
|
-
});
|
|
368
|
-
});
|
|
369
|
-
|
|
370
294
|
describe('CLI HTTP helpers', () => {
|
|
371
295
|
it('retries UI-authenticated API requests with the stored instance password', async () => {
|
|
372
296
|
await withTempOpenChamberDataDir(async () => {
|
|
@@ -395,17 +319,16 @@ describe('CLI HTTP helpers', () => {
|
|
|
395
319
|
};
|
|
396
320
|
|
|
397
321
|
try {
|
|
398
|
-
const { response, body } = await requestJson(port, '/api/openchamber/
|
|
399
|
-
method: '
|
|
400
|
-
body: JSON.stringify({ provider: 'ngrok', mode: 'quick' }),
|
|
322
|
+
const { response, body } = await requestJson(port, '/api/openchamber/relay/status', {
|
|
323
|
+
method: 'GET',
|
|
401
324
|
});
|
|
402
325
|
|
|
403
326
|
expect(response.ok).toBe(true);
|
|
404
327
|
expect(body).toEqual({ ok: true });
|
|
405
328
|
expect(calls.map((call) => new URL(call.url).pathname)).toEqual([
|
|
406
|
-
'/api/openchamber/
|
|
329
|
+
'/api/openchamber/relay/status',
|
|
407
330
|
'/auth/session',
|
|
408
|
-
'/api/openchamber/
|
|
331
|
+
'/api/openchamber/relay/status',
|
|
409
332
|
]);
|
|
410
333
|
} finally {
|
|
411
334
|
globalThis.fetch = originalFetch;
|
package/bin/lib/DOCUMENTATION.md
CHANGED
|
@@ -26,7 +26,7 @@ Command modules implement user-facing commands and preserve output contracts acr
|
|
|
26
26
|
|
|
27
27
|
- `commands-status.js`
|
|
28
28
|
- Implements `openchamber status`.
|
|
29
|
-
- Formats discovered instances
|
|
29
|
+
- Formats discovered instances for human, quiet, and JSON output.
|
|
30
30
|
|
|
31
31
|
- `commands-logs.js`
|
|
32
32
|
- Implements `openchamber logs`.
|
|
@@ -47,11 +47,6 @@ Command modules implement user-facing commands and preserve output contracts acr
|
|
|
47
47
|
- Implements `openchamber update`.
|
|
48
48
|
- Loads the package-manager helper, performs update flow, and coordinates restart behavior after updates.
|
|
49
49
|
|
|
50
|
-
- `commands-tunnel.js`
|
|
51
|
-
- Implements `openchamber tunnel` and its subcommands: `profile`, `providers`, `ready`, `doctor`, `status`, `start`, `stop`, and `completion`.
|
|
52
|
-
- Owns tunnel-specific command flow, interactive prompt decisions, managed-local/managed-remote startup, QR display rules, tunnel start/stop API calls, and tunnel profile command handling.
|
|
53
|
-
- Receives `serveCommand` and `stopCommand` by dependency injection. Do not reach back into `cli.js` command globals from this module.
|
|
54
|
-
|
|
55
50
|
## Shared Helper Modules
|
|
56
51
|
|
|
57
52
|
These modules hold reusable, non-presentational logic for commands.
|
|
@@ -60,19 +55,19 @@ These modules hold reusable, non-presentational logic for commands.
|
|
|
60
55
|
- Argument parsing, defaults, help text, completion script generation, and typo suggestions.
|
|
61
56
|
|
|
62
57
|
- `cli-errors.js`
|
|
63
|
-
- CLI exit codes and typed
|
|
58
|
+
- CLI exit codes and typed CLI errors.
|
|
64
59
|
|
|
65
60
|
- `cli-paths.js`
|
|
66
|
-
- Data, run, log,
|
|
61
|
+
- Data, run, log, and settings paths.
|
|
67
62
|
|
|
68
63
|
- `cli-process.js`
|
|
69
64
|
- PID files, instance registry files, process identity checks, runtime metadata checks, and process termination helpers.
|
|
70
65
|
|
|
71
66
|
- `cli-lifecycle.js`
|
|
72
|
-
- Instance discovery, live health probing, attachability checks,
|
|
67
|
+
- Instance discovery, live health probing, attachability checks, and status aggregation used by lifecycle/status commands.
|
|
73
68
|
|
|
74
69
|
- `cli-http.js`
|
|
75
|
-
- HTTP helpers for health checks, shutdown requests, JSON API calls,
|
|
70
|
+
- HTTP helpers for health checks, shutdown requests, JSON API calls, and system info fetches.
|
|
76
71
|
|
|
77
72
|
- `cli-network.js`
|
|
78
73
|
- Host resolution, URL building, LAN detection, unsafe browser port validation, and UI password/network exposure checks.
|
|
@@ -89,15 +84,6 @@ These modules hold reusable, non-presentational logic for commands.
|
|
|
89
84
|
- `cli-startup.js`
|
|
90
85
|
- Native startup service detection, install/uninstall/status helpers, and platform-specific startup command execution.
|
|
91
86
|
|
|
92
|
-
- `cli-tunnel-profiles.js`
|
|
93
|
-
- Tunnel profile normalization, token resolution/redaction, profile storage, migration, file-permission warnings, and managed-remote pair persistence.
|
|
94
|
-
|
|
95
|
-
- `cli-tunnel-utils.js`
|
|
96
|
-
- Tunnel-specific command string builders, TTL parsing/formatting, and replay command helpers.
|
|
97
|
-
|
|
98
|
-
- `cli-tunnel-capabilities.js`
|
|
99
|
-
- Built-in tunnel provider capability fallbacks used when a live server cannot provide tunnel metadata.
|
|
100
|
-
|
|
101
87
|
## Placement Rules
|
|
102
88
|
|
|
103
89
|
- Add new CLI commands as `commands-*.js` modules and wire them from `cli.js`.
|