Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/agentHost/test/node/protocol/sessionDiffs.integrationTest.ts
13405 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import assert from 'assert';
7
import * as cp from 'child_process';
8
import { mkdtempSync, rmSync, writeFileSync } from 'fs';
9
import { tmpdir } from 'os';
10
import { join } from '../../../../../base/common/path.js';
11
import { URI } from '../../../../../base/common/uri.js';
12
import { SubscribeResult } from '../../../common/state/protocol/commands.js';
13
import type { SessionAddedNotification, SessionDiffsChangedAction } from '../../../common/state/sessionActions.js';
14
import { PROTOCOL_VERSION } from '../../../common/state/sessionCapabilities.js';
15
import type { INotificationBroadcastParams } from '../../../common/state/sessionProtocol.js';
16
import {
17
dispatchTurnStarted,
18
getActionEnvelope,
19
IServerHandle,
20
isActionNotification,
21
nextSessionUri,
22
startServer,
23
TestProtocolClient,
24
} from './testHelpers.js';
25
26
const hasGit = (() => {
27
try { cp.execFileSync('git', ['--version'], { stdio: 'ignore' }); return true; } catch { return false; }
28
})();
29
30
(hasGit ? suite : suite.skip)('Protocol WebSocket — Git-driven session diffs', function () {
31
32
let server: IServerHandle;
33
let client: TestProtocolClient;
34
let tmpRoot: string;
35
36
suiteSetup(async function () {
37
this.timeout(15_000);
38
server = await startServer();
39
});
40
41
suiteTeardown(function () {
42
server.process.kill();
43
});
44
45
setup(async function () {
46
this.timeout(10_000);
47
// Initialize a tmp git repo as the session's working directory.
48
tmpRoot = mkdtempSync(join(tmpdir(), 'agent-host-proto-diff-'));
49
const env = { ...process.env, GIT_AUTHOR_NAME: 't', GIT_AUTHOR_EMAIL: 't@t', GIT_COMMITTER_NAME: 't', GIT_COMMITTER_EMAIL: 't@t' };
50
const run = (...args: string[]) => cp.execFileSync('git', args, { cwd: tmpRoot, env, stdio: 'pipe' });
51
run('init', '-q', '-b', 'main');
52
writeFileSync(join(tmpRoot, 'seed.txt'), 'seed\n');
53
run('add', '.');
54
run('commit', '-q', '-m', 'init');
55
56
client = new TestProtocolClient(server.port);
57
await client.connect();
58
});
59
60
teardown(function () {
61
client.close();
62
if (tmpRoot) {
63
rmSync(tmpRoot, { recursive: true, force: true });
64
}
65
});
66
67
test('terminal-driven file edit (no ToolResultFileEditContent) is reported via summary.diffs', async function () {
68
this.timeout(15_000);
69
70
// Create a session whose working directory is the tmp git repo.
71
await client.call('initialize', { protocolVersion: PROTOCOL_VERSION, clientId: 'test-git-diffs' });
72
73
const workingDirectory = URI.file(tmpRoot).toString();
74
await client.call('createSession', { session: nextSessionUri(), provider: 'mock', workingDirectory });
75
76
const addedNotif = await client.waitForNotification(n =>
77
n.method === 'notification' && (n.params as INotificationBroadcastParams).notification.type === 'notify/sessionAdded'
78
);
79
const sessionUri = ((addedNotif.params as INotificationBroadcastParams).notification as SessionAddedNotification).summary.resource;
80
81
await client.call<SubscribeResult>('subscribe', { resource: sessionUri });
82
client.clearReceived();
83
84
// Fire a turn that runs the `terminal-edit:<path>` mock prompt. The mock
85
// agent writes the file via fs.writeFile (no ToolResultFileEditContent),
86
// so the diff must come from the git-driven path.
87
const editedFile = join(tmpRoot, 'from-terminal.txt');
88
dispatchTurnStarted(client, sessionUri, 'turn-1', `terminal-edit:${editedFile}`, 1);
89
90
// Wait for the diff broadcast that comes after the idle event.
91
const diffNotif = await client.waitForNotification(n => isActionNotification(n, 'session/diffsChanged'), 10_000);
92
const action = getActionEnvelope(diffNotif).action as SessionDiffsChangedAction;
93
94
// On macOS, git's `--show-toplevel` resolves symlinks (/var → /private/var)
95
// so the diff URI may differ in prefix; match by basename instead.
96
const matching = action.diffs.find(d => {
97
const u = d.after?.uri ?? d.before?.uri;
98
return typeof u === 'string' && u.endsWith('/from-terminal.txt');
99
});
100
assert.ok(matching, `expected diff for from-terminal.txt; got ${JSON.stringify(action.diffs.map(d => d.after?.uri ?? d.before?.uri))}`);
101
assert.ok(matching!.after, 'expected after-side for newly added file');
102
assert.ok(!matching!.before, 'newly added file should have no before-side');
103
});
104
});
105
106