Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
6e5b61c
Implementation for debug-isolated flag and streaming func CLI output
nturinski Oct 24, 2025
e9c255d
Update src/utils/stream.ts
nturinski Oct 24, 2025
067e04d
Address copilot feedback
nturinski Oct 24, 2025
d046ac9
Merge branch 'nat/fileBasedPickProcess' of https://github.com/microso…
nturinski Oct 24, 2025
606f130
Refactor to set up stream in funcHostTasks
nturinski Oct 24, 2025
44e8382
Delete test snippet
nturinski Oct 24, 2025
9726543
Add headerto stream file
nturinski Oct 24, 2025
d4f3b56
Remove the done call
nturinski Oct 24, 2025
c7618c7
Update src/debug/FuncTaskProvider.ts
nturinski Oct 24, 2025
b8dd0bf
WIP waiting for VSCode insiders fix
nturinski Oct 29, 2025
d673a73
Use onDidStartTerminalShellExecution API instead of proposed
nturinski Oct 30, 2025
2dfd68d
Remove proposed files
nturinski Oct 30, 2025
5035c9a
Merge branch 'nat/fileBasedPickProcess' of https://github.com/microso…
nturinski Oct 30, 2025
8a751c8
Add note
nturinski Oct 30, 2025
e5adbb9
Remove unused async moniker
nturinski Oct 30, 2025
6454ca8
Whoops, wrong async
nturinski Oct 30, 2025
544cd45
Little bit of cleaning
nturinski Oct 30, 2025
52780f7
Remove unusued function helper
nturinski Oct 30, 2025
3dc0fc5
Last commit, I swears it
nturinski Oct 30, 2025
e36604c
Move event handler, added note
nturinski Nov 3, 2025
5bfbb42
Rename function due to PR feedback
nturinski Nov 3, 2025
a9c1f08
Merge branch 'main' of https://github.com/microsoft/vscode-azurefunct…
nturinski Nov 19, 2025
e1ee414
Merge branch 'nat/fileBasedPickProcess' of https://github.com/microso…
nturinski Nov 21, 2025
bc365fa
Push up WIP
nturinski Nov 21, 2025
5d5b38f
Push up WIP
nturinski Nov 21, 2025
192b107
Merge branch 'nat/fileBasedPickProcess' of https://github.com/microso…
Nov 21, 2025
577a57d
WIP for postDebug copilot analysis
Nov 25, 2025
e8b519d
Add debug command activity
Nov 25, 2025
e0e5c03
WIP for copilot postdebug
Dec 1, 2025
8786288
Merge branch 'main' of https://github.com/microsoft/vscode-azurefunct…
Jan 7, 2026
adc4bc4
Merge with main
Jan 7, 2026
df16af2
Fix linter
Jan 7, 2026
8707910
MVP for func debugger view
Jan 8, 2026
6dff88e
Setting for debugger view, show first error
Jan 14, 2026
412b751
Refactoring/cleaning up
Jan 14, 2026
8fae446
Remove the stop action and implement clear errors
Jan 14, 2026
9e897af
Clean up some code
Jan 14, 2026
d30fda1
Remove the terminal dispose since it is not reinstantiated later
Jan 14, 2026
759fb6a
Update src/funcCoreTools/funcHostTask.ts
nturinski Jan 15, 2026
8ac0664
Update src/funcCoreTools/funcHostErrorUtils.ts
nturinski Jan 15, 2026
4213222
Add JSDoc documentation for IStartFuncProcessResult stream property (…
Copilot Jan 15, 2026
db407f4
Prevent infinite stream iteration when func host task terminates (#4887)
Copilot Jan 15, 2026
e8fea65
Initial plan
Copilot Jan 15, 2026
d076846
Fix race condition in terminal event handling by filtering func host …
Copilot Jan 15, 2026
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
2 changes: 2 additions & 0 deletions extension.bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ export * from './src/utils/durableUtils';
export { activateInternal, deactivateInternal } from './src/extension';
export * from './src/extensionVariables';
export * from './src/funcConfig/function';
export { extractFuncHostErrorContextForErrorMessage, isFuncHostErrorLog } from './src/funcCoreTools/funcHostErrorUtils';
export * from './src/funcCoreTools/hasMinFuncCliVersion';
export * from './src/FuncVersion';
export * from './src/templates/CentralTemplateProvider';
export * from './src/templates/IFunctionTemplate';
export * from './src/templates/script/getScriptResourcesLanguage';
export * from './src/templates/TemplateProviderBase';
export * from './src/tree/AzureAccountTreeItemWithProjects';
export { stripAnsiControlCharacters } from './src/utils/ansiUtils';
export * from './src/utils/cpUtils';
export * from './src/utils/delay';
export * from './src/utils/envUtils';
Expand Down
92 changes: 92 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@
]
}
},
"views": {
"debug": [
{
"id": "azureFunctions.funcHostDebugView",
"name": "%azureFunctions.funcHostDebugView.title%",
"when": "!virtualWorkspace && azureFunctions.funcHostDebugVisible",
"icon": "resources/azure-functions.svg"
}
]
},
"commands": [
{
"command": "azureFunctions.addBinding",
Expand Down Expand Up @@ -467,6 +477,36 @@
"command": "azureFunctions.getMcpHostKey",
"title": "%azureFunctions.getMcpHostKey%",
"category": "Azure Functions"
},
{
"command": "azureFunctions.funcHostDebug.refresh",
"title": "%azureFunctions.funcHostDebug.refresh%",
"category": "Azure Functions",
"icon": "$(refresh)"
},
{
"command": "azureFunctions.funcHostDebug.clearErrors",
"title": "%azureFunctions.funcHostDebug.clearErrors%",
"category": "Azure Functions",
"icon": "$(clear-all)"
},
{
"command": "azureFunctions.funcHostDebug.showRecentLogs",
"title": "%azureFunctions.funcHostDebug.showRecentLogs%",
"category": "Azure Functions",
"icon": "$(output)"
},
{
"command": "azureFunctions.funcHostDebug.copyRecentLogs",
"title": "%azureFunctions.funcHostDebug.copyRecentLogs%",
"category": "Azure Functions",
"icon": "$(copy)"
},
{
"command": "azureFunctions.funcHostDebug.askCopilot",
"title": "%azureFunctions.funcHostDebug.askCopilot%",
"category": "Azure Functions",
"icon": "$(sparkle)"
}
],
"submenus": [
Expand Down Expand Up @@ -503,9 +543,34 @@
"submenu": "azureFunctions.submenus.workspaceActions",
"when": "view == azureWorkspace",
"group": "navigation@1"
},
{
"command": "azureFunctions.funcHostDebug.refresh",
"when": "view == azureFunctions.funcHostDebugView",
"group": "navigation@1"
},
{
"command": "azureFunctions.funcHostDebug.clearErrors",
"when": "view == azureFunctions.funcHostDebugView",
"group": "navigation@1"
}
],
"view/item/context": [
{
"command": "azureFunctions.funcHostDebug.showRecentLogs",
"when": "view == azureFunctions.funcHostDebugView && viewItem == azFunc.funcHostDebug.hostTask",
"group": "inline"
},
{
"command": "azureFunctions.funcHostDebug.copyRecentLogs",
"when": "view == azureFunctions.funcHostDebugView && viewItem == azFunc.funcHostDebug.hostTask",
"group": "inline"
},
{
"command": "azureFunctions.funcHostDebug.askCopilot",
"when": "view == azureFunctions.funcHostDebugView && viewItem == azFunc.funcHostDebug.hostError",
"group": "1@1"
},
{
"command": "azureFunctions.createFunction",
"when": "view == azureWorkspace && viewItem =~ /azFuncLocalProject/i",
Expand Down Expand Up @@ -947,6 +1012,22 @@
{
"command": "azureFunctions.unassignManagedIdentity",
"when": "never"
},
{
"command": "azureFunctions.funcHostDebug.refresh",
"when": "never"
},
{
"command": "azureFunctions.funcHostDebug.showRecentLogs",
"when": "never"
},
{
"command": "azureFunctions.funcHostDebug.copyRecentLogs",
"when": "never"
},
{
"command": "azureFunctions.funcHostDebug.askCopilot",
"when": "never"
}
],
"editor/context": [
Expand Down Expand Up @@ -990,6 +1071,12 @@
"properties": {
"command": {
"type": "string"
},
"args": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
Expand Down Expand Up @@ -1186,6 +1273,11 @@
"description": "%azureFunctions.enableJavaRemoteDebugging%",
"default": false
},
"azureFunctions.alwaysShowFuncHostDebugView": {
"type": "boolean",
"description": "%azureFunctions.alwaysShowFuncHostDebugView%",
"default": false
},
"azureFunctions.showProjectWarning": {
"type": "boolean",
"description": "%azureFunctions.showProjectWarning%",
Expand Down
9 changes: 8 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"azureFunctions.disconnectRepo": "Disconnect from Repo...",
"azureFunctions.enableFunction": "Enable Function",
"azureFunctions.enableJavaRemoteDebugging": "Enable remote debugging for Java Functions Apps running on Windows. (experimental)",
"azureFunctions.alwaysShowFuncHostDebugView": "Always show the Function Host Debug view in Run and Debug, even when no host task is running.",
"azureFunctions.enableOutputTimestamps": "Prepends each line displayed in the output channel with a timestamp.",
"azureFunctions.enableRemoteDebugging": "Enable remote debugging for Node.js Function Apps running on Linux App Service plans. Consumption plans are not supported. (experimental)",
"azureFunctions.enableSystemIdentity": "Enable System Assigned Identity",
Expand Down Expand Up @@ -144,5 +145,11 @@
"azureFunctions.mcpProjectType": "The type of MCP integration the project uses.",
"azureFunctions.mcpProjectType.NoMcpServer": "Runs the standard Azure Functions runtime with no MCP integration.",
"azureFunctions.mcpProjectType.McpExtensionServer": "Runs the Functions host with an embedded MCP server provided by the Azure Functions MCP extension.",
"azureFunctions.mcpProjectType.SelfHostedMcpServer": "Runs the Functions host in custom-handler mode, forwarding requests to a self-hosted MCP server process."
"azureFunctions.mcpProjectType.SelfHostedMcpServer": "Runs the Functions host in custom-handler mode, forwarding requests to a self-hosted MCP server process.",
"azureFunctions.funcHostDebugView.title": "Function Host Debug",
"azureFunctions.funcHostDebug.refresh": "Refresh",
"azureFunctions.funcHostDebug.clearErrors": "Clear Function Host Errors",
"azureFunctions.funcHostDebug.showRecentLogs": "Show Recent Host Logs",
"azureFunctions.funcHostDebug.copyRecentLogs": "Copy Recent Host Logs",
"azureFunctions.funcHostDebug.askCopilot": "Ask Copilot"
}
1 change: 0 additions & 1 deletion src/commands/CommandAttributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,4 @@ export class CommandAttributes {
"Task hub creation fails — if an existing parent DTS resource was selected, check that the scheduler is not stuck in a provisioning state.",
],
};

}
38 changes: 35 additions & 3 deletions src/commands/pickFuncProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,44 @@ import { getWorkspaceSetting } from '../vsCodeConfig/settings';
const funcTaskReadyEmitter = new vscode.EventEmitter<vscode.WorkspaceFolder>();
export const onDotnetFuncTaskReady = funcTaskReadyEmitter.event;

