fix: restore CLI validation and test baseline (#1857)

Fixed lazy CLI helper imports for tunnel flows
Restored update command version detection
Made web test and dead-code commands run reliably
This commit is contained in:
Bohdan Triapitsyn
2026-06-27 09:45:34 +03:00
parent 38c9ff77c9
commit 5cc37d0c33
12 changed files with 70 additions and 11 deletions
+1 -1
View File
@@ -51,7 +51,7 @@
"vscode:package": "bun run --cwd packages/vscode package",
"vscode:type-check": "bun run --cwd packages/vscode type-check",
"docs:validate": "node scripts/docs/validate-docs.mjs",
"dead-code": "bunx knip --no-exit-code --include files,exports,nsExports,types,nsTypes,enumMembers,namespaceMembers,duplicates",
"dead-code": "bunx knip@5.80.0 --no-exit-code --include files,exports,nsExports,types,nsTypes,enumMembers,duplicates",
"doctor": "node scripts/react-doctor.mjs",
"icons:sprite": "node scripts/generate-file-type-sprite.mjs",
"icons:generate": "bun run scripts/generate-icon-sprite.mjs",
+1
View File
@@ -210,6 +210,7 @@ export {
requestServerShutdown,
requestJson,
isServerHealthReady,
waitForServerHealth,
fetchTunnelProvidersFromPort,
fetchSystemInfoFromPort,
};
+1
View File
@@ -145,6 +145,7 @@ export {
resolveServeHost,
resolveApiHost,
formatHostForUrl,
isUnsafeBrowserPort,
buildLocalUrl,
detectLanIPv4Address,
assertSafeBrowserPort,
+2
View File
@@ -107,5 +107,7 @@ export {
getLogFilePath,
getTunnelProfilesFilePath,
getLegacyCloudflareManagedRemoteFilePath,
readLastManagedLocalConfigPath,
writeLastManagedLocalConfigPath,
getRunDir,
};
+6 -2
View File
@@ -4,7 +4,7 @@ import path from 'path';
import crypto from 'crypto';
import { EXIT_CODE, TunnelCliError } from './cli-errors.js';
import { DEFAULT_PORT, findClosestMatch, generateCompletionScript, showTunnelHelp } from './cli-args.js';
import { requestJson, fetchSystemInfoFromPort } from './cli-http.js';
import { requestJson, fetchSystemInfoFromPort, waitForServerHealth } from './cli-http.js';
import {
discoverRunningInstances,
getLatestInstance,
@@ -34,7 +34,11 @@ import {
resolveTunnelTtlOverrides,
} from './cli-tunnel-utils.js';
import { DEFAULT_TUNNEL_PROVIDER_CAPABILITIES } from './cli-tunnel-capabilities.js';
import { assertSafeBrowserPort, buildLocalUrl } from './cli-network.js';
import { assertSafeBrowserPort, buildLocalUrl, isUnsafeBrowserPort } from './cli-network.js';
import {
readLastManagedLocalConfigPath,
writeLastManagedLocalConfigPath,
} from './cli-paths.js';
import {
intro as clackIntro,
outro as clackOutro,
+4 -4
View File
@@ -1,11 +1,11 @@
import { beforeEach, describe, expect, it, mock } from 'bun:test';
import { beforeEach, describe, expect, it, vi } from 'vitest';
const gitLibraries = {
stageFiles: mock(),
unstageFiles: mock(),
stageFiles: vi.fn(),
unstageFiles: vi.fn(),
};
mock.module('./index.js', () => ({
vi.mock('./index.js', () => ({
stageFiles: gitLibraries.stageFiles,
unstageFiles: gitLibraries.unstageFiles,
}));
+1
View File
@@ -982,6 +982,7 @@ export function registerGitHubRoutes(app) {
if (upstream) {
try {
const { getRemotes } = await import('../git/index.js');
const { resolveGitHubRepoFromDirectory } = await import('./index.js');
const remotes = await getRemotes(directory);
for (const r of remotes) {
if (r?.name) {
+1 -1
View File
@@ -621,7 +621,7 @@ export function getUpdateCommand(pm = detectPackageManager()) {
/**
* Get current installed version from package.json
*/
function getCurrentVersion() {
export function getCurrentVersion() {
try {
const pkgPath = path.resolve(__dirname, '..', '..', 'package.json');
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
@@ -6,7 +6,7 @@ vi.mock('node:child_process', () => ({
spawnSync: vi.fn(() => ({ status: 0, stdout: '/usr/local/bin', stderr: '' })),
}));
const { checkForUpdates } = await import('./package-manager.js');
const { checkForUpdates, getCurrentVersion } = await import('./package-manager.js');
/** Helper: create a fetch mock that routes by URL pattern */
function createFetchMock() {
@@ -244,3 +244,10 @@ describe('checkForUpdates', () => {
expect(result.available).toBe(false);
});
});
describe('getCurrentVersion', () => {
it('is exported for the CLI update command', () => {
expect(typeof getCurrentVersion).toBe('function');
expect(getCurrentVersion()).toMatch(/^\d+\.\d+\.\d+|unknown$/);
});
});
+4 -2
View File
@@ -32,14 +32,16 @@ describe('createWebFilesAPI', () => {
runtimeFetchMock.mockResolvedValueOnce(Response.json({ path: '/worktree-b/file.txt', isFile: true, size: 12 }));
await api.statFile?.('/worktree-b/file.txt', { directory: '/worktree-a' });
expect(runtimeFetchMock).toHaveBeenLastCalledWith('/api/fs/stat?path=%2Fworktree-b%2Ffile.txt', {
expect(runtimeFetchMock).toHaveBeenLastCalledWith('/api/fs/stat', {
query: new URLSearchParams({ path: '/worktree-b/file.txt' }),
headers: { 'x-opencode-directory': '/worktree-a' },
});
runtimeFetchMock.mockResolvedValueOnce(new Response('content'));
await api.readFile?.('/worktree-b/file.txt', { directory: '/worktree-a' });
expect(runtimeFetchMock).toHaveBeenLastCalledWith('/api/fs/read?path=%2Fworktree-b%2Ffile.txt', {
expect(runtimeFetchMock).toHaveBeenLastCalledWith('/api/fs/read', {
query: new URLSearchParams({ path: '/worktree-b/file.txt' }),
cache: 'default',
headers: { 'x-opencode-directory': '/worktree-a' },
});
+31
View File
@@ -0,0 +1,31 @@
import {
afterAll,
afterEach,
beforeAll,
beforeEach,
describe,
expect,
it,
test,
vi,
} from 'vitest';
const mock = Object.assign(
<T extends (...args: never[]) => unknown>(implementation?: T) => vi.fn(implementation),
{
module: vi.mock,
},
);
export {
afterAll,
afterEach,
beforeAll,
beforeEach,
describe,
expect,
it,
mock,
test,
vi,
};
+10
View File
@@ -0,0 +1,10 @@
import { fileURLToPath } from 'node:url';
import { defineConfig } from 'vitest/config';
export default defineConfig({
resolve: {
alias: {
'bun:test': fileURLToPath(new URL('./test/bun-test-shim.ts', import.meta.url)),
},
},
});