Repository: microsoft/typespec
Pull request #6783: [Typespec-vscode] Install packages for unrecognized import
Author: login: mzhongl524
Labels: name: ide
description: Issues for VS, VSCode, Monaco, etc.
Created: 2025-03-31T08:12:11Z | Merged: 2025-05-29T02:10:51Z

Fix: https://github.com/microsoft/typespec/issues/5633

IDE could help to scaffold/update `package.json` and install the packages for unrecognized import


Diff:
diff --git a/.chronus/changes/install-packages-for-unrecognized-import-2025-4-8-7-32-21.md b/.chronus/changes/install-packages-for-unrecognized-import-2025-4-8-7-32-21.md
new file mode 100644
index 00000000000..e491f579d10
--- /dev/null
+++ b/.chronus/changes/install-packages-for-unrecognized-import-2025-4-8-7-32-21.md
@@ -0,0 +1,9 @@
+---
+# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
+changeKind: feature
+packages:
+  - "@typespec/compiler"
+  - typespec-vscode
+---
+
+Install packages for unrecognized import via npm command
diff --git a/packages/compiler/src/server/serverlib.ts b/packages/compiler/src/server/serverlib.ts
index 1305af6b8b3..e6c65a51bf8 100644
--- a/packages/compiler/src/server/serverlib.ts
+++ b/packages/compiler/src/server/serverlib.ts
@@ -681,7 +681,10 @@ export function createServer(host: ServerHost): Server {
             diagnostic.severity = DiagnosticSeverity.Hint;
           }
         }
-        diagnostic.data = { id: diagnosticIdCounter++ };
+        diagnostic.data = {
+          id: diagnosticIdCounter++,
+          file: diagDocument.uri,
+        };
         const diagnostics = diagnosticMap.get(diagDocument);
         compilerAssert(
           diagnostics,
diff --git a/packages/typespec-vscode/src/code-action-provider.ts b/packages/typespec-vscode/src/code-action-provider.ts
index 218c765f5d7..b723ac1571f 100644
--- a/packages/typespec-vscode/src/code-action-provider.ts
+++ b/packages/typespec-vscode/src/code-action-provider.ts
@@ -1,5 +1,9 @@
+import { PackageJson } from "@typespec/compiler";
 import vscode from "vscode";
-import { CommandName } from "./types.js";
+import logger from "./log/logger.js";
+import { getDirectoryPath, isPathAbsolute } from "./path-utils.js";
+import { CodeActionCommand } from "./types.js";
+import { searchAndLoadPackageJson } from "./utils.js";
 
 export function createCodeActionProvider() {
   return vscode.languages.registerCodeActionsProvider(
@@ -17,20 +21,21 @@ export function createCodeActionProvider() {
 export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
   public static readonly providedCodeActionKinds = [vscode.CodeActionKind.QuickFix];
 
-  provideCodeActions(
+  public async provideCodeActions(
     _document: vscode.TextDocument,
     _range: vscode.Range | vscode.Selection,
     context: vscode.CodeActionContext,
     _token: vscode.CancellationToken,
-  ): vscode.CodeAction[] {
-    // for each diagnostic entry that has the matching `code`, create a code action command
-    // A CodeAction will only be created if it is a TypeSpec diagnostic and code is an object and has a target attribute
-    // target attribute is the URL to open
-
-    // target is a Uri type, which corresponds to diagnostic.codeDescription.href in compiler
-    // When target is empty, it does not exist in the code object, so the code action will not be created
+  ): Promise<vscode.CodeAction[]> {
     const actions: vscode.CodeAction[] = [];
-    context.diagnostics.forEach((diagnostic) => {
+
+    for (const diagnostic of context.diagnostics) {
+      // for each diagnostic entry that has the matching `code`, create a code action command
+      // A CodeAction will only be created if it is a TypeSpec diagnostic and code is an object and has a target attribute
+      // target attribute is the URL to open
+
+      // target is a Uri type, which corresponds to diagnostic.codeDescription.href in compiler
+      // When target is empty, it does not exist in the code object, so the code action will not be created
       if (
         diagnostic.source === "TypeSpec" &&
         diagnostic.code &&
@@ -46,10 +51,98 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           ),
         );
       }
-    });
+
+      // When the corresponding node dependency package is not installed,
+      // consider generating a quick fix to install via npm command
+      if (
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found" &&
+        "data" in diagnostic &&
+        diagnostic.data &&
+        typeof diagnostic.data === "object" &&
+        "file" in diagnostic.data
+      ) {
+        // The message content is `Couldn't resolve import "@typespec/http"`.
+        // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+        // so a regular expression is used to extract the package name within the double quotes,
+        // if no match is reached, the original string is returned
+        const targetPackage = diagnostic.message.replace(/.*"([^"]+)".*/, "$1");
+        logger.debug(`The target package name is '${targetPackage}'.`);
+
+        const packageFile = diagnostic.data.file as string;
+        const packageFileUri = vscode.Uri.parse(packageFile);
+        const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+          getDirectoryPath(packageFileUri.fsPath),
+        );
+
+        const pkgNameInPkgFile = this.isPackageInPackageJson(targetPackage, packageJson);
+
+        // Whether there is or not the package.json file, the installation command will be created;
+        // when there is no package.json file, the user will be given a clear message prompt.
+        actions.push(
+          this.createInstallPackageCodeAction(
+            diagnostic,
+            targetPackage,
+            pkgNameInPkgFile,
+            packageJsonFolder,
+          ),
+        );
+      }
+    }
+
     return actions;
   }
 
+  /**
+   * Determines whether the given packageName is in the package.json file.
+   *
+   * - targetPackage is not a relative or absolute path
+   * - if it's listed in the package.json's dependencies, devDependencies, or peerDependencies.
+   *
+   * @param targetPackage - The name of the package to check.
+   * @param packageJson - The parsed package.json file content or undefined if not available.
+   * @returns True if packageName is in package.json file, false otherwise.
+   */
+  private isPackageInPackageJson(
+    targetPackage: string,
+    packageJson: PackageJson | undefined,
+  ): boolean {
+    if (
+      !targetPackage.startsWith("./") &&
+      !targetPackage.startsWith("../") &&
+      !isPathAbsolute(targetPackage) &&
+      packageJson
+    ) {
+      return !!(
+        (packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
+        (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
+        (packageJson.devDependencies && targetPackage in packageJson.devDependencies)
+      );
+    }
+
+    return false;
+  }
+
+  private createInstallPackageCodeAction(
+    diagnostic: vscode.Diagnostic,
+    pkgName: string,
+    pkgNameInPkgFile: boolean,
+    projectFolder?: string,
+  ): vscode.CodeAction {
+    const action = new vscode.CodeAction(
+      `Install "${pkgName}" using npm`,
+      vscode.CodeActionKind.QuickFix,
+    );
+    action.command = {
+      command: CodeActionCommand.NpmInstallPackage,
+      title: diagnostic.message,
+      arguments: [projectFolder, pkgName, pkgNameInPkgFile],
+    };
+    action.diagnostics = [diagnostic];
+    return action;
+  }
+
   private createOpenUrlCodeAction(
     diagnostic: vscode.Diagnostic,
     url: string,
@@ -61,7 +154,7 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
       vscode.CodeActionKind.QuickFix,
     );
     action.command = {
-      command: CommandName.OpenUrl,
+      command: CodeActionCommand.OpenUrl,
       title: diagnostic.message,
       arguments: [url],
     };
diff --git a/packages/typespec-vscode/src/extension.ts b/packages/typespec-vscode/src/extension.ts
index ddd2aea8cc3..2ea8282d0a4 100644
--- a/packages/typespec-vscode/src/extension.ts
+++ b/packages/typespec-vscode/src/extension.ts
@@ -16,6 +16,7 @@ import telemetryClient from "./telemetry/telemetry-client.js";
 import { OperationTelemetryEvent, TelemetryEventName } from "./telemetry/telemetry-event.js";
 import { TspLanguageClient } from "./tsp-language-client.js";
 import {
+  CodeActionCommand,
   CommandName,
   InstallGlobalCliCommandArgs,
   RestartServerCommandArgs,
@@ -25,7 +26,7 @@ import {
   SettingName,
 } from "./types.js";
 import { installCompilerWithUi } from "./typespec-utils.js";
-import { isWhitespaceStringOrUndefined } from "./utils.js";
+import { isWhitespaceStringOrUndefined, spawnExecutionAndLogToOutput } from "./utils.js";
 import { createTypeSpecProject } from "./vscode-cmd/create-tsp-project.js";
 import { emitCode } from "./vscode-cmd/emit-code/emit-code.js";
 import { importFromOpenApi3 } from "./vscode-cmd/import-from-openapi3.js";
@@ -63,7 +64,40 @@ export async function activate(context: ExtensionContext) {
       );
 
       context.subscriptions.push(
-        commands.registerCommand(CommandName.OpenUrl, (url: string) => {
+        commands.registerCommand(
+          CodeActionCommand.NpmInstallPackage,
+          async (projectFolder: string | undefined, pkgName: string, pkgNameInPkgFile: boolean) => {
+            try {
+              if (projectFolder) {
+                await spawnExecutionAndLogToOutput(
+                  "npm",
+                  pkgNameInPkgFile ? ["install"] : ["install", pkgName],
+                  projectFolder,
+                );
+              } else {
+                logger.error(
+                  "No package.json file was found, and the dependency package could not be installed",
+                  [],
+                  {
+                    showPopup: true,
+                  },
+                );
+              }
+            } catch (error) {
+              logger.error(
+                "Failed to execute npm install, please check the output for details",
+                [error],
+                {
+                  showPopup: true,
+                },
+              );
+            }
+          },
+        ),
+      );
+
+      context.subscriptions.push(
+        commands.registerCommand(CodeActionCommand.OpenUrl, (url: string) => {
           try {
             vscode.env.openExternal(vscode.Uri.parse(url));
           } catch (error) {
diff --git a/packages/typespec-vscode/src/types.ts b/packages/typespec-vscode/src/types.ts
index 766a3bb1817..25bb2e204fa 100644
--- a/packages/typespec-vscode/src/types.ts
+++ b/packages/typespec-vscode/src/types.ts
@@ -10,12 +10,16 @@ export const enum CommandName {
   RestartServer = "typespec.restartServer",
   InstallGlobalCompilerCli = "typespec.installGlobalCompilerCli",
   CreateProject = "typespec.createProject",
-  OpenUrl = "typespec.openUrl",
   EmitCode = "typespec.emitCode",
   ImportFromOpenApi3 = "typespec.importFromOpenApi3",
   ShowOpenApi3 = "typespec.showOpenApi3",
 }
 
+export const enum CodeActionCommand {
+  OpenUrl = "typespec.openUrl",
+  NpmInstallPackage = "typespec.npmInstallPackage",
+}
+
 export type RestartServerCommandResult = Result<TspLanguageClient>;
 
 export interface BaseCommandArgs {


Reviews:
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T08:34:36Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T08:35:49Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T08:38:32Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-31T08:41:52Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T10:17:29Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T10:21:06Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T10:23:17Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T10:23:47Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T10:27:26Z
user: login: chunyu3
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T06:00:48Z
user: login: chunyu3
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T06:10:33Z
user: login: chunyu3
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-29T07:12:58Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T03:31:03Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T03:32:34Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T03:32:58Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T03:37:15Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T03:37:46Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T04:01:44Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T04:03:22Z
user: login: mzhongl524
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T07:33:11Z
user: login: mzhongl524
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-06T07:38:54Z
user: login: chunyu3
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T09:27:58Z
user: login: chunyu3
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-06T09:32:29Z
user: login: chunyu3
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T05:03:05Z
user: login: chunyu3
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T01:51:28Z
user: login: mzhongl524
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-09T05:42:28Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T09:07:29Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T09:08:58Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-09T09:09:09Z
user: login: RodgeFu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T06:15:13Z
user: login: timotheeguerin
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T15:37:05Z
user: login: timotheeguerin
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T15:38:03Z
user: login: timotheeguerin
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T15:39:08Z
user: login: timotheeguerin
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-15T15:40:40Z
user: login: mzhongl524
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T01:55:36Z
user: login: timotheeguerin
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T18:00:57Z
user: login: timotheeguerin
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-16T18:02:11Z
user: login: mzhongl524
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T01:31:27Z
user: login: timotheeguerin
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-19T15:03:41Z
user: login: mzhongl524
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-20T03:05:35Z
user: login: timotheeguerin
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-20T03:08:20Z
user: login: mzhongl524
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-20T03:36:36Z
user: login: timotheeguerin
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-28T15:20:52Z

Review comments:
diff_hunk: @@ -46,10 +46,30 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           ),
         );
       }
+      if (
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found"
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: user may import files instead of package. we should only provide this quick fix when user import packages
created_at: 2025-03-31T08:34:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -46,10 +46,30 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           ),
         );
       }
+      if (
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found"
+      ) {
+        actions.push(this.createInstallPackageCodeAction(diagnostic));
+      }
     });
     return actions;
   }
 
+  private createInstallPackageCodeAction(diagnostic: vscode.Diagnostic): vscode.CodeAction {
+    const action = new vscode.CodeAction(
+      "Install Package for Unrecognized Import",
+      vscode.CodeActionKind.QuickFix,
+    );
+    action.command = {
+      command: CommandName.InstallImportPackage,
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: Why do we need to have a command for this?
created_at: 2025-03-31T08:35:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,6 +63,21 @@ export async function activate(context: ExtensionContext) {
     }),
   );
 
+  context.subscriptions.push(
+    commands.registerCommand(CommandName.InstallImportPackage, async () => {
+      try {
+        const projectFiles = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
path: packages/typespec-vscode/src/extension.ts
user: login: RodgeFu
body: We need to check the corresponding package.json file to help install package instead of always installing to the first workspace folder. 
created_at: 2025-03-31T08:38:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -46,10 +46,30 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           ),
         );
       }
+      if (
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found"
+      ) {
+        actions.push(this.createInstallPackageCodeAction(diagnostic));
+      }
     });
     return actions;
   }
 
+  private createInstallPackageCodeAction(diagnostic: vscode.Diagnostic): vscode.CodeAction {
+    const action = new vscode.CodeAction(
+      "Install Package for Unrecognized Import",
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: it's better to say it clearly that we are using ```npm install``` to install the unrecognized package (at least for now, before we support other package managers), so that user can understand what will happen in case he doesn't want to use npm for some reason.
created_at: 2025-03-31T08:41:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,97 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return actions;
+    }
+
+    const uris = await vscode.workspace
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: you should be able to find the package.json from the diagnstoic. The package.json from the whole project may not be related to the diagnstoic.
created_at: 2025-04-09T10:17:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,97 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return actions;
+    }
+
+    const uris = await vscode.workspace
+      .findFiles("**/package.json", "**/node_modules/**")
+      .then((uris) =>
+        uris
+          .filter((uri) => uri.scheme === "file" && !uri.fsPath.includes("node_modules"))
+          .map((uri) => normalizeSlashes(uri.fsPath)),
+      );
+    if (uris.length === 0) {
+      return actions;
+    }
+
+    const packageNames: Map<string, string> = new Map();
+    for (const uri of uris) {
+      const packageJson = await loadPackageJsonFile(uri);
+      if (packageJson && packageJson.peerDependencies) {
+        for (const key in packageJson.peerDependencies) {
+          if (!packageNames.has(key) && !key.startsWith("./") && !isPathAbsolute(key)) {
+            packageNames.set(key, uri);
+          }
+        }
+      }
+      if (packageJson && packageJson.dependencies) {
+        for (const key in packageJson.dependencies) {
+          if (!packageNames.has(key) && !key.startsWith("./") && !isPathAbsolute(key)) {
+            packageNames.set(key, uri);
+          }
+        }
+      }
+      if (packageJson && packageJson.devDependencies) {
+        for (const key in packageJson.devDependencies) {
+          if (!packageNames.has(key) && !key.startsWith("./") && !isPathAbsolute(key)) {
+            packageNames.set(key, uri);
+          }
+        }
+      }
+    }
+
+    for (const diagnostic of diagnostics) {
+      const targets = diagnostic.message.match(/"([^"]+)"/);
+      if (targets === null) {
+        continue;
+      }
+
+      // The position with index 0 contains double quotes, and the position with 1 does not contain
+      const targetPackage = targets[1];
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: 1. avoid magic number
2. package.dependencies?.[tagetPackage] !== undefined || ...devdependency || ...peerdepe..
created_at: 2025-04-09T10:21:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,97 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return actions;
+    }
+
+    const uris = await vscode.workspace
+      .findFiles("**/package.json", "**/node_modules/**")
+      .then((uris) =>
+        uris
+          .filter((uri) => uri.scheme === "file" && !uri.fsPath.includes("node_modules"))
+          .map((uri) => normalizeSlashes(uri.fsPath)),
+      );
+    if (uris.length === 0) {
+      return actions;
+    }
+
+    const packageNames: Map<string, string> = new Map();
+    for (const uri of uris) {
+      const packageJson = await loadPackageJsonFile(uri);
+      if (packageJson && packageJson.peerDependencies) {
+        for (const key in packageJson.peerDependencies) {
+          if (!packageNames.has(key) && !key.startsWith("./") && !isPathAbsolute(key)) {
+            packageNames.set(key, uri);
+          }
+        }
+      }
+      if (packageJson && packageJson.dependencies) {
+        for (const key in packageJson.dependencies) {
+          if (!packageNames.has(key) && !key.startsWith("./") && !isPathAbsolute(key)) {
+            packageNames.set(key, uri);
+          }
+        }
+      }
+      if (packageJson && packageJson.devDependencies) {
+        for (const key in packageJson.devDependencies) {
+          if (!packageNames.has(key) && !key.startsWith("./") && !isPathAbsolute(key)) {
+            packageNames.set(key, uri);
+          }
+        }
+      }
+    }
+
+    for (const diagnostic of diagnostics) {
+      const targets = diagnostic.message.match(/"([^"]+)"/);
+      if (targets === null) {
+        continue;
+      }
+
+      // The position with index 0 contains double quotes, and the position with 1 does not contain
+      const targetPackage = targets[1];
+      if (!packageNames.has(targetPackage)) {
+        continue;
+      }
+
+      const action = this.createInstallPackageCodeAction(
+        diagnostic,
+        packageNames.get(targetPackage)!,
+      );
+      if (!actions.some((item) => item.title === action.title)) {
+        actions.push(action);
+      }
+    }
+
     return actions;
   }
 
+  private createInstallPackageCodeAction(
+    diagnostic: vscode.Diagnostic,
+    path: string,
+  ): vscode.CodeAction {
+    const action = new vscode.CodeAction(
+      "Install(Npm) Package for Unrecognized Import",
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: Npm install ....
created_at: 2025-04-09T10:23:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,6 +63,26 @@ export async function activate(context: ExtensionContext) {
     }),
   );
 
+  context.subscriptions.push(
+    commands.registerCommand(CommandName.NpmInstallImportPackage, async (path: string) => {
+      try {
+        const projectFiles = getDirectoryPath(path);
+        await spawnExecutionAndLogToOutput("npm", ["install"], normalizeSlashes(projectFiles));
+
+        // Will not recompile after installation, so consider the user experience, close the current file and reopen it
+        const filePath = vscode.window.activeTextEditor?.document.uri.fsPath;
path: packages/typespec-vscode/src/extension.ts
user: login: RodgeFu
body: this is not necessary.
created_at: 2025-04-09T10:23:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -14,6 +14,7 @@ export const enum CommandName {
   EmitCode = "typespec.emitCode",
   ImportFromOpenApi3 = "typespec.importFromOpenApi3",
   ShowOpenApi3 = "typespec.showOpenApi3",
+  NpmInstallImportPackage = "typespec.npmInstallImportPackage",
path: packages/typespec-vscode/src/types.ts
user: login: RodgeFu
body: The command is for CodeAction which is different from other external command. Please create a enum "CodeActionCommand" for it.
created_at: 2025-04-09T10:27:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,87 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+    actions: vscode.CodeAction[],
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return [];
+    }
+
+    for (const diagnostic of diagnostics) {
+      if ("data" in diagnostic) {
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: chunyu3
body: it check `diagnostic.data` in next line. No need this line check
created_at: 2025-04-29T06:00:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -525,7 +525,10 @@ export function createServer(host: ServerHost): Server {
             diagnostic.severity = DiagnosticSeverity.Hint;
           }
         }
-        diagnostic.data = { id: diagnosticIdCounter++ };
+        diagnostic.data = {
+          id: diagnosticIdCounter++,
+          file: await fileService.getPath({ uri: diagDocument.uri }),
path: packages/compiler/src/server/serverlib.ts
user: login: chunyu3
body: We may not need to set `file` for each diagnostic. The `file` is only useful for the import-not-found diagnostic, right?
created_at: 2025-04-29T06:10:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,87 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+    actions: vscode.CodeAction[],
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return [];
+    }
+
+    for (const diagnostic of diagnostics) {
+      if ("data" in diagnostic) {
+        if (diagnostic.data && typeof diagnostic.data === "object" && "file" in diagnostic.data) {
+          const packageFile = diagnostic.data.file as string;
+          const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: chunyu3
body: When there is no package.json in the typespec project, we still need to install the missing package.
created_at: 2025-04-29T06:56:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,87 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+    actions: vscode.CodeAction[],
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return [];
+    }
+
+    for (const diagnostic of diagnostics) {
+      if ("data" in diagnostic) {
+        if (diagnostic.data && typeof diagnostic.data === "object" && "file" in diagnostic.data) {
+          const packageFile = diagnostic.data.file as string;
+          const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+            getDirectoryPath(packageFile),
+          );
+          if (packageJsonFolder === undefined) {
+            continue;
+          }
+
+          // The message content is Couldn't resolve import "@typespec/http".
+          // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+          // so a regular expression is used to extract the package name within the double quotes
+          const targets = diagnostic.message.match(/"([^"]+)"/);
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: chunyu3
body: How about import from a file not a package? when the file does not exist, import-not-found diagnostic will be reported also.
created_at: 2025-04-29T06:58:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,87 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+    actions: vscode.CodeAction[],
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return [];
+    }
+
+    for (const diagnostic of diagnostics) {
+      if ("data" in diagnostic) {
+        if (diagnostic.data && typeof diagnostic.data === "object" && "file" in diagnostic.data) {
+          const packageFile = diagnostic.data.file as string;
+          const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+            getDirectoryPath(packageFile),
+          );
+          if (packageJsonFolder === undefined) {
+            continue;
+          }
+
+          // The message content is Couldn't resolve import "@typespec/http".
+          // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+          // so a regular expression is used to extract the package name within the double quotes
+          const targets = diagnostic.message.match(/"([^"]+)"/);
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: chunyu3
body: ```suggestion
          const target = diagnostic.message.match(/"([^"]+)"/);
```
created_at: 2025-04-29T06:59:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,87 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+    actions: vscode.CodeAction[],
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return [];
+    }
+
+    for (const diagnostic of diagnostics) {
+      if ("data" in diagnostic) {
+        if (diagnostic.data && typeof diagnostic.data === "object" && "file" in diagnostic.data) {
+          const packageFile = diagnostic.data.file as string;
+          const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+            getDirectoryPath(packageFile),
+          );
+          if (packageJsonFolder === undefined) {
+            continue;
+          }
+
+          // The message content is Couldn't resolve import "@typespec/http".
+          // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+          // so a regular expression is used to extract the package name within the double quotes
+          const targets = diagnostic.message.match(/"([^"]+)"/);
+          if (targets === null) {
+            continue;
+          }
+
+          // The position with index 0 contains double quotes, and the position with 1 does not contain
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: chunyu3
body: can we refine the regex to get the package name without double quote? then we will not need special handling here.
created_at: 2025-04-29T07:01:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,87 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+    actions: vscode.CodeAction[],
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return [];
+    }
+
+    for (const diagnostic of diagnostics) {
+      if ("data" in diagnostic) {
+        if (diagnostic.data && typeof diagnostic.data === "object" && "file" in diagnostic.data) {
+          const packageFile = diagnostic.data.file as string;
+          const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+            getDirectoryPath(packageFile),
+          );
+          if (packageJsonFolder === undefined) {
+            continue;
+          }
+
+          // The message content is Couldn't resolve import "@typespec/http".
+          // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+          // so a regular expression is used to extract the package name within the double quotes
+          const targets = diagnostic.message.match(/"([^"]+)"/);
+          if (targets === null) {
+            continue;
+          }
+
+          // The position with index 0 contains double quotes, and the position with 1 does not contain
+          const packageNameIndex = 1;
+          const targetPackage = targets[packageNameIndex];
+
+          if (
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: chunyu3
body: same as above. even the missing package does not set in the package.json, we still need to install.
created_at: 2025-04-29T07:04:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,87 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+    actions: vscode.CodeAction[],
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return [];
+    }
+
+    for (const diagnostic of diagnostics) {
+      if ("data" in diagnostic) {
+        if (diagnostic.data && typeof diagnostic.data === "object" && "file" in diagnostic.data) {
+          const packageFile = diagnostic.data.file as string;
+          const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+            getDirectoryPath(packageFile),
+          );
+          if (packageJsonFolder === undefined) {
+            continue;
+          }
+
+          // The message content is Couldn't resolve import "@typespec/http".
+          // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+          // so a regular expression is used to extract the package name within the double quotes
+          const targets = diagnostic.message.match(/"([^"]+)"/);
+          if (targets === null) {
+            continue;
+          }
+
+          // The position with index 0 contains double quotes, and the position with 1 does not contain
+          const packageNameIndex = 1;
+          const targetPackage = targets[packageNameIndex];
+
+          if (
+            !targetPackage.startsWith("./") &&
+            !isPathAbsolute(targetPackage) &&
+            packageJson &&
+            ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
+              (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
+              (packageJson.devDependencies && targetPackage in packageJson.devDependencies))
+          ) {
+            const action = this.createInstallPackageCodeAction(diagnostic, packageJsonFolder);
+            if (!actions.some((item) => item.title === action.title)) {
+              return [action];
+            }
+          }
+        }
+      }
+    }
+    return [];
+  }
+
+  private createInstallPackageCodeAction(
+    diagnostic: vscode.Diagnostic,
+    path: string,
+  ): vscode.CodeAction {
+    const action = new vscode.CodeAction(
+      "Npm install Package for Unrecognized Import",
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: chunyu3
body: ```suggestion
      "Install package by `npm install` for unrecognized import",
```
created_at: 2025-04-29T07:10:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,97 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: why isn't this in the forEach loop above?
created_at: 2025-05-06T03:31:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,97 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+    actions: vscode.CodeAction[],
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return [];
+    }
+
+    for (const diagnostic of diagnostics) {
+      if (
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: why not having these criteria in the filter above directly?
created_at: 2025-05-06T03:32:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,97 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+    actions: vscode.CodeAction[],
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return [];
+    }
+
+    for (const diagnostic of diagnostics) {
+      if (
+        "data" in diagnostic &&
+        diagnostic.data &&
+        typeof diagnostic.data === "object" &&
+        "file" in diagnostic.data
+      ) {
+        // The message content is `Couldn't resolve import "@typespec/http"`.
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: please add a test which will fail if the error message changes in the future
created_at: 2025-05-06T03:32:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,97 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+    actions: vscode.CodeAction[],
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return [];
+    }
+
+    for (const diagnostic of diagnostics) {
+      if (
+        "data" in diagnostic &&
+        diagnostic.data &&
+        typeof diagnostic.data === "object" &&
+        "file" in diagnostic.data
+      ) {
+        // The message content is `Couldn't resolve import "@typespec/http"`.
+        // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+        // so a regular expression is used to extract the package name within the double quotes
+        const targetPackage = diagnostic.message.replace(/.*"([^"]+)".*/, "$1");
+        const packageFile = diagnostic.data.file as string;
+        const packageFileUri = vscode.Uri.parse(packageFile);
+        const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+          getDirectoryPath(packageFileUri.fsPath),
+        );
+
+        let packageName: string = "";
+        let projectFolder: string | undefined;
+        if (packageJsonFolder === undefined) {
+          // If the package.json file is not found, install the specified `targetPackage` directly
+          packageName = targetPackage;
+          projectFolder = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: i dont think it's a good idea to install to the root folder of workspace[0] silently, which may not be what user expect. I would prefer not to provide quick fix in this case. Or provide a way for user to choose but it's likely a bigger stuff user needs to fix if user doesn't have package.json which should be  handled by a quick action.
created_at: 2025-05-06T03:37:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,97 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+    actions: vscode.CodeAction[],
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return [];
+    }
+
+    for (const diagnostic of diagnostics) {
+      if (
+        "data" in diagnostic &&
+        diagnostic.data &&
+        typeof diagnostic.data === "object" &&
+        "file" in diagnostic.data
+      ) {
+        // The message content is `Couldn't resolve import "@typespec/http"`.
+        // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+        // so a regular expression is used to extract the package name within the double quotes
+        const targetPackage = diagnostic.message.replace(/.*"([^"]+)".*/, "$1");
+        const packageFile = diagnostic.data.file as string;
+        const packageFileUri = vscode.Uri.parse(packageFile);
+        const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+          getDirectoryPath(packageFileUri.fsPath),
+        );
+
+        let packageName: string = "";
+        let projectFolder: string | undefined;
+        if (packageJsonFolder === undefined) {
+          // If the package.json file is not found, install the specified `targetPackage` directly
+          packageName = targetPackage;
+          projectFolder = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
+        } else if (
+          !targetPackage.startsWith("./") &&
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: is it possible to start with ../ ?
created_at: 2025-05-06T03:37:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,97 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+    actions: vscode.CodeAction[],
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return [];
+    }
+
+    for (const diagnostic of diagnostics) {
+      if (
+        "data" in diagnostic &&
+        diagnostic.data &&
+        typeof diagnostic.data === "object" &&
+        "file" in diagnostic.data
+      ) {
+        // The message content is `Couldn't resolve import "@typespec/http"`.
+        // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+        // so a regular expression is used to extract the package name within the double quotes
+        const targetPackage = diagnostic.message.replace(/.*"([^"]+)".*/, "$1");
+        const packageFile = diagnostic.data.file as string;
+        const packageFileUri = vscode.Uri.parse(packageFile);
+        const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+          getDirectoryPath(packageFileUri.fsPath),
+        );
+
+        let packageName: string = "";
+        let projectFolder: string | undefined;
+        if (packageJsonFolder === undefined) {
+          // If the package.json file is not found, install the specified `targetPackage` directly
+          packageName = targetPackage;
+          projectFolder = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
+        } else if (
+          !targetPackage.startsWith("./") &&
+          !isPathAbsolute(targetPackage) &&
+          packageJson &&
+          ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
+            (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
+            (packageJson.devDependencies && targetPackage in packageJson.devDependencies))
+        ) {
+          // If the package.json file is found, and the file contains the specified package,
+          // it is installed according to the package name in the package.json file.
+          projectFolder = packageJsonFolder;
+        }
+
+        if (projectFolder) {
+          const action = this.createInstallPackageCodeAction(
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: why not just put it at line 107?
created_at: 2025-05-06T04:01:44Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,97 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+    actions: vscode.CodeAction[],
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const diagnostics = context.diagnostics.filter(
+      (diagnostic) =>
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found",
+    );
+    if (diagnostics.length === 0) {
+      return [];
+    }
+
+    for (const diagnostic of diagnostics) {
+      if (
+        "data" in diagnostic &&
+        diagnostic.data &&
+        typeof diagnostic.data === "object" &&
+        "file" in diagnostic.data
+      ) {
+        // The message content is `Couldn't resolve import "@typespec/http"`.
+        // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+        // so a regular expression is used to extract the package name within the double quotes
+        const targetPackage = diagnostic.message.replace(/.*"([^"]+)".*/, "$1");
+        const packageFile = diagnostic.data.file as string;
+        const packageFileUri = vscode.Uri.parse(packageFile);
+        const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+          getDirectoryPath(packageFileUri.fsPath),
+        );
+
+        let packageName: string = "";
+        let projectFolder: string | undefined;
+        if (packageJsonFolder === undefined) {
+          // If the package.json file is not found, install the specified `targetPackage` directly
+          packageName = targetPackage;
+          projectFolder = vscode.workspace.workspaceFolders?.[0].uri.fsPath;
+        } else if (
+          !targetPackage.startsWith("./") &&
+          !isPathAbsolute(targetPackage) &&
+          packageJson &&
+          ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
+            (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
+            (packageJson.devDependencies && targetPackage in packageJson.devDependencies))
+        ) {
+          // If the package.json file is found, and the file contains the specified package,
+          // it is installed according to the package name in the package.json file.
+          projectFolder = packageJsonFolder;
+        }
+
+        if (projectFolder) {
+          const action = this.createInstallPackageCodeAction(
+            diagnostic,
+            projectFolder,
+            packageName,
+          );
+          if (!actions.some((item) => item.title === action.title)) {
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: let the caller to make the call to include the action or not, the function should just generate the action
created_at: 2025-05-06T04:03:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +49,97 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: mzhongl524
body: Earlier you proposed to put the block logic into a separate method
created_at: 2025-05-06T07:33:11Z
author_association: MEMBER
diff_hunk: @@ -47,9 +49,97 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context, actions)));
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: mzhongl524
body: Moreover, it includes some asynchronous operations, which, if handled together, will not be included in the final actions.
created_at: 2025-05-06T07:38:54Z
author_association: MEMBER
diff_hunk: @@ -62,6 +63,31 @@ export async function activate(context: ExtensionContext) {
     }),
   );
 
+  context.subscriptions.push(
+    commands.registerCommand(
+      CodeActionCommand.NpmInstallImportPackage,
+      async (projectFolder: string, hasPackageFile: boolean = true) => {
+        try {
+          if (hasPackageFile) {
path: packages/typespec-vscode/src/extension.ts
user: login: chunyu3
body: Do we need to check the package.json here again instead of passing a parameter?
considering this scenario: the import-not-found has reported, and then user add a package.json, this `hasPackageFile` is out-of-date, not correct.
created_at: 2025-05-06T09:27:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,6 +63,31 @@ export async function activate(context: ExtensionContext) {
     }),
   );
 
+  context.subscriptions.push(
+    commands.registerCommand(
+      CodeActionCommand.NpmInstallImportPackage,
+      async (projectFolder: string, hasPackageFile: boolean = true) => {
path: packages/typespec-vscode/src/extension.ts
user: login: chunyu3
body: What's the behavior when `projectFolder` is empty string? where the package is installed? it may cause problem.

may need to check `projectFolder`
created_at: 2025-05-06T09:32:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +50,76 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: chunyu3
body: ```suggestion
  private async createInstallPackageByNpmCodeActions(
```
created_at: 2025-05-08T04:46:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +50,76 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context)));
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: chunyu3
body: can we combine this to above traversal loop, in that case no need to traverse twice?
created_at: 2025-05-08T04:56:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,6 +63,31 @@ export async function activate(context: ExtensionContext) {
     }),
   );
 
+  context.subscriptions.push(
+    commands.registerCommand(
+      CodeActionCommand.NpmInstallImportPackage,
+      async (projectFolder: string | undefined) => {
+        try {
+          if (projectFolder !== undefined) {
path: packages/typespec-vscode/src/extension.ts
user: login: chunyu3
body: ```suggestion
          if (projectFolder ) {
```
created_at: 2025-05-08T04:58:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -47,9 +50,76 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
         );
       }
     });
+
+    actions.push(...(await this.createInstallPackageByNpm(context)));
+
     return actions;
   }
 
+  private async createInstallPackageByNpm(
+    context: vscode.CodeActionContext,
+  ): Promise<vscode.CodeAction[]> {
+    // When the corresponding node dependency package is not installed,
+    // consider generating a quick fix to install via npm command
+    const actions: vscode.CodeAction[] = [];
+    for (const diagnostic of context.diagnostics) {
+      if (
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found" &&
+        "data" in diagnostic &&
+        diagnostic.data &&
+        typeof diagnostic.data === "object" &&
+        "file" in diagnostic.data
+      ) {
+        // The message content is `Couldn't resolve import "@typespec/http"`.
+        // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+        // so a regular expression is used to extract the package name within the double quotes,
+        // if no match is reached, the original string is returned
+        const targetPackage = diagnostic.message.replace(/.*"([^"]+)".*/, "$1");
+        logger.debug(`The target package name is '${targetPackage}'.`);
+
+        const packageFile = diagnostic.data.file as string;
+        const packageFileUri = vscode.Uri.parse(packageFile);
+        const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+          getDirectoryPath(packageFileUri.fsPath),
+        );
+
+        if (packageJsonFolder === undefined) {
+          actions.push(this.createInstallPackageCodeAction(diagnostic, packageJsonFolder));
+        } else if (
+          !targetPackage.startsWith("./") &&
+          !targetPackage.startsWith("../") &&
+          !isPathAbsolute(targetPackage) &&
+          packageJson &&
+          ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
+            (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
+            (packageJson.devDependencies && targetPackage in packageJson.devDependencies))
+        ) {
+          actions.push(this.createInstallPackageCodeAction(diagnostic, packageJsonFolder));
+        }
+      }
+    }
+    return actions;
+  }
+
+  private createInstallPackageCodeAction(
+    diagnostic: vscode.Diagnostic,
+    projectFolder: string | undefined,
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: chunyu3
body: ```suggestion
    packageJsonFolder?: string,
```
created_at: 2025-05-08T05:00:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,6 +63,31 @@ export async function activate(context: ExtensionContext) {
     }),
   );
 
+  context.subscriptions.push(
+    commands.registerCommand(
+      CodeActionCommand.NpmInstallImportPackage,
+      async (projectFolder: string | undefined) => {
+        try {
+          if (projectFolder !== undefined) {
+            await spawnExecutionAndLogToOutput("npm", ["install"], projectFolder);
+          } else {
+            vscode.window.showErrorMessage(
+              "No package.json file was found, and the dependency package could not be installed",
+            );
+            logger.debug(
path: packages/typespec-vscode/src/extension.ts
user: login: chunyu3
body: ```suggestion
            logger.error(
```
created_at: 2025-05-08T05:01:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -10,12 +10,16 @@ export const enum CommandName {
   RestartServer = "typespec.restartServer",
   InstallGlobalCompilerCli = "typespec.installGlobalCompilerCli",
   CreateProject = "typespec.createProject",
-  OpenUrl = "typespec.openUrl",
   EmitCode = "typespec.emitCode",
   ImportFromOpenApi3 = "typespec.importFromOpenApi3",
   ShowOpenApi3 = "typespec.showOpenApi3",
 }
 
+export const enum CodeActionCommand {
+  OpenUrl = "typespec.openUrl",
+  NpmInstallImportPackage = "typespec.npmInstallImportPackage",
path: packages/typespec-vscode/src/types.ts
user: login: chunyu3
body: ```suggestion
  NpmInstallPackage = "typespec.npmInstallPackage",
```
created_at: 2025-05-08T05:02:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,6 +63,31 @@ export async function activate(context: ExtensionContext) {
     }),
   );
 
+  context.subscriptions.push(
+    commands.registerCommand(
+      CodeActionCommand.NpmInstallImportPackage,
+      async (projectFolder: string, hasPackageFile: boolean = true) => {
+        try {
+          if (hasPackageFile) {
path: packages/typespec-vscode/src/extension.ts
user: login: chunyu3
body: instead of passing the projectFolder as packageJsonFolder, we need to check the package.json again.
created_at: 2025-05-09T01:51:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,6 +63,31 @@ export async function activate(context: ExtensionContext) {
     }),
   );
 
+  context.subscriptions.push(
+    commands.registerCommand(
+      CodeActionCommand.NpmInstallImportPackage,
+      async (projectFolder: string, hasPackageFile: boolean = true) => {
+        try {
+          if (hasPackageFile) {
path: packages/typespec-vscode/src/extension.ts
user: login: mzhongl524
body: The user's mouse will trigger the execution of `provideCodeActions` every time it hovers, otherwise the quick fix menu will not be generated, so there is no need to re-judgment whether the `package.json` file exists.
created_at: 2025-05-09T05:42:28Z
author_association: MEMBER
diff_hunk: @@ -46,10 +50,67 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           ),
         );
       }
-    });
+
+      // When the corresponding node dependency package is not installed,
+      // consider generating a quick fix to install via npm command
+      if (
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found" &&
+        "data" in diagnostic &&
+        diagnostic.data &&
+        typeof diagnostic.data === "object" &&
+        "file" in diagnostic.data
+      ) {
+        // The message content is `Couldn't resolve import "@typespec/http"`.
+        // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+        // so a regular expression is used to extract the package name within the double quotes,
+        // if no match is reached, the original string is returned
+        const targetPackage = diagnostic.message.replace(/.*"([^"]+)".*/, "$1");
+        logger.debug(`The target package name is '${targetPackage}'.`);
+
+        const packageFile = diagnostic.data.file as string;
+        const packageFileUri = vscode.Uri.parse(packageFile);
+        const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+          getDirectoryPath(packageFileUri.fsPath),
+        );
+
+        if (packageJsonFolder === undefined) {
+          actions.push(this.createInstallPackageCodeAction(diagnostic, packageJsonFolder));
+        } else if (
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: RodgeFu
body: the if and else-if takes the same action, why not merge them into one?
created_at: 2025-05-09T09:07:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,6 +63,31 @@ export async function activate(context: ExtensionContext) {
     }),
   );
 
+  context.subscriptions.push(
+    commands.registerCommand(
+      CodeActionCommand.NpmInstallPackage,
+      async (projectFolder: string | undefined) => {
+        try {
+          if (projectFolder) {
+            await spawnExecutionAndLogToOutput("npm", ["install"], projectFolder);
+          } else {
+            vscode.window.showErrorMessage(
path: packages/typespec-vscode/src/extension.ts
user: login: RodgeFu
body: you dont need this explicitly. the logger has an option to do that.
created_at: 2025-05-09T09:08:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -62,6 +63,31 @@ export async function activate(context: ExtensionContext) {
     }),
   );
 
+  context.subscriptions.push(
+    commands.registerCommand(
+      CodeActionCommand.NpmInstallPackage,
+      async (projectFolder: string | undefined) => {
+        try {
+          if (projectFolder) {
+            await spawnExecutionAndLogToOutput("npm", ["install"], projectFolder);
+          } else {
+            vscode.window.showErrorMessage(
+              "No package.json file was found, and the dependency package could not be installed",
+            );
+            logger.error(
+              "No package.json file was found, and the dependency package could not be installed",
+            );
+          }
+        } catch (error) {
+          vscode.window.showErrorMessage(
path: packages/typespec-vscode/src/extension.ts
user: login: RodgeFu
body: same comment as above.
created_at: 2025-05-09T09:09:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -71,18 +71,24 @@ export async function activate(context: ExtensionContext) {
           if (projectFolder) {
             await spawnExecutionAndLogToOutput("npm", ["install"], projectFolder);
           } else {
-            vscode.window.showErrorMessage(
-              "No package.json file was found, and the dependency package could not be installed",
-            );
             logger.error(
               "No package.json file was found, and the dependency package could not be installed",
+              [],
+              {
+                showPopup: true,
+                popupButtonText: "",
path: packages/typespec-vscode/src/extension.ts
user: login: RodgeFu
body: you dont need to set popupButtonText to "" explicitly. just set showPopup is enough
created_at: 2025-05-12T06:15:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -46,10 +50,66 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           ),
         );
       }
-    });
+
+      // When the corresponding node dependency package is not installed,
+      // consider generating a quick fix to install via npm command
+      if (
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found" &&
+        "data" in diagnostic &&
+        diagnostic.data &&
+        typeof diagnostic.data === "object" &&
+        "file" in diagnostic.data
+      ) {
+        // The message content is `Couldn't resolve import "@typespec/http"`.
+        // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+        // so a regular expression is used to extract the package name within the double quotes,
+        // if no match is reached, the original string is returned
+        const targetPackage = diagnostic.message.replace(/.*"([^"]+)".*/, "$1");
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: timotheeguerin
body: just want to make sure that you understand that this message is not part of the api contract and can change and this will break.
created_at: 2025-05-15T15:37:05Z
author_association: MEMBER
diff_hunk: @@ -46,10 +50,66 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           ),
         );
       }
-    });
+
+      // When the corresponding node dependency package is not installed,
+      // consider generating a quick fix to install via npm command
+      if (
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found" &&
+        "data" in diagnostic &&
+        diagnostic.data &&
+        typeof diagnostic.data === "object" &&
+        "file" in diagnostic.data
+      ) {
+        // The message content is `Couldn't resolve import "@typespec/http"`.
+        // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+        // so a regular expression is used to extract the package name within the double quotes,
+        // if no match is reached, the original string is returned
+        const targetPackage = diagnostic.message.replace(/.*"([^"]+)".*/, "$1");
+        logger.debug(`The target package name is '${targetPackage}'.`);
+
+        const packageFile = diagnostic.data.file as string;
+        const packageFileUri = vscode.Uri.parse(packageFile);
+        const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+          getDirectoryPath(packageFileUri.fsPath),
+        );
+
+        if (
+          packageJsonFolder === undefined ||
+          (!targetPackage.startsWith("./") &&
+            !targetPackage.startsWith("../") &&
+            !isPathAbsolute(targetPackage) &&
+            packageJson &&
+            ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
+              (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
+              (packageJson.devDependencies && targetPackage in packageJson.devDependencies)))
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: timotheeguerin
body: is this just going to install the package if its already in the package.json dependencies?
created_at: 2025-05-15T15:38:03Z
author_association: MEMBER
diff_hunk: @@ -46,10 +50,66 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           ),
         );
       }
-    });
+
+      // When the corresponding node dependency package is not installed,
+      // consider generating a quick fix to install via npm command
+      if (
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found" &&
+        "data" in diagnostic &&
+        diagnostic.data &&
+        typeof diagnostic.data === "object" &&
+        "file" in diagnostic.data
+      ) {
+        // The message content is `Couldn't resolve import "@typespec/http"`.
+        // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+        // so a regular expression is used to extract the package name within the double quotes,
+        // if no match is reached, the original string is returned
+        const targetPackage = diagnostic.message.replace(/.*"([^"]+)".*/, "$1");
+        logger.debug(`The target package name is '${targetPackage}'.`);
+
+        const packageFile = diagnostic.data.file as string;
+        const packageFileUri = vscode.Uri.parse(packageFile);
+        const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+          getDirectoryPath(packageFileUri.fsPath),
+        );
+
+        if (
+          packageJsonFolder === undefined ||
+          (!targetPackage.startsWith("./") &&
+            !targetPackage.startsWith("../") &&
+            !isPathAbsolute(targetPackage) &&
+            packageJson &&
+            ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
+              (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
+              (packageJson.devDependencies && targetPackage in packageJson.devDependencies)))
+        ) {
+          actions.push(this.createInstallPackageCodeAction(diagnostic, packageJsonFolder));
+        }
+      }
+    }
+
     return actions;
   }
 
+  private createInstallPackageCodeAction(
+    diagnostic: vscode.Diagnostic,
+    projectFolder?: string,
+  ): vscode.CodeAction {
+    const action = new vscode.CodeAction(
+      "Install package by `npm install` for unrecognized import",
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: timotheeguerin
body: ```suggestion
      `Install "${pkgName}" using npm`,
```
created_at: 2025-05-15T15:39:07Z
author_association: MEMBER
diff_hunk: @@ -46,10 +50,66 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           ),
         );
       }
-    });
+
+      // When the corresponding node dependency package is not installed,
+      // consider generating a quick fix to install via npm command
+      if (
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found" &&
+        "data" in diagnostic &&
+        diagnostic.data &&
+        typeof diagnostic.data === "object" &&
+        "file" in diagnostic.data
+      ) {
+        // The message content is `Couldn't resolve import "@typespec/http"`.
+        // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+        // so a regular expression is used to extract the package name within the double quotes,
+        // if no match is reached, the original string is returned
+        const targetPackage = diagnostic.message.replace(/.*"([^"]+)".*/, "$1");
+        logger.debug(`The target package name is '${targetPackage}'.`);
+
+        const packageFile = diagnostic.data.file as string;
+        const packageFileUri = vscode.Uri.parse(packageFile);
+        const { packageJsonFolder, packageJson } = await searchAndLoadPackageJson(
+          getDirectoryPath(packageFileUri.fsPath),
+        );
+
+        if (
+          packageJsonFolder === undefined ||
+          (!targetPackage.startsWith("./") &&
+            !targetPackage.startsWith("../") &&
+            !isPathAbsolute(targetPackage) &&
+            packageJson &&
+            ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
+              (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
+              (packageJson.devDependencies && targetPackage in packageJson.devDependencies)))
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: timotheeguerin
body: can you also move this complex condition to a dedicated function explaining what its looking for
created_at: 2025-05-15T15:40:40Z
author_association: MEMBER
diff_hunk: @@ -46,10 +50,66 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           ),
         );
       }
-    });
+
+      // When the corresponding node dependency package is not installed,
+      // consider generating a quick fix to install via npm command
+      if (
+        diagnostic.source === "TypeSpec" &&
+        diagnostic.code &&
+        diagnostic.code === "import-not-found" &&
+        "data" in diagnostic &&
+        diagnostic.data &&
+        typeof diagnostic.data === "object" &&
+        "file" in diagnostic.data
+      ) {
+        // The message content is `Couldn't resolve import "@typespec/http"`.
+        // The compiler's diagnostics do not provide a specific attribute to obtain the package name,
+        // so a regular expression is used to extract the package name within the double quotes,
+        // if no match is reached, the original string is returned
+        const targetPackage = diagnostic.message.replace(/.*"([^"]+)".*/, "$1");
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: mzhongl524
body: Yes, so I added debug logs to make it easier to troubleshoot if the message changes in the future.
created_at: 2025-05-16T01:55:36Z
author_association: MEMBER
diff_hunk: @@ -75,30 +76,62 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           getDirectoryPath(packageFileUri.fsPath),
         );
 
-        if (
-          packageJsonFolder === undefined ||
-          (!targetPackage.startsWith("./") &&
-            !targetPackage.startsWith("../") &&
-            !isPathAbsolute(targetPackage) &&
-            packageJson &&
-            ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
-              (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
-              (packageJson.devDependencies && targetPackage in packageJson.devDependencies)))
-        ) {
-          actions.push(this.createInstallPackageCodeAction(diagnostic, packageJsonFolder));
+        if (this.shouldOfferPackageInstallation(targetPackage, packageJsonFolder, packageJson)) {
+          actions.push(
+            this.createInstallPackageCodeAction(diagnostic, targetPackage, packageJsonFolder),
+          );
         }
       }
     }
 
     return actions;
   }
 
+  /**
+   * Determines if a package should be installed based on the following criteria:
+   * - No package.json found in parent directories, OR
+   * - The target is a npm package (not a local path or absolute path) that exists
+   *   in package.json dependencies but isn't installed
+   *
+   * @param targetPackage The package to check for installation
+   * @param packageJsonFolder The folder containing package.json, if found
+   * @param packageJson The parsed package.json contents, if found
+   * @returns True if the package should be installed
+   */
+  private shouldOfferPackageInstallation(
+    targetPackage: string,
+    packageJsonFolder: string | undefined,
+    packageJson: PackageJson | undefined,
+  ): boolean {
+    if (packageJsonFolder === undefined) {
+      return true;
+    }
+
+    if (
+      !targetPackage.startsWith("./") &&
+      !targetPackage.startsWith("../") &&
+      !isPathAbsolute(targetPackage) &&
+      packageJson
+    ) {
+      // Add `false` to resolve the error of returning `boolean|undefined` type
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: timotheeguerin
body: use `Boolean(` or `!!` instead  of this
created_at: 2025-05-16T18:00:56Z
author_association: MEMBER
diff_hunk: @@ -75,30 +76,62 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           getDirectoryPath(packageFileUri.fsPath),
         );
 
-        if (
-          packageJsonFolder === undefined ||
-          (!targetPackage.startsWith("./") &&
-            !targetPackage.startsWith("../") &&
-            !isPathAbsolute(targetPackage) &&
-            packageJson &&
-            ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
-              (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
-              (packageJson.devDependencies && targetPackage in packageJson.devDependencies)))
-        ) {
-          actions.push(this.createInstallPackageCodeAction(diagnostic, packageJsonFolder));
+        if (this.shouldOfferPackageInstallation(targetPackage, packageJsonFolder, packageJson)) {
+          actions.push(
+            this.createInstallPackageCodeAction(diagnostic, targetPackage, packageJsonFolder),
+          );
         }
       }
     }
 
     return actions;
   }
 
+  /**
+   * Determines if a package should be installed based on the following criteria:
+   * - No package.json found in parent directories, OR
+   * - The target is a npm package (not a local path or absolute path) that exists
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: timotheeguerin
body: so back to the original comment, why is this a limitation? Doesn't feel to make sense that it will do that if there is no package.json and then only if you already added the package.json there. Its more likely you are trying to import a library you haven't added yet.
created_at: 2025-05-16T18:02:11Z
author_association: MEMBER
diff_hunk: @@ -75,30 +76,62 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           getDirectoryPath(packageFileUri.fsPath),
         );
 
-        if (
-          packageJsonFolder === undefined ||
-          (!targetPackage.startsWith("./") &&
-            !targetPackage.startsWith("../") &&
-            !isPathAbsolute(targetPackage) &&
-            packageJson &&
-            ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
-              (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
-              (packageJson.devDependencies && targetPackage in packageJson.devDependencies)))
-        ) {
-          actions.push(this.createInstallPackageCodeAction(diagnostic, packageJsonFolder));
+        if (this.shouldOfferPackageInstallation(targetPackage, packageJsonFolder, packageJson)) {
+          actions.push(
+            this.createInstallPackageCodeAction(diagnostic, targetPackage, packageJsonFolder),
+          );
         }
       }
     }
 
     return actions;
   }
 
+  /**
+   * Determines if a package should be installed based on the following criteria:
+   * - No package.json found in parent directories, OR
+   * - The target is a npm package (not a local path or absolute path) that exists
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: mzhongl524
body: After discussion between @RodgeFu  and @chunyu3 , when there is a package file, if the packageName is in the file, a quick fix will be generated for installation. If there is no package file, a quick fix will be generated. However, when clicking the menu to execute, the installation will not be performed and a clear prompt will be given.
created_at: 2025-05-19T01:31:27Z
author_association: MEMBER
diff_hunk: @@ -75,30 +76,62 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           getDirectoryPath(packageFileUri.fsPath),
         );
 
-        if (
-          packageJsonFolder === undefined ||
-          (!targetPackage.startsWith("./") &&
-            !targetPackage.startsWith("../") &&
-            !isPathAbsolute(targetPackage) &&
-            packageJson &&
-            ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
-              (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
-              (packageJson.devDependencies && targetPackage in packageJson.devDependencies)))
-        ) {
-          actions.push(this.createInstallPackageCodeAction(diagnostic, packageJsonFolder));
+        if (this.shouldOfferPackageInstallation(targetPackage, packageJsonFolder, packageJson)) {
+          actions.push(
+            this.createInstallPackageCodeAction(diagnostic, targetPackage, packageJsonFolder),
+          );
         }
       }
     }
 
     return actions;
   }
 
+  /**
+   * Determines if a package should be installed based on the following criteria:
+   * - No package.json found in parent directories, OR
+   * - The target is a npm package (not a local path or absolute path) that exists
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: timotheeguerin
body: Not sure I fully get what is your plan here.

The way I see it is:
1. If you have no package.json - This should somehow suggest some init flow for the user
2. If you have a package.json
   - If the import is in a depdency field, suggest running `tsp install` and do that
   - If not suggest installing it as a dependency
created_at: 2025-05-19T15:03:41Z
author_association: MEMBER
diff_hunk: @@ -75,30 +76,62 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           getDirectoryPath(packageFileUri.fsPath),
         );
 
-        if (
-          packageJsonFolder === undefined ||
-          (!targetPackage.startsWith("./") &&
-            !targetPackage.startsWith("../") &&
-            !isPathAbsolute(targetPackage) &&
-            packageJson &&
-            ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
-              (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
-              (packageJson.devDependencies && targetPackage in packageJson.devDependencies)))
-        ) {
-          actions.push(this.createInstallPackageCodeAction(diagnostic, packageJsonFolder));
+        if (this.shouldOfferPackageInstallation(targetPackage, packageJsonFolder, packageJson)) {
+          actions.push(
+            this.createInstallPackageCodeAction(diagnostic, targetPackage, packageJsonFolder),
+          );
         }
       }
     }
 
     return actions;
   }
 
+  /**
+   * Determines if a package should be installed based on the following criteria:
+   * - No package.json found in parent directories, OR
+   * - The target is a npm package (not a local path or absolute path) that exists
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: mzhongl524
body: A little different：

1. If you have no package.json  - When the user clicks on the Quick fix menu, just clearly tells the user that there is no package file and cannot install dependency packages. As for how the user wants to handle it, it's up to the user.
2. If you have a package.json
            - If the import is in a depdency field, suggest running `npm install` and do that
            - If not, no quick fix will be generated
        


created_at: 2025-05-20T03:05:35Z
author_association: MEMBER
diff_hunk: @@ -75,30 +76,62 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           getDirectoryPath(packageFileUri.fsPath),
         );
 
-        if (
-          packageJsonFolder === undefined ||
-          (!targetPackage.startsWith("./") &&
-            !targetPackage.startsWith("../") &&
-            !isPathAbsolute(targetPackage) &&
-            packageJson &&
-            ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
-              (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
-              (packageJson.devDependencies && targetPackage in packageJson.devDependencies)))
-        ) {
-          actions.push(this.createInstallPackageCodeAction(diagnostic, packageJsonFolder));
+        if (this.shouldOfferPackageInstallation(targetPackage, packageJsonFolder, packageJson)) {
+          actions.push(
+            this.createInstallPackageCodeAction(diagnostic, targetPackage, packageJsonFolder),
+          );
         }
       }
     }
 
     return actions;
   }
 
+  /**
+   * Determines if a package should be installed based on the following criteria:
+   * - No package.json found in parent directories, OR
+   * - The target is a npm package (not a local path or absolute path) that exists
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: timotheeguerin
body: Feels like having the case 2.b work is the whole point of this fix. Why do you not want to add a code fix for that 
created_at: 2025-05-20T03:08:20Z
author_association: MEMBER
diff_hunk: @@ -75,30 +76,62 @@ export class TypeSpecCodeActionProvider implements vscode.CodeActionProvider {
           getDirectoryPath(packageFileUri.fsPath),
         );
 
-        if (
-          packageJsonFolder === undefined ||
-          (!targetPackage.startsWith("./") &&
-            !targetPackage.startsWith("../") &&
-            !isPathAbsolute(targetPackage) &&
-            packageJson &&
-            ((packageJson.peerDependencies && targetPackage in packageJson.peerDependencies) ||
-              (packageJson.dependencies && targetPackage in packageJson.dependencies) ||
-              (packageJson.devDependencies && targetPackage in packageJson.devDependencies)))
-        ) {
-          actions.push(this.createInstallPackageCodeAction(diagnostic, packageJsonFolder));
+        if (this.shouldOfferPackageInstallation(targetPackage, packageJsonFolder, packageJson)) {
+          actions.push(
+            this.createInstallPackageCodeAction(diagnostic, targetPackage, packageJsonFolder),
+          );
         }
       }
     }
 
     return actions;
   }
 
+  /**
+   * Determines if a package should be installed based on the following criteria:
+   * - No package.json found in parent directories, OR
+   * - The target is a npm package (not a local path or absolute path) that exists
path: packages/typespec-vscode/src/code-action-provider.ts
user: login: mzhongl524
body: I confirmed with Rodge and I will solve this problem
created_at: 2025-05-20T03:36:36Z
author_association: MEMBER

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-31T08:14:53Z
body: <!--chronus-github-change-commenter-->
All changed packages have been documented.
 - :white_check_mark: `@typespec/compiler`
 - :white_check_mark: `typespec-vscode`

<details>
<summary>Show changes</summary>

### `@typespec/compiler` - _feature_ [✏️](https://github.com/mzhongl524/typespec/edit/install-packages-for-unrecognized-import/.chronus/changes/install-packages-for-unrecognized-import-2025-4-8-7-32-21.md?pr=/microsoft/typespec/pull/6783)
> Install packages for unrecognized import via npm command
### `typespec-vscode` - _feature_ [✏️](https://github.com/mzhongl524/typespec/edit/install-packages-for-unrecognized-import/.chronus/changes/install-packages-for-unrecognized-import-2025-4-8-7-32-21.md?pr=/microsoft/typespec/pull/6783)
> Install packages for unrecognized import via npm command
</details>

author_association: CONTRIBUTOR
user: login: azure-sdk
created_at: 2025-03-31T08:29:10Z
body: <!-- _TSP_TRYIT_COMMENT_ -->
You can try these changes here

| [🛝 Playground]( https://cadlplayground.z22.web.core.windows.net/prs/6783/)|[🌐 Website](https://tspwebsitepr.z22.web.core.windows.net/prs/6783/)|[🛝 VSCode Extension]( https://artprodcus3.artifacts.visualstudio.com/A0fb41ef4-5012-48a9-bf39-4ee3de03ee35/590cfd2a-581c-4dcb-a12e-6568ce786175/_apis/artifact/cGlwZWxpbmVhcnRpZmFjdDovL2F6dXJlLXNkay9wcm9qZWN0SWQvNTkwY2ZkMmEtNTgxYy00ZGNiLWExMmUtNjU2OGNlNzg2MTc1L2J1aWxkSWQvNDg4NTI3OC9hcnRpZmFjdE5hbWUvdnNjb2RlLWV4dGVuc2lvbg2/content?format=zip) |
| ---|---|--- |
author_association: COLLABORATOR
user: login: mzhongl524
created_at: 2025-05-14T08:03:00Z
body: @timotheeguerin  please help review
author_association: MEMBER
user: login: mzhongl524
created_at: 2025-05-21T08:03:12Z
body: @timotheeguerin  please help review
author_association: MEMBER
user: login: mzhongl524
created_at: 2025-05-28T07:51:45Z
body: @timotheeguerin  please help review
author_association: MEMBER