@openchamber/web 1.11.5 → 1.11.7
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 +6 -0
- package/bin/cli.js +443 -2
- package/dist/assets/{MarkdownRendererImpl-C3-ZpwEx.js → MarkdownRendererImpl-DaF15QNC.js} +1 -1
- package/dist/assets/{MultiRunWindow-BDfPzMDy.js → MultiRunWindow-Cl7wS_CB.js} +1 -1
- package/dist/assets/{OnboardingScreen-DGgh4IXB.js → OnboardingScreen-DTv6YJI1.js} +2 -2
- package/dist/assets/{SettingsWindow-B8QKr5dB.js → SettingsWindow-_c3TTL2z.js} +1 -1
- package/dist/assets/{TerminalView-D7IIkSGJ.js → TerminalView-CuXkDROt.js} +4 -4
- package/dist/assets/es-CYoUf2D-.js +15 -0
- package/dist/assets/{index-DHluop4D.js → index-3WXrN3AX.js} +1 -1
- package/dist/assets/index-BREIbhcb.css +1 -0
- package/dist/assets/ko-2tM0fIna.js +15 -0
- package/dist/assets/main-BF3kWAJ9.js +239 -0
- package/dist/assets/{main-VVcyjpiF.js → main-o8ZERrmU.js} +2 -2
- package/dist/assets/miniChat-BZQjpK23.js +2 -0
- package/dist/assets/{modelPrefsAutoSave-Ctdc3cCY.js → modelPrefsAutoSave-wwnbqBk7.js} +109 -107
- package/dist/assets/pl-Dq8uAotM.js +15 -0
- package/dist/assets/pt-BR-nh9s9DFT.js +15 -0
- package/dist/assets/{renderElectronMiniChatApp-CsddCM3q.js → renderElectronMiniChatApp-C-Ezew9P.js} +2 -2
- package/dist/assets/uk-BZtz0wUV.js +15 -0
- package/dist/assets/{vendor-.bun-Bum-iBXX.js → vendor-.bun-CV3tusA8.js} +1 -1
- package/dist/assets/zh-CN-j_nYMchE.js +15 -0
- package/dist/assets/zh-TW-B11UpkDJ.js +15 -0
- package/dist/index.html +11 -28
- package/dist/mini-chat.html +4 -4
- package/package.json +1 -1
- package/server/index.js +2 -0
- package/server/lib/cloudflare-tunnel.js +3 -5
- package/server/lib/fs/routes.js +5 -0
- package/server/lib/fs/routes.test.js +61 -1
- package/server/lib/git/DOCUMENTATION.md +1 -0
- package/server/lib/git/routes.js +82 -1
- package/server/lib/git/service.js +338 -19
- package/server/lib/git/service.test.js +414 -8
- package/server/lib/ngrok-tunnel.js +209 -0
- package/server/lib/opencode/core-routes.js +1 -0
- package/server/lib/opencode/env-runtime.js +52 -4
- package/server/lib/opencode/env-runtime.test.js +82 -6
- package/server/lib/opencode/feature-routes-runtime.js +35 -0
- package/server/lib/opencode/index.js +19 -0
- package/server/lib/opencode/npm-registry.js +157 -0
- package/server/lib/opencode/npm-registry.test.js +179 -0
- package/server/lib/opencode/openchamber-routes.js +9 -7
- package/server/lib/opencode/plugin-routes.js +373 -0
- package/server/lib/opencode/plugin-routes.test.js +384 -0
- package/server/lib/opencode/plugin-spec.js +107 -0
- package/server/lib/opencode/plugin-spec.test.js +154 -0
- package/server/lib/opencode/plugins.js +393 -0
- package/server/lib/opencode/plugins.test.js +176 -0
- package/server/lib/opencode/settings-helpers.js +6 -0
- package/server/lib/opencode/settings-helpers.test.js +11 -0
- package/server/lib/opencode/settings-runtime.js +39 -1
- package/server/lib/opencode/settings-runtime.test.js +39 -0
- package/server/lib/skills-catalog/source.js +1 -1
- package/server/lib/tunnels/DOCUMENTATION.md +1 -0
- package/server/lib/tunnels/providers/ngrok.js +117 -0
- package/server/lib/tunnels/types.js +2 -0
- package/dist/assets/es-dIVpApmS.js +0 -15
- package/dist/assets/index-Bk9IWJe1.css +0 -1
- package/dist/assets/ko-Cqf3E9-d.js +0 -15
- package/dist/assets/main-D45l3Dxw.js +0 -232
- package/dist/assets/miniChat-a9w7WM0c.js +0 -2
- package/dist/assets/pl-C577DpsX.js +0 -15
- package/dist/assets/pt-BR-BeeF6VlK.js +0 -15
- package/dist/assets/uk-CZ7XVz_D.js +0 -15
- package/dist/assets/zh-CN-BMSSqdyO.js +0 -15
|
@@ -82,4 +82,43 @@ describe('settings runtime', () => {
|
|
|
82
82
|
await cleanup();
|
|
83
83
|
}
|
|
84
84
|
});
|
|
85
|
+
|
|
86
|
+
it.skipIf(process.platform !== 'win32')('falls back when Windows blocks atomic settings replacement', async () => {
|
|
87
|
+
const tempRoot = await fsPromises.mkdtemp(path.join(os.tmpdir(), 'oc-settings-runtime-'));
|
|
88
|
+
const settingsFilePath = path.join(tempRoot, 'settings.json');
|
|
89
|
+
const wrappedFs = {
|
|
90
|
+
...fsPromises,
|
|
91
|
+
rename: async () => {
|
|
92
|
+
const error = new Error('operation not permitted');
|
|
93
|
+
error.code = 'EPERM';
|
|
94
|
+
throw error;
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
const runtime = createSettingsRuntime({
|
|
98
|
+
fsPromises: wrappedFs,
|
|
99
|
+
path,
|
|
100
|
+
crypto,
|
|
101
|
+
SETTINGS_FILE_PATH: settingsFilePath,
|
|
102
|
+
sanitizeProjects: (projects) => Array.isArray(projects) ? projects : [],
|
|
103
|
+
sanitizeSettingsUpdate: (settings) => settings,
|
|
104
|
+
mergePersistedSettings: (_current, changes) => changes,
|
|
105
|
+
normalizeSettingsPaths: (settings) => ({ settings, changed: false }),
|
|
106
|
+
normalizeStringArray: (values) => Array.isArray(values) ? values.filter((value) => typeof value === 'string') : [],
|
|
107
|
+
formatSettingsResponse: (settings) => settings,
|
|
108
|
+
resolveDirectoryCandidate: (value) => value,
|
|
109
|
+
normalizeManagedRemoteTunnelHostname: (value) => value,
|
|
110
|
+
normalizeManagedRemoteTunnelPresets: (value) => value,
|
|
111
|
+
normalizeManagedRemoteTunnelPresetTokens: (value) => value,
|
|
112
|
+
syncManagedRemoteTunnelConfigWithPresets: async () => {},
|
|
113
|
+
upsertManagedRemoteTunnelToken: async () => {},
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
await runtime.writeSettingsToDisk({ theme: 'dark' });
|
|
118
|
+
|
|
119
|
+
await expect(fsPromises.readFile(settingsFilePath, 'utf8')).resolves.toBe(JSON.stringify({ theme: 'dark' }, null, 2));
|
|
120
|
+
} finally {
|
|
121
|
+
await fsPromises.rm(tempRoot, { recursive: true, force: true });
|
|
122
|
+
}
|
|
123
|
+
});
|
|
85
124
|
});
|
|
@@ -17,7 +17,7 @@ export function parseSkillRepoSource(input, options = {}) {
|
|
|
17
17
|
return { ok: false, error: { kind: 'invalidSource', message: 'Repository source is required' } };
|
|
18
18
|
}
|
|
19
19
|
const explicitSubpath = typeof options.subpath === 'string' && options.subpath.trim() ? options.subpath.trim() : null;
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
const urlFormat = raw.startsWith('https://') ? 'https' : raw.startsWith('git@') ? 'ssh' : 'shorthand';
|
|
22
22
|
const gitHost = urlFormat === 'https' ? raw.split('/')[2] : urlFormat === 'ssh' ? raw.split('@')[1].split(':')[0] : null;
|
|
23
23
|
|
|
@@ -10,6 +10,7 @@ This module contains tunnel provider orchestration for OpenChamber, including pr
|
|
|
10
10
|
- `packages/web/server/lib/tunnels/routes.js`: tunnel API route registration and request orchestration runtime.
|
|
11
11
|
- `packages/web/server/lib/tunnels/types.js`: tunnel constants, normalization, and shared type helpers.
|
|
12
12
|
- `packages/web/server/lib/tunnels/providers/cloudflare.js`: Cloudflare tunnel provider implementation.
|
|
13
|
+
- `packages/web/server/lib/tunnels/providers/ngrok.js`: Ngrok quick tunnel provider implementation.
|
|
13
14
|
|
|
14
15
|
## Public exports (routes.js)
|
|
15
16
|
- `createTunnelRoutesRuntime(dependencies)`: creates tunnel routes runtime and helpers.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import {
|
|
2
|
+
checkNgrokApiReachability,
|
|
3
|
+
checkNgrokAuthtokenConfigured,
|
|
4
|
+
checkNgrokAvailable,
|
|
5
|
+
startNgrokQuickTunnel,
|
|
6
|
+
} from '../../ngrok-tunnel.js';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
TUNNEL_INTENT_EPHEMERAL_PUBLIC,
|
|
10
|
+
TUNNEL_MODE_QUICK,
|
|
11
|
+
TUNNEL_PROVIDER_NGROK,
|
|
12
|
+
TunnelServiceError,
|
|
13
|
+
} from '../types.js';
|
|
14
|
+
|
|
15
|
+
export const ngrokTunnelProviderCapabilities = {
|
|
16
|
+
provider: TUNNEL_PROVIDER_NGROK,
|
|
17
|
+
defaults: {
|
|
18
|
+
mode: TUNNEL_MODE_QUICK,
|
|
19
|
+
optionDefaults: {},
|
|
20
|
+
},
|
|
21
|
+
modes: [
|
|
22
|
+
{
|
|
23
|
+
key: TUNNEL_MODE_QUICK,
|
|
24
|
+
label: 'Quick Tunnel',
|
|
25
|
+
intent: TUNNEL_INTENT_EPHEMERAL_PUBLIC,
|
|
26
|
+
requires: [],
|
|
27
|
+
supports: ['sessionTTL'],
|
|
28
|
+
stability: 'beta',
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export function createNgrokTunnelProvider() {
|
|
34
|
+
return {
|
|
35
|
+
id: TUNNEL_PROVIDER_NGROK,
|
|
36
|
+
capabilities: ngrokTunnelProviderCapabilities,
|
|
37
|
+
checkAvailability: async () => {
|
|
38
|
+
const result = await checkNgrokAvailable();
|
|
39
|
+
if (result.available) {
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
...result,
|
|
44
|
+
message: 'ngrok is not installed. Install it with: brew install ngrok',
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
diagnose: async () => {
|
|
48
|
+
const dependency = await checkNgrokAvailable();
|
|
49
|
+
const authtoken = await checkNgrokAuthtokenConfigured(dependency.path);
|
|
50
|
+
const network = await checkNgrokApiReachability();
|
|
51
|
+
const startupReady = dependency.available && authtoken.configured && network.reachable;
|
|
52
|
+
const providerChecks = [
|
|
53
|
+
{
|
|
54
|
+
id: 'dependency',
|
|
55
|
+
label: 'ngrok installed',
|
|
56
|
+
status: dependency.available ? 'pass' : 'fail',
|
|
57
|
+
detail: dependency.available
|
|
58
|
+
? (dependency.version || dependency.path || 'ngrok available')
|
|
59
|
+
: 'ngrok is not installed. Install it with: brew install ngrok',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: 'authtoken',
|
|
63
|
+
label: 'ngrok authtoken configured',
|
|
64
|
+
status: authtoken.configured ? 'pass' : 'fail',
|
|
65
|
+
detail: authtoken.configured
|
|
66
|
+
? authtoken.detail
|
|
67
|
+
: (authtoken.detail || 'Run: ngrok config add-authtoken <your-ngrok-token>'),
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: 'network',
|
|
71
|
+
label: 'ngrok API reachable',
|
|
72
|
+
status: network.reachable ? 'pass' : 'fail',
|
|
73
|
+
detail: network.reachable
|
|
74
|
+
? (network.status ? `HTTP ${network.status}` : 'Reachable')
|
|
75
|
+
: (network.error || 'Could not reach api.ngrok.com'),
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
providerChecks,
|
|
81
|
+
modes: [
|
|
82
|
+
{
|
|
83
|
+
mode: TUNNEL_MODE_QUICK,
|
|
84
|
+
checks: [
|
|
85
|
+
{
|
|
86
|
+
id: 'startup_readiness',
|
|
87
|
+
label: 'Provider startup readiness',
|
|
88
|
+
status: startupReady ? 'pass' : 'fail',
|
|
89
|
+
detail: startupReady
|
|
90
|
+
? 'Provider dependency, auth, and network checks passed.'
|
|
91
|
+
: 'Resolve provider checks before starting tunnels.',
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
summary: {
|
|
95
|
+
ready: startupReady,
|
|
96
|
+
failures: startupReady ? 0 : 1,
|
|
97
|
+
warnings: 0,
|
|
98
|
+
},
|
|
99
|
+
ready: startupReady,
|
|
100
|
+
blockers: startupReady ? [] : ['Resolve provider checks before starting tunnels.'],
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
start: async (request, context = {}) => {
|
|
106
|
+
if (request.mode !== TUNNEL_MODE_QUICK) {
|
|
107
|
+
throw new TunnelServiceError('mode_unsupported', `Ngrok only supports '${TUNNEL_MODE_QUICK}' mode right now`);
|
|
108
|
+
}
|
|
109
|
+
return startNgrokQuickTunnel({ port: context.activePort });
|
|
110
|
+
},
|
|
111
|
+
stop: (controller) => {
|
|
112
|
+
controller?.stop?.();
|
|
113
|
+
},
|
|
114
|
+
resolvePublicUrl: (controller) => controller?.getPublicUrl?.() ?? null,
|
|
115
|
+
getMetadata: () => null,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
@@ -2,6 +2,7 @@ import os from 'os';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
4
|
export const TUNNEL_PROVIDER_CLOUDFLARE = 'cloudflare';
|
|
5
|
+
export const TUNNEL_PROVIDER_NGROK = 'ngrok';
|
|
5
6
|
|
|
6
7
|
export const TUNNEL_MODE_QUICK = 'quick';
|
|
7
8
|
export const TUNNEL_MODE_MANAGED_REMOTE = 'managed-remote';
|
|
@@ -34,6 +35,7 @@ export class TunnelServiceError extends Error {
|
|
|
34
35
|
|
|
35
36
|
const SUPPORTED_TUNNEL_PROVIDERS = new Set([
|
|
36
37
|
TUNNEL_PROVIDER_CLOUDFLARE,
|
|
38
|
+
TUNNEL_PROVIDER_NGROK,
|
|
37
39
|
]);
|
|
38
40
|
|
|
39
41
|
export function normalizeTunnelProvider(value) {
|