/**
* Result returned from starting a function host process via the API.
*/
export interface IStartFuncProcessResult {
/**
* The process ID of the started function host.
*/
processId: string;
/**
* Whether the function host was successfully started.
*/
success: boolean;
/**
* Error message if the function host failed to start.
*/
error: string;
/**
* An async iterable stream of terminal output from the function host task.
* This stream provides real-time access to the output of the `func host start` command,
* allowing consumers to monitor host status, capture logs, and detect errors.
*
* The stream will be undefined if the host failed to start or if output streaming is not available.
* Consumers should iterate over the stream asynchronously to read output lines as they are produced.
* The stream remains active for the lifetime of the function host process.
*/
stream: AsyncIterable<string> | undefined;
}

export async function startFuncProcessFromApi(
buildPath: string,
args: string[],
env: { [key: string]: string }
): Promise<{ processId: string; success: boolean; error: string }> {
const result = {
): Promise<IStartFuncProcessResult> {
const result: IStartFuncProcessResult = {
processId: '',
success: false,
error: ''
error: '',
stream: undefined
};

let funcHostStartCmd: string = 'func host start';
Expand Down Expand Up @@ -66,6 +95,7 @@ export async function startFuncProcessFromApi(
const taskInfo = await startFuncTask(context, workspaceFolder, buildPath, funcTask);
result.processId = await pickChildProcess(taskInfo);
result.success = true;
result.stream = taskInfo.stream;
} catch (err) {
const pError = parseError(err);
result.error = pError.message;
Expand Down Expand Up @@ -140,6 +170,7 @@ async function startFuncTask(context: IActionContext, workspaceFolder: vscode.Wo
const funcPort: string = await getFuncPortFromTaskOrProject(context, funcTask, workspaceFolder);
let statusRequestTimeout: number = intervalMs;
const maxTime: number = Date.now() + timeoutInSeconds * 1000;

while (Date.now() < maxTime) {
if (taskError !== undefined) {
throw taskError;
Expand Down Expand Up @@ -171,6 +202,7 @@ async function startFuncTask(context: IActionContext, workspaceFolder: vscode.Wo
}
}
}

}

await delay(intervalMs);
Expand Down
5 changes: 5 additions & 0 deletions src/debug/FuncTaskProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ export class FuncTaskProvider implements TaskProvider {

private async createTask(context: IActionContext, command: string, folder: WorkspaceFolder, projectRoot: string | undefined, language: string | undefined, definition?: TaskDefinition): Promise<Task> {
const funcCliPath = await getFuncCliPath(context, folder);
const args = (definition?.args || []) as string[];
if (args.length > 0) {
command = `${command} ${args.join(' ')}`;
}

let commandLine: string = `${funcCliPath} ${command}`;
if (language === ProjectLanguage.Python) {
commandLine = venvUtils.convertToVenvCommand(commandLine, folder.uri.fsPath);
Expand Down
Loading