Skip to content
Merged
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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ debugjava -cp bin com.example.Main arg1 arg2

The debugger will automatically attach. See [No-Config Debug Documentation](bundled/scripts/noConfigScripts/README.md) for more details.

No-Config Debug is enabled by default. To disable the terminal integration and the AI `debug_java_application` tool, set `"java.debug.settings.enableNoConfigDebug": false`, reload VS Code, and recreate existing terminals. Standard Java launch/attach debugging, including F5 and Run/Debug CodeLens, remains available.

## AI-Assisted Debugging

When using GitHub Copilot Chat, you can now ask AI to help you debug Java applications! The extension provides a Language Model Tool that enables natural language debugging:
Expand Down Expand Up @@ -164,6 +166,7 @@ See [Language Model Tool Documentation](bundled/agents/README.md) for more detai
- `auto` - Automatically apply the changes after compilation. This only works when `'java.autobuild.enabled'` is on.
- `never` - Never apply the changes.
- `java.debug.settings.enableRunDebugCodeLens`: enable the code lens provider for the run and debug buttons over main entry points, defaults to `true`.
- `java.debug.settings.enableNoConfigDebug`: enable automatic attachment through `debugjava` and the AI `debug_java_application` tool, defaults to `true`. Can be set at user or workspace level. Changes require reloading VS Code and recreating existing terminals; standard Java launch/attach debugging is unaffected.
- `java.debug.settings.forceBuildBeforeLaunch`: force building the workspace before launching java program, defaults to `true`.
- `java.debug.settings.onBuildFailureProceed`: Force to proceed when build fails, defaults to false.
- `java.debug.settings.console`: The specified console to launch Java program, defaults to `integratedTerminal`. If you want to customize the console for a specific debug session, please modify the 'console' config in launch.json.
Expand Down
2 changes: 2 additions & 0 deletions bundled/agents/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ Make sure the Java project is properly loaded. Check that:

### Debug Session Won't Start

The `debug_java_application` tool requires `java.debug.settings.enableNoConfigDebug` (enabled by default). If you disable this setting, reload VS Code and recreate existing terminals. The launch tool then returns an explanatory message without running `debugjava`; tools that inspect or control existing debug sessions remain available.

Ensure:
- Your project compiles successfully
- No other debug session is running
Expand Down
22 changes: 22 additions & 0 deletions bundled/scripts/noConfigScripts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,20 @@ When you open a terminal in VS Code with this extension installed, the following

Note: `JAVA_TOOL_OPTIONS` is NOT set globally to avoid affecting other Java tools (javac, maven, gradle). Instead, it's set only when you run the `debugjava` command.

## Disabling No-Config Debug

No-Config Debug is enabled by default. To opt out for all workspaces or just the current workspace, add this to the corresponding VS Code settings:

```json
"java.debug.settings.enableNoConfigDebug": false
```

Reload VS Code and recreate existing terminals after changing this setting. The value is read once during extension activation; there is no live enable/disable switch. Existing terminal processes retain their old environment until they are recreated.

When disabled, the extension skips endpoint storage, file watching, Java executable detection, and wrapper permission setup, and removes this feature's cached terminal environment contributions. It does not clear the user's PATH or delete endpoint files as part of opting out. Standard Java launch/attach debugging, F5, and Run/Debug CodeLens are unaffected.

The AI `debug_java_application` tool requires this integration. When disabled, it returns instructions to enable the setting instead of building, launching a terminal, or stopping an existing debug session. Other AI tools for existing debug sessions remain available.

## Usage

### Basic Usage
Expand Down Expand Up @@ -72,8 +86,16 @@ debugjava -jar myapp.jar --spring.profiles.active=dev
6. The port is written to a communication file
7. VS Code's file watcher detects the file and automatically starts an attach debug session

The communication file is stored in the extension's workspace-specific VS Code storage directory, not its installation directory. It contains only the local debug host and port, is deleted after a successful attach, and any stale file is removed before the next registration. Its path remains stable across window reloads.

## Troubleshooting

### No-Config Debug Could Not Be Initialized

If the workspace storage directory or its file watcher cannot be initialized, the extension displays a warning and leaves standard Java launch/attach debugging available. No-Config Debug requires an open workspace and writable VS Code workspace storage.

After upgrading from a version that stored the communication file in the extension directory, recreate existing terminals to pick up the new endpoint path.

### Port Already in Use

If you see "Address already in use", another Java debug session is running. Terminate it first.
Expand Down
6 changes: 6 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,12 @@
"description": "%java.debugger.configuration.enableRunDebugCodeLens.description%",
"default": true
},
"java.debug.settings.enableNoConfigDebug": {
"type": "boolean",
"description": "%java.debugger.configuration.enableNoConfigDebug.description%",
"default": true,
"scope": "window"
},
"java.debug.settings.forceBuildBeforeLaunch": {
"type": "boolean",
"description": "%java.debugger.configuration.forceBuildBeforeLaunch%",
Expand Down
1 change: 1 addition & 0 deletions package.nls.es.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"java.debugger.configuration.numericPrecision.description": "La precisión en el formato de números reales en la vista \"Variables\" o \"Consola de Depuración\".",
"java.debugger.configuration.hotCodeReplace.description": "Recargar las clases de Java modificadas durante la depuración. Asegúrate de que 'java.autobuild.enabled' no esté desactivado.",
"java.debugger.configuration.enableRunDebugCodeLens.description": "Habilitar proveedores de CodeLens para la ejecución y depuración sobre los métodos principales.",
"java.debugger.configuration.enableNoConfigDebug.description": "Habilitar la conexión automática del depurador mediante el comando de terminal debugjava y la herramienta de IA debug_java_application. La depuración estándar de Java no se ve afectada. Los cambios requieren recargar VS Code y volver a crear los terminales existentes.",
"java.debugger.configuration.forceBuildBeforeLaunch": "Forzar la compilación del área de trabajo antes de lanzar el programa Java.",
"java.debugger.configuration.onBuildFailureProceed": "Forzar continuar cuando falla la compilación.",
"java.debugger.configuration.console": "La consola establecida para lanzar el programa Java. Si quieres personalizar la consola para una sesión de depuración específica, por favor modifica la configuración de la 'console' en launch.json.",
Expand Down
1 change: 1 addition & 0 deletions package.nls.it.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
"java.debugger.configuration.showQualifiedNames.description": "Mostra nome completo delle classi nella scheda \"variabili\".",
"java.debugger.configuration.maxStringLength.description": "Lunghezza massima delle stringhe visualizzate nella scheda \"Variabili\" o \"Console di Debug\", stringhe più lunghe di questo numero verranno tagliate, se 0 nessun taglio viene eseguito.",
"java.debugger.configuration.enableRunDebugCodeLens.description": "Abilitare i provider di lenti di codice run e debug sui metodi principali.",
"java.debugger.configuration.enableNoConfigDebug.description": "Abilita la connessione automatica del debugger tramite il comando da terminale debugjava e lo strumento IA debug_java_application. Il debug Java standard non viene modificato. Le modifiche richiedono di ricaricare VS Code e ricreare i terminali esistenti.",
"java.debugger.configuration.suspendAllThreads.description": "Sospende tutti i thread quando si raggiunge un punto di interruzione o ci si ferma per un'eccezione. Ha effetto solo nelle nuove sessioni di debug; le modifiche durante una sessione in esecuzione non si applicano."
}
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"java.debugger.configuration.numericPrecision.description": "The precision when formatting doubles in \"Variables\" or \"Debug Console\" viewlet.",
"java.debugger.configuration.hotCodeReplace.description": "Reload the changed Java classes during debugging.",
"java.debugger.configuration.enableRunDebugCodeLens.description": "Enable the run and debug code lens providers over main methods.",
"java.debugger.configuration.enableNoConfigDebug.description": "Enable automatic attachment through the debugjava terminal command and the AI debug_java_application tool. Standard Java launch/attach debugging is unaffected. Changes require reloading VS Code and recreating existing terminals.",
"java.debugger.configuration.forceBuildBeforeLaunch": "Force building the workspace before launching java program.",
"java.debugger.configuration.onBuildFailureProceed": "Force to proceed when build fails",
"java.debugger.configuration.console": "The specified console to launch Java program. If you want to customize the console for a specific debug session, please modify the 'console' config in launch.json.",
Expand Down
1 change: 1 addition & 0 deletions package.nls.zh-cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"java.debugger.configuration.maxStringLength.description": "设定“变量”或“调试控制台”视图中显示的字符串最大长度,长度超过部分将被剪掉。如果值为0,则不执行修剪。",
"java.debugger.configuration.hotCodeReplace.description": "在调试期间重新加载已更改的Java类。",
"java.debugger.configuration.enableRunDebugCodeLens.description": "在main方法上启用CodeLens标记。",
"java.debugger.configuration.enableNoConfigDebug.description": "启用通过终端 debugjava 命令和 AI debug_java_application 工具自动附加调试器的功能。不影响标准 Java 启动和附加调试。修改后需要重新加载 VS Code 并重新创建现有终端。",
"java.debugger.configuration.forceBuildBeforeLaunch": "在启动java程序之前强制编译整个工作空间。",
"java.debugger.configuration.console": "指定的控制台用于启动Java程序。如果要为特定的调试会话自定义控制台,请修改launch.json中的“console”配置。",
"java.debugger.configuration.exceptionBreakpoint.exceptionTypes": "指定要中断的一组异常类型,例如 java.lang.NullPointerException。可以为捕获的异常、未捕获的异常或两者都选择一个特定的异常类型及其子类。",
Expand Down
1 change: 1 addition & 0 deletions package.nls.zh-tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
"java.debugger.configuration.maxStringLength.description": "設定「變數」或「偵錯主控台」視圖中顯示的字元串最大長度,長度超過部分將被剪掉。如果值為0,則不執行修剪。",
"java.debugger.configuration.hotCodeReplace.description": "在偵錯期間重新載入已更改的 Java 類別。確保未停用 'java.autobuild.enabled'。",
"java.debugger.configuration.enableRunDebugCodeLens.description": "在 main 方法上啟用 CodeLens 標記。",
"java.debugger.configuration.enableNoConfigDebug.description": "啟用透過終端機 debugjava 命令和 AI debug_java_application 工具自動附加偵錯器的功能。不影響標準 Java 啟動和附加偵錯。修改後需要重新載入 VS Code 並重新建立現有終端機。",
"java.debugger.configuration.forceBuildBeforeLaunch": "在啟動 Java 程式之前強制編譯整個工作空間。",
"java.debugger.configuration.console": "指定用於啟動 Java 程式的主控台。如果要為特定的偵錯會話自訂義主控台,請修改 launch.json 中的「console」設定。",
"java.debugger.configuration.exceptionBreakpoint.skipClasses": "當發生異常時,跳過指定的類別。你可以使用內建變數,如 '$JDK' 和 '$Libraries' 來跳過一組類別,或者添加一個特定的類別名表達式,如 java.*,*.Foo。",
Expand Down
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const JAVA_LANGID: string = "java";
export const TELEMETRY_EVENT = "telemetry";
export const HCR_EVENT = "hotcodereplace";
export const USER_NOTIFICATION_EVENT = "usernotification";
export const ENABLE_NO_CONFIG_DEBUG = "java.debug.settings.enableNoConfigDebug";

export enum ClasspathVariable {
Auto = "$Auto",
Expand Down
19 changes: 12 additions & 7 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { dispose as disposeTelemetryWrapper, initializeFromJsonFile, instrumentO
instrumentOperationAsVsCodeCommand, sendInfo, setUserError } from "vscode-extension-telemetry-wrapper";
import * as commands from "./commands";
import { JavaDebugConfigurationProvider, lastUsedLaunchConfig } from "./configurationProvider";
import { HCR_EVENT, JAVA_LANGID, TELEMETRY_EVENT, USER_NOTIFICATION_EVENT } from "./constants";
import { ENABLE_NO_CONFIG_DEBUG, HCR_EVENT, JAVA_LANGID, TELEMETRY_EVENT, USER_NOTIFICATION_EVENT } from "./constants";
import { NotificationBar } from "./customWidget";
import { initializeCodeLensProvider, startDebugging } from "./debugCodeLensProvider";
import { initExpService } from "./experimentationService";
Expand Down Expand Up @@ -37,15 +37,20 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
await initializeFromJsonFile(context.asAbsolutePath("./package.json"));
await initExpService(context);

// Register No-Config Debug functionality
// Capture once so terminal integration and the AI launch tool both require a reload to change.
const noConfigDebugEnabled = vscode.workspace.getConfiguration().get<boolean>(ENABLE_NO_CONFIG_DEBUG, true);
const noConfigDisposable = await registerNoConfigDebug(
context.environmentVariableCollection,
context.extensionPath
context.extensionPath,
context.storageUri,
noConfigDebugEnabled,
);
context.subscriptions.push(noConfigDisposable);
if (noConfigDisposable) {
context.subscriptions.push(noConfigDisposable);
}

// Register Language Model Tools after Java Language Server is ready
registerLanguageModelToolsWhenReady(context);
registerLanguageModelToolsWhenReady(context, noConfigDebugEnabled);

return instrumentOperation("activation", initializeExtension)(context);
}
Expand Down Expand Up @@ -112,7 +117,7 @@ const delay = promisify(setTimeout);
* The debug tools depend on JDT.LS for compilation, classpath resolution,
* and executing debug server commands.
*/
async function registerLanguageModelToolsWhenReady(context: vscode.ExtensionContext): Promise<void> {
async function registerLanguageModelToolsWhenReady(context: vscode.ExtensionContext, noConfigDebugEnabled: boolean): Promise<void> {
// Check if Language Model API is available
if (!vscode.lm || typeof vscode.lm.registerTool !== 'function') {
return;
Expand All @@ -124,7 +129,7 @@ async function registerLanguageModelToolsWhenReady(context: vscode.ExtensionCont
}

// Register Language Model Tools for AI-assisted debugging
registerLanguageModelTool(context);
registerLanguageModelTool(context, noConfigDebugEnabled);
const debugToolsDisposables = registerDebugSessionTools(context);
context.subscriptions.push(...debugToolsDisposables);

Expand Down
16 changes: 15 additions & 1 deletion src/languageModelTool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
import { ENABLE_NO_CONFIG_DEBUG } from "./constants";
import {
beginDebugSessionInvocation,
classifyBreakpoint,
Expand Down Expand Up @@ -112,7 +113,10 @@ interface LanguageModelTool<T = any> {
* Registers the Language Model Tool for debugging Java applications.
* This allows AI assistants to help users debug Java code by invoking the debugjava command.
*/
export function registerLanguageModelTool(context: vscode.ExtensionContext): vscode.Disposable | undefined {
export function registerLanguageModelTool(
context: Pick<vscode.ExtensionContext, "subscriptions">,
noConfigDebugEnabled: boolean = true,
): vscode.Disposable | undefined {
// Check if the Language Model API is available
const lmApi = (vscode as any).lm;
if (!lmApi || typeof lmApi.registerTool !== 'function') {
Expand All @@ -122,6 +126,16 @@ export function registerLanguageModelTool(context: vscode.ExtensionContext): vsc

const tool: LanguageModelTool<DebugJavaApplicationInput> = {
async invoke(options: { input: DebugJavaApplicationInput }, token: vscode.CancellationToken): Promise<any> {
if (!noConfigDebugEnabled) {
return new vscode.LanguageModelToolResult([
new vscode.LanguageModelTextPart(
`Java No-Config Debug is disabled by ${ENABLE_NO_CONFIG_DEBUG}. `
+ "To use this tool, enable that setting, reload VS Code, and recreate existing terminals. "
+ "Standard Java launch/attach debugging remains available.",
),
]);
}

const startedAt = Date.now();
const targetType = classifyTarget(options.input.target);
const attempt = nextAttempt(TOOL_NAMES.DEBUG_JAVA_APPLICATION);
Expand Down
Loading