Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .eslintignore

This file was deleted.

128 changes: 0 additions & 128 deletions .eslintrc.json

This file was deleted.

189 changes: 189 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
// @ts-check
import eslint from "@eslint/js";
import { defineConfig } from "eslint/config";
import markdown from "@eslint/markdown";
import tseslint from "typescript-eslint";
import prettierConfig from "eslint-config-prettier";
import prettierPlugin from "eslint-plugin-prettier";
import { createTypeScriptImportResolver } from "eslint-import-resolver-typescript";
import { flatConfigs as importXFlatConfigs } from "eslint-plugin-import-x";
import packageJson from "eslint-plugin-package-json";
import globals from "globals";

export default defineConfig(
// Global ignores
{
ignores: [
"out/**",
"dist/**",
"**/*.d.ts",
"vitest.config.ts",
".vscode-test/**",
],
},

// Base ESLint recommended rules (for JS/TS files only)
{
files: ["**/*.ts", "**/*.js", "**/*.mjs"],
...eslint.configs.recommended,
},

// TypeScript configuration with type-checked rules
{
files: ["**/*.ts"],
extends: [
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked,
importXFlatConfigs.typescript,
],
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
plugins: {
prettier: prettierPlugin,
},
settings: {
"import-x/resolver-next": [
createTypeScriptImportResolver({ project: "./tsconfig.json" }),
],
"import-x/internal-regex": "^@/",
},
rules: {
// Prettier integration
"prettier/prettier": "error",

// Core ESLint rules
curly: "error",
eqeqeq: "error",
"no-throw-literal": "error",
"no-console": "error",

// TypeScript rules (extending/overriding presets)
"require-await": "off",
"@typescript-eslint/require-await": "error",
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/switch-exhaustiveness-check": [
"error",
{ considerDefaultExhaustiveForUnions: true },
],
"@typescript-eslint/no-unused-vars": [
"error",
{ varsIgnorePattern: "^_" },
],
"@typescript-eslint/array-type": ["error", { default: "array-simple" }],
"@typescript-eslint/prefer-nullish-coalescing": [
"error",
// Allow || for strings where empty string should be treated as falsy
{ ignorePrimitives: { string: true } },
],
"@typescript-eslint/dot-notation": [
"error",
// Allow bracket notation for index signatures (e.g., Record<string, T>)
{ allowIndexSignaturePropertyAccess: true },
],

// Import rules
"import-x/order": [
"error",
{
groups: [
["builtin", "external"],
"internal",
"parent",
["sibling", "index"],
"type",
],
pathGroups: [
{ pattern: "@/**", group: "internal", position: "before" },
],
pathGroupsExcludedImportTypes: ["builtin", "external"],
"newlines-between": "always",
alphabetize: { order: "asc", caseInsensitive: true },
sortTypesGroup: true,
},
],
"no-duplicate-imports": "off",
"import-x/no-duplicates": ["error", { "prefer-inline": true }],
"import-x/no-unresolved": ["error", { ignore: ["vscode"] }],

// Custom AST selector rule
"no-restricted-syntax": [
"error",
{
selector:
"CallExpression[callee.property.name='executeCommand'][arguments.0.value='setContext'][arguments.length>=3]",
message:
"Do not use executeCommand('setContext', ...) directly. Use the ContextManager class instead.",
},
],
},
},

// Test files - use test tsconfig and relax some rules
{
files: ["test/**/*.ts", "**/*.test.ts", "**/*.spec.ts"],
settings: {
"import-x/resolver-next": [
createTypeScriptImportResolver({ project: "test/tsconfig.json" }),
],
},
rules: {
// Allow type annotations in tests (e.g., for vi.fn<SomeType>())
"@typescript-eslint/consistent-type-imports": [
"error",
{
disallowTypeAnnotations: false,
},
],
// vitest mocks trigger false positives for unbound-method
"@typescript-eslint/unbound-method": "off",
// Empty callbacks are common in test stubs
"@typescript-eslint/no-empty-function": "off",
// Test mocks often have loose typing - relax unsafe rules
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-return": "off",
},
},

// Disable no-restricted-syntax for contextManager
{
files: ["src/core/contextManager.ts"],
rules: {
"no-restricted-syntax": "off",
},
},

// Webpack config - CommonJS with Node globals
{
files: ["webpack.config.js"],
languageOptions: {
globals: {
...globals.node,
},
},
},

// Package.json linting
packageJson.configs.recommended,

// Markdown linting with GitHub-flavored admonitions allowed
...markdown.configs.recommended,
{
files: ["**/*.md"],
rules: {
"markdown/no-missing-label-refs": [
"error",
{
allowLabels: ["!NOTE", "!TIP", "!IMPORTANT", "!WARNING", "!CAUTION"],
},
],
},
},

// Prettier must be last to override other formatting rules
prettierConfig,
);
26 changes: 14 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"scripts": {
"build": "webpack",
"fmt": "prettier --write .",
"lint": "eslint . --ext ts,md,json",
"lint": "eslint .",
"lint:fix": "yarn lint --fix",
"package": "webpack --mode production --devtool hidden-source-map",
"package:prerelease": "npx vsce package --pre-release",
Expand Down Expand Up @@ -418,35 +418,37 @@
"zod": "^4.3.2"
},
"devDependencies": {
"@types/eventsource": "^3.0.0",
"@types/node": "^22.14.1",
"@eslint/js": "^9.39.2",
"@eslint/markdown": "^7.5.1",
"@types/node": "^18",
"@types/proper-lockfile": "^4.1.4",
"@types/semver": "^7.7.1",
"@types/ua-parser-js": "0.7.39",
"@types/vscode": "^1.73.0",
"@types/ws": "^8.18.1",
"@typescript-eslint/eslint-plugin": "^8.49.0",
"@typescript-eslint/parser": "^8.50.1",
"@typescript-eslint/eslint-plugin": "^8.52.0",
"@typescript-eslint/parser": "^8.52.0",
"@vitest/coverage-v8": "^4.0.16",
"@vscode/test-cli": "^0.0.12",
"@vscode/test-electron": "^2.5.2",
"@vscode/vsce": "^3.7.1",
"bufferutil": "^4.0.9",
"bufferutil": "^4.1.0",
"coder": "https://github.com/coder/coder#main",
"dayjs": "^1.11.19",
"electron": "^39.2.6",
"eslint": "^8.57.1",
"electron": "^39.2.7",
"eslint": "^9.39.2",
"eslint-config-prettier": "^10.1.8",
"eslint-import-resolver-typescript": "^4.4.4",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-md": "^1.0.19",
"eslint-plugin-package-json": "^0.85.0",
"eslint-plugin-import-x": "^4.16.1",
"eslint-plugin-package-json": "^0.88.1",
"eslint-plugin-prettier": "^5.5.4",
"globals": "^16.5.0",
"jsonc-eslint-parser": "^2.4.2",
"markdown-eslint-parser": "^1.2.1",
"memfs": "^4.51.1",
"prettier": "^3.7.4",
"ts-loader": "^9.5.4",
"typescript": "^5.9.3",
"typescript-eslint": "^8.52.0",
"utf-8-validate": "^6.0.6",
"vitest": "^4.0.16",
"webpack": "^5.104.1",
Expand Down
4 changes: 2 additions & 2 deletions src/api/agentMetadataHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import {
} from "./api-helper";
import { type CoderApi } from "./coderApi";

export type AgentMetadataWatcher = {
export interface AgentMetadataWatcher {
onChange: vscode.EventEmitter<null>["event"];
dispose: () => void;
metadata?: AgentMetadataEvent[];
error?: unknown;
};
}

/**
* Opens a websocket connection to watch metadata for a given workspace agent.
Expand Down
Loading