Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
32 changes: 28 additions & 4 deletions src/languageModelTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,26 @@ const CONSTANTS = {
MAX_FILE_SEARCH_DEPTH: 10
};

const SEARCH_SKIPPED_DIRECTORIES = new Set([
'.git',
'.gradle',
'.idea',
'.vscode',
'bin',
'build',
'classes',
'dist',
'generated',
'generated-sources',
'node_modules',
'out',
'target',
]);

function shouldSkipSearchDirectory(name: string): boolean {
return SEARCH_SKIPPED_DIRECTORIES.has(name);
}

const LAUNCH_FAILURE_GUIDANCE = '\n\nDo not automatically retry debug_java_application or start the program again '
+ 'through a terminal command. Report the result and diagnose the cause first. '
+ 'After a timeout, you may check get_debug_session_info once and inspect existing terminal output; '
Expand Down Expand Up @@ -923,14 +943,14 @@ function findJavaFile(dir: string, className: string, depth: number = 0): string
const files = fs.readdirSync(dir);

for (const file of files) {
if (shouldSkipSearchDirectory(file)) {
continue;
}

const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);

if (stat.isDirectory()) {
// Skip common non-source directories
if (file === 'node_modules' || file === '.git' || file === 'target' || file === 'build') {
continue;
}
const found = findJavaFile(filePath, className, depth + 1);
if (found) {
return found;
Expand Down Expand Up @@ -972,6 +992,10 @@ function hasClassFiles(dir: string, depth: number = 0): boolean {
try {
const files = fs.readdirSync(dir);
for (const file of files) {
if (shouldSkipSearchDirectory(file)) {
continue;
}

const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);

Expand Down
28 changes: 28 additions & 0 deletions test/languageModelToolLaunchPolicy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import * as assert from "assert";
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import * as vscode from "vscode";
import * as telemetry from "vscode-extension-telemetry-wrapper";
Expand Down Expand Up @@ -124,6 +125,33 @@ suite("Language Model Tool launch retry policy", () => {
assert.strictEqual(text.includes("Call debug_java_application again"), false);
}

test("ignores generated build directories when resolving simple class names", async () => {
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), "java-debug-class-detection-"));
const sourceFile = path.join(tempRoot, "src", "main", "java", "com", "example", "App.java");
const generatedFile = path.join(tempRoot, "build", "generated", "App.java");

fs.mkdirSync(path.dirname(sourceFile), { recursive: true });
fs.mkdirSync(path.dirname(generatedFile), { recursive: true });

fs.writeFileSync(sourceFile, "package com.example;\npublic class App {}\n");
fs.writeFileSync(generatedFile, "public class App {}\n");

try {
const text = await invoke({
target: "App",
workspacePath: tempRoot,
skipBuild: true,
classpath: tempRoot,
});

assert.ok(text.includes("Debug session started") || text.includes("Startup is unconfirmed, not necessarily failed"));
assert.ok(!text.includes("Could not auto-detect package name"));
assert.strictEqual(commandsSent, 1);
} finally {
fs.rmSync(tempRoot, { recursive: true, force: true });
}
});

for (const waitForSession of [false, true]) {
test(`reports unconfirmed startup without relaunching (waitForSession=${waitForSession})`, async () => {
const text = await invoke({
Expand Down