fix: address Windows smoke review findings (#122)

Co-authored-by: iliya <iliyazelenkog@gmail.com>
This commit is contained in:
infiniti 2026-05-16 18:03:05 +03:00 committed by GitHub
parent 9c438e7c84
commit f08e228a7d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 103 additions and 4 deletions

View file

@ -173,4 +173,13 @@ async function main() {
fail(`Timed out after ${STARTUP_TIMEOUT_MS}ms waiting for packaged startup`, log);
}
main().catch((error) => fail(error?.stack || String(error)));
if (require.main === module) {
main().catch((error) => fail(error?.stack || String(error)));
}
module.exports = {
_internal: {
terminateChild,
waitForProcessClose,
},
};

View file

@ -12,13 +12,13 @@ import type { ClaudeMdContextInjection } from '@renderer/types/contextInjection'
*/
export function buildDirectoryTree(
injections: ClaudeMdContextInjection[],
projectRoot: string
projectRoot?: string
): TreeNode {
const root: TreeNode = { name: '', path: '', isFile: false, children: new Map() };
for (const injection of injections) {
const relativePath = projectRoot
? getRelativePathWithinPrefix(projectRoot, injection.path) ?? injection.path
? (getRelativePathWithinPrefix(projectRoot, injection.path) ?? injection.path)
: injection.path;
const parts = relativePath.split(/[\\/]/);

View file

@ -169,6 +169,21 @@ describe('recentProjectOpenHistory', () => {
it('ignores blank project paths without throwing', () => {
expect(() => recordRecentProjectOpenPaths([' '], 10_000)).not.toThrow();
expect(getRecentProjectLastOpenedAt(makeProject({ primaryPath: ' ', associatedPaths: [' '] }))).toBe(0);
expect(
getRecentProjectLastOpenedAt(makeProject({ primaryPath: ' ', associatedPaths: [' '] }))
).toBe(0);
});
it('ignores paths that normalize to an empty history key', () => {
recordRecentProjectOpenPaths(['///'], 10_000);
expect(
getRecentProjectLastOpenedAt(
makeProject({
primaryPath: '/',
associatedPaths: ['/'],
})
)
).toBe(0);
});
});

View file

@ -0,0 +1,69 @@
// @vitest-environment node
import { createRequire } from 'node:module';
import { describe, expect, it, vi } from 'vitest';
interface SmokePackagedAppInternals {
terminateChild(
child: { exitCode: number | null; signalCode: string | null; kill: () => void },
exitPromise: Promise<unknown>,
platform: string
): Promise<void>;
waitForProcessClose(
child: { exitCode: number | null; signalCode: string | null },
exitPromise: Promise<unknown>,
timeoutMs: number
): Promise<boolean>;
}
interface SmokePackagedAppModule {
default?: { _internal?: SmokePackagedAppInternals };
_internal?: SmokePackagedAppInternals;
}
const requireFromTest: (id: string) => unknown = createRequire(import.meta.url);
const smokePackagedApp = requireFromTest(
'../../../scripts/electron-builder/smokePackagedApp.cjs'
) as SmokePackagedAppModule;
const smokePackagedAppInternals =
smokePackagedApp._internal ?? smokePackagedApp.default?._internal;
if (!smokePackagedAppInternals) {
throw new Error('smokePackagedApp internals were not exported');
}
const { terminateChild, waitForProcessClose } = smokePackagedAppInternals;
describe('smokePackagedApp shutdown handling', () => {
it('reports successful process closure before the timeout', async () => {
let resolveExit!: (value: unknown) => void;
const exitPromise = new Promise((resolve) => {
resolveExit = resolve;
});
const child = { exitCode: null, signalCode: null };
const closed = waitForProcessClose(child, exitPromise, 1_000);
resolveExit({ code: 0, signal: null });
await expect(closed).resolves.toBe(true);
});
it('reports shutdown timeout instead of treating it as success', async () => {
vi.useFakeTimers();
try {
const exitPromise = new Promise(() => undefined);
const child = {
exitCode: null,
signalCode: null,
kill: vi.fn(),
};
const termination = terminateChild(child, exitPromise, 'linux');
const rejection = expect(termination).rejects.toThrow('Timed out after 5000ms');
await vi.advanceTimersByTimeAsync(5_000);
await rejection;
expect(child.kill).toHaveBeenCalledTimes(1);
} finally {
vi.useRealTimers();
}
});
});

View file

@ -44,4 +44,10 @@ describe('buildDirectoryTree Windows paths', () => {
expect(root.children.get('C:')?.children.get('Users')).toBeDefined();
});
it('falls back to absolute injection paths when project root is unavailable', () => {
const root = buildDirectoryTree([injection('C:\\Users\\Alice\\Repo\\CLAUDE.md')]);
expect(root.children.get('C:')?.children.get('Users')).toBeDefined();
});
});