Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1784,6 +1784,7 @@ jobs:
QWEN_DEFAULT_AUTH_TYPE: ''
run: |-
node -e "const fs = require('node:fs'); for (const key of ['HOME', 'USERPROFILE']) { const dir = process.env[key]; if (dir) fs.mkdirSync(dir, { recursive: true }); }"
git config --global core.autocrlf false
Comment thread
yiliang114 marked this conversation as resolved.
Resolved
# ENOSPC has failed test steps mid-suite while the host looks
# healthy afterwards — a transient spike, likely /tmp inodes or a
# tmpfs cap. Sample the routed temp filesystem every 10s so the
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/windows-runner-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,5 @@ jobs:
QWEN_DEFAULT_AUTH_TYPE: ''
run: |-
node -e "const fs = require('node:fs'); for (const key of ['HOME', 'USERPROFILE']) { const dir = process.env[key]; if (dir) fs.mkdirSync(dir, { recursive: true }); }"
git config --global core.autocrlf false
npm run test:ci
84 changes: 83 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion packages/acp-bridge/src/sessionAttachments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1456,7 +1456,9 @@ describe('SessionAttachmentStore', () => {
);
await fs.mkdir(directory, { recursive: true });
await fs.writeFile(path.join(directory, 'notes.txt'), 'a');
await fs.writeFile(path.join(directory, 'bad?.txt'), 'b');
if (process.platform !== 'win32') {
await fs.writeFile(path.join(directory, 'bad?.txt'), 'b');
}
await fs.mkdir(path.join(directory, 'sub'));

expect((await store.list()).map((item) => item.attachmentId)).toEqual([
Expand Down
17 changes: 13 additions & 4 deletions packages/cli/src/acp-integration/acpAgent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7361,7 +7361,7 @@ describe('QwenAgent MCP SSE/HTTP support', () => {
});
});

it('rejects a standalone directory identity replaced during Config relocation', async () => {
it('rejects a standalone directory identity replaced during Config relocation', async (ctx) => {
await withEmptyTrustedFolders(async (directory) => {
const settings = makeSessionSettings({ mcpServers: {} });
const { agent, agentPromise, sessionId, innerConfig } =
Expand All @@ -7370,6 +7370,12 @@ describe('QwenAgent MCP SSE/HTTP support', () => {
const target = path.join(root, getConversationDirectoryName(sessionId));
await fs.mkdir(target, { recursive: true, mode: 0o700 });
const expectation = await managedConversationExpectation(root, sessionId);
if (expectation.child.inode === 0) {
mockConnectionState.resolve();
await agentPromise;
ctx.skip();
return;
}
innerConfig.getSessionSourceType.mockReturnValue('standalone');
innerConfig.relocateWorkingDirectory.mockImplementation(async () => {
const previous = `${expectation.child.canonicalPath}.previous`;
Expand Down Expand Up @@ -7970,7 +7976,8 @@ describe('QwenAgent MCP SSE/HTTP support', () => {
'trusted-capability',
);
try {
await agent.newSession({ cwd: '/tmp', mcpServers: [] });
const workspaceCwd = path.resolve('/tmp');
await agent.newSession({ cwd: workspaceCwd, mcpServers: [] });
const input = {
title: 'Docs',
locator: { type: 'workspace_file', workspacePath: 'README.md' },
Expand All @@ -7979,7 +7986,9 @@ describe('QwenAgent MCP SSE/HTTP support', () => {
sessionId,
input,
});
innerConfig.getTargetDir.mockReturnValue('/tmp/subdir');
innerConfig.getTargetDir.mockReturnValue(
path.join(workspaceCwd, 'subdir'),
);
const after = await agent.extMethod('qwen/session/sources/upsert', {
sessionId,
input,
Expand All @@ -7989,7 +7998,7 @@ describe('QwenAgent MCP SSE/HTTP support', () => {
change: 'unchanged',
source: before['source'],
});
expect(after['source']).toMatchObject({ workspaceCwd: '/tmp' });
expect(after['source']).toMatchObject({ workspaceCwd });
} finally {
mockConnectionState.resolve();
await agentPromise;
Expand Down
6 changes: 5 additions & 1 deletion packages/cli/src/commands/review/cleanup.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,11 @@ describe('runCleanup', () => {
},
);

it('reads process.cwd() ONCE per run — the entry capture — and never downstream (R30-6)', () => {
it('reads process.cwd() ONCE per run — the entry capture — and never downstream (R30-6)', (ctx) => {
if (process.platform === 'win32') {
ctx.skip();
return;
}
// The mid-run half of the deleted-cwd class: the entry guard covers a cwd
// already gone, but `scratchWorktreesOf` used to read the cwd again later
// (`resolve(worktree)` against it, `redirectedAncestor`'s default stop),
Expand Down
8 changes: 7 additions & 1 deletion packages/cli/src/commands/review/findings.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
mkdtempSync,
readFileSync,
rmSync,
statSync,
symlinkSync,
writeFileSync,
} from 'node:fs';
Expand Down Expand Up @@ -1444,7 +1445,7 @@ describe('findings (command boundary)', () => {
).toThrow(/--to-anchors must not be a symlink/);
});

it('refuses a --to-anchors hardlinked to a sibling file', () => {
it('refuses a --to-anchors hardlinked to a sibling file', (ctx) => {
// realpathSync never resolves hard links: two names of one inode compare
// as different path strings, so a string-identity guard admits them and
// both writes hit the same file — the exact destruction the guard exists
Expand All @@ -1455,6 +1456,11 @@ describe('findings (command boundary)', () => {
writeFileSync(out, JSON.stringify([base])); // a previous run's artifact
const anchors = join(dir, 'anchors.json');
linkSync(out, anchors);
const inode = statSync(out).ino;
if (!Number.isSafeInteger(inode) || inode <= 0) {
ctx.skip();
return;
}
expect(() =>
(findingsCommand.handler as (a: unknown) => void)({
input,
Expand Down
12 changes: 10 additions & 2 deletions packages/cli/src/commands/review/lib/git.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,11 @@ describe('releaseWorktree', () => {
},
);

it('degrades through the result — never throws — when the cwd is deleted mid-release', () => {
it('degrades through the result — never throws — when the cwd is deleted mid-release', (ctx) => {
if (process.platform === 'win32') {
ctx.skip();
return;
}
// The never-throws contract starts before the first git call: `resolve`
// of the RELATIVE path production callers pass reads the cwd, and so does
// `redirectedAncestor`'s default `stopAt = process.cwd()` — both threw
Expand Down Expand Up @@ -629,7 +633,11 @@ describe('gitProbe — the exit status the anchor taxonomy rests on', () => {
}
});

it('answers "could not be run" when the process cwd no longer exists', () => {
it('answers "could not be run" when the process cwd no longer exists', (ctx) => {
if (process.platform === 'win32') {
ctx.skip();
return;
}
// The launch-dir pre-check reads `process.cwd()`, which throws ENOENT once
// the directory is gone. Left outside the try it took the whole probe with
// it — and `releaseWorktree`'s documented never-throws contract, cleanup's
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/commands/review/lib/same-file.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@ describe('isSameFile', () => {
// Hard-link identity rides dev/ino; on volumes that expose no inode
// numbers (ino 0) the comparison degrades to canonical spellings by
// design and cannot see through a hard link.
if (Number(statSync(original).ino) === 0) {
const inode = statSync(original).ino;
if (!Number.isSafeInteger(inode) || inode <= 0) {
ctx.skip();
return;
}
Expand Down
Loading
Loading