@xopcai/xopc 0.0.77 → 0.0.78
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/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agents-DN3vr8pb.js → agents-Bh_9-1KB.js} +2 -2
- package/dist/gateway/static/root/assets/{agents-DN3vr8pb.js.map → agents-Bh_9-1KB.js.map} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-BUn41aPi.js → apps-page-CB5anZpc.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-BUn41aPi.js.map → apps-page-CB5anZpc.js.map} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-CYMmWDtP.js → channels-settings-Bt1sprhC.js} +2 -2
- package/dist/gateway/static/root/assets/{channels-settings-CYMmWDtP.js.map → channels-settings-Bt1sprhC.js.map} +1 -1
- package/dist/gateway/static/root/assets/{channels-status-swr-sJj4ueTp.js → channels-status-swr-Crgak3fg.js} +2 -2
- package/dist/gateway/static/root/assets/{channels-status-swr-sJj4ueTp.js.map → channels-status-swr-Crgak3fg.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-api-CLxnaHdq.js → cron-api-CzJGvQQ7.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-api-CLxnaHdq.js.map → cron-api-CzJGvQQ7.js.map} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-BAQ8xSnJ.js → cron-page-BoNRJNVV.js} +2 -2
- package/dist/gateway/static/root/assets/{cron-page-BAQ8xSnJ.js.map → cron-page-BoNRJNVV.js.map} +1 -1
- package/dist/gateway/static/root/assets/{dist-BfJYxiK5.js → dist-a-eaOUvs.js} +2 -2
- package/dist/gateway/static/root/assets/{dist-BfJYxiK5.js.map → dist-a-eaOUvs.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-bgvVs-Sy.js → extension-debug-page-D-O1XjAa.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-debug-page-bgvVs-Sy.js.map → extension-debug-page-D-O1XjAa.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-SG4TVv-u.js → extension-page-B2VpqBTH.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-page-SG4TVv-u.js.map → extension-page-B2VpqBTH.js.map} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-CJZRTsjF.js → extension-settings-page-CmBcQfeO.js} +2 -2
- package/dist/gateway/static/root/assets/{extension-settings-page-CJZRTsjF.js.map → extension-settings-page-CmBcQfeO.js.map} +1 -1
- package/dist/gateway/static/root/assets/{fetch-K_0JRCXU.js → fetch-EGO9T3MN.js} +3 -3
- package/dist/gateway/static/root/assets/{fetch-K_0JRCXU.js.map → fetch-EGO9T3MN.js.map} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-Z76hyBYS.js → field-primitives-Bh7G1y4D.js} +2 -2
- package/dist/gateway/static/root/assets/{field-primitives-Z76hyBYS.js.map → field-primitives-Bh7G1y4D.js.map} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-BqfDabSI.js → heartbeat-config-api-DxpIEZNs.js} +2 -2
- package/dist/gateway/static/root/assets/{heartbeat-config-api-BqfDabSI.js.map → heartbeat-config-api-DxpIEZNs.js.map} +1 -1
- package/dist/gateway/static/root/assets/{index-ChiUhJAs.js → index-Dxy9ZCtC.js} +5 -5
- package/dist/gateway/static/root/assets/{index-ChiUhJAs.js.map → index-Dxy9ZCtC.js.map} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-DrIMhDE2.js → logs-page-Dw58E2GE.js} +2 -2
- package/dist/gateway/static/root/assets/{logs-page-DrIMhDE2.js.map → logs-page-Dw58E2GE.js.map} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-B-RGO3N0.js → sessions-page-CPkhCy57.js} +2 -2
- package/dist/gateway/static/root/assets/{sessions-page-B-RGO3N0.js.map → sessions-page-CPkhCy57.js.map} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-Csvl1iL6.js → settings-form-section-DLZDVMEf.js} +2 -2
- package/dist/gateway/static/root/assets/{settings-form-section-Csvl1iL6.js.map → settings-form-section-DLZDVMEf.js.map} +1 -1
- package/dist/gateway/static/root/assets/settings-page-CVPCa0PE.js +4 -0
- package/dist/gateway/static/root/assets/settings-page-CVPCa0PE.js.map +1 -0
- package/dist/gateway/static/root/assets/{skills-page-dHwx2vh0.js → skills-page-DueZ9Qfg.js} +2 -2
- package/dist/gateway/static/root/assets/{skills-page-dHwx2vh0.js.map → skills-page-DueZ9Qfg.js.map} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-Bl5A2Fd_.js → theme-store-CWPq9gW1.js} +2 -2
- package/dist/gateway/static/root/assets/{theme-store-Bl5A2Fd_.js.map → theme-store-CWPq9gW1.js.map} +1 -1
- package/dist/gateway/static/root/assets/{utils-COYrNFF7.js → utils-Cnix55r9.js} +2 -2
- package/dist/gateway/static/root/assets/{utils-COYrNFF7.js.map → utils-Cnix55r9.js.map} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-5WZZaxH3.js → voice-api-key-field-BR3Ut06g.js} +2 -2
- package/dist/gateway/static/root/assets/{voice-api-key-field-5WZZaxH3.js.map → voice-api-key-field-BR3Ut06g.js.map} +1 -1
- package/dist/gateway/static/root/index.html +3 -3
- package/dist/package.js +1 -1
- package/dist/src/browser/providers/browser-ext-install.js +23 -4
- package/dist/src/browser/providers/browser-ext-install.js.map +1 -1
- package/dist/src/cli/commands/tunnel.js +4 -5
- package/dist/src/cli/commands/tunnel.js.map +1 -1
- package/dist/src/config/index.js +2 -2
- package/dist/src/config/rules.js +0 -5
- package/dist/src/config/rules.js.map +1 -1
- package/dist/src/config/schema.d.ts +0 -27
- package/dist/src/config/schema.js +4 -18
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/gateway/auth-rate-limit.d.ts +2 -0
- package/dist/src/gateway/auth-rate-limit.js +9 -3
- package/dist/src/gateway/auth-rate-limit.js.map +1 -1
- package/dist/src/gateway/hono/app.js +19 -13
- package/dist/src/gateway/hono/app.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +3 -1
- package/dist/src/gateway/hono/lib/config-payload.js +1 -2
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/routes/tunnel.js +32 -30
- package/dist/src/gateway/hono/routes/tunnel.js.map +1 -1
- package/dist/src/gateway/host.d.ts +24 -0
- package/dist/src/gateway/host.js +33 -1
- package/dist/src/gateway/host.js.map +1 -1
- package/dist/src/gateway/index.d.ts +1 -1
- package/dist/src/gateway/index.js +2 -2
- package/dist/src/gateway/runtime-config.js +1 -8
- package/dist/src/gateway/runtime-config.js.map +1 -1
- package/dist/src/gateway/security/audit.js +4 -4
- package/dist/src/gateway/security/audit.js.map +1 -1
- package/dist/src/gateway/server.js +2 -3
- package/dist/src/gateway/server.js.map +1 -1
- package/dist/src/gateway/service/types.d.ts +2 -0
- package/dist/src/gateway/service.d.ts +2 -0
- package/dist/src/gateway/service.js +7 -2
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/tunnel/frp-subdomain-host.d.ts +2 -0
- package/dist/src/tunnel/frp-subdomain-host.js +15 -0
- package/dist/src/tunnel/frp-subdomain-host.js.map +1 -0
- package/dist/src/tunnel/gateway-lifecycle.d.ts +0 -4
- package/dist/src/tunnel/gateway-lifecycle.js +9 -11
- package/dist/src/tunnel/gateway-lifecycle.js.map +1 -1
- package/dist/src/tunnel/index.d.ts +2 -4
- package/dist/src/tunnel/index.js +2 -4
- package/dist/src/tunnel/pair-url.js +7 -1
- package/dist/src/tunnel/pair-url.js.map +1 -1
- package/dist/src/tunnel/pairing.d.ts +13 -0
- package/dist/src/tunnel/pairing.js +48 -1
- package/dist/src/tunnel/pairing.js.map +1 -1
- package/dist/src/tunnel/tunnel-config.js +2 -16
- package/dist/src/tunnel/tunnel-config.js.map +1 -1
- package/dist/src/tunnel/tunnel-service.d.ts +1 -10
- package/dist/src/tunnel/tunnel-service.js +7 -60
- package/dist/src/tunnel/tunnel-service.js.map +1 -1
- package/dist/src/tunnel/tunnel-types.d.ts +3 -18
- package/dist/src/tunnel/well-known.d.ts +5 -0
- package/dist/src/tunnel/well-known.js +2 -1
- package/dist/src/tunnel/well-known.js.map +1 -1
- package/package.json +2 -2
- package/dist/gateway/static/root/assets/settings-page-nxAc0ta1.js +0 -4
- package/dist/gateway/static/root/assets/settings-page-nxAc0ta1.js.map +0 -1
- package/dist/src/tunnel/acme-cert-store.d.ts +0 -34
- package/dist/src/tunnel/acme-cert-store.js +0 -184
- package/dist/src/tunnel/acme-cert-store.js.map +0 -1
- package/dist/src/tunnel/acme-client.d.ts +0 -50
- package/dist/src/tunnel/acme-client.js +0 -473
- package/dist/src/tunnel/acme-client.js.map +0 -1
- package/dist/src/tunnel/acme-crypto.d.ts +0 -25
- package/dist/src/tunnel/acme-crypto.js +0 -58
- package/dist/src/tunnel/acme-crypto.js.map +0 -1
- package/dist/src/tunnel/acme-csr.d.ts +0 -5
- package/dist/src/tunnel/acme-csr.js +0 -48
- package/dist/src/tunnel/acme-csr.js.map +0 -1
- package/dist/src/tunnel/tls-server.d.ts +0 -14
- package/dist/src/tunnel/tls-server.js +0 -126
- package/dist/src/tunnel/tls-server.js.map +0 -1
- package/dist/src/tunnel/tunnel-e2e-config.d.ts +0 -11
- package/dist/src/tunnel/tunnel-e2e-config.js +0 -29
- package/dist/src/tunnel/tunnel-e2e-config.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-ext-install.js","names":[],"sources":["../../../../src/browser/providers/browser-ext-install.ts"],"sourcesContent":["/**\n * Install bundled Chrome extension artifacts into {resolveBinDir()}/browser-ext/.\n */\n\nimport { cpSync, existsSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, symlinkSync } from 'node:fs';\nimport { readFile, readdir, rm } from 'node:fs/promises';\nimport { spawn } from 'node:child_process';\nimport { dirname, join, relative, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { PACKAGE_VERSION } from '../../package-version.js';\nimport { resolveBinDir } from '../../config/paths.js';\nimport { resolvePackageRoot } from '../../infra/update-check.js';\nimport { writeTextAtomic } from '../../infra/write-file-atomic.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { assertCacheDir } from '../cache-dir-policy.js';\n\nconst log = createLogger('BrowserExtInstall');\n\nconst META_FILENAME = '.meta.json';\nconst CURRENT_LINK = 'current';\nconst STAGING_MAX_AGE_MS = 60 * 60 * 1000;\n\nexport const BROWSER_EXT_REQUIRED_FILES = [\n 'manifest.json',\n 'popup.html',\n 'dist/background.js',\n 'dist/content.js',\n 'dist/popup.js',\n] as const;\n\nexport type BrowserExtBundledFrom = 'npm-dist' | 'git-dev' | 'electron-asar' | 'env-override';\n\nexport interface BrowserExtInstallMeta {\n xopcVersion: string;\n manifestVersion: string;\n source: 'bundled';\n bundledFrom: BrowserExtBundledFrom;\n installedAt: string;\n installPath: string;\n previousVersion?: string;\n}\n\nexport interface BrowserExtDoctor {\n bundledAvailable: boolean;\n installed: boolean;\n xopcVersion: string;\n installedVersion?: string;\n manifestVersion?: string;\n extensionDir?: string;\n cacheDir: string;\n needsRefresh: boolean;\n needsChromeReload?: boolean;\n bundledFrom?: BrowserExtBundledFrom;\n runtimeExtensionVersion?: string;\n}\n\nexport interface EnsureBrowserExtResult {\n extensionDir: string;\n xopcVersion: string;\n copied: boolean;\n previousVersion?: string;\n}\n\nfunction moduleDir(): string {\n return dirname(fileURLToPath(import.meta.url));\n}\n\n/** Validate a directory contains a loadable extension tree. */\nexport function validateBrowserExtLayout(dir: string): boolean {\n return BROWSER_EXT_REQUIRED_FILES.every((rel) => existsSync(join(dir, rel)));\n}\n\nfunction readManifestVersion(dir: string): string | undefined {\n try {\n const raw = readFileSync(join(dir, 'manifest.json'), 'utf8');\n const parsed = JSON.parse(raw) as { version?: unknown };\n return typeof parsed.version === 'string' ? parsed.version : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function readMeta(metaPath: string): Promise<BrowserExtInstallMeta | null> {\n try {\n const raw = await readFile(metaPath, 'utf8');\n const parsed = JSON.parse(raw) as BrowserExtInstallMeta;\n if (parsed && typeof parsed === 'object' && typeof parsed.xopcVersion === 'string') {\n return parsed;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nfunction browserExtRoot(cacheDir: string): string {\n return join(cacheDir, 'browser-ext');\n}\n\nfunction resolveCurrentPath(cacheDir: string): string {\n return join(browserExtRoot(cacheDir), CURRENT_LINK);\n}\n\nfunction resolveMetaPath(cacheDir: string): string {\n return join(browserExtRoot(cacheDir), META_FILENAME);\n}\n\nfunction resolveCurrentRealPath(cacheDir: string): string | null {\n const current = resolveCurrentPath(cacheDir);\n if (!existsSync(current)) return null;\n try {\n const real = realpathSync(current);\n return validateBrowserExtLayout(real) ? real : null;\n } catch {\n return null;\n }\n}\n\nfunction walkAncestorsForGitDevBundled(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 12; i++) {\n const candidate = join(dir, 'packages/browser-ext');\n if (validateBrowserExtLayout(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Resolve the bundled extension source directory (read-only).\n */\nexport async function resolveBundledBrowserExtDir(): Promise<{\n dir: string;\n bundledFrom: BrowserExtBundledFrom;\n} | null> {\n const envOverride = process.env.XOPC_BROWSER_EXT_BUNDLED_ROOT?.trim();\n if (envOverride && validateBrowserExtLayout(envOverride)) {\n return { dir: envOverride, bundledFrom: 'env-override' };\n }\n\n const fromModule = join(moduleDir(), '../../../browser-ext');\n if (validateBrowserExtLayout(fromModule)) {\n const root = await resolvePackageRoot();\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: fromModule, bundledFrom };\n }\n\n const gitDev = walkAncestorsForGitDevBundled(moduleDir());\n if (gitDev) {\n return { dir: gitDev, bundledFrom: 'git-dev' };\n }\n\n const root = await resolvePackageRoot();\n if (root) {\n const distBundled = join(root, 'dist/browser-ext');\n if (validateBrowserExtLayout(distBundled)) {\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: distBundled, bundledFrom };\n }\n }\n\n return null;\n}\n\nexport function computeNeedsRefresh(params: {\n force?: boolean;\n bundledManifestVersion: string;\n currentRealPath: string | null;\n meta: BrowserExtInstallMeta | null;\n}): boolean {\n if (params.force) return true;\n if (!params.currentRealPath || !validateBrowserExtLayout(params.currentRealPath)) return true;\n\n const currentManifest = readManifestVersion(params.currentRealPath);\n if (!currentManifest || currentManifest !== params.bundledManifestVersion) return true;\n\n if (!params.meta || params.meta.xopcVersion !== PACKAGE_VERSION) return true;\n\n return false;\n}\n\nasync function cleanupStaleStaging(root: string): Promise<void> {\n if (!existsSync(root)) return;\n let entries: string[];\n try {\n entries = await readdir(root);\n } catch {\n return;\n }\n const now = Date.now();\n for (const name of entries) {\n if (!name.startsWith('.staging-')) continue;\n const full = join(root, name);\n try {\n const st = statSync(full);\n if (now - st.mtimeMs > STAGING_MAX_AGE_MS) {\n await rm(full, { recursive: true, force: true });\n }\n } catch {\n /* */\n }\n }\n}\n\nfunction switchCurrentLink(root: string, versionDir: string): void {\n const currentPath = join(root, CURRENT_LINK);\n const versionName = relative(root, versionDir);\n const tmpLink = join(root, `.current-${process.pid}`);\n\n if (existsSync(tmpLink)) {\n rmSync(tmpLink, { recursive: true, force: true });\n }\n if (existsSync(currentPath)) {\n rmSync(currentPath, { recursive: true, force: true });\n }\n\n if (process.platform === 'win32') {\n const target = resolve(versionDir);\n cpSync(target, currentPath, { recursive: true });\n return;\n }\n\n try {\n symlinkSync(versionName, tmpLink, 'dir');\n renameSync(tmpLink, currentPath);\n } catch {\n cpSync(versionDir, currentPath, { recursive: true });\n }\n}\n\nasync function gcOldVersions(root: string, keepVersions: Set<string>): Promise<void> {\n if (!existsSync(root)) return;\n let entries: string[];\n try {\n entries = await readdir(root);\n } catch {\n return;\n }\n for (const name of entries) {\n if (name === CURRENT_LINK || name === META_FILENAME || name.startsWith('.')) continue;\n if (!keepVersions.has(name)) {\n try {\n await rm(join(root, name), { recursive: true, force: true });\n log.info({ version: name }, 'Removed old browser extension version directory');\n } catch (err) {\n log.warn({ err, version: name }, 'Failed to remove old browser extension version');\n }\n }\n }\n}\n\nfunction copyBundledTree(src: string, dest: string): void {\n mkdirSync(dest, { recursive: true });\n for (const name of ['manifest.json', 'popup.html']) {\n cpSync(join(src, name), join(dest, name));\n }\n cpSync(join(src, 'dist'), join(dest, 'dist'), { recursive: true });\n cpSync(join(src, 'icons'), join(dest, 'icons'), { recursive: true });\n if (!validateBrowserExtLayout(dest)) {\n throw new Error('Bundled browser extension copy failed validation');\n }\n}\n\nexport async function browserExtDoctor(opts?: {\n cacheDir?: string;\n runtimeExtensionVersion?: string;\n}): Promise<BrowserExtDoctor> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n const bundledManifestVersion = bundled ? readManifestVersion(bundled.dir) : undefined;\n const currentRealPath = resolveCurrentRealPath(cacheDir);\n const meta = await readMeta(resolveMetaPath(cacheDir));\n\n const needsRefresh = bundled\n ? computeNeedsRefresh({\n force: false,\n bundledManifestVersion: bundledManifestVersion ?? PACKAGE_VERSION,\n currentRealPath,\n meta,\n })\n : false;\n\n const installed = Boolean(currentRealPath) && !needsRefresh;\n const manifestVersion = currentRealPath ? readManifestVersion(currentRealPath) : undefined;\n\n let needsChromeReload: boolean | undefined;\n const runtimeVer = opts?.runtimeExtensionVersion?.trim();\n if (runtimeVer && manifestVersion && runtimeVer !== manifestVersion) {\n needsChromeReload = true;\n }\n\n return {\n bundledAvailable: Boolean(bundled),\n installed,\n xopcVersion: PACKAGE_VERSION,\n installedVersion: meta?.xopcVersion,\n manifestVersion,\n extensionDir: currentRealPath ?? undefined,\n cacheDir,\n needsRefresh,\n needsChromeReload,\n bundledFrom: bundled?.bundledFrom,\n runtimeExtensionVersion: runtimeVer,\n };\n}\n\nexport async function ensureBrowserExtensionArtifacts(opts?: {\n force?: boolean;\n cacheDir?: string;\n}): Promise<EnsureBrowserExtResult> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n if (!bundled) {\n throw new Error(\n 'Bundled browser extension not found. Reinstall xopc or run from a built checkout (pnpm run build).',\n );\n }\n\n const bundledManifestVersion = readManifestVersion(bundled.dir) ?? PACKAGE_VERSION;\n const root = browserExtRoot(cacheDir);\n mkdirSync(root, { recursive: true });\n await cleanupStaleStaging(root);\n\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const currentRealPath = resolveCurrentRealPath(cacheDir);\n const needsRefresh = computeNeedsRefresh({\n force: opts?.force,\n bundledManifestVersion,\n currentRealPath,\n meta,\n });\n\n if (!needsRefresh && currentRealPath) {\n return {\n extensionDir: currentRealPath,\n xopcVersion: PACKAGE_VERSION,\n copied: false,\n previousVersion: meta?.previousVersion,\n };\n }\n\n const versionKey = PACKAGE_VERSION;\n const versionDir = join(root, versionKey);\n const stagingDir = join(root, `.staging-${versionKey}-${process.pid}`);\n\n if (existsSync(stagingDir)) {\n rmSync(stagingDir, { recursive: true, force: true });\n }\n copyBundledTree(bundled.dir, stagingDir);\n\n if (existsSync(versionDir)) {\n rmSync(versionDir, { recursive: true, force: true });\n }\n renameSync(stagingDir, versionDir);\n\n switchCurrentLink(root, versionDir);\n const extensionDir = resolveCurrentRealPath(cacheDir) ?? versionDir;\n\n const previousVersion =\n meta?.xopcVersion && meta.xopcVersion !== PACKAGE_VERSION ? meta.xopcVersion : meta?.previousVersion;\n\n const nextMeta: BrowserExtInstallMeta = {\n xopcVersion: PACKAGE_VERSION,\n manifestVersion: bundledManifestVersion,\n source: 'bundled',\n bundledFrom: bundled.bundledFrom,\n installedAt: new Date().toISOString(),\n installPath: versionDir,\n ...(previousVersion ? { previousVersion } : {}),\n };\n await writeTextAtomic(resolveMetaPath(cacheDir), JSON.stringify(nextMeta, null, 2));\n\n const keep = new Set<string>([versionKey]);\n if (previousVersion) keep.add(previousVersion);\n await gcOldVersions(root, keep);\n\n log.info(\n { extensionDir, xopcVersion: PACKAGE_VERSION, bundledFrom: bundled.bundledFrom },\n 'Browser extension artifacts installed',\n );\n\n return {\n extensionDir,\n xopcVersion: PACKAGE_VERSION,\n copied: true,\n previousVersion,\n };\n}\n\n/**\n * Gateway startup hook: ensure artifacts when extension backend is enabled or prior install exists.\n */\nexport async function ensureBrowserExtensionOnStartup(config: {\n agents?: { defaults?: { browser?: { backend?: string } } };\n}): Promise<void> {\n const backend = config.agents?.defaults?.browser?.backend;\n const cacheDir = resolveBinDir();\n const metaExists = existsSync(resolveMetaPath(cacheDir));\n if (backend !== 'extension' && !metaExists) {\n return;\n }\n await ensureBrowserExtensionArtifacts();\n}\n\nexport async function readInstalledExtensionDir(cacheDir?: string): Promise<string | null> {\n const dir = cacheDir?.trim() ? assertCacheDir(cacheDir) : resolveBinDir();\n return resolveCurrentRealPath(dir || resolveBinDir());\n}\n\nexport type BrowserExtensionOpenAction = 'chrome' | 'folder' | 'both';\n\nfunction spawnDetached(command: string, args: readonly string[]): void {\n spawn(command, [...args], { stdio: 'ignore', detached: true }).unref();\n}\n\nfunction openChromeExtensionsPage(): void {\n const chromeUrl = 'chrome://extensions';\n if (process.platform === 'darwin') {\n spawnDetached('open', ['-a', 'Google Chrome', chromeUrl]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('cmd', ['/c', 'start', 'chrome', chromeUrl]);\n return;\n }\n spawnDetached('xdg-open', [chromeUrl]);\n}\n\nfunction revealFolderInFileManager(dir: string): void {\n if (process.platform === 'darwin') {\n spawnDetached('open', [dir]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('explorer', [dir]);\n return;\n }\n spawnDetached('xdg-open', [dir]);\n}\n\n/**\n * Open chrome://extensions and/or reveal the installed extension folder on the gateway host.\n */\nexport async function openBrowserExtensionInstallUi(opts: {\n action: BrowserExtensionOpenAction;\n cacheDir?: string;\n}): Promise<{ extensionDir: string }> {\n const doctor = await browserExtDoctor({ cacheDir: opts.cacheDir });\n const dir = doctor.extensionDir;\n if (!dir) {\n throw new Error('Extension not installed. Run xopc browser extension install first.');\n }\n\n if (opts.action === 'chrome' || opts.action === 'both') {\n openChromeExtensionsPage();\n }\n if (opts.action === 'folder' || opts.action === 'both') {\n revealFolderInFileManager(dir);\n }\n\n return { extensionDir: dir };\n}\n"],"mappings":";;;;;;;;;;;;;;;;sBAU2D;YACL;wBAEa;aACd;uBACG;AAExD,MAAM,MAAM,aAAa,oBAAoB;AAE7C,MAAM,gBAAgB;AACtB,MAAM,eAAe;AACrB,MAAM,qBAAqB,OAAU;AAErC,MAAa,6BAA6B;CACxC;CACA;CACA;CACA;CACA;CACD;AAmCD,SAAS,YAAoB;AAC3B,QAAO,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;;;AAIhD,SAAgB,yBAAyB,KAAsB;AAC7D,QAAO,2BAA2B,OAAO,QAAQ,WAAW,KAAK,KAAK,IAAI,CAAC,CAAC;;AAG9E,SAAS,oBAAoB,KAAiC;AAC5D,KAAI;EACF,MAAM,MAAM,aAAa,KAAK,KAAK,gBAAgB,EAAE,OAAO;EAC5D,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,SAAO,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU,KAAA;SACvD;AACN;;;AAIJ,eAAe,SAAS,UAAyD;AAC/E,KAAI;EACF,MAAM,MAAM,MAAM,SAAS,UAAU,OAAO;EAC5C,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,MAAI,UAAU,OAAO,WAAW,YAAY,OAAO,OAAO,gBAAgB,SACxE,QAAO;AAET,SAAO;SACD;AACN,SAAO;;;AAIX,SAAS,eAAe,UAA0B;AAChD,QAAO,KAAK,UAAU,cAAc;;AAGtC,SAAS,mBAAmB,UAA0B;AACpD,QAAO,KAAK,eAAe,SAAS,EAAE,aAAa;;AAGrD,SAAS,gBAAgB,UAA0B;AACjD,QAAO,KAAK,eAAe,SAAS,EAAE,cAAc;;AAGtD,SAAS,uBAAuB,UAAiC;CAC/D,MAAM,UAAU,mBAAmB,SAAS;AAC5C,KAAI,CAAC,WAAW,QAAQ,CAAE,QAAO;AACjC,KAAI;EACF,MAAM,OAAO,aAAa,QAAQ;AAClC,SAAO,yBAAyB,KAAK,GAAG,OAAO;SACzC;AACN,SAAO;;;AAIX,SAAS,8BAA8B,OAA8B;CACnE,IAAI,MAAM;AACV,MAAK,IAAI,IAAI,GAAG,IAAI,IAAI,KAAK;EAC3B,MAAM,YAAY,KAAK,KAAK,uBAAuB;AACnD,MAAI,yBAAyB,UAAU,CACrC,QAAO;EAET,MAAM,SAAS,QAAQ,IAAI;AAC3B,MAAI,WAAW,IAAK;AACpB,QAAM;;AAER,QAAO;;;;;AAMT,eAAsB,8BAGZ;CACR,MAAM,cAAc,QAAQ,IAAI,+BAA+B,MAAM;AACrE,KAAI,eAAe,yBAAyB,YAAY,CACtD,QAAO;EAAE,KAAK;EAAa,aAAa;EAAgB;CAG1D,MAAM,aAAa,KAAK,WAAW,EAAE,uBAAuB;AAC5D,KAAI,yBAAyB,WAAW,EAAE;EACxC,MAAM,OAAO,MAAM,oBAAoB;AAGvC,SAAO;GAAE,KAAK;GAAY,aADxB,QAAQ,SAAS,YAAY,QAAQ,KAAK,SAAS,WAAW,GAAG,kBAAkB;GAC9C;;CAGzC,MAAM,SAAS,8BAA8B,WAAW,CAAC;AACzD,KAAI,OACF,QAAO;EAAE,KAAK;EAAQ,aAAa;EAAW;CAGhD,MAAM,OAAO,MAAM,oBAAoB;AACvC,KAAI,MAAM;EACR,MAAM,cAAc,KAAK,MAAM,mBAAmB;AAClD,MAAI,yBAAyB,YAAY,CAGvC,QAAO;GAAE,KAAK;GAAa,aADzB,QAAQ,SAAS,YAAY,KAAK,SAAS,WAAW,GAAG,kBAAkB;GACrC;;AAI5C,QAAO;;AAGT,SAAgB,oBAAoB,QAKxB;AACV,KAAI,OAAO,MAAO,QAAO;AACzB,KAAI,CAAC,OAAO,mBAAmB,CAAC,yBAAyB,OAAO,gBAAgB,CAAE,QAAO;CAEzF,MAAM,kBAAkB,oBAAoB,OAAO,gBAAgB;AACnE,KAAI,CAAC,mBAAmB,oBAAoB,OAAO,uBAAwB,QAAO;AAElF,KAAI,CAAC,OAAO,QAAQ,OAAO,KAAK,gBAAgB,gBAAiB,QAAO;AAExE,QAAO;;AAGT,eAAe,oBAAoB,MAA6B;AAC9D,KAAI,CAAC,WAAW,KAAK,CAAE;CACvB,IAAI;AACJ,KAAI;AACF,YAAU,MAAM,QAAQ,KAAK;SACvB;AACN;;CAEF,MAAM,MAAM,KAAK,KAAK;AACtB,MAAK,MAAM,QAAQ,SAAS;AAC1B,MAAI,CAAC,KAAK,WAAW,YAAY,CAAE;EACnC,MAAM,OAAO,KAAK,MAAM,KAAK;AAC7B,MAAI;AAEF,OAAI,MADO,SAAS,KACR,CAAC,UAAU,mBACrB,OAAM,GAAG,MAAM;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;UAE5C;;;AAMZ,SAAS,kBAAkB,MAAc,YAA0B;CACjE,MAAM,cAAc,KAAK,MAAM,aAAa;CAC5C,MAAM,cAAc,SAAS,MAAM,WAAW;CAC9C,MAAM,UAAU,KAAK,MAAM,YAAY,QAAQ,MAAM;AAErD,KAAI,WAAW,QAAQ,CACrB,QAAO,SAAS;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAEnD,KAAI,WAAW,YAAY,CACzB,QAAO,aAAa;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAGvD,KAAI,QAAQ,aAAa,SAAS;AAEhC,SADe,QAAQ,WACV,EAAE,aAAa,EAAE,WAAW,MAAM,CAAC;AAChD;;AAGF,KAAI;AACF,cAAY,aAAa,SAAS,MAAM;AACxC,aAAW,SAAS,YAAY;SAC1B;AACN,SAAO,YAAY,aAAa,EAAE,WAAW,MAAM,CAAC;;;AAIxD,eAAe,cAAc,MAAc,cAA0C;AACnF,KAAI,CAAC,WAAW,KAAK,CAAE;CACvB,IAAI;AACJ,KAAI;AACF,YAAU,MAAM,QAAQ,KAAK;SACvB;AACN;;AAEF,MAAK,MAAM,QAAQ,SAAS;AAC1B,MAAI,SAAS,gBAAgB,SAAS,iBAAiB,KAAK,WAAW,IAAI,CAAE;AAC7E,MAAI,CAAC,aAAa,IAAI,KAAK,CACzB,KAAI;AACF,SAAM,GAAG,KAAK,MAAM,KAAK,EAAE;IAAE,WAAW;IAAM,OAAO;IAAM,CAAC;AAC5D,OAAI,KAAK,EAAE,SAAS,MAAM,EAAE,kDAAkD;WACvE,KAAK;AACZ,OAAI,KAAK;IAAE;IAAK,SAAS;IAAM,EAAE,iDAAiD;;;;AAM1F,SAAS,gBAAgB,KAAa,MAAoB;AACxD,WAAU,MAAM,EAAE,WAAW,MAAM,CAAC;AACpC,MAAK,MAAM,QAAQ,CAAC,iBAAiB,aAAa,CAChD,QAAO,KAAK,KAAK,KAAK,EAAE,KAAK,MAAM,KAAK,CAAC;AAE3C,QAAO,KAAK,KAAK,OAAO,EAAE,KAAK,MAAM,OAAO,EAAE,EAAE,WAAW,MAAM,CAAC;AAClE,QAAO,KAAK,KAAK,QAAQ,EAAE,KAAK,MAAM,QAAQ,EAAE,EAAE,WAAW,MAAM,CAAC;AACpE,KAAI,CAAC,yBAAyB,KAAK,CACjC,OAAM,IAAI,MAAM,mDAAmD;;AAIvE,eAAsB,iBAAiB,MAGT;CAI5B,MAAM,YAHgB,MAAM,UAAU,MAAM,GACxC,eAAe,KAAK,SAAS,GAC7B,eAAe,KACe,eAAe;CAEjD,MAAM,UAAU,MAAM,6BAA6B;CACnD,MAAM,yBAAyB,UAAU,oBAAoB,QAAQ,IAAI,GAAG,KAAA;CAC5E,MAAM,kBAAkB,uBAAuB,SAAS;CACxD,MAAM,OAAO,MAAM,SAAS,gBAAgB,SAAS,CAAC;CAEtD,MAAM,eAAe,UACjB,oBAAoB;EAClB,OAAO;EACP,wBAAwB,0BAA0B;EAClD;EACA;EACD,CAAC,GACF;CAEJ,MAAM,YAAY,QAAQ,gBAAgB,IAAI,CAAC;CAC/C,MAAM,kBAAkB,kBAAkB,oBAAoB,gBAAgB,GAAG,KAAA;CAEjF,IAAI;CACJ,MAAM,aAAa,MAAM,yBAAyB,MAAM;AACxD,KAAI,cAAc,mBAAmB,eAAe,gBAClD,qBAAoB;AAGtB,QAAO;EACL,kBAAkB,QAAQ,QAAQ;EAClC;EACA,aAAa;EACb,kBAAkB,MAAM;EACxB;EACA,cAAc,mBAAmB,KAAA;EACjC;EACA;EACA;EACA,aAAa,SAAS;EACtB,yBAAyB;EAC1B;;AAGH,eAAsB,gCAAgC,MAGlB;CAIlC,MAAM,YAHgB,MAAM,UAAU,MAAM,GACxC,eAAe,KAAK,SAAS,GAC7B,eAAe,KACe,eAAe;CAEjD,MAAM,UAAU,MAAM,6BAA6B;AACnD,KAAI,CAAC,QACH,OAAM,IAAI,MACR,qGACD;CAGH,MAAM,yBAAyB,oBAAoB,QAAQ,IAAI,IAAI;CACnE,MAAM,OAAO,eAAe,SAAS;AACrC,WAAU,MAAM,EAAE,WAAW,MAAM,CAAC;AACpC,OAAM,oBAAoB,KAAK;CAE/B,MAAM,OAAO,MAAM,SAAS,gBAAgB,SAAS,CAAC;CACtD,MAAM,kBAAkB,uBAAuB,SAAS;AAQxD,KAAI,CAPiB,oBAAoB;EACvC,OAAO,MAAM;EACb;EACA;EACA;EACD,CAEgB,IAAI,gBACnB,QAAO;EACL,cAAc;EACd,aAAa;EACb,QAAQ;EACR,iBAAiB,MAAM;EACxB;CAGH,MAAM,aAAa;CACnB,MAAM,aAAa,KAAK,MAAM,WAAW;CACzC,MAAM,aAAa,KAAK,MAAM,YAAY,WAAW,GAAG,QAAQ,MAAM;AAEtE,KAAI,WAAW,WAAW,CACxB,QAAO,YAAY;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAEtD,iBAAgB,QAAQ,KAAK,WAAW;AAExC,KAAI,WAAW,WAAW,CACxB,QAAO,YAAY;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAEtD,YAAW,YAAY,WAAW;AAElC,mBAAkB,MAAM,WAAW;CACnC,MAAM,eAAe,uBAAuB,SAAS,IAAI;CAEzD,MAAM,kBACJ,MAAM,eAAe,KAAK,gBAAgB,kBAAkB,KAAK,cAAc,MAAM;CAEvF,MAAM,WAAkC;EACtC,aAAa;EACb,iBAAiB;EACjB,QAAQ;EACR,aAAa,QAAQ;EACrB,8BAAa,IAAI,MAAM,EAAC,aAAa;EACrC,aAAa;EACb,GAAI,kBAAkB,EAAE,iBAAiB,GAAG,EAAE;EAC/C;AACD,OAAM,gBAAgB,gBAAgB,SAAS,EAAE,KAAK,UAAU,UAAU,MAAM,EAAE,CAAC;CAEnF,MAAM,OAAO,IAAI,IAAY,CAAC,WAAW,CAAC;AAC1C,KAAI,gBAAiB,MAAK,IAAI,gBAAgB;AAC9C,OAAM,cAAc,MAAM,KAAK;AAE/B,KAAI,KACF;EAAE;EAAc,aAAa;EAAiB,aAAa,QAAQ;EAAa,EAChF,wCACD;AAED,QAAO;EACL;EACA,aAAa;EACb,QAAQ;EACR;EACD;;;;;AAMH,eAAsB,gCAAgC,QAEpC;CAChB,MAAM,UAAU,OAAO,QAAQ,UAAU,SAAS;CAElD,MAAM,aAAa,WAAW,gBADb,eACqC,CAAC,CAAC;AACxD,KAAI,YAAY,eAAe,CAAC,WAC9B;AAEF,OAAM,iCAAiC;;AAGzC,eAAsB,0BAA0B,UAA2C;AAEzF,QAAO,wBADK,UAAU,MAAM,GAAG,eAAe,SAAS,GAAG,eAAe,KACpC,eAAe,CAAC;;AAKvD,SAAS,cAAc,SAAiB,MAA+B;AACrE,OAAM,SAAS,CAAC,GAAG,KAAK,EAAE;EAAE,OAAO;EAAU,UAAU;EAAM,CAAC,CAAC,OAAO;;AAGxE,SAAS,2BAAiC;CACxC,MAAM,YAAY;AAClB,KAAI,QAAQ,aAAa,UAAU;AACjC,gBAAc,QAAQ;GAAC;GAAM;GAAiB;GAAU,CAAC;AACzD;;AAEF,KAAI,QAAQ,aAAa,SAAS;AAChC,gBAAc,OAAO;GAAC;GAAM;GAAS;GAAU;GAAU,CAAC;AAC1D;;AAEF,eAAc,YAAY,CAAC,UAAU,CAAC;;AAGxC,SAAS,0BAA0B,KAAmB;AACpD,KAAI,QAAQ,aAAa,UAAU;AACjC,gBAAc,QAAQ,CAAC,IAAI,CAAC;AAC5B;;AAEF,KAAI,QAAQ,aAAa,SAAS;AAChC,gBAAc,YAAY,CAAC,IAAI,CAAC;AAChC;;AAEF,eAAc,YAAY,CAAC,IAAI,CAAC;;;;;AAMlC,eAAsB,8BAA8B,MAGd;CAEpC,MAAM,OAAM,MADS,iBAAiB,EAAE,UAAU,KAAK,UAAU,CAAC,EAC/C;AACnB,KAAI,CAAC,IACH,OAAM,IAAI,MAAM,qEAAqE;AAGvF,KAAI,KAAK,WAAW,YAAY,KAAK,WAAW,OAC9C,2BAA0B;AAE5B,KAAI,KAAK,WAAW,YAAY,KAAK,WAAW,OAC9C,2BAA0B,IAAI;AAGhC,QAAO,EAAE,cAAc,KAAK"}
|
|
1
|
+
{"version":3,"file":"browser-ext-install.js","names":[],"sources":["../../../../src/browser/providers/browser-ext-install.ts"],"sourcesContent":["/**\n * Install bundled Chrome extension artifacts into {resolveBinDir()}/browser-ext/.\n */\n\nimport {\n cpSync,\n existsSync,\n mkdirSync,\n readFileSync,\n realpathSync,\n renameSync,\n rmSync,\n statSync,\n symlinkSync,\n writeFileSync,\n} from 'node:fs';\nimport { readFile, readdir, rm } from 'node:fs/promises';\nimport { spawn } from 'node:child_process';\nimport { dirname, join, relative, resolve } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { PACKAGE_VERSION } from '../../package-version.js';\nimport { resolveBinDir } from '../../config/paths.js';\nimport { resolvePackageRoot } from '../../infra/update-check.js';\nimport { writeTextAtomic } from '../../infra/write-file-atomic.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { assertCacheDir } from '../cache-dir-policy.js';\n\nconst log = createLogger('BrowserExtInstall');\n\nconst META_FILENAME = '.meta.json';\nconst CURRENT_LINK = 'current';\nconst STAGING_MAX_AGE_MS = 60 * 60 * 1000;\n\nexport const BROWSER_EXT_REQUIRED_FILES = [\n 'manifest.json',\n 'popup.html',\n 'dist/background.js',\n 'dist/content.js',\n 'dist/popup.js',\n] as const;\n\nexport type BrowserExtBundledFrom = 'npm-dist' | 'git-dev' | 'electron-asar' | 'env-override';\n\nexport interface BrowserExtInstallMeta {\n xopcVersion: string;\n manifestVersion: string;\n source: 'bundled';\n bundledFrom: BrowserExtBundledFrom;\n installedAt: string;\n installPath: string;\n previousVersion?: string;\n}\n\nexport interface BrowserExtDoctor {\n bundledAvailable: boolean;\n installed: boolean;\n xopcVersion: string;\n installedVersion?: string;\n manifestVersion?: string;\n extensionDir?: string;\n cacheDir: string;\n needsRefresh: boolean;\n needsChromeReload?: boolean;\n bundledFrom?: BrowserExtBundledFrom;\n runtimeExtensionVersion?: string;\n}\n\nexport interface EnsureBrowserExtResult {\n extensionDir: string;\n xopcVersion: string;\n copied: boolean;\n previousVersion?: string;\n}\n\nfunction moduleDir(): string {\n return dirname(fileURLToPath(import.meta.url));\n}\n\n/** Validate a directory contains a loadable extension tree. */\nexport function validateBrowserExtLayout(dir: string): boolean {\n return BROWSER_EXT_REQUIRED_FILES.every((rel) => existsSync(join(dir, rel)));\n}\n\nfunction readManifestVersion(dir: string): string | undefined {\n try {\n const raw = readFileSync(join(dir, 'manifest.json'), 'utf8');\n const parsed = JSON.parse(raw) as { version?: unknown };\n return typeof parsed.version === 'string' ? parsed.version : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function readMeta(metaPath: string): Promise<BrowserExtInstallMeta | null> {\n try {\n const raw = await readFile(metaPath, 'utf8');\n const parsed = JSON.parse(raw) as BrowserExtInstallMeta;\n if (parsed && typeof parsed === 'object' && typeof parsed.xopcVersion === 'string') {\n return parsed;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nfunction browserExtRoot(cacheDir: string): string {\n return join(cacheDir, 'browser-ext');\n}\n\nfunction resolveCurrentPath(cacheDir: string): string {\n return join(browserExtRoot(cacheDir), CURRENT_LINK);\n}\n\nfunction resolveMetaPath(cacheDir: string): string {\n return join(browserExtRoot(cacheDir), META_FILENAME);\n}\n\nfunction resolveCurrentRealPath(cacheDir: string): string | null {\n const current = resolveCurrentPath(cacheDir);\n if (!existsSync(current)) return null;\n try {\n const real = realpathSync(current);\n return validateBrowserExtLayout(real) ? real : null;\n } catch {\n return null;\n }\n}\n\nfunction walkAncestorsForGitDevBundled(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 12; i++) {\n const candidate = join(dir, 'packages/browser-ext');\n if (validateBrowserExtLayout(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Resolve the bundled extension source directory (read-only).\n */\nexport async function resolveBundledBrowserExtDir(): Promise<{\n dir: string;\n bundledFrom: BrowserExtBundledFrom;\n} | null> {\n const envOverride = process.env.XOPC_BROWSER_EXT_BUNDLED_ROOT?.trim();\n if (envOverride && validateBrowserExtLayout(envOverride)) {\n return { dir: envOverride, bundledFrom: 'env-override' };\n }\n\n const fromModule = join(moduleDir(), '../../../browser-ext');\n if (validateBrowserExtLayout(fromModule)) {\n const root = await resolvePackageRoot();\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: fromModule, bundledFrom };\n }\n\n const gitDev = walkAncestorsForGitDevBundled(moduleDir());\n if (gitDev) {\n return { dir: gitDev, bundledFrom: 'git-dev' };\n }\n\n const root = await resolvePackageRoot();\n if (root) {\n const distBundled = join(root, 'dist/browser-ext');\n if (validateBrowserExtLayout(distBundled)) {\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: distBundled, bundledFrom };\n }\n }\n\n return null;\n}\n\nexport function computeNeedsRefresh(params: {\n force?: boolean;\n bundledManifestVersion: string;\n currentRealPath: string | null;\n meta: BrowserExtInstallMeta | null;\n}): boolean {\n if (params.force) return true;\n if (!params.currentRealPath || !validateBrowserExtLayout(params.currentRealPath)) return true;\n\n const currentManifest = readManifestVersion(params.currentRealPath);\n if (!currentManifest || currentManifest !== params.bundledManifestVersion) return true;\n\n if (!params.meta || params.meta.xopcVersion !== PACKAGE_VERSION) return true;\n\n return false;\n}\n\nasync function cleanupStaleStaging(root: string): Promise<void> {\n if (!existsSync(root)) return;\n let entries: string[];\n try {\n entries = await readdir(root);\n } catch {\n return;\n }\n const now = Date.now();\n for (const name of entries) {\n if (!name.startsWith('.staging-')) continue;\n const full = join(root, name);\n try {\n const st = statSync(full);\n if (now - st.mtimeMs > STAGING_MAX_AGE_MS) {\n await rm(full, { recursive: true, force: true });\n }\n } catch {\n /* */\n }\n }\n}\n\nfunction switchCurrentLink(root: string, versionDir: string): void {\n const currentPath = join(root, CURRENT_LINK);\n const versionName = relative(root, versionDir);\n const tmpLink = join(root, `.current-${process.pid}`);\n\n if (existsSync(tmpLink)) {\n rmSync(tmpLink, { recursive: true, force: true });\n }\n if (existsSync(currentPath)) {\n rmSync(currentPath, { recursive: true, force: true });\n }\n\n if (process.platform === 'win32') {\n const target = resolve(versionDir);\n cpSync(target, currentPath, { recursive: true });\n return;\n }\n\n try {\n symlinkSync(versionName, tmpLink, 'dir');\n renameSync(tmpLink, currentPath);\n } catch {\n cpSync(versionDir, currentPath, { recursive: true });\n }\n}\n\nasync function gcOldVersions(root: string, keepVersions: Set<string>): Promise<void> {\n if (!existsSync(root)) return;\n let entries: string[];\n try {\n entries = await readdir(root);\n } catch {\n return;\n }\n for (const name of entries) {\n if (name === CURRENT_LINK || name === META_FILENAME || name.startsWith('.')) continue;\n if (!keepVersions.has(name)) {\n try {\n await rm(join(root, name), { recursive: true, force: true });\n log.info({ version: name }, 'Removed old browser extension version directory');\n } catch (err) {\n log.warn({ err, version: name }, 'Failed to remove old browser extension version');\n }\n }\n }\n}\n\n/** Copy one bundled file (read/write works when src is inside Electron app.asar). */\nfunction copyBundledFile(src: string, dest: string): void {\n mkdirSync(dirname(dest), { recursive: true });\n writeFileSync(dest, readFileSync(src));\n}\n\nconst BROWSER_EXT_DIST_FILES = ['background.js', 'content.js', 'popup.js'] as const;\nconst BROWSER_EXT_ICON_FILES = ['icon-16.png', 'icon-32.png', 'icon-48.png', 'icon-128.png'] as const;\n\nfunction copyBundledTree(src: string, dest: string): void {\n mkdirSync(dest, { recursive: true });\n for (const name of ['manifest.json', 'popup.html']) {\n copyBundledFile(join(src, name), join(dest, name));\n }\n for (const file of BROWSER_EXT_DIST_FILES) {\n copyBundledFile(join(src, 'dist', file), join(dest, 'dist', file));\n }\n for (const icon of BROWSER_EXT_ICON_FILES) {\n const iconSrc = join(src, 'icons', icon);\n if (existsSync(iconSrc)) {\n copyBundledFile(iconSrc, join(dest, 'icons', icon));\n }\n }\n if (!validateBrowserExtLayout(dest)) {\n throw new Error('Bundled browser extension copy failed validation');\n }\n}\n\nexport async function browserExtDoctor(opts?: {\n cacheDir?: string;\n runtimeExtensionVersion?: string;\n}): Promise<BrowserExtDoctor> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n const bundledManifestVersion = bundled ? readManifestVersion(bundled.dir) : undefined;\n const currentRealPath = resolveCurrentRealPath(cacheDir);\n const meta = await readMeta(resolveMetaPath(cacheDir));\n\n const needsRefresh = bundled\n ? computeNeedsRefresh({\n force: false,\n bundledManifestVersion: bundledManifestVersion ?? PACKAGE_VERSION,\n currentRealPath,\n meta,\n })\n : false;\n\n const installed = Boolean(currentRealPath) && !needsRefresh;\n const manifestVersion = currentRealPath ? readManifestVersion(currentRealPath) : undefined;\n\n let needsChromeReload: boolean | undefined;\n const runtimeVer = opts?.runtimeExtensionVersion?.trim();\n if (runtimeVer && manifestVersion && runtimeVer !== manifestVersion) {\n needsChromeReload = true;\n }\n\n return {\n bundledAvailable: Boolean(bundled),\n installed,\n xopcVersion: PACKAGE_VERSION,\n installedVersion: meta?.xopcVersion,\n manifestVersion,\n extensionDir: currentRealPath ?? undefined,\n cacheDir,\n needsRefresh,\n needsChromeReload,\n bundledFrom: bundled?.bundledFrom,\n runtimeExtensionVersion: runtimeVer,\n };\n}\n\nexport async function ensureBrowserExtensionArtifacts(opts?: {\n force?: boolean;\n cacheDir?: string;\n}): Promise<EnsureBrowserExtResult> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n if (!bundled) {\n throw new Error(\n 'Bundled browser extension not found. Reinstall xopc or run from a built checkout (pnpm run build).',\n );\n }\n\n const bundledManifestVersion = readManifestVersion(bundled.dir) ?? PACKAGE_VERSION;\n const root = browserExtRoot(cacheDir);\n mkdirSync(root, { recursive: true });\n await cleanupStaleStaging(root);\n\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const currentRealPath = resolveCurrentRealPath(cacheDir);\n const needsRefresh = computeNeedsRefresh({\n force: opts?.force,\n bundledManifestVersion,\n currentRealPath,\n meta,\n });\n\n if (!needsRefresh && currentRealPath) {\n return {\n extensionDir: currentRealPath,\n xopcVersion: PACKAGE_VERSION,\n copied: false,\n previousVersion: meta?.previousVersion,\n };\n }\n\n const versionKey = PACKAGE_VERSION;\n const versionDir = join(root, versionKey);\n const stagingDir = join(root, `.staging-${versionKey}-${process.pid}`);\n\n if (existsSync(stagingDir)) {\n rmSync(stagingDir, { recursive: true, force: true });\n }\n copyBundledTree(bundled.dir, stagingDir);\n\n if (existsSync(versionDir)) {\n rmSync(versionDir, { recursive: true, force: true });\n }\n renameSync(stagingDir, versionDir);\n\n switchCurrentLink(root, versionDir);\n const extensionDir = resolveCurrentRealPath(cacheDir) ?? versionDir;\n\n const previousVersion =\n meta?.xopcVersion && meta.xopcVersion !== PACKAGE_VERSION ? meta.xopcVersion : meta?.previousVersion;\n\n const nextMeta: BrowserExtInstallMeta = {\n xopcVersion: PACKAGE_VERSION,\n manifestVersion: bundledManifestVersion,\n source: 'bundled',\n bundledFrom: bundled.bundledFrom,\n installedAt: new Date().toISOString(),\n installPath: versionDir,\n ...(previousVersion ? { previousVersion } : {}),\n };\n await writeTextAtomic(resolveMetaPath(cacheDir), JSON.stringify(nextMeta, null, 2));\n\n const keep = new Set<string>([versionKey]);\n if (previousVersion) keep.add(previousVersion);\n await gcOldVersions(root, keep);\n\n log.info(\n { extensionDir, xopcVersion: PACKAGE_VERSION, bundledFrom: bundled.bundledFrom },\n 'Browser extension artifacts installed',\n );\n\n return {\n extensionDir,\n xopcVersion: PACKAGE_VERSION,\n copied: true,\n previousVersion,\n };\n}\n\n/**\n * Gateway startup hook: ensure artifacts when extension backend is enabled or prior install exists.\n */\nexport async function ensureBrowserExtensionOnStartup(config: {\n agents?: { defaults?: { browser?: { backend?: string } } };\n}): Promise<void> {\n const backend = config.agents?.defaults?.browser?.backend;\n const cacheDir = resolveBinDir();\n const metaExists = existsSync(resolveMetaPath(cacheDir));\n if (backend !== 'extension' && !metaExists) {\n return;\n }\n await ensureBrowserExtensionArtifacts();\n}\n\nexport async function readInstalledExtensionDir(cacheDir?: string): Promise<string | null> {\n const dir = cacheDir?.trim() ? assertCacheDir(cacheDir) : resolveBinDir();\n return resolveCurrentRealPath(dir || resolveBinDir());\n}\n\nexport type BrowserExtensionOpenAction = 'chrome' | 'folder' | 'both';\n\nfunction spawnDetached(command: string, args: readonly string[]): void {\n spawn(command, [...args], { stdio: 'ignore', detached: true }).unref();\n}\n\nfunction openChromeExtensionsPage(): void {\n const chromeUrl = 'chrome://extensions';\n if (process.platform === 'darwin') {\n spawnDetached('open', ['-a', 'Google Chrome', chromeUrl]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('cmd', ['/c', 'start', 'chrome', chromeUrl]);\n return;\n }\n spawnDetached('xdg-open', [chromeUrl]);\n}\n\nfunction revealFolderInFileManager(dir: string): void {\n if (process.platform === 'darwin') {\n spawnDetached('open', [dir]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('explorer', [dir]);\n return;\n }\n spawnDetached('xdg-open', [dir]);\n}\n\n/**\n * Open chrome://extensions and/or reveal the installed extension folder on the gateway host.\n */\nexport async function openBrowserExtensionInstallUi(opts: {\n action: BrowserExtensionOpenAction;\n cacheDir?: string;\n}): Promise<{ extensionDir: string }> {\n const doctor = await browserExtDoctor({ cacheDir: opts.cacheDir });\n const dir = doctor.extensionDir;\n if (!dir) {\n throw new Error('Extension not installed. Run xopc browser extension install first.');\n }\n\n if (opts.action === 'chrome' || opts.action === 'both') {\n openChromeExtensionsPage();\n }\n if (opts.action === 'folder' || opts.action === 'both') {\n revealFolderInFileManager(dir);\n }\n\n return { extensionDir: dir };\n}\n"],"mappings":"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"}
|
|
@@ -9,7 +9,7 @@ import { resolveTunnelBrokerUrl, resolveTunnelRegistrationSecret } from "../../t
|
|
|
9
9
|
import { ensureFrpcBinary } from "../../tunnel/frpc-binary.js";
|
|
10
10
|
import { loadTunnelState } from "../../tunnel/tunnel-state.js";
|
|
11
11
|
import { getTunnelService } from "../../tunnel/tunnel-service.js";
|
|
12
|
-
import { resolveFrpSubdomainHost
|
|
12
|
+
import { resolveFrpSubdomainHost } from "../../tunnel/frp-subdomain-host.js";
|
|
13
13
|
import { applyTunnelConsentToConfig, mergeTunnelConfigPatch, setTunnelEnabledInConfig } from "../../tunnel/tunnel-config.js";
|
|
14
14
|
import "../../tunnel/index.js";
|
|
15
15
|
import { Command } from "commander";
|
|
@@ -34,14 +34,13 @@ function resolveGatewayToken(config) {
|
|
|
34
34
|
}
|
|
35
35
|
function configureTunnel(ctx) {
|
|
36
36
|
const config = loadConfig(ctx.configPath);
|
|
37
|
-
const {
|
|
37
|
+
const { host } = resolveGatewayPortHost(config);
|
|
38
38
|
const brokerUrl = resolveTunnelBrokerUrl(config.tunnel?.brokerUrl);
|
|
39
39
|
getTunnelService().configure({
|
|
40
40
|
brokerUrl,
|
|
41
41
|
registrationSecret: resolveTunnelRegistrationSecret(process.env, brokerUrl, config.tunnel?.registrationSecret),
|
|
42
42
|
autoStart: config.tunnel?.autoStart ?? false,
|
|
43
43
|
gatewayHost: host,
|
|
44
|
-
e2e: resolveTunnelE2eConfig(config.tunnel, port),
|
|
45
44
|
frpSubdomainHost: resolveFrpSubdomainHost(resolveTunnelBrokerUrl(config.tunnel?.brokerUrl))
|
|
46
45
|
});
|
|
47
46
|
}
|
|
@@ -213,10 +212,10 @@ function createTunnelCommand(ctx) {
|
|
|
213
212
|
consentValid: hasValidTunnelConsent(config)
|
|
214
213
|
}, null, 2));
|
|
215
214
|
});
|
|
216
|
-
cmd.command("qr").description("Print mobile connect QR payload (tunnel must be active)").action(() => {
|
|
215
|
+
cmd.command("qr").description("Print mobile connect QR payload (tunnel must be active)").action(async () => {
|
|
217
216
|
configureTunnel(ctx);
|
|
218
217
|
const { port, host } = resolveGatewayPortHost(loadConfig(ctx.configPath));
|
|
219
|
-
const qr = getTunnelService().buildQr(port, host);
|
|
218
|
+
const qr = await getTunnelService().buildQr(port, host);
|
|
220
219
|
if (!qr.qrPayload) {
|
|
221
220
|
console.error("No active tunnel. Run: xopc tunnel start");
|
|
222
221
|
process.exit(1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tunnel.js","names":[],"sources":["../../../../src/cli/commands/tunnel.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport { loadConfig, saveConfig } from '../../config/index.js';\nimport { createLogger } from '../../utils/logger.js';\nimport {\n assertTunnelMayStart,\n hasValidTunnelConsent,\n TUNNEL_RISK_SUMMARY_LINES,\n TunnelConsentError,\n} from '../../tunnel/consent.js';\nimport { resolveTunnelBrokerUrl, resolveTunnelRegistrationSecret } from '../../tunnel/env.js';\nimport { ensureFrpcBinary, getTunnelService } from '../../tunnel/index.js';\nimport { resolveFrpSubdomainHost, resolveTunnelE2eConfig } from '../../tunnel/tunnel-e2e-config.js';\nimport { applyTunnelConsentToConfig, mergeTunnelConfigPatch, setTunnelEnabledInConfig } from '../../tunnel/tunnel-config.js';\nimport { loadTunnelState } from '../../tunnel/tunnel-state.js';\nimport { formatExamples, register, type CLIContext } from '../registry.js';\n\nconst log = createLogger('TunnelCommand');\n\nfunction isInteractive(): boolean {\n return Boolean(process.stdin.isTTY && process.stdout.isTTY);\n}\n\nimport { resolveGatewayEffectiveHost } from '../../config/gateway-bind.js';\n\nfunction resolveGatewayPortHost(config: ReturnType<typeof loadConfig>): { port: number; host: string } {\n return {\n port: config.gateway.port ?? 18790,\n host: resolveGatewayEffectiveHost(config),\n };\n}\n\nfunction resolveGatewayToken(config: ReturnType<typeof loadConfig>): string {\n const fromEnv = process.env.XOPC_GATEWAY_TOKEN?.trim();\n if (fromEnv) return fromEnv;\n const token = config.gateway.auth?.token?.trim();\n if (token) return token;\n throw new Error('Gateway token not configured. Set gateway.auth.token or XOPC_GATEWAY_TOKEN.');\n}\n\nfunction configureTunnel(ctx: CLIContext): void {\n const config = loadConfig(ctx.configPath);\n const { port, host } = resolveGatewayPortHost(config);\n const brokerUrl = resolveTunnelBrokerUrl(config.tunnel?.brokerUrl);\n getTunnelService().configure({\n brokerUrl,\n registrationSecret: resolveTunnelRegistrationSecret(\n process.env,\n brokerUrl,\n config.tunnel?.registrationSecret,\n ),\n autoStart: config.tunnel?.autoStart ?? false,\n gatewayHost: host,\n e2e: resolveTunnelE2eConfig(config.tunnel, port),\n frpSubdomainHost: resolveFrpSubdomainHost(resolveTunnelBrokerUrl(config.tunnel?.brokerUrl)),\n });\n}\n\nasync function ensureCliTunnelConsent(\n ctx: CLIContext,\n opts: { acceptRisk?: boolean; yes?: boolean },\n): Promise<void> {\n const config = loadConfig(ctx.configPath);\n if (hasValidTunnelConsent(config)) return;\n\n if (opts.acceptRisk) {\n applyTunnelConsentToConfig(config);\n await saveConfig(config, ctx.configPath);\n return;\n }\n\n if (opts.yes) {\n throw new TunnelConsentError(\n 'Security consent not recorded. Run without --yes and confirm, or pass --accept-risk after reading the risks.',\n );\n }\n\n if (!isInteractive()) {\n throw new TunnelConsentError(\n 'Security consent required. Run interactively, use --accept-risk, or accept in gateway settings.',\n );\n }\n\n const { confirm } = await import('@inquirer/prompts');\n console.log('');\n console.log('⚠️ Remote access security notice');\n for (const line of TUNNEL_RISK_SUMMARY_LINES) {\n console.log(` • ${line}`);\n }\n console.log('');\n const accepted = await confirm({\n message: 'I understand these risks and want to enable remote access',\n default: false,\n });\n if (!accepted) {\n throw new TunnelConsentError('Remote access not started (consent declined).');\n }\n applyTunnelConsentToConfig(config);\n await saveConfig(config, ctx.configPath);\n}\n\nasync function readTunnelRegistrationSecretFromCli(opts: {\n secretArg?: string;\n stdin?: boolean;\n}): Promise<string> {\n const fromArg = opts.secretArg?.trim();\n if (fromArg) return fromArg;\n\n if (opts.stdin) {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n const value = Buffer.concat(chunks).toString('utf8').trim();\n if (!value) {\n throw new Error('Empty registration secret from stdin.');\n }\n return value;\n }\n\n if (isInteractive()) {\n const { password } = await import('@inquirer/prompts');\n const value = await password({\n message: 'Tunnel broker registration secret',\n mask: '*',\n });\n if (!value?.trim()) {\n throw new Error('Registration secret is required.');\n }\n return value.trim();\n }\n\n throw new Error(\n 'Provide the secret as an argument, pass --stdin, or run in an interactive terminal.',\n );\n}\n\nasync function saveTunnelRegistrationSecret(ctx: CLIContext, secret: string): Promise<void> {\n const config = loadConfig(ctx.configPath);\n const result = mergeTunnelConfigPatch(config, { registrationSecret: secret });\n if (result.ok === false) {\n throw new Error(result.message);\n }\n await saveConfig(config, ctx.configPath);\n}\n\nfunction createTunnelCommand(ctx: CLIContext): Command {\n const cmd = new Command('tunnel')\n .description('Manage FRP remote access tunnel')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc tunnel start',\n 'xopc tunnel start --accept-risk',\n 'xopc tunnel stop',\n 'xopc tunnel status',\n 'xopc tunnel qr',\n 'xopc tunnel consent',\n 'xopc tunnel prefetch',\n 'xopc tunnel secret set',\n 'xopc tunnel secret set --stdin',\n ]),\n );\n\n cmd\n .command('prefetch')\n .description('Download frpc to the state bin directory without starting the tunnel')\n .action(async () => {\n try {\n const path = await ensureFrpcBinary({\n onProgress: (progress) => {\n if (!process.stderr.isTTY) return;\n if (progress.phase === 'extracting') {\n process.stderr.write('\\rExtracting frpc… \\n');\n return;\n }\n if (progress.percent != null) {\n process.stderr.write(`\\rDownloading frpc… ${progress.percent}%`);\n } else if (progress.bytesReceived != null) {\n process.stderr.write(`\\rDownloading frpc… ${progress.bytesReceived} bytes`);\n }\n },\n });\n if (process.stderr.isTTY) process.stderr.write('\\n');\n console.log(`frpc ready at ${path}`);\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err }, `frpc prefetch failed: ${em}`);\n process.exit(1);\n }\n });\n\n cmd\n .command('consent')\n .description('Record acceptance of the remote access security notice')\n .option('--accept-risk', 'Non-interactive: record consent without prompts')\n .action(async (opts: { acceptRisk?: boolean }) => {\n await ensureCliTunnelConsent(ctx, { acceptRisk: opts.acceptRisk, yes: false });\n console.log('Tunnel security consent recorded.');\n });\n\n const secretCmd = cmd.command('secret').description('Manage tunnel broker registration secret in config');\n\n secretCmd\n .command('set')\n .description('Save tunnel.registrationSecret to xopc.json (env XOPC_TUNNEL_REGISTRATION_SECRET overrides at runtime)')\n .argument('[secret]', 'Registration secret (prompts securely when omitted in a TTY)')\n .option('--stdin', 'Read secret from stdin (single line, trimmed)')\n .action(async (secretArg: string | undefined, opts: { stdin?: boolean }) => {\n try {\n const secret = await readTunnelRegistrationSecretFromCli({\n secretArg,\n stdin: opts.stdin,\n });\n await saveTunnelRegistrationSecret(ctx, secret);\n if (process.env.XOPC_TUNNEL_REGISTRATION_SECRET?.trim()) {\n console.log(\n 'Note: XOPC_TUNNEL_REGISTRATION_SECRET is set in the environment and overrides the saved config at runtime.',\n );\n }\n console.log(`Saved tunnel registration secret to ${ctx.configPath}.`);\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err, phase: 'tunnel_secret_set' }, `Tunnel secret set failed: ${em}`);\n console.error(em);\n process.exit(1);\n }\n });\n\n cmd\n .command('start')\n .description('Register tunnel, start frpc, print connection info')\n .option('--yes', 'Skip interactive consent prompt when consent is already recorded')\n .option(\n '--accept-risk',\n 'Record security consent and start (non-interactive; read risks in docs/tunnel-security.md first)',\n )\n .action(async (opts: { yes?: boolean; acceptRisk?: boolean }) => {\n configureTunnel(ctx);\n await ensureCliTunnelConsent(ctx, { acceptRisk: opts.acceptRisk, yes: opts.yes });\n\n const config = loadConfig(ctx.configPath);\n assertTunnelMayStart(config);\n\n const { port, host } = resolveGatewayPortHost(config);\n const token = resolveGatewayToken(config);\n const tunnel = getTunnelService();\n\n console.log('🚀 Starting tunnel...');\n try {\n const qr = await tunnel.start(port, token);\n setTunnelEnabledInConfig(config, true);\n await saveConfig(config, ctx.configPath);\n\n const status = tunnel.getStatus();\n console.log('');\n console.log('✅ Tunnel is active');\n if (status.publicUrl) console.log(` URL: ${status.publicUrl}`);\n if (qr.lanUrl) console.log(` LAN: ${qr.lanUrl}`);\n console.log('');\n console.log('📱 Mobile connect QR payload:');\n console.log(qr.qrPayload);\n console.log('');\n console.log(\n `💡 Gateway must be running at ${host}:${port}. Keep frpc alive or use gateway / Web console.`,\n );\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err }, `Tunnel start failed: ${em}`);\n process.exit(1);\n }\n });\n\n cmd\n .command('stop')\n .description('Stop frpc (keeps broker registration for stable subdomain)')\n .option(\n '--release',\n 'Deregister from broker and clear saved subdomain (next start gets a new public URL)',\n )\n .option('--yes', 'Skip confirmation when using --release')\n .action(async (opts: { release?: boolean; yes?: boolean }) => {\n configureTunnel(ctx);\n if (opts.release) {\n if (!opts.yes && isInteractive()) {\n const { confirm } = await import('@inquirer/prompts');\n const ok = await confirm({\n message:\n 'Release will revoke the public URL and subdomain on the broker. Continue?',\n default: false,\n });\n if (!ok) {\n console.log('Cancelled.');\n return;\n }\n }\n }\n const { released } = await getTunnelService().stop({ release: opts.release });\n const config = loadConfig(ctx.configPath);\n setTunnelEnabledInConfig(config, false);\n await saveConfig(config, ctx.configPath);\n console.log(released ? 'Tunnel stopped and broker registration released.' : 'Tunnel stopped.');\n });\n\n cmd\n .command('status')\n .description('Show tunnel status')\n .action(() => {\n configureTunnel(ctx);\n const config = loadConfig(ctx.configPath);\n const status = getTunnelService().getStatus();\n const persisted = loadTunnelState();\n console.log(\n JSON.stringify(\n {\n ...status,\n persistedSubdomain: persisted?.subdomain ?? null,\n consentValid: hasValidTunnelConsent(config),\n },\n null,\n 2,\n ),\n );\n });\n\n cmd\n .command('qr')\n .description('Print mobile connect QR payload (tunnel must be active)')\n .action(() => {\n configureTunnel(ctx);\n const config = loadConfig(ctx.configPath);\n const { port, host } = resolveGatewayPortHost(config);\n const qr = getTunnelService().buildQr(port, host);\n if (!qr.qrPayload) {\n console.error('No active tunnel. Run: xopc tunnel start');\n process.exit(1);\n }\n console.log(qr.qrPayload);\n });\n\n cmd\n .command('broker')\n .description('Self-hosted FRP broker helpers')\n .addCommand(\n new Command('init')\n .description('Print a starter frps + broker configuration template')\n .option('--domain <domain>', 'Public domain for frps', 'tunnel.example.com')\n .action((opts) => {\n const domain = String(opts.domain ?? 'tunnel.example.com');\n console.log(`# Self-hosted FRP broker sketch for ${domain}`);\n console.log('# 1. Run frps with vhost HTTP/HTTPS and a registration token');\n console.log(`# 2. Point tunnel.brokerUrl to https://${domain}/api`);\n console.log(`# 3. Set XOPC_TUNNEL_REGISTRATION_SECRET in the gateway environment`);\n console.log('');\n console.log(JSON.stringify({\n frps: {\n bindPort: 7000,\n vhostHTTPPort: 8080,\n subdomainHost: domain,\n },\n broker: {\n apiUrl: `https://${domain}/api`,\n registrationSecretEnv: 'XOPC_TUNNEL_REGISTRATION_SECRET',\n },\n }, null, 2));\n }),\n );\n\n return cmd;\n}\n\nregister({\n id: 'tunnel',\n name: 'tunnel',\n description: 'FRP remote access tunnel',\n factory: createTunnelCommand,\n metadata: {\n category: 'runtime',\n examples: ['xopc tunnel start', 'xopc tunnel status', 'xopc tunnel secret set'],\n },\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tunnel.js","names":[],"sources":["../../../../src/cli/commands/tunnel.ts"],"sourcesContent":["import { Command } from 'commander';\n\nimport { loadConfig, saveConfig } from '../../config/index.js';\nimport { createLogger } from '../../utils/logger.js';\nimport {\n assertTunnelMayStart,\n hasValidTunnelConsent,\n TUNNEL_RISK_SUMMARY_LINES,\n TunnelConsentError,\n} from '../../tunnel/consent.js';\nimport { resolveTunnelBrokerUrl, resolveTunnelRegistrationSecret } from '../../tunnel/env.js';\nimport { ensureFrpcBinary, getTunnelService } from '../../tunnel/index.js';\nimport { resolveFrpSubdomainHost } from '../../tunnel/frp-subdomain-host.js';\nimport { applyTunnelConsentToConfig, mergeTunnelConfigPatch, setTunnelEnabledInConfig } from '../../tunnel/tunnel-config.js';\nimport { loadTunnelState } from '../../tunnel/tunnel-state.js';\nimport { formatExamples, register, type CLIContext } from '../registry.js';\n\nconst log = createLogger('TunnelCommand');\n\nfunction isInteractive(): boolean {\n return Boolean(process.stdin.isTTY && process.stdout.isTTY);\n}\n\nimport { resolveGatewayEffectiveHost } from '../../config/gateway-bind.js';\n\nfunction resolveGatewayPortHost(config: ReturnType<typeof loadConfig>): { port: number; host: string } {\n return {\n port: config.gateway.port ?? 18790,\n host: resolveGatewayEffectiveHost(config),\n };\n}\n\nfunction resolveGatewayToken(config: ReturnType<typeof loadConfig>): string {\n const fromEnv = process.env.XOPC_GATEWAY_TOKEN?.trim();\n if (fromEnv) return fromEnv;\n const token = config.gateway.auth?.token?.trim();\n if (token) return token;\n throw new Error('Gateway token not configured. Set gateway.auth.token or XOPC_GATEWAY_TOKEN.');\n}\n\nfunction configureTunnel(ctx: CLIContext): void {\n const config = loadConfig(ctx.configPath);\n const { host } = resolveGatewayPortHost(config);\n const brokerUrl = resolveTunnelBrokerUrl(config.tunnel?.brokerUrl);\n getTunnelService().configure({\n brokerUrl,\n registrationSecret: resolveTunnelRegistrationSecret(\n process.env,\n brokerUrl,\n config.tunnel?.registrationSecret,\n ),\n autoStart: config.tunnel?.autoStart ?? false,\n gatewayHost: host,\n frpSubdomainHost: resolveFrpSubdomainHost(resolveTunnelBrokerUrl(config.tunnel?.brokerUrl)),\n });\n}\n\nasync function ensureCliTunnelConsent(\n ctx: CLIContext,\n opts: { acceptRisk?: boolean; yes?: boolean },\n): Promise<void> {\n const config = loadConfig(ctx.configPath);\n if (hasValidTunnelConsent(config)) return;\n\n if (opts.acceptRisk) {\n applyTunnelConsentToConfig(config);\n await saveConfig(config, ctx.configPath);\n return;\n }\n\n if (opts.yes) {\n throw new TunnelConsentError(\n 'Security consent not recorded. Run without --yes and confirm, or pass --accept-risk after reading the risks.',\n );\n }\n\n if (!isInteractive()) {\n throw new TunnelConsentError(\n 'Security consent required. Run interactively, use --accept-risk, or accept in gateway settings.',\n );\n }\n\n const { confirm } = await import('@inquirer/prompts');\n console.log('');\n console.log('⚠️ Remote access security notice');\n for (const line of TUNNEL_RISK_SUMMARY_LINES) {\n console.log(` • ${line}`);\n }\n console.log('');\n const accepted = await confirm({\n message: 'I understand these risks and want to enable remote access',\n default: false,\n });\n if (!accepted) {\n throw new TunnelConsentError('Remote access not started (consent declined).');\n }\n applyTunnelConsentToConfig(config);\n await saveConfig(config, ctx.configPath);\n}\n\nasync function readTunnelRegistrationSecretFromCli(opts: {\n secretArg?: string;\n stdin?: boolean;\n}): Promise<string> {\n const fromArg = opts.secretArg?.trim();\n if (fromArg) return fromArg;\n\n if (opts.stdin) {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n const value = Buffer.concat(chunks).toString('utf8').trim();\n if (!value) {\n throw new Error('Empty registration secret from stdin.');\n }\n return value;\n }\n\n if (isInteractive()) {\n const { password } = await import('@inquirer/prompts');\n const value = await password({\n message: 'Tunnel broker registration secret',\n mask: '*',\n });\n if (!value?.trim()) {\n throw new Error('Registration secret is required.');\n }\n return value.trim();\n }\n\n throw new Error(\n 'Provide the secret as an argument, pass --stdin, or run in an interactive terminal.',\n );\n}\n\nasync function saveTunnelRegistrationSecret(ctx: CLIContext, secret: string): Promise<void> {\n const config = loadConfig(ctx.configPath);\n const result = mergeTunnelConfigPatch(config, { registrationSecret: secret });\n if (result.ok === false) {\n throw new Error(result.message);\n }\n await saveConfig(config, ctx.configPath);\n}\n\nfunction createTunnelCommand(ctx: CLIContext): Command {\n const cmd = new Command('tunnel')\n .description('Manage FRP remote access tunnel')\n .addHelpText(\n 'after',\n formatExamples([\n 'xopc tunnel start',\n 'xopc tunnel start --accept-risk',\n 'xopc tunnel stop',\n 'xopc tunnel status',\n 'xopc tunnel qr',\n 'xopc tunnel consent',\n 'xopc tunnel prefetch',\n 'xopc tunnel secret set',\n 'xopc tunnel secret set --stdin',\n ]),\n );\n\n cmd\n .command('prefetch')\n .description('Download frpc to the state bin directory without starting the tunnel')\n .action(async () => {\n try {\n const path = await ensureFrpcBinary({\n onProgress: (progress) => {\n if (!process.stderr.isTTY) return;\n if (progress.phase === 'extracting') {\n process.stderr.write('\\rExtracting frpc… \\n');\n return;\n }\n if (progress.percent != null) {\n process.stderr.write(`\\rDownloading frpc… ${progress.percent}%`);\n } else if (progress.bytesReceived != null) {\n process.stderr.write(`\\rDownloading frpc… ${progress.bytesReceived} bytes`);\n }\n },\n });\n if (process.stderr.isTTY) process.stderr.write('\\n');\n console.log(`frpc ready at ${path}`);\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err }, `frpc prefetch failed: ${em}`);\n process.exit(1);\n }\n });\n\n cmd\n .command('consent')\n .description('Record acceptance of the remote access security notice')\n .option('--accept-risk', 'Non-interactive: record consent without prompts')\n .action(async (opts: { acceptRisk?: boolean }) => {\n await ensureCliTunnelConsent(ctx, { acceptRisk: opts.acceptRisk, yes: false });\n console.log('Tunnel security consent recorded.');\n });\n\n const secretCmd = cmd.command('secret').description('Manage tunnel broker registration secret in config');\n\n secretCmd\n .command('set')\n .description('Save tunnel.registrationSecret to xopc.json (env XOPC_TUNNEL_REGISTRATION_SECRET overrides at runtime)')\n .argument('[secret]', 'Registration secret (prompts securely when omitted in a TTY)')\n .option('--stdin', 'Read secret from stdin (single line, trimmed)')\n .action(async (secretArg: string | undefined, opts: { stdin?: boolean }) => {\n try {\n const secret = await readTunnelRegistrationSecretFromCli({\n secretArg,\n stdin: opts.stdin,\n });\n await saveTunnelRegistrationSecret(ctx, secret);\n if (process.env.XOPC_TUNNEL_REGISTRATION_SECRET?.trim()) {\n console.log(\n 'Note: XOPC_TUNNEL_REGISTRATION_SECRET is set in the environment and overrides the saved config at runtime.',\n );\n }\n console.log(`Saved tunnel registration secret to ${ctx.configPath}.`);\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err, phase: 'tunnel_secret_set' }, `Tunnel secret set failed: ${em}`);\n console.error(em);\n process.exit(1);\n }\n });\n\n cmd\n .command('start')\n .description('Register tunnel, start frpc, print connection info')\n .option('--yes', 'Skip interactive consent prompt when consent is already recorded')\n .option(\n '--accept-risk',\n 'Record security consent and start (non-interactive; read risks in docs/tunnel-security.md first)',\n )\n .action(async (opts: { yes?: boolean; acceptRisk?: boolean }) => {\n configureTunnel(ctx);\n await ensureCliTunnelConsent(ctx, { acceptRisk: opts.acceptRisk, yes: opts.yes });\n\n const config = loadConfig(ctx.configPath);\n assertTunnelMayStart(config);\n\n const { port, host } = resolveGatewayPortHost(config);\n const token = resolveGatewayToken(config);\n const tunnel = getTunnelService();\n\n console.log('🚀 Starting tunnel...');\n try {\n const qr = await tunnel.start(port, token);\n setTunnelEnabledInConfig(config, true);\n await saveConfig(config, ctx.configPath);\n\n const status = tunnel.getStatus();\n console.log('');\n console.log('✅ Tunnel is active');\n if (status.publicUrl) console.log(` URL: ${status.publicUrl}`);\n if (qr.lanUrl) console.log(` LAN: ${qr.lanUrl}`);\n console.log('');\n console.log('📱 Mobile connect QR payload:');\n console.log(qr.qrPayload);\n console.log('');\n console.log(\n `💡 Gateway must be running at ${host}:${port}. Keep frpc alive or use gateway / Web console.`,\n );\n } catch (err) {\n const em = err instanceof Error ? err.message : String(err);\n log.error({ err }, `Tunnel start failed: ${em}`);\n process.exit(1);\n }\n });\n\n cmd\n .command('stop')\n .description('Stop frpc (keeps broker registration for stable subdomain)')\n .option(\n '--release',\n 'Deregister from broker and clear saved subdomain (next start gets a new public URL)',\n )\n .option('--yes', 'Skip confirmation when using --release')\n .action(async (opts: { release?: boolean; yes?: boolean }) => {\n configureTunnel(ctx);\n if (opts.release) {\n if (!opts.yes && isInteractive()) {\n const { confirm } = await import('@inquirer/prompts');\n const ok = await confirm({\n message:\n 'Release will revoke the public URL and subdomain on the broker. Continue?',\n default: false,\n });\n if (!ok) {\n console.log('Cancelled.');\n return;\n }\n }\n }\n const { released } = await getTunnelService().stop({ release: opts.release });\n const config = loadConfig(ctx.configPath);\n setTunnelEnabledInConfig(config, false);\n await saveConfig(config, ctx.configPath);\n console.log(released ? 'Tunnel stopped and broker registration released.' : 'Tunnel stopped.');\n });\n\n cmd\n .command('status')\n .description('Show tunnel status')\n .action(() => {\n configureTunnel(ctx);\n const config = loadConfig(ctx.configPath);\n const status = getTunnelService().getStatus();\n const persisted = loadTunnelState();\n console.log(\n JSON.stringify(\n {\n ...status,\n persistedSubdomain: persisted?.subdomain ?? null,\n consentValid: hasValidTunnelConsent(config),\n },\n null,\n 2,\n ),\n );\n });\n\n cmd\n .command('qr')\n .description('Print mobile connect QR payload (tunnel must be active)')\n .action(async () => {\n configureTunnel(ctx);\n const config = loadConfig(ctx.configPath);\n const { port, host } = resolveGatewayPortHost(config);\n const qr = await getTunnelService().buildQr(port, host);\n if (!qr.qrPayload) {\n console.error('No active tunnel. Run: xopc tunnel start');\n process.exit(1);\n }\n console.log(qr.qrPayload);\n });\n\n cmd\n .command('broker')\n .description('Self-hosted FRP broker helpers')\n .addCommand(\n new Command('init')\n .description('Print a starter frps + broker configuration template')\n .option('--domain <domain>', 'Public domain for frps', 'tunnel.example.com')\n .action((opts) => {\n const domain = String(opts.domain ?? 'tunnel.example.com');\n console.log(`# Self-hosted FRP broker sketch for ${domain}`);\n console.log('# 1. Run frps with vhost HTTP/HTTPS and a registration token');\n console.log(`# 2. Point tunnel.brokerUrl to https://${domain}/api`);\n console.log(`# 3. Set XOPC_TUNNEL_REGISTRATION_SECRET in the gateway environment`);\n console.log('');\n console.log(JSON.stringify({\n frps: {\n bindPort: 7000,\n vhostHTTPPort: 8080,\n subdomainHost: domain,\n },\n broker: {\n apiUrl: `https://${domain}/api`,\n registrationSecretEnv: 'XOPC_TUNNEL_REGISTRATION_SECRET',\n },\n }, null, 2));\n }),\n );\n\n return cmd;\n}\n\nregister({\n id: 'tunnel',\n name: 'tunnel',\n description: 'FRP remote access tunnel',\n factory: createTunnelCommand,\n metadata: {\n category: 'runtime',\n examples: ['xopc tunnel start', 'xopc tunnel status', 'xopc tunnel secret set'],\n },\n});\n"],"mappings":"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"}
|
package/dist/src/config/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { resolveDefaultAgentWorkspaceDir } from "./workspace-defaults.js";
|
|
|
4
4
|
import { resolveAgentDir as resolveAgentDir$1, resolveAgentHomeDir as resolveAgentHomeDir$1, resolveAgentWorkspaceDir, resolveSessionsDir as resolveSessionsDir$1 } from "../agent/agent-scope.js";
|
|
5
5
|
import { TelegramAccountConfigSchema, TelegramConfigSchema, TelegramGroupConfigSchema, TelegramTopicConfigSchema } from "../../extensions/telegram/src/config-schema.js";
|
|
6
6
|
import { WeixinAccountConfigSchema, WeixinConfigSchema } from "../../extensions/weixin/src/config-schema.js";
|
|
7
|
-
import { AgentConfigSchema, AgentDefaultsSchema, AgentImageGenerationModelSchema, AgentModelRefSchema, AgentsConfigSchema, BindingMatchSchema, BindingRuleSchema, BindingsConfigSchema, ChannelsConfigSchema, ConfigSchema, CronConfigSchema, ExtensionSecurityConfigSchema, ExtensionSlotsConfigSchema, ExtensionsConfigSchema, GatewayAuthRateLimitSchema, GatewayAuthSchema, GatewayBindModeSchema, GatewayChannelConnectDeferModeSchema, GatewayConfigSchema, GatewayModeSchema, GatewayRemoteSchema, GatewaySecuritySchema, GatewayTailscaleConsentSchema, GatewayTailscaleSchema, GatewayTlsSchema, GatewayTrustedProxySchema, GoalsConfigSchema, HeartbeatConfigSchema, McpConfigSchema, McpServerSchema, MediaUnderstandingCapabilitiesSchema, MediaUnderstandingModelSchema, MessagesConfigSchema, ModelsDevConfigSchema, ProviderAuthConfigSchema, ProviderAzureConfigSchema, ProviderRequestOverridesSchema, ProvidersConfigSchema, STTConfigSchema, STTFallbackConfigSchema, STTProviderConfigSchema, SearchProviderEntrySchema, SessionConfigSchema, SessionDmScopeSchema, SessionStorageConfigSchema, TTSConfigSchema, TTSEdgeConfigSchema, TTSFallbackConfigSchema, TTSModelOverridesConfigSchema, TTSProviderConfigSchema, TTSSummarizationConfigSchema, ToolsConfigSchema, ToolsMediaAudioConfigSchema, ToolsMediaConfigSchema, TunnelConfigSchema, TunnelConsentSchema,
|
|
7
|
+
import { AgentConfigSchema, AgentDefaultsSchema, AgentImageGenerationModelSchema, AgentModelRefSchema, AgentsConfigSchema, BindingMatchSchema, BindingRuleSchema, BindingsConfigSchema, ChannelsConfigSchema, ConfigSchema, CronConfigSchema, ExtensionSecurityConfigSchema, ExtensionSlotsConfigSchema, ExtensionsConfigSchema, GatewayAuthRateLimitSchema, GatewayAuthSchema, GatewayBindModeSchema, GatewayChannelConnectDeferModeSchema, GatewayConfigSchema, GatewayModeSchema, GatewayRemoteSchema, GatewaySecuritySchema, GatewayTailscaleConsentSchema, GatewayTailscaleSchema, GatewayTlsSchema, GatewayTrustedProxySchema, GoalsConfigSchema, HeartbeatConfigSchema, McpConfigSchema, McpServerSchema, MediaUnderstandingCapabilitiesSchema, MediaUnderstandingModelSchema, MessagesConfigSchema, ModelsDevConfigSchema, ProviderAuthConfigSchema, ProviderAzureConfigSchema, ProviderRequestOverridesSchema, ProvidersConfigSchema, STTConfigSchema, STTFallbackConfigSchema, STTProviderConfigSchema, SearchProviderEntrySchema, SessionConfigSchema, SessionDmScopeSchema, SessionStorageConfigSchema, TTSConfigSchema, TTSEdgeConfigSchema, TTSFallbackConfigSchema, TTSModelOverridesConfigSchema, TTSProviderConfigSchema, TTSSummarizationConfigSchema, ToolsConfigSchema, ToolsMediaAudioConfigSchema, ToolsMediaConfigSchema, TunnelConfigSchema, TunnelConsentSchema, UpdateAutoConfigSchema, UpdateConfigSchema, WebSearchConfigSchema, WebToolsConfigSchema, WebsiteBlocklistSchema, WorkspaceConfigSchema, WorkspaceImportConfigSchema, getAgentDefaultModelRef, getWorkspacePath, init_schema, parseModelRef } from "./schema.js";
|
|
8
8
|
import { applyConfigOverrides, getConfigOverrides, resetConfigOverrides, setConfigOverride, unsetConfigOverride } from "./runtime-overrides.js";
|
|
9
9
|
import { extractProfileAgentId, resolveEffectiveAgentProfile, resolveEffectiveAgentProfileForSession } from "./agent-profile.js";
|
|
10
10
|
import { resolveSessionFilePath, resolveSessionTranscriptPathInDir } from "../session/parity/transcript-paths.js";
|
|
@@ -28,6 +28,6 @@ init_workspace_path();
|
|
|
28
28
|
init_models_json();
|
|
29
29
|
init_resolve_config_value();
|
|
30
30
|
//#endregion
|
|
31
|
-
export { AgentConfigSchema, AgentDefaultsSchema, AgentImageGenerationModelSchema, AgentModelRefSchema, AgentsConfigSchema, BASE_RELOAD_RULES, BindingMatchSchema, BindingRuleSchema, BindingsConfigSchema, ChannelsConfigSchema, ConfigHotReloader, ConfigSchema, CronConfigSchema, CustomModelSchema, ENV_VARS, ExtensionSecurityConfigSchema, ExtensionSlotsConfigSchema, ExtensionsConfigSchema, FILENAMES, GatewayAuthRateLimitSchema, GatewayAuthSchema, GatewayBindModeSchema, GatewayChannelConnectDeferModeSchema, GatewayConfigSchema, GatewayModeSchema, GatewayRemoteSchema, GatewaySecuritySchema, GatewayTailscaleConsentSchema, GatewayTailscaleSchema, GatewayTlsSchema, GatewayTrustedProxySchema, GoalsConfigSchema, HeartbeatConfigSchema, McpConfigSchema, McpServerSchema, MediaUnderstandingCapabilitiesSchema, MediaUnderstandingModelSchema, MessagesConfigSchema, ModelOverrideSchema, ModelsDevConfigSchema, ModelsJsonSchema, OpenAICompatSchema, OpenAICompletionsCompatSchema, OpenAIResponsesCompatSchema, OpenRouterRoutingSchema, ProfileManager, ProviderAuthConfigSchema, ProviderAzureConfigSchema, ProviderConfigSchema, ProviderRequestOverridesSchema, ProvidersConfigSchema, STTConfigSchema, STTFallbackConfigSchema, STTProviderConfigSchema, SearchProviderEntrySchema, SessionConfigSchema, SessionDmScopeSchema, SessionStorageConfigSchema, TTSConfigSchema, TTSEdgeConfigSchema, TTSFallbackConfigSchema, TTSModelOverridesConfigSchema, TTSProviderConfigSchema, TTSSummarizationConfigSchema, TelegramAccountConfigSchema, TelegramConfigSchema, TelegramGroupConfigSchema, TelegramTopicConfigSchema, ToolsConfigSchema, ToolsMediaAudioConfigSchema, ToolsMediaConfigSchema, TunnelConfigSchema, TunnelConsentSchema,
|
|
31
|
+
export { AgentConfigSchema, AgentDefaultsSchema, AgentImageGenerationModelSchema, AgentModelRefSchema, AgentsConfigSchema, BASE_RELOAD_RULES, BindingMatchSchema, BindingRuleSchema, BindingsConfigSchema, ChannelsConfigSchema, ConfigHotReloader, ConfigSchema, CronConfigSchema, CustomModelSchema, ENV_VARS, ExtensionSecurityConfigSchema, ExtensionSlotsConfigSchema, ExtensionsConfigSchema, FILENAMES, GatewayAuthRateLimitSchema, GatewayAuthSchema, GatewayBindModeSchema, GatewayChannelConnectDeferModeSchema, GatewayConfigSchema, GatewayModeSchema, GatewayRemoteSchema, GatewaySecuritySchema, GatewayTailscaleConsentSchema, GatewayTailscaleSchema, GatewayTlsSchema, GatewayTrustedProxySchema, GoalsConfigSchema, HeartbeatConfigSchema, McpConfigSchema, McpServerSchema, MediaUnderstandingCapabilitiesSchema, MediaUnderstandingModelSchema, MessagesConfigSchema, ModelOverrideSchema, ModelsDevConfigSchema, ModelsJsonSchema, OpenAICompatSchema, OpenAICompletionsCompatSchema, OpenAIResponsesCompatSchema, OpenRouterRoutingSchema, ProfileManager, ProviderAuthConfigSchema, ProviderAzureConfigSchema, ProviderConfigSchema, ProviderRequestOverridesSchema, ProvidersConfigSchema, STTConfigSchema, STTFallbackConfigSchema, STTProviderConfigSchema, SearchProviderEntrySchema, SessionConfigSchema, SessionDmScopeSchema, SessionStorageConfigSchema, TTSConfigSchema, TTSEdgeConfigSchema, TTSFallbackConfigSchema, TTSModelOverridesConfigSchema, TTSProviderConfigSchema, TTSSummarizationConfigSchema, TelegramAccountConfigSchema, TelegramConfigSchema, TelegramGroupConfigSchema, TelegramTopicConfigSchema, ToolsConfigSchema, ToolsMediaAudioConfigSchema, ToolsMediaConfigSchema, TunnelConfigSchema, TunnelConsentSchema, UpdateAutoConfigSchema, UpdateConfigSchema, VercelGatewayRoutingSchema, WORKSPACE_FILES, WebSearchConfigSchema, WebToolsConfigSchema, WebsiteBlocklistSchema, WeixinAccountConfigSchema, WeixinConfigSchema, WorkspaceConfigSchema, WorkspaceImportConfigSchema, applyConfigOverrides, buildReloadPlan, canonicalizeConfiguredMcpServer, clearConfigValueCache, createProfile, deleteProfile, diffConfigPaths, existsSync, expandWorkspacePathString, extractProfileAgentId, formatThinkingLevels, getAgentDefaultModelRef, getAllowedCommands, getCacheStats, getConfigOverrides, getCurrentProfile, getDefaultModelValues, resolveModelsJsonPath as getModelsJsonPath, getProfileManager, getProfileNameFromDir, getSwitchCommand, getWorkspacePath, isKnownCliMcpTypeAlias, listAgentProfileMarkdownDirs, listAgentWorkspaceDirs, listConfiguredMcpServers, listProfiles, listThinkingLevels, loadConfig, loadModelsJson, matchReloadRule, modelsJsonExists, normalizeConfiguredMcpServers, normalizeElevatedMode, normalizeReasoningLevel, normalizeThinkLevel, normalizeVerboseLevel, normalizeWorkspaceDir, parseModelRef, registerChannelConfigValidator, resetConfigOverrides, resolveAgentAuthProfilesPath, resolveAgentDir, resolveAgentDir$1 as resolveAgentDirFromConfig, resolveAgentHomeDir, resolveAgentHomeDir$1 as resolveAgentHomeDirFromConfig, resolveAgentMetadataPath, resolveAgentProfileDir, resolveAgentProfileMarkdownPath, resolveAgentWorkspaceDir, resolveAuthProfilesPath, resolveBinDir, resolveBundledExtensionsDir, resolveBundledSkillsDir, resolveConfigPath, resolveConfigValue, resolveCredentialsDir, resolveCronDir, resolveCronJobsPath, resolveCronLogPath, resolveCronLogsDir, resolveCronRunsDir, resolveDefaultAgentWorkspaceDir, resolveEffectiveAgentProfile, resolveEffectiveAgentProfileForSession, resolveExtensionSdkPath, resolveExtensionsDir, resolveExtensionsLockPath, resolveHeaders, resolveHomeDir, resolveInboxDir, resolveInboxMessagePath, resolveInboxPendingDir, resolveInboxProcessedDir, resolveLogPath, resolveLogsDir, resolveMemoryDir, resolveMemoryPath, resolveModelsJsonPath, resolveNodeBinDir, resolveNodeBinPath, resolveNodeToolsDir, resolveNpmBinPath, resolveOAuthPath, resolvePidPath, resolveProfileStateDir, resolveSessionFilePath, resolveSessionTranscriptPath, resolveSessionTranscriptPathInDir, resolveSessionsArchiveDir, resolveSessionsDir, resolveSessionsDir$1 as resolveSessionsDirFromConfig, resolveSessionsMapPath, resolveSkillPath, resolveSkillsCachePath, resolveSkillsDir, resolveSkillsLockPath, resolveSocketPath, resolveStateDir, resolveStatusPath, resolveToolsDir, resolveWorkspaceExtensionsDir, resolveWorkspaceFile, resolveWorkspaceRoot, resolveWorkspaceStateDir, resolveWorkspaceStatePath, resolveXopcBinPath, resolveXopcMcpTransportAlias, saveConfig, saveModelsJson, setConfigOverride, setConfiguredMcpServer, testApiKeyResolution, thinkLevelToNumber, unsetConfigOverride, unsetConfiguredMcpServer, validateModelsConfig };
|
|
32
32
|
|
|
33
33
|
//# sourceMappingURL=index.js.map
|
package/dist/src/config/rules.js
CHANGED
|
@@ -230,11 +230,6 @@ const BASE_RELOAD_RULES = [
|
|
|
230
230
|
kind: "hot",
|
|
231
231
|
description: "MCP server definitions and idle TTL"
|
|
232
232
|
},
|
|
233
|
-
{
|
|
234
|
-
prefix: "tunnel.e2e",
|
|
235
|
-
kind: "restart",
|
|
236
|
-
description: "Tunnel E2E TLS settings"
|
|
237
|
-
},
|
|
238
233
|
{
|
|
239
234
|
prefix: "tunnel",
|
|
240
235
|
kind: "hot",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.js","names":[],"sources":["../../../src/config/rules.ts"],"sourcesContent":["/**\n * Configuration reload rules\n * \n * Defines how different config paths are handled:\n * - hot: Apply changes immediately without restart\n * - restart: Require gateway restart\n * - none: Ignore changes (no action needed)\n */\n\nimport type { ChannelPlugin } from '../channels/plugin-types.js';\nimport { bundledChannelPlugins } from '../generated/bundled-channel-plugins.js';\nimport { listChannelPlugins } from '../channels/plugins/registry.js';\n\nexport type ReloadKind = 'hot' | 'restart' | 'none';\n\nexport interface ReloadRule {\n prefix: string;\n kind: ReloadKind;\n description?: string;\n}\n\nexport interface ReloadPlan {\n changedPaths: string[];\n hotPaths: string[];\n restartPaths: string[];\n noopPaths: string[];\n requiresRestart: boolean;\n requiresHotReload: boolean;\n}\n\n/**\n * Base reload rules for config paths\n */\nexport const BASE_RELOAD_RULES: ReloadRule[] = [\n // Models config - hot reload\n { prefix: 'models.providers', kind: 'hot', description: 'Model provider API keys, base URLs' },\n { prefix: 'models.mode', kind: 'hot', description: 'Model merge mode' },\n \n // Agent defaults - hot reload\n { prefix: 'agents.defaults.model', kind: 'hot', description: 'Model configuration' },\n { prefix: 'agents.defaults.maxTaskDurationMs', kind: 'hot', description: 'Per-turn wall-clock timeout (ms)' },\n { prefix: 'agents.defaults.maxTokens', kind: 'hot', description: 'Max tokens' },\n { prefix: 'agents.defaults.temperature', kind: 'hot', description: 'Temperature' },\n { prefix: 'agents.defaults.maxToolIterations', kind: 'hot', description: 'Max tool iterations' },\n { prefix: 'agents.defaults.compaction', kind: 'hot', description: 'Compaction settings' },\n { prefix: 'agents.defaults.pruning', kind: 'hot', description: 'Pruning settings' },\n { prefix: 'agents.defaults.webExtract', kind: 'hot', description: 'Web extract model and limits' },\n { prefix: 'agents.defaults.browser', kind: 'hot', description: 'Browser automation (Playwright) tools' },\n { prefix: 'agents.defaults.delegate', kind: 'hot', description: 'delegate_task sub-agent tool' },\n { prefix: 'agents.defaults.executeCode', kind: 'hot', description: 'execute_code sandbox tool' },\n {\n prefix: 'agents.defaults.backgroundReview',\n kind: 'hot',\n description: 'Post-turn memory/skill nudge + background review',\n },\n { prefix: 'agents.defaults.workspace', kind: 'none', description: 'Workspace path - no runtime effect' },\n \n // Gateway - restart required\n { prefix: 'gateway.bind', kind: 'restart', description: 'Gateway bind mode' },\n { prefix: 'gateway.customBindHost', kind: 'restart', description: 'Gateway custom bind host' },\n { prefix: 'gateway.port', kind: 'restart', description: 'Port number' },\n { prefix: 'gateway.mode', kind: 'restart', description: 'Gateway local/remote CLI mode' },\n { prefix: 'gateway.remote', kind: 'restart', description: 'Remote gateway CLI target' },\n { prefix: 'gateway.tailscale', kind: 'restart', description: 'Tailscale Serve/Funnel exposure' },\n { prefix: 'gateway.tls', kind: 'restart', description: 'Gateway native TLS' },\n { prefix: 'gateway.auth', kind: 'restart', description: 'Authentication settings' },\n { prefix: 'gateway.security', kind: 'restart', description: 'Gateway security policy' },\n { prefix: 'gateway.corsOrigins', kind: 'restart', description: 'CORS settings' },\n { prefix: 'gateway.trustedProxies', kind: 'restart', description: 'Trusted reverse proxy CIDRs' },\n {\n prefix: 'gateway.allowRealIpFallback',\n kind: 'restart',\n description: 'Trusted-proxy X-Real-IP fallback',\n },\n {\n prefix: 'gateway.dangerouslyAllowHostHeaderOriginFallback',\n kind: 'restart',\n description: 'Host-header origin fallback',\n },\n { prefix: 'gateway.maxSseConnections', kind: 'restart', description: 'SSE connection limit' },\n { prefix: 'gateway.channelConnectDeferMode', kind: 'restart', description: 'Channel connect defer mode' },\n { prefix: 'gateway.channelConnectDeferIds', kind: 'restart', description: 'Explicit channel connect defer list' },\n { prefix: 'gateway.channelConnectDeferSkipIds', kind: 'restart', description: 'Channel connect defer skip list' },\n { prefix: 'gateway.share', kind: 'restart', description: 'File share policy' },\n {\n prefix: 'gateway.skillsStoreBaseUrl',\n kind: 'restart',\n description: 'Skills marketplace API base URL',\n },\n { prefix: 'gateway.enableHotReload', kind: 'hot', description: 'Hot reload toggle' },\n \n // Channels - hot reload (channel-specific prefixes are registered by channel plugins)\n { prefix: 'channels', kind: 'hot', description: 'Any channel subtree (e.g. future extensions)' },\n \n // Cron - hot reload\n { prefix: 'cron', kind: 'hot', description: 'Scheduled tasks' },\n \n // Heartbeat lives under gateway.heartbeat in config JSON (not top-level `heartbeat`)\n { prefix: 'gateway.heartbeat', kind: 'hot', description: 'Heartbeat settings' },\n \n // Web search - hot reload\n { prefix: 'webSearch', kind: 'hot', description: 'Web search settings' },\n { prefix: 'webTools', kind: 'hot', description: 'Web tools settings' },\n \n // Extension list toggles — still require process restart to load/unload modules\n {\n prefix: 'extensions.enabled',\n kind: 'restart',\n description: 'Extension enable list (requires restart)',\n },\n {\n prefix: 'extensions.disabled',\n kind: 'restart',\n description: 'Extension disable list (requires restart)',\n },\n // Extension instance config — hot-reloaded via extension registerReload handlers\n {\n prefix: 'extensions',\n kind: 'hot',\n description: 'Extension configuration (hot-reloaded via extension handlers)',\n },\n \n // Tools - hot reload (for tool-specific settings)\n { prefix: 'tools', kind: 'hot', description: 'Tools configuration' },\n\n // MCP servers - hot reload (dispose and reconnect runtimes)\n { prefix: 'mcp', kind: 'hot', description: 'MCP server definitions and idle TTL' },\n\n // Tunnel E2E TLS — restart (local HTTPS terminator port)\n { prefix: 'tunnel.e2e', kind: 'restart', description: 'Tunnel E2E TLS settings' },\n { prefix: 'tunnel', kind: 'hot', description: 'Tunnel broker and auto-start settings' },\n];\n\nfunction pluginsForReloadRules(): ChannelPlugin[] {\n const listed = listChannelPlugins();\n return listed.length > 0 ? [...listed] : [...bundledChannelPlugins];\n}\n\nfunction getChannelReloadRules(): ReloadRule[] {\n return pluginsForReloadRules()\n .filter((plugin) => plugin.reload?.configPrefixes?.length)\n .flatMap((plugin) =>\n plugin.reload!.configPrefixes.map((prefix) => ({\n prefix,\n kind: 'hot' as const,\n description: `${plugin.meta.label} settings`,\n })),\n );\n}\n\nfunction mergedReloadRules(): ReloadRule[] {\n return [...BASE_RELOAD_RULES, ...getChannelReloadRules()];\n}\n\n/**\n * Find matching rule for a config path\n */\nexport function matchReloadRule(path: string): ReloadRule | null {\n const merged = mergedReloadRules();\n const exact = merged.find((r) => r.prefix === path);\n if (exact) return exact;\n const sorted = [...merged].sort((a, b) => b.prefix.length - a.prefix.length);\n for (const rule of sorted) {\n if (path === rule.prefix || path.startsWith(`${rule.prefix}.`)) {\n return rule;\n }\n }\n return null;\n}\n\n/**\n * Build reload plan from changed paths\n */\nexport function buildReloadPlan(changedPaths: string[]): ReloadPlan {\n const plan: ReloadPlan = {\n changedPaths,\n hotPaths: [],\n restartPaths: [],\n noopPaths: [],\n requiresRestart: false,\n requiresHotReload: false,\n };\n\n for (const path of changedPaths) {\n const rule = matchReloadRule(path);\n \n if (!rule) {\n // No rule matched - default to restart for safety\n plan.restartPaths.push(path);\n plan.requiresRestart = true;\n continue;\n }\n\n switch (rule.kind) {\n case 'hot':\n plan.hotPaths.push(path);\n plan.requiresHotReload = true;\n break;\n case 'restart':\n plan.restartPaths.push(path);\n plan.requiresRestart = true;\n break;\n case 'none':\n plan.noopPaths.push(path);\n break;\n }\n }\n\n return plan;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"rules.js","names":[],"sources":["../../../src/config/rules.ts"],"sourcesContent":["/**\n * Configuration reload rules\n * \n * Defines how different config paths are handled:\n * - hot: Apply changes immediately without restart\n * - restart: Require gateway restart\n * - none: Ignore changes (no action needed)\n */\n\nimport type { ChannelPlugin } from '../channels/plugin-types.js';\nimport { bundledChannelPlugins } from '../generated/bundled-channel-plugins.js';\nimport { listChannelPlugins } from '../channels/plugins/registry.js';\n\nexport type ReloadKind = 'hot' | 'restart' | 'none';\n\nexport interface ReloadRule {\n prefix: string;\n kind: ReloadKind;\n description?: string;\n}\n\nexport interface ReloadPlan {\n changedPaths: string[];\n hotPaths: string[];\n restartPaths: string[];\n noopPaths: string[];\n requiresRestart: boolean;\n requiresHotReload: boolean;\n}\n\n/**\n * Base reload rules for config paths\n */\nexport const BASE_RELOAD_RULES: ReloadRule[] = [\n // Models config - hot reload\n { prefix: 'models.providers', kind: 'hot', description: 'Model provider API keys, base URLs' },\n { prefix: 'models.mode', kind: 'hot', description: 'Model merge mode' },\n \n // Agent defaults - hot reload\n { prefix: 'agents.defaults.model', kind: 'hot', description: 'Model configuration' },\n { prefix: 'agents.defaults.maxTaskDurationMs', kind: 'hot', description: 'Per-turn wall-clock timeout (ms)' },\n { prefix: 'agents.defaults.maxTokens', kind: 'hot', description: 'Max tokens' },\n { prefix: 'agents.defaults.temperature', kind: 'hot', description: 'Temperature' },\n { prefix: 'agents.defaults.maxToolIterations', kind: 'hot', description: 'Max tool iterations' },\n { prefix: 'agents.defaults.compaction', kind: 'hot', description: 'Compaction settings' },\n { prefix: 'agents.defaults.pruning', kind: 'hot', description: 'Pruning settings' },\n { prefix: 'agents.defaults.webExtract', kind: 'hot', description: 'Web extract model and limits' },\n { prefix: 'agents.defaults.browser', kind: 'hot', description: 'Browser automation (Playwright) tools' },\n { prefix: 'agents.defaults.delegate', kind: 'hot', description: 'delegate_task sub-agent tool' },\n { prefix: 'agents.defaults.executeCode', kind: 'hot', description: 'execute_code sandbox tool' },\n {\n prefix: 'agents.defaults.backgroundReview',\n kind: 'hot',\n description: 'Post-turn memory/skill nudge + background review',\n },\n { prefix: 'agents.defaults.workspace', kind: 'none', description: 'Workspace path - no runtime effect' },\n \n // Gateway - restart required\n { prefix: 'gateway.bind', kind: 'restart', description: 'Gateway bind mode' },\n { prefix: 'gateway.customBindHost', kind: 'restart', description: 'Gateway custom bind host' },\n { prefix: 'gateway.port', kind: 'restart', description: 'Port number' },\n { prefix: 'gateway.mode', kind: 'restart', description: 'Gateway local/remote CLI mode' },\n { prefix: 'gateway.remote', kind: 'restart', description: 'Remote gateway CLI target' },\n { prefix: 'gateway.tailscale', kind: 'restart', description: 'Tailscale Serve/Funnel exposure' },\n { prefix: 'gateway.tls', kind: 'restart', description: 'Gateway native TLS' },\n { prefix: 'gateway.auth', kind: 'restart', description: 'Authentication settings' },\n { prefix: 'gateway.security', kind: 'restart', description: 'Gateway security policy' },\n { prefix: 'gateway.corsOrigins', kind: 'restart', description: 'CORS settings' },\n { prefix: 'gateway.trustedProxies', kind: 'restart', description: 'Trusted reverse proxy CIDRs' },\n {\n prefix: 'gateway.allowRealIpFallback',\n kind: 'restart',\n description: 'Trusted-proxy X-Real-IP fallback',\n },\n {\n prefix: 'gateway.dangerouslyAllowHostHeaderOriginFallback',\n kind: 'restart',\n description: 'Host-header origin fallback',\n },\n { prefix: 'gateway.maxSseConnections', kind: 'restart', description: 'SSE connection limit' },\n { prefix: 'gateway.channelConnectDeferMode', kind: 'restart', description: 'Channel connect defer mode' },\n { prefix: 'gateway.channelConnectDeferIds', kind: 'restart', description: 'Explicit channel connect defer list' },\n { prefix: 'gateway.channelConnectDeferSkipIds', kind: 'restart', description: 'Channel connect defer skip list' },\n { prefix: 'gateway.share', kind: 'restart', description: 'File share policy' },\n {\n prefix: 'gateway.skillsStoreBaseUrl',\n kind: 'restart',\n description: 'Skills marketplace API base URL',\n },\n { prefix: 'gateway.enableHotReload', kind: 'hot', description: 'Hot reload toggle' },\n \n // Channels - hot reload (channel-specific prefixes are registered by channel plugins)\n { prefix: 'channels', kind: 'hot', description: 'Any channel subtree (e.g. future extensions)' },\n \n // Cron - hot reload\n { prefix: 'cron', kind: 'hot', description: 'Scheduled tasks' },\n \n // Heartbeat lives under gateway.heartbeat in config JSON (not top-level `heartbeat`)\n { prefix: 'gateway.heartbeat', kind: 'hot', description: 'Heartbeat settings' },\n \n // Web search - hot reload\n { prefix: 'webSearch', kind: 'hot', description: 'Web search settings' },\n { prefix: 'webTools', kind: 'hot', description: 'Web tools settings' },\n \n // Extension list toggles — still require process restart to load/unload modules\n {\n prefix: 'extensions.enabled',\n kind: 'restart',\n description: 'Extension enable list (requires restart)',\n },\n {\n prefix: 'extensions.disabled',\n kind: 'restart',\n description: 'Extension disable list (requires restart)',\n },\n // Extension instance config — hot-reloaded via extension registerReload handlers\n {\n prefix: 'extensions',\n kind: 'hot',\n description: 'Extension configuration (hot-reloaded via extension handlers)',\n },\n \n // Tools - hot reload (for tool-specific settings)\n { prefix: 'tools', kind: 'hot', description: 'Tools configuration' },\n\n // MCP servers - hot reload (dispose and reconnect runtimes)\n { prefix: 'mcp', kind: 'hot', description: 'MCP server definitions and idle TTL' },\n\n // Tunnel E2E TLS — restart (local HTTPS terminator port)\n { prefix: 'tunnel', kind: 'hot', description: 'Tunnel broker and auto-start settings' },\n];\n\nfunction pluginsForReloadRules(): ChannelPlugin[] {\n const listed = listChannelPlugins();\n return listed.length > 0 ? [...listed] : [...bundledChannelPlugins];\n}\n\nfunction getChannelReloadRules(): ReloadRule[] {\n return pluginsForReloadRules()\n .filter((plugin) => plugin.reload?.configPrefixes?.length)\n .flatMap((plugin) =>\n plugin.reload!.configPrefixes.map((prefix) => ({\n prefix,\n kind: 'hot' as const,\n description: `${plugin.meta.label} settings`,\n })),\n );\n}\n\nfunction mergedReloadRules(): ReloadRule[] {\n return [...BASE_RELOAD_RULES, ...getChannelReloadRules()];\n}\n\n/**\n * Find matching rule for a config path\n */\nexport function matchReloadRule(path: string): ReloadRule | null {\n const merged = mergedReloadRules();\n const exact = merged.find((r) => r.prefix === path);\n if (exact) return exact;\n const sorted = [...merged].sort((a, b) => b.prefix.length - a.prefix.length);\n for (const rule of sorted) {\n if (path === rule.prefix || path.startsWith(`${rule.prefix}.`)) {\n return rule;\n }\n }\n return null;\n}\n\n/**\n * Build reload plan from changed paths\n */\nexport function buildReloadPlan(changedPaths: string[]): ReloadPlan {\n const plan: ReloadPlan = {\n changedPaths,\n hotPaths: [],\n restartPaths: [],\n noopPaths: [],\n requiresRestart: false,\n requiresHotReload: false,\n };\n\n for (const path of changedPaths) {\n const rule = matchReloadRule(path);\n \n if (!rule) {\n // No rule matched - default to restart for safety\n plan.restartPaths.push(path);\n plan.requiresRestart = true;\n continue;\n }\n\n switch (rule.kind) {\n case 'hot':\n plan.hotPaths.push(path);\n plan.requiresHotReload = true;\n break;\n case 'restart':\n plan.restartPaths.push(path);\n plan.requiresRestart = true;\n break;\n case 'none':\n plan.noopPaths.push(path);\n break;\n }\n }\n\n return plan;\n}\n"],"mappings":"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"}
|
|
@@ -838,34 +838,16 @@ export declare const TunnelConsentSchema: z.ZodObject<{
|
|
|
838
838
|
version: z.ZodString;
|
|
839
839
|
acceptedAt: z.ZodString;
|
|
840
840
|
}, z.core.$strip>;
|
|
841
|
-
export declare const TunnelE2eSchema: z.ZodDefault<z.ZodObject<{
|
|
842
|
-
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
843
|
-
tlsPort: z.ZodDefault<z.ZodNumber>;
|
|
844
|
-
staging: z.ZodDefault<z.ZodBoolean>;
|
|
845
|
-
}, z.core.$strip>>;
|
|
846
|
-
export declare const TunnelExposureModeSchema: z.ZodEnum<{
|
|
847
|
-
public: "public";
|
|
848
|
-
"pairing-only": "pairing-only";
|
|
849
|
-
}>;
|
|
850
841
|
export declare const TunnelConfigSchema: z.ZodDefault<z.ZodObject<{
|
|
851
842
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
852
843
|
brokerUrl: z.ZodDefault<z.ZodString>;
|
|
853
844
|
registrationSecret: z.ZodOptional<z.ZodString>;
|
|
854
845
|
autoStart: z.ZodDefault<z.ZodBoolean>;
|
|
855
846
|
subdomain: z.ZodOptional<z.ZodString>;
|
|
856
|
-
exposure: z.ZodDefault<z.ZodEnum<{
|
|
857
|
-
public: "public";
|
|
858
|
-
"pairing-only": "pairing-only";
|
|
859
|
-
}>>;
|
|
860
847
|
consent: z.ZodOptional<z.ZodObject<{
|
|
861
848
|
version: z.ZodString;
|
|
862
849
|
acceptedAt: z.ZodString;
|
|
863
850
|
}, z.core.$strip>>;
|
|
864
|
-
e2e: z.ZodOptional<z.ZodDefault<z.ZodObject<{
|
|
865
|
-
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
866
|
-
tlsPort: z.ZodDefault<z.ZodNumber>;
|
|
867
|
-
staging: z.ZodDefault<z.ZodBoolean>;
|
|
868
|
-
}, z.core.$strip>>>;
|
|
869
851
|
}, z.core.$strip>>;
|
|
870
852
|
export type TunnelConfig = z.infer<typeof TunnelConfigSchema>;
|
|
871
853
|
/**
|
|
@@ -1911,19 +1893,10 @@ export declare const ConfigSchema: z.ZodDefault<z.ZodObject<{
|
|
|
1911
1893
|
registrationSecret: z.ZodOptional<z.ZodString>;
|
|
1912
1894
|
autoStart: z.ZodDefault<z.ZodBoolean>;
|
|
1913
1895
|
subdomain: z.ZodOptional<z.ZodString>;
|
|
1914
|
-
exposure: z.ZodDefault<z.ZodEnum<{
|
|
1915
|
-
public: "public";
|
|
1916
|
-
"pairing-only": "pairing-only";
|
|
1917
|
-
}>>;
|
|
1918
1896
|
consent: z.ZodOptional<z.ZodObject<{
|
|
1919
1897
|
version: z.ZodString;
|
|
1920
1898
|
acceptedAt: z.ZodString;
|
|
1921
1899
|
}, z.core.$strip>>;
|
|
1922
|
-
e2e: z.ZodOptional<z.ZodDefault<z.ZodObject<{
|
|
1923
|
-
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
1924
|
-
tlsPort: z.ZodDefault<z.ZodNumber>;
|
|
1925
|
-
staging: z.ZodDefault<z.ZodBoolean>;
|
|
1926
|
-
}, z.core.$strip>>>;
|
|
1927
1900
|
}, z.core.$strip>>>;
|
|
1928
1901
|
workspace: z.ZodOptional<z.ZodObject<{
|
|
1929
1902
|
import: z.ZodOptional<z.ZodObject<{
|
|
@@ -33,7 +33,7 @@ function parseModelRef(ref) {
|
|
|
33
33
|
model: trimmed.slice(idx + 1).trim()
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
|
-
var AgentModelRefSchema, AgentImageGenerationModelSchema, AgentDefaultsSchema, AgentConfigSchema, AgentsConfigSchema, BindingMatchSchema, BindingRuleSchema, BindingsConfigSchema, SessionDmScopeSchema, SessionStorageConfigSchema, SessionConfigSchema, ChannelsConfigSchema, SearchProviderEntrySchema, WebSearchConfigSchema, WebsiteBlocklistSchema, WebToolsConfigSchema, ToolsConfigSchema, GatewayAuthRateLimitSchema, GatewaySecuritySchema, GatewayTrustedProxySchema, GatewayAuthSchema, GatewayTailscaleConsentSchema, GatewayTailscaleSchema, GatewayRemoteSchema, GatewayTlsSchema, GatewayModeSchema, HeartbeatConfigSchema, GatewayChannelConnectDeferModeSchema, TunnelConsentSchema,
|
|
36
|
+
var AgentModelRefSchema, AgentImageGenerationModelSchema, AgentDefaultsSchema, AgentConfigSchema, AgentsConfigSchema, BindingMatchSchema, BindingRuleSchema, BindingsConfigSchema, SessionDmScopeSchema, SessionStorageConfigSchema, SessionConfigSchema, ChannelsConfigSchema, SearchProviderEntrySchema, WebSearchConfigSchema, WebsiteBlocklistSchema, WebToolsConfigSchema, ToolsConfigSchema, GatewayAuthRateLimitSchema, GatewaySecuritySchema, GatewayTrustedProxySchema, GatewayAuthSchema, GatewayTailscaleConsentSchema, GatewayTailscaleSchema, GatewayRemoteSchema, GatewayTlsSchema, GatewayModeSchema, HeartbeatConfigSchema, GatewayChannelConnectDeferModeSchema, TunnelConsentSchema, TunnelConfigSchema, WorkspaceImportConfigSchema, WorkspaceConfigSchema, GatewayBindModeSchema, GatewayConfigSchema, CronConfigSchema, ModelsDevConfigSchema, SttProviderConfigCatchallSchema, STTProviderConfigSchema, STTFallbackConfigSchema, MediaUnderstandingCapabilitiesSchema, MediaUnderstandingModelSchema, STTConfigSchema, TtsProviderConfigCatchallSchema, TTSProviderConfigSchema, TTSFallbackConfigSchema, TTSModelOverridesConfigSchema, TTSEdgeConfigSchema, TTSSummarizationConfigSchema, TTSConfigSchema, MessagesConfigSchema, ToolsMediaAudioConfigSchema, ToolsMediaConfigSchema, ProviderAzureConfigSchema, ProviderRequestOverridesSchema, ProviderAuthConfigSchema, ProvidersConfigSchema, ExtensionSecurityConfigSchema, ExtensionSlotsConfigSchema, ExtensionsConfigSchema, UpdateAutoConfigSchema, GoalsConfigSchema, UpdateConfigSchema, McpHttpUrlSchema, McpServerSchema, McpConfigSchema, ConfigSchema;
|
|
37
37
|
var init_schema = __esmMin((() => {
|
|
38
38
|
init_agent_scope();
|
|
39
39
|
init_cache_dir_policy();
|
|
@@ -585,16 +585,6 @@ strict: z.boolean().optional() }).optional();
|
|
|
585
585
|
version: z.string().min(1),
|
|
586
586
|
acceptedAt: z.string().min(1)
|
|
587
587
|
});
|
|
588
|
-
TunnelE2eSchema = z.object({
|
|
589
|
-
enabled: z.boolean().default(true),
|
|
590
|
-
tlsPort: z.number().int().min(1024).max(65535).default(18791),
|
|
591
|
-
staging: z.boolean().default(false)
|
|
592
|
-
}).default({
|
|
593
|
-
enabled: true,
|
|
594
|
-
tlsPort: 18791,
|
|
595
|
-
staging: false
|
|
596
|
-
});
|
|
597
|
-
TunnelExposureModeSchema = z.enum(["public", "pairing-only"]);
|
|
598
588
|
TunnelConfigSchema = z.object({
|
|
599
589
|
enabled: z.boolean().default(false),
|
|
600
590
|
brokerUrl: z.string().url().default("https://frp.xopc.ai/api"),
|
|
@@ -602,15 +592,11 @@ strict: z.boolean().optional() }).optional();
|
|
|
602
592
|
registrationSecret: z.string().min(1).optional(),
|
|
603
593
|
autoStart: z.boolean().default(false),
|
|
604
594
|
subdomain: z.string().optional(),
|
|
605
|
-
|
|
606
|
-
exposure: TunnelExposureModeSchema.default("public"),
|
|
607
|
-
consent: TunnelConsentSchema.optional(),
|
|
608
|
-
e2e: TunnelE2eSchema.optional()
|
|
595
|
+
consent: TunnelConsentSchema.optional()
|
|
609
596
|
}).default({
|
|
610
597
|
enabled: false,
|
|
611
598
|
brokerUrl: "https://frp.xopc.ai/api",
|
|
612
|
-
autoStart: false
|
|
613
|
-
exposure: "public"
|
|
599
|
+
autoStart: false
|
|
614
600
|
});
|
|
615
601
|
WorkspaceImportConfigSchema = z.object({
|
|
616
602
|
/** Workspace-relative subdir for imported files. Default `imports`. */
|
|
@@ -1094,6 +1080,6 @@ tts: TTSConfigSchema.optional() }).optional();
|
|
|
1094
1080
|
}));
|
|
1095
1081
|
//#endregion
|
|
1096
1082
|
init_schema();
|
|
1097
|
-
export { AgentConfigSchema, AgentDefaultsSchema, AgentImageGenerationModelSchema, AgentModelRefSchema, AgentsConfigSchema, BindingMatchSchema, BindingRuleSchema, BindingsConfigSchema, ChannelsConfigSchema, ConfigSchema, CronConfigSchema, ExtensionSecurityConfigSchema, ExtensionSlotsConfigSchema, ExtensionsConfigSchema, GatewayAuthRateLimitSchema, GatewayAuthSchema, GatewayBindModeSchema, GatewayChannelConnectDeferModeSchema, GatewayConfigSchema, GatewayModeSchema, GatewayRemoteSchema, GatewaySecuritySchema, GatewayTailscaleConsentSchema, GatewayTailscaleSchema, GatewayTlsSchema, GatewayTrustedProxySchema, GoalsConfigSchema, HeartbeatConfigSchema, McpConfigSchema, McpServerSchema, MediaUnderstandingCapabilitiesSchema, MediaUnderstandingModelSchema, MessagesConfigSchema, ModelsDevConfigSchema, ProviderAuthConfigSchema, ProviderAzureConfigSchema, ProviderRequestOverridesSchema, ProvidersConfigSchema, STTConfigSchema, STTFallbackConfigSchema, STTProviderConfigSchema, SearchProviderEntrySchema, SessionConfigSchema, SessionDmScopeSchema, SessionStorageConfigSchema, TTSConfigSchema, TTSEdgeConfigSchema, TTSFallbackConfigSchema, TTSModelOverridesConfigSchema, TTSProviderConfigSchema, TTSSummarizationConfigSchema, TelegramAccountConfigSchema, TelegramConfigSchema, TelegramGroupConfigSchema, TelegramTopicConfigSchema, ToolsConfigSchema, ToolsMediaAudioConfigSchema, ToolsMediaConfigSchema, TunnelConfigSchema, TunnelConsentSchema,
|
|
1083
|
+
export { AgentConfigSchema, AgentDefaultsSchema, AgentImageGenerationModelSchema, AgentModelRefSchema, AgentsConfigSchema, BindingMatchSchema, BindingRuleSchema, BindingsConfigSchema, ChannelsConfigSchema, ConfigSchema, CronConfigSchema, ExtensionSecurityConfigSchema, ExtensionSlotsConfigSchema, ExtensionsConfigSchema, GatewayAuthRateLimitSchema, GatewayAuthSchema, GatewayBindModeSchema, GatewayChannelConnectDeferModeSchema, GatewayConfigSchema, GatewayModeSchema, GatewayRemoteSchema, GatewaySecuritySchema, GatewayTailscaleConsentSchema, GatewayTailscaleSchema, GatewayTlsSchema, GatewayTrustedProxySchema, GoalsConfigSchema, HeartbeatConfigSchema, McpConfigSchema, McpServerSchema, MediaUnderstandingCapabilitiesSchema, MediaUnderstandingModelSchema, MessagesConfigSchema, ModelsDevConfigSchema, ProviderAuthConfigSchema, ProviderAzureConfigSchema, ProviderRequestOverridesSchema, ProvidersConfigSchema, STTConfigSchema, STTFallbackConfigSchema, STTProviderConfigSchema, SearchProviderEntrySchema, SessionConfigSchema, SessionDmScopeSchema, SessionStorageConfigSchema, TTSConfigSchema, TTSEdgeConfigSchema, TTSFallbackConfigSchema, TTSModelOverridesConfigSchema, TTSProviderConfigSchema, TTSSummarizationConfigSchema, TelegramAccountConfigSchema, TelegramConfigSchema, TelegramGroupConfigSchema, TelegramTopicConfigSchema, ToolsConfigSchema, ToolsMediaAudioConfigSchema, ToolsMediaConfigSchema, TunnelConfigSchema, TunnelConsentSchema, UpdateAutoConfigSchema, UpdateConfigSchema, WebSearchConfigSchema, WebToolsConfigSchema, WebsiteBlocklistSchema, WeixinAccountConfigSchema, WeixinConfigSchema, WorkspaceConfigSchema, WorkspaceImportConfigSchema, getAgentDefaultModelRef, getWorkspacePath, init_schema, parseModelRef };
|
|
1098
1084
|
|
|
1099
1085
|
//# sourceMappingURL=schema.js.map
|