From 9b78353d7e07892dd69da216f623c42246d79b7b Mon Sep 17 00:00:00 2001 From: John Tuckner Date: Fri, 5 Jun 2026 08:21:49 -0500 Subject: [PATCH 01/10] docs: document org-scoped tools and SOCKET_API_KEY auth flow Add README reference entries for the organizations, alerts, threat_feed, package_files, package_file_contents, and package_file_grep tools, plus an authentication section and a worked organizations -> alerts example. Mirror the tool inventory in the architecture doc. --- README.md | 113 ++++++++++++++++++++++++++++ docs/claude.md/repo/architecture.md | 8 ++ 2 files changed, 121 insertions(+) diff --git a/README.md b/README.md index 3312a38c..22307a61 100644 --- a/README.md +++ b/README.md @@ -268,6 +268,119 @@ pkg:pypi/fastapi@0.100.0: supply_chain: 1.0, quality: 0.95, maintenance: 0.98, v Report: https://socket.dev/pypi/package/fastapi ``` +#### organizations + +List the Socket organizations the authenticated user belongs to. Takes no parameters. Use it to discover the `org_slug` value that the org-scoped tools (`alerts`, `threat_feed`) require. + +This tool needs a Socket API token. See [Authentication for organization-scoped tools](#authentication-for-organization-scoped-tools) below. + +#### alerts + +List the latest security alerts for one Socket organization: supply-chain, vulnerability, quality, license, and maintenance issues across the org's monitored packages. Backed by `GET /v0/orgs/{org_slug}/alerts`. Results are paginated; pass the previous response's `endCursor` as `cursor` to fetch the next page. + +| Parameter | Type | Required | Default | Description | +| --------------- | ------- | -------- | ------- | -------------------------------------------------------------------------------------------- | +| `org_slug` | String | ✅ Yes | - | Organization slug (get it from the `organizations` tool) | +| `severity` | String | No | - | Comma-separated subset of `low,medium,high,critical` | +| `status` | String | No | - | `open` or `cleared` | +| `category` | String | No | - | Comma-separated subset of `supplyChainRisk,maintenance,quality,license,vulnerability` | +| `artifact_type` | String | No | - | Comma-separated ecosystems: `npm,pypi,gem,maven,golang,nuget,cargo,chrome,openvsx` | +| `artifact_name` | String | No | - | Restrict to a single package name | +| `alert_type` | String | No | - | Comma-separated Socket alert types (e.g. `usesEval,unmaintained`) | +| `repo_slug` | String | No | - | Comma-separated repository slugs | +| `per_page` | Integer | No | `100` | Results per page (1–5000) | +| `cursor` | String | No | - | Pagination cursor — the `endCursor` from a previous response | + +#### threat_feed + +Look up items in a Socket organization's threat feed: packages recently flagged as malware, typosquats, obfuscated code, and similar. Backed by `GET /v0/orgs/{org_slug}/threat-feed`. The response carries a `nextPageCursor`; pass it as `cursor` to page forward. + +| Parameter | Type | Required | Default | Description | +| ------------------- | ------- | -------- | -------------- | ---------------------------------------------------------------------------------------------------------- | +| `org_slug` | String | ✅ Yes | - | Organization slug (get it from the `organizations` tool) | +| `filter` | String | No | `mal` | Threat category: `mal` (malware), `vuln`, `typ` (typosquat), `obf` (obfuscated), `mjo`, `kes`, `spy`, etc. | +| `ecosystem` | String | No | - | Ecosystem: `npm`, `pypi`, `gem`, `maven`, `golang`, `nuget`, `cargo`, `chrome`, `openvsx`, `huggingface` | +| `name` | String | No | - | Filter by package name | +| `version` | String | No | - | Filter by package version | +| `is_human_reviewed` | Boolean | No | `false` | Only return human-reviewed items | +| `sort` | String | No | `updated_at` | Sort field: `id`, `created_at`, `updated_at` | +| `direction` | String | No | `desc` | Sort direction: `asc`, `desc` | +| `updated_after` | String | No | - | ISO timestamp; only items updated after this | +| `created_after` | String | No | - | ISO timestamp; only items created after this | +| `per_page` | Integer | No | `30` | Results per page (1–100) | +| `cursor` | String | No | - | Pagination cursor — the `nextPageCursor` from a previous response | + +#### package_files + +List the files published in a package: a tree of paths and sizes for any package on a supported ecosystem. Use it to inspect what a dependency ships before installing it. Each entry prints a blob `hash` that `package_file_contents` and `package_file_grep` consume. + +| Parameter | Type | Required | Default | Description | +| ------------ | ------ | -------- | ------- | -------------------------------------------------------------------------------------- | +| `ecosystem` | String | No | `npm` | `npm`, `pypi`, `gem`, `cargo`, `maven`, `golang`, `nuget`, `chrome`, `openvsx` | +| `depname` | String | ✅ Yes | - | Package name (e.g. `lodash`, `@babel/core`, `org.springframework:spring-core`) | +| `version` | String | ✅ Yes | - | Package version | +| `artifactId` | String | No | - | Per-version disambiguator (PyPI filename, Maven artifact id, NuGet asset) | +| `platform` | String | No | - | Platform qualifier for per-OS/arch artifacts (e.g. openvsx `linux-x64`, `darwin-arm64`) | + +#### package_file_contents + +Read a single file from a package. Pass the `hash` printed next to an entry in `package_files` output. Returns up to 1 MB of UTF-8 text; binary files return metadata only. + +| Parameter | Type | Required | Default | Description | +| --------- | ------ | -------- | ------- | ------------------------------------------------------ | +| `hash` | String | ✅ Yes | - | Blob hash from `package_files` | +| `path` | String | No | - | File path, for display only; does not affect the lookup | + +#### package_file_grep + +Search a single file from a package for lines matching a JavaScript regular expression, returning matches with line numbers (grep -n style). The file is fetched once per session and cached, so repeated greps on the same hash skip the network. + +| Parameter | Type | Required | Default | Description | +| ----------------- | ------- | -------- | ------- | ------------------------------------------------------ | +| `hash` | String | ✅ Yes | - | Blob hash from `package_files` | +| `pattern` | String | ✅ Yes | - | JavaScript regular expression (plain literals work too) | +| `caseInsensitive` | Boolean | No | `false` | Match case-insensitively | +| `contextLines` | Integer | No | `0` | Lines of context before and after each match (0–5) | +| `maxMatches` | Integer | No | `100` | Cap on matching lines returned (1–500) | +| `path` | String | No | - | File path, for display only; does not affect the lookup | + +### Authentication for organization-scoped tools + +`depscore` works without credentials on the public server. The `organizations`, `alerts`, `threat_feed`, and `package_files` tools call Socket's authenticated REST API, so they need a Socket API token. + +How the server resolves a token depends on the transport: + +- **stdio mode** reads one token at startup from the environment and uses it for every request. Set `SOCKET_API_TOKEN`. The server also accepts these aliases, in priority order: `SOCKET_API_TOKEN` → `SOCKET_API_KEY` → `SOCKET_CLI_API_TOKEN` → `SOCKET_CLI_API_KEY` → `SOCKET_SECURITY_API_TOKEN` → `SOCKET_SECURITY_API_KEY`. `SOCKET_API_TOKEN` is canonical; `SOCKET_API_KEY` is the alias most local setups already export. +- **HTTP mode** prefers a per-request OAuth token from the client and falls back to the startup token when no OAuth token is present. + +Generate a token from the [Socket dashboard](https://socket.dev/) under API tokens, then export it before launching the server: + +```sh +export SOCKET_API_TOKEN="your-socket-api-token" +``` + +When no token is available, these tools return: `Authentication is required. Configure SOCKET_API_TOKEN (or a legacy alias) for stdio mode or connect through OAuth-enabled HTTP mode.` + +### Worked example: organization details and alerts + +With `SOCKET_API_KEY` (or `SOCKET_API_TOKEN`) set, ask your assistant something like "show me the open critical alerts for my Socket org". Under the hood the assistant chains two tools: + +1. **Discover the org slug.** Call `organizations` (no arguments). The server reads your token, calls `GET /v0/organizations`, and returns the organizations your token can see. Pick the `slug` you want, e.g. `my-org`. + +2. **Fetch alerts for that org.** Call `alerts` with the slug and any filters: + + ```json + { + "org_slug": "my-org", + "severity": "high,critical", + "status": "open" + } + ``` + + The server calls `GET /v0/orgs/my-org/alerts` with the same token and returns the matching alerts plus pagination metadata. To page forward, pass the response's `endCursor` back as `cursor`. + +The same token scopes every org-scoped tool, so `threat_feed` and `package_files` work the moment `organizations` confirms which slug the token belongs to. + ### Adjusting tool usage via client rules You can customize how the MCP server interacts with your AI assistant by editing your client's rules file: diff --git a/docs/claude.md/repo/architecture.md b/docs/claude.md/repo/architecture.md index 7d896cf4..ed456ce6 100644 --- a/docs/claude.md/repo/architecture.md +++ b/docs/claude.md/repo/architecture.md @@ -10,6 +10,14 @@ socket-mcp is the **Socket Model Context Protocol server** — exposes Socket de - `lib/` — tool implementations and Socket API wrappers. - `artifacts.test.ts` — co-located unit tests; additional fixtures under `docs/`. +## Tools + +Registered in `lib/server.ts` (`buildToolSpecs`); user-facing reference lives in `README.md` under "Tools exposed". + +- `depscore` — dependency scores; works without a token on the public server. +- `organizations` / `alerts` / `threat_feed` — org-scoped Socket REST API; require a token resolved by `resolveAuthToken` (per-request OAuth in HTTP mode, else the boot-time static key from `setStaticApiKey`). +- `package_files` / `package_file_contents` / `package_file_grep` — package file listing, read, and grep; `package_files` requires a token, the read/grep tools resolve a cached blob by hash. + ## Commands - Install: `pnpm install`. From 52a87e8371de51e712c952c82a77b0744c904f4b Mon Sep 17 00:00:00 2001 From: John Tuckner Date: Fri, 5 Jun 2026 08:39:16 -0500 Subject: [PATCH 02/10] fix(auth): scope org tools to the caller, not the deploy key in HTTP mode The organizations, alerts, threat_feed, and package_files tools resolved their Socket token through resolveAuthToken, which falls back to the boot-time static key. In HTTP mode that key is the deploy operator's, so a shared/hosted server answered every caller's org lookup with the operator's private organizations, alerts, and threat feed. Split the resolver: resolveScopedAuthToken (per-tenant tools) returns the per-request token, and only falls back to the static key when it is the local user's own (stdio mode); in HTTP mode it returns undefined so the tool emits the auth-required error. setStaticApiKey now records whether the key is shared (HTTP) or user-owned (stdio). Non-OAuth HTTP mode reads the caller's Authorization: Bearer token into req.auth so per-tenant tools act on the caller's behalf. depscore keeps the public static fallback since package scores are not tenant-scoped. --- README.md | 4 ++-- index.ts | 6 ++++- lib/http-server.ts | 20 ++++++++++++++++ lib/server.ts | 49 +++++++++++++++++++++++++++++++-------- lib/tool-alerts.ts | 4 ++-- lib/tool-organizations.ts | 4 ++-- lib/tool-package-files.ts | 4 ++-- lib/tool-threat-feed.ts | 4 ++-- test/http-server.test.ts | 35 ++++++++++++++++++++++++++++ test/server.test.ts | 46 ++++++++++++++++++++++++++++++++++++ 10 files changed, 155 insertions(+), 21 deletions(-) create mode 100644 test/http-server.test.ts create mode 100644 test/server.test.ts diff --git a/README.md b/README.md index 22307a61..056f4d99 100644 --- a/README.md +++ b/README.md @@ -350,8 +350,8 @@ Search a single file from a package for lines matching a JavaScript regular expr How the server resolves a token depends on the transport: -- **stdio mode** reads one token at startup from the environment and uses it for every request. Set `SOCKET_API_TOKEN`. The server also accepts these aliases, in priority order: `SOCKET_API_TOKEN` → `SOCKET_API_KEY` → `SOCKET_CLI_API_TOKEN` → `SOCKET_CLI_API_KEY` → `SOCKET_SECURITY_API_TOKEN` → `SOCKET_SECURITY_API_KEY`. `SOCKET_API_TOKEN` is canonical; `SOCKET_API_KEY` is the alias most local setups already export. -- **HTTP mode** prefers a per-request OAuth token from the client and falls back to the startup token when no OAuth token is present. +- **stdio mode** reads one token at startup from the environment and uses it for every request. Set `SOCKET_API_TOKEN`. The server also accepts these aliases, in priority order: `SOCKET_API_TOKEN` → `SOCKET_API_KEY` → `SOCKET_CLI_API_TOKEN` → `SOCKET_CLI_API_KEY` → `SOCKET_SECURITY_API_TOKEN` → `SOCKET_SECURITY_API_KEY`. `SOCKET_API_TOKEN` is canonical; `SOCKET_API_KEY` is the alias most local setups already export. Because the process belongs to one user, this token is yours and scopes every tool to your account. +- **HTTP mode** scopes the organization tools to the caller, never to the server's own token. Send your Socket API token as an `Authorization: Bearer ` header on each request, or use an OAuth access token when the server runs OAuth. The server uses that per-request token for the Socket API calls it makes on your behalf. A shared deployment never answers `organizations`, `alerts`, `threat_feed`, or `package_files` with the operator's data: when a request carries no token, those tools return the auth-required error. `depscore` alone may fall back to the server's startup token, since package scores are the same for every caller. Generate a token from the [Socket dashboard](https://socket.dev/) under API tokens, then export it before launching the server: diff --git a/index.ts b/index.ts index 4a3eecfa..898714ce 100755 --- a/index.ts +++ b/index.ts @@ -79,7 +79,11 @@ async function main(): Promise { } } - setStaticApiKey(apiKey) + // `shared` marks the static key as a deploy-operator key in HTTP mode, so + // per-tenant tools refuse to fall back to it and use the caller's + // per-request token instead. In stdio mode the static key is the local + // user's own token, so it stays usable everywhere. + setStaticApiKey(apiKey, { shared: useHttp }) if (oauthEnabled && oauthEnabledResult) { try { diff --git a/lib/http-server.ts b/lib/http-server.ts index 352bd82e..9274746b 100644 --- a/lib/http-server.ts +++ b/lib/http-server.ts @@ -45,6 +45,24 @@ const ALLOWED_ORIGINS = [ 'https://mcp.socket-staging.dev', ] +// Non-OAuth HTTP mode: forward a client-supplied Socket API key (sent as +// `Authorization: Bearer `) to the tool layer via `req.auth`, so +// per-tenant tools act on the caller's behalf instead of the deploy's static +// key. A missing or malformed header leaves `req.auth` unset, which makes +// per-tenant tools return AUTH_REQUIRED while public tools (depscore) still +// fall back to the static key. +export function applyClientApiKey(req: AuthenticatedRequest): void { + const authHeader = getRequestHeaderValue(req.headers.authorization).trim() + if (!authHeader) { + return + } + const [type, token] = authHeader.split(/\s+/u) + if ((type || '').toLowerCase() !== 'bearer' || !token) { + return + } + req.auth = { token, clientId: 'socket-api-key', scopes: [] } +} + // Destroy a session — close transport (best-effort) and detach the MCP // server. Safe to call multiple times. export function destroySession( @@ -380,6 +398,8 @@ export async function routeRequest( if (!authResult.ok) { return } + } else { + applyClientApiKey(req as AuthenticatedRequest) } if (req.method === 'POST') { diff --git a/lib/server.ts b/lib/server.ts index 606427c8..9b441856 100644 --- a/lib/server.ts +++ b/lib/server.ts @@ -42,12 +42,15 @@ export const SOCKET_API_BASE_URL = getSocketApiUrl() || 'https://api.socket.dev' // The single auth-missing message every tool returns when no token is // available — kept here so the wording stays identical across tools. export const AUTH_REQUIRED_MSG = - 'Authentication is required. Configure SOCKET_API_TOKEN (or a legacy alias) for stdio mode or connect through OAuth-enabled HTTP mode.' + 'Authentication is required. Set SOCKET_API_TOKEN (or a legacy alias) for stdio mode, or send your Socket API token as an `Authorization: Bearer ` header (or connect through OAuth) in HTTP mode.' -// Boot-time static API key (stdio mode reads it from SOCKET_API_TOKEN via -// setStaticApiKey in index.ts). Tools fall back to it when a request carries -// no per-request authInfo token. +// Boot-time static API key. In stdio mode this is the local user's own token +// (set from SOCKET_API_TOKEN in index.ts), so it is safe to use for any tool. +// In HTTP mode it is the deploy operator's token, shared across every caller — +// `staticApiKeyShared` records that distinction so per-tenant tools never hand +// the operator's private data to an arbitrary caller. let staticApiKey: string = '' +let staticApiKeyShared = false // Shared "auth missing" tool result — every tool returns the same shape so // clients get a consistent error. @@ -141,17 +144,43 @@ export function getStaticApiKey(): string { return staticApiKey } -// Resolve the access token a tool should use: the per-request OAuth token -// (HTTP mode) takes precedence, falling back to the boot-time static key -// (stdio mode). Returns undefined when neither is available. +// Resolve the access token a PUBLIC-data tool (depscore) should use: the +// per-request token takes precedence, then the boot-time static key. Falling +// back to a shared deploy key is fine here because package scores are not +// tenant-scoped. Returns undefined when neither is available. export function resolveAuthToken( authInfoToken: string | undefined, ): string | undefined { return authInfoToken || staticApiKey || undefined } -// Set the static API key. Called once during boot from index.ts. Subsequent -// calls overwrite — only the most recent value is used. -export function setStaticApiKey(value: string): void { +// Resolve the access token a PER-TENANT tool (organizations, alerts, +// threat_feed, package_files) should use. The per-request token always wins. +// The static key is only an acceptable fallback when it is the local user's +// own token (stdio mode); in HTTP mode the static key belongs to the deploy +// operator, so returning it would expose the operator's private org data to +// every caller. Returns undefined in that case so the tool emits +// AUTH_REQUIRED instead of silently acting as the operator. +export function resolveScopedAuthToken( + authInfoToken: string | undefined, +): string | undefined { + if (authInfoToken) { + return authInfoToken + } + if (!staticApiKeyShared && staticApiKey) { + return staticApiKey + } + return undefined +} + +// Set the static API key. Called once during boot from index.ts. `shared` +// marks the key as a deploy-operator key (HTTP mode) rather than the local +// user's own (stdio mode). Subsequent calls overwrite — only the most recent +// value is used. +export function setStaticApiKey( + value: string, + options?: { shared?: boolean | undefined } | undefined, +): void { staticApiKey = value + staticApiKeyShared = options?.shared ?? false } diff --git a/lib/tool-alerts.ts b/lib/tool-alerts.ts index d4097928..97ca9fe0 100644 --- a/lib/tool-alerts.ts +++ b/lib/tool-alerts.ts @@ -8,7 +8,7 @@ import { AUTH_REQUIRED_MSG, SOCKET_API_BASE_URL, authRequiredResult, - resolveAuthToken, + resolveScopedAuthToken, } from './server.ts' import type { ToolSpec } from './tool-types.ts' import { VERSION } from './version.ts' @@ -105,7 +105,7 @@ export function defineAlertsTool(): ToolSpec { }, 'tool invoked', ) - const accessToken = resolveAuthToken(extra.authInfo?.token) + const accessToken = resolveScopedAuthToken(extra.authInfo?.token) if (!accessToken) { logger.error('alerts: ' + AUTH_REQUIRED_MSG) return authRequiredResult() diff --git a/lib/tool-organizations.ts b/lib/tool-organizations.ts index ff73975c..308a6e5c 100644 --- a/lib/tool-organizations.ts +++ b/lib/tool-organizations.ts @@ -8,7 +8,7 @@ import { AUTH_REQUIRED_MSG, SOCKET_API_BASE_URL, authRequiredResult, - resolveAuthToken, + resolveScopedAuthToken, } from './server.ts' import type { ToolSpec } from './tool-types.ts' import { VERSION } from './version.ts' @@ -23,7 +23,7 @@ export function defineOrganizationsTool(): ToolSpec { annotations: { readOnlyHint: true }, async handler(_args, extra) { logger.info({ tool: 'organizations' }, 'tool invoked') - const accessToken = resolveAuthToken(extra.authInfo?.token) + const accessToken = resolveScopedAuthToken(extra.authInfo?.token) if (!accessToken) { logger.error('organizations: ' + AUTH_REQUIRED_MSG) return authRequiredResult() diff --git a/lib/tool-package-files.ts b/lib/tool-package-files.ts index 189430a4..f1f300de 100644 --- a/lib/tool-package-files.ts +++ b/lib/tool-package-files.ts @@ -11,7 +11,7 @@ import { AUTH_REQUIRED_MSG, SOCKET_API_BASE_URL, authRequiredResult, - resolveAuthToken, + resolveScopedAuthToken, } from './server.ts' import type { ToolSpec } from './tool-types.ts' @@ -331,7 +331,7 @@ export function definePackageFilesTool(): ToolSpec { }, 'tool invoked', ) - const accessToken = resolveAuthToken(extra.authInfo?.token) + const accessToken = resolveScopedAuthToken(extra.authInfo?.token) if (!accessToken) { logger.error('package_files: ' + AUTH_REQUIRED_MSG) return authRequiredResult() diff --git a/lib/tool-threat-feed.ts b/lib/tool-threat-feed.ts index 5b5dc576..47133036 100644 --- a/lib/tool-threat-feed.ts +++ b/lib/tool-threat-feed.ts @@ -7,7 +7,7 @@ import { AUTH_REQUIRED_MSG, SOCKET_API_BASE_URL, authRequiredResult, - resolveAuthToken, + resolveScopedAuthToken, } from './server.ts' import { fetchThreatFeed } from './threat-feed.ts' import type { ToolSpec } from './tool-types.ts' @@ -117,7 +117,7 @@ export function defineThreatFeedTool(): ToolSpec { }, 'tool invoked', ) - const accessToken = resolveAuthToken(extra.authInfo?.token) + const accessToken = resolveScopedAuthToken(extra.authInfo?.token) if (!accessToken) { logger.error('threat_feed: ' + AUTH_REQUIRED_MSG) return authRequiredResult() diff --git a/test/http-server.test.ts b/test/http-server.test.ts new file mode 100644 index 00000000..32d4b24e --- /dev/null +++ b/test/http-server.test.ts @@ -0,0 +1,35 @@ +import { expect, test } from 'vitest' + +import { applyClientApiKey } from '../lib/http-server.ts' +import type { AuthenticatedRequest } from '../lib/oauth.ts' + +function reqWith(authorization?: string): AuthenticatedRequest { + return { + headers: authorization === undefined ? {} : { authorization }, + } as unknown as AuthenticatedRequest +} + +test('applyClientApiKey forwards a Bearer token onto req.auth', () => { + const req = reqWith('Bearer sk-abc') + applyClientApiKey(req) + expect(req.auth?.token).toBe('sk-abc') + expect(req.auth?.clientId).toBe('socket-api-key') +}) + +test('applyClientApiKey is case-insensitive on the scheme', () => { + const req = reqWith('bearer sk-xyz') + applyClientApiKey(req) + expect(req.auth?.token).toBe('sk-xyz') +}) + +test('applyClientApiKey ignores a missing Authorization header', () => { + const req = reqWith() + applyClientApiKey(req) + expect(req.auth).toBeUndefined() +}) + +test('applyClientApiKey ignores a non-bearer scheme', () => { + const req = reqWith('Basic dXNlcjpwYXNz') + applyClientApiKey(req) + expect(req.auth).toBeUndefined() +}) diff --git a/test/server.test.ts b/test/server.test.ts new file mode 100644 index 00000000..16740a82 --- /dev/null +++ b/test/server.test.ts @@ -0,0 +1,46 @@ +import { afterEach, expect, test } from 'vitest' + +import { + resolveAuthToken, + resolveScopedAuthToken, + setStaticApiKey, +} from '../lib/server.ts' + +afterEach(() => { + // Reset module-level static-key state so cases don't leak into each other. + setStaticApiKey('') +}) + +test('resolveAuthToken prefers the per-request token', () => { + setStaticApiKey('static-key', { shared: true }) + expect(resolveAuthToken('req-token')).toBe('req-token') +}) + +test('resolveAuthToken falls back to the static key for public data', () => { + setStaticApiKey('static-key', { shared: true }) + expect(resolveAuthToken(undefined)).toBe('static-key') +}) + +test('resolveAuthToken returns undefined when nothing is set', () => { + expect(resolveAuthToken(undefined)).toBeUndefined() +}) + +test('resolveScopedAuthToken prefers the per-request token', () => { + setStaticApiKey('operator-key', { shared: true }) + expect(resolveScopedAuthToken('caller-token')).toBe('caller-token') +}) + +test('resolveScopedAuthToken uses the static key in stdio mode (user-owned)', () => { + setStaticApiKey('user-key', { shared: false }) + expect(resolveScopedAuthToken(undefined)).toBe('user-key') +}) + +test('resolveScopedAuthToken refuses a shared deploy key in HTTP mode', () => { + setStaticApiKey('operator-key', { shared: true }) + expect(resolveScopedAuthToken(undefined)).toBeUndefined() +}) + +test('setStaticApiKey defaults shared to false', () => { + setStaticApiKey('user-key') + expect(resolveScopedAuthToken(undefined)).toBe('user-key') +}) From 269acc08771b525c17e5957812f579069166f3c2 Mon Sep 17 00:00:00 2001 From: John Tuckner Date: Fri, 5 Jun 2026 08:50:04 -0500 Subject: [PATCH 03/10] docs: drop legacy-alias note from auth-required message --- README.md | 2 +- lib/server.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 056f4d99..4fc48e63 100644 --- a/README.md +++ b/README.md @@ -359,7 +359,7 @@ Generate a token from the [Socket dashboard](https://socket.dev/) under API toke export SOCKET_API_TOKEN="your-socket-api-token" ``` -When no token is available, these tools return: `Authentication is required. Configure SOCKET_API_TOKEN (or a legacy alias) for stdio mode or connect through OAuth-enabled HTTP mode.` +When no token is available, these tools return: `Authentication is required. Configure SOCKET_API_TOKEN for stdio mode or connect through OAuth-enabled HTTP mode.` ### Worked example: organization details and alerts diff --git a/lib/server.ts b/lib/server.ts index 9b441856..43a2dc72 100644 --- a/lib/server.ts +++ b/lib/server.ts @@ -42,7 +42,7 @@ export const SOCKET_API_BASE_URL = getSocketApiUrl() || 'https://api.socket.dev' // The single auth-missing message every tool returns when no token is // available — kept here so the wording stays identical across tools. export const AUTH_REQUIRED_MSG = - 'Authentication is required. Set SOCKET_API_TOKEN (or a legacy alias) for stdio mode, or send your Socket API token as an `Authorization: Bearer ` header (or connect through OAuth) in HTTP mode.' + 'Authentication is required. Set SOCKET_API_TOKEN for stdio mode, or send your Socket API token as an `Authorization: Bearer ` header (or connect through OAuth) in HTTP mode.' // Boot-time static API key. In stdio mode this is the local user's own token // (set from SOCKET_API_TOKEN in index.ts), so it is safe to use for any tool. From d718248e22cae0689a0ada866f0ab49ba0c74ace Mon Sep 17 00:00:00 2001 From: John Tuckner Date: Fri, 5 Jun 2026 09:06:55 -0500 Subject: [PATCH 04/10] style: format README with oxfmt --- README.md | 82 +++++++++++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 4fc48e63..1eca06f6 100644 --- a/README.md +++ b/README.md @@ -278,70 +278,70 @@ This tool needs a Socket API token. See [Authentication for organization-scoped List the latest security alerts for one Socket organization: supply-chain, vulnerability, quality, license, and maintenance issues across the org's monitored packages. Backed by `GET /v0/orgs/{org_slug}/alerts`. Results are paginated; pass the previous response's `endCursor` as `cursor` to fetch the next page. -| Parameter | Type | Required | Default | Description | -| --------------- | ------- | -------- | ------- | -------------------------------------------------------------------------------------------- | -| `org_slug` | String | ✅ Yes | - | Organization slug (get it from the `organizations` tool) | -| `severity` | String | No | - | Comma-separated subset of `low,medium,high,critical` | -| `status` | String | No | - | `open` or `cleared` | -| `category` | String | No | - | Comma-separated subset of `supplyChainRisk,maintenance,quality,license,vulnerability` | -| `artifact_type` | String | No | - | Comma-separated ecosystems: `npm,pypi,gem,maven,golang,nuget,cargo,chrome,openvsx` | -| `artifact_name` | String | No | - | Restrict to a single package name | -| `alert_type` | String | No | - | Comma-separated Socket alert types (e.g. `usesEval,unmaintained`) | -| `repo_slug` | String | No | - | Comma-separated repository slugs | -| `per_page` | Integer | No | `100` | Results per page (1–5000) | -| `cursor` | String | No | - | Pagination cursor — the `endCursor` from a previous response | +| Parameter | Type | Required | Default | Description | +| --------------- | ------- | -------- | ------- | ------------------------------------------------------------------------------------- | +| `org_slug` | String | ✅ Yes | - | Organization slug (get it from the `organizations` tool) | +| `severity` | String | No | - | Comma-separated subset of `low,medium,high,critical` | +| `status` | String | No | - | `open` or `cleared` | +| `category` | String | No | - | Comma-separated subset of `supplyChainRisk,maintenance,quality,license,vulnerability` | +| `artifact_type` | String | No | - | Comma-separated ecosystems: `npm,pypi,gem,maven,golang,nuget,cargo,chrome,openvsx` | +| `artifact_name` | String | No | - | Restrict to a single package name | +| `alert_type` | String | No | - | Comma-separated Socket alert types (e.g. `usesEval,unmaintained`) | +| `repo_slug` | String | No | - | Comma-separated repository slugs | +| `per_page` | Integer | No | `100` | Results per page (1–5000) | +| `cursor` | String | No | - | Pagination cursor — the `endCursor` from a previous response | #### threat_feed Look up items in a Socket organization's threat feed: packages recently flagged as malware, typosquats, obfuscated code, and similar. Backed by `GET /v0/orgs/{org_slug}/threat-feed`. The response carries a `nextPageCursor`; pass it as `cursor` to page forward. -| Parameter | Type | Required | Default | Description | -| ------------------- | ------- | -------- | -------------- | ---------------------------------------------------------------------------------------------------------- | -| `org_slug` | String | ✅ Yes | - | Organization slug (get it from the `organizations` tool) | -| `filter` | String | No | `mal` | Threat category: `mal` (malware), `vuln`, `typ` (typosquat), `obf` (obfuscated), `mjo`, `kes`, `spy`, etc. | -| `ecosystem` | String | No | - | Ecosystem: `npm`, `pypi`, `gem`, `maven`, `golang`, `nuget`, `cargo`, `chrome`, `openvsx`, `huggingface` | -| `name` | String | No | - | Filter by package name | -| `version` | String | No | - | Filter by package version | -| `is_human_reviewed` | Boolean | No | `false` | Only return human-reviewed items | -| `sort` | String | No | `updated_at` | Sort field: `id`, `created_at`, `updated_at` | -| `direction` | String | No | `desc` | Sort direction: `asc`, `desc` | -| `updated_after` | String | No | - | ISO timestamp; only items updated after this | -| `created_after` | String | No | - | ISO timestamp; only items created after this | -| `per_page` | Integer | No | `30` | Results per page (1–100) | -| `cursor` | String | No | - | Pagination cursor — the `nextPageCursor` from a previous response | +| Parameter | Type | Required | Default | Description | +| ------------------- | ------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------- | +| `org_slug` | String | ✅ Yes | - | Organization slug (get it from the `organizations` tool) | +| `filter` | String | No | `mal` | Threat category: `mal` (malware), `vuln`, `typ` (typosquat), `obf` (obfuscated), `mjo`, `kes`, `spy`, etc. | +| `ecosystem` | String | No | - | Ecosystem: `npm`, `pypi`, `gem`, `maven`, `golang`, `nuget`, `cargo`, `chrome`, `openvsx`, `huggingface` | +| `name` | String | No | - | Filter by package name | +| `version` | String | No | - | Filter by package version | +| `is_human_reviewed` | Boolean | No | `false` | Only return human-reviewed items | +| `sort` | String | No | `updated_at` | Sort field: `id`, `created_at`, `updated_at` | +| `direction` | String | No | `desc` | Sort direction: `asc`, `desc` | +| `updated_after` | String | No | - | ISO timestamp; only items updated after this | +| `created_after` | String | No | - | ISO timestamp; only items created after this | +| `per_page` | Integer | No | `30` | Results per page (1–100) | +| `cursor` | String | No | - | Pagination cursor — the `nextPageCursor` from a previous response | #### package_files List the files published in a package: a tree of paths and sizes for any package on a supported ecosystem. Use it to inspect what a dependency ships before installing it. Each entry prints a blob `hash` that `package_file_contents` and `package_file_grep` consume. -| Parameter | Type | Required | Default | Description | -| ------------ | ------ | -------- | ------- | -------------------------------------------------------------------------------------- | -| `ecosystem` | String | No | `npm` | `npm`, `pypi`, `gem`, `cargo`, `maven`, `golang`, `nuget`, `chrome`, `openvsx` | -| `depname` | String | ✅ Yes | - | Package name (e.g. `lodash`, `@babel/core`, `org.springframework:spring-core`) | -| `version` | String | ✅ Yes | - | Package version | -| `artifactId` | String | No | - | Per-version disambiguator (PyPI filename, Maven artifact id, NuGet asset) | +| Parameter | Type | Required | Default | Description | +| ------------ | ------ | -------- | ------- | --------------------------------------------------------------------------------------- | +| `ecosystem` | String | No | `npm` | `npm`, `pypi`, `gem`, `cargo`, `maven`, `golang`, `nuget`, `chrome`, `openvsx` | +| `depname` | String | ✅ Yes | - | Package name (e.g. `lodash`, `@babel/core`, `org.springframework:spring-core`) | +| `version` | String | ✅ Yes | - | Package version | +| `artifactId` | String | No | - | Per-version disambiguator (PyPI filename, Maven artifact id, NuGet asset) | | `platform` | String | No | - | Platform qualifier for per-OS/arch artifacts (e.g. openvsx `linux-x64`, `darwin-arm64`) | #### package_file_contents Read a single file from a package. Pass the `hash` printed next to an entry in `package_files` output. Returns up to 1 MB of UTF-8 text; binary files return metadata only. -| Parameter | Type | Required | Default | Description | -| --------- | ------ | -------- | ------- | ------------------------------------------------------ | -| `hash` | String | ✅ Yes | - | Blob hash from `package_files` | +| Parameter | Type | Required | Default | Description | +| --------- | ------ | -------- | ------- | ------------------------------------------------------- | +| `hash` | String | ✅ Yes | - | Blob hash from `package_files` | | `path` | String | No | - | File path, for display only; does not affect the lookup | #### package_file_grep Search a single file from a package for lines matching a JavaScript regular expression, returning matches with line numbers (grep -n style). The file is fetched once per session and cached, so repeated greps on the same hash skip the network. -| Parameter | Type | Required | Default | Description | -| ----------------- | ------- | -------- | ------- | ------------------------------------------------------ | -| `hash` | String | ✅ Yes | - | Blob hash from `package_files` | +| Parameter | Type | Required | Default | Description | +| ----------------- | ------- | -------- | ------- | ------------------------------------------------------- | +| `hash` | String | ✅ Yes | - | Blob hash from `package_files` | | `pattern` | String | ✅ Yes | - | JavaScript regular expression (plain literals work too) | -| `caseInsensitive` | Boolean | No | `false` | Match case-insensitively | -| `contextLines` | Integer | No | `0` | Lines of context before and after each match (0–5) | -| `maxMatches` | Integer | No | `100` | Cap on matching lines returned (1–500) | +| `caseInsensitive` | Boolean | No | `false` | Match case-insensitively | +| `contextLines` | Integer | No | `0` | Lines of context before and after each match (0–5) | +| `maxMatches` | Integer | No | `100` | Cap on matching lines returned (1–500) | | `path` | String | No | - | File path, for display only; does not affect the lookup | ### Authentication for organization-scoped tools From a56e09c43b0f3bc1aa055ee74b39c2be2e233480 Mon Sep 17 00:00:00 2001 From: annextuckner Date: Tue, 9 Jun 2026 09:40:05 -0500 Subject: [PATCH 05/10] Update README.md Co-authored-by: John-David Dalton Signed-off-by: annextuckner --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1eca06f6..a3703580 100644 --- a/README.md +++ b/README.md @@ -359,7 +359,7 @@ Generate a token from the [Socket dashboard](https://socket.dev/) under API toke export SOCKET_API_TOKEN="your-socket-api-token" ``` -When no token is available, these tools return: `Authentication is required. Configure SOCKET_API_TOKEN for stdio mode or connect through OAuth-enabled HTTP mode.` +When no token is available, these tools return an authentication-required error explaining how to supply one for each transport. ### Worked example: organization details and alerts From 524d035e4ffacd85ca643c500b1ebda0a9ca7b85 Mon Sep 17 00:00:00 2001 From: John Tuckner Date: Wed, 10 Jun 2026 11:03:37 -0500 Subject: [PATCH 06/10] style: export top-level surface and sort imports/equality disjunctions --- hooks/socket-gate/index.mts | 4 ++-- lib/artifacts.ts | 2 +- lib/blob.ts | 6 +++--- lib/files.ts | 6 +++--- lib/http-helpers.ts | 2 +- lib/http-server.ts | 4 ++-- lib/tool-alerts.ts | 4 ++-- lib/tool-organizations.ts | 2 +- lib/tool-package-files.ts | 8 ++++---- lib/tool-threat-feed.ts | 4 ++-- mock-client/debug-client.ts | 2 +- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/hooks/socket-gate/index.mts b/hooks/socket-gate/index.mts index f02807cb..23e69a25 100644 --- a/hooks/socket-gate/index.mts +++ b/hooks/socket-gate/index.mts @@ -36,9 +36,9 @@ const MCP_URL = 'https://mcp.socket.dev/' const SUPPLY_CHAIN_THRESHOLD = 20 const REQUEST_TIMEOUT_MS = 10_000 -type Ecosystem = 'npm' | 'pypi' | 'cargo' | 'gem' | 'golang' | 'nuget' +export type Ecosystem = 'npm' | 'pypi' | 'cargo' | 'gem' | 'golang' | 'nuget' -interface HookInput { +export interface HookInput { session_id: string tool_name: string tool_input: Record | string diff --git a/lib/artifacts.ts b/lib/artifacts.ts index 6672f38b..8b7a65fc 100644 --- a/lib/artifacts.ts +++ b/lib/artifacts.ts @@ -9,7 +9,7 @@ export interface ArtifactData { [key: string]: unknown } -type PlatformPattern = RegExp +export type PlatformPattern = RegExp const PLATFORM_PATTERNS: Record = { 'darwin-arm64': [/macosx.*arm64/i], diff --git a/lib/blob.ts b/lib/blob.ts index 81e249b5..aafc258c 100644 --- a/lib/blob.ts +++ b/lib/blob.ts @@ -23,19 +23,19 @@ export interface FetchBlobOptions { const DEFAULT_MAX_BYTES = 1024 * 1024 // 1 MB -interface ChunkedManifest { +export interface ChunkedManifest { _version?: string | undefined size?: number | undefined chunks?: unknown | undefined offset?: unknown | undefined } -interface RawFetchResult { +export interface RawFetchResult { bytes: Uint8Array contentType: string | undefined } -interface ChunkedFetchResult { +export interface ChunkedFetchResult { // Concatenated chunk bytes, possibly less than `totalSize` when stopped // early at maxBytes. bytes: Uint8Array diff --git a/lib/files.ts b/lib/files.ts index 33a48980..ed33af66 100644 --- a/lib/files.ts +++ b/lib/files.ts @@ -61,18 +61,18 @@ export interface FetchFileListOptions { onRequest?: ((url: string) => void) | undefined } -interface RawFileEntry { +export interface RawFileEntry { path?: unknown | undefined type?: unknown | undefined size?: unknown | undefined hash?: unknown | undefined } -interface RawFileListResponse { +export interface RawFileListResponse { files?: RawFileEntry[] | undefined } -interface TreeNode { +export interface TreeNode { name: string isFile: boolean size?: number | undefined diff --git a/lib/http-helpers.ts b/lib/http-helpers.ts index fdb1cf3e..07f6a8a6 100644 --- a/lib/http-helpers.ts +++ b/lib/http-helpers.ts @@ -42,7 +42,7 @@ export function assertSafeHttpUrl( throw new Error(`${label} must be http(s): ${rawUrl}`) } const host = url.hostname.toLowerCase() - const isLocal = host === '127.0.0.1' || host === '::1' || host === 'localhost' + const isLocal = host === '::1' || host === '127.0.0.1' || host === 'localhost' if (isLocal && allowLocalhost) { return url } diff --git a/lib/http-server.ts b/lib/http-server.ts index 9274746b..fcb32925 100644 --- a/lib/http-server.ts +++ b/lib/http-server.ts @@ -13,12 +13,12 @@ import { } from './http-helpers.ts' import { logger } from './logger.ts' import { - OAUTH_PROTECTED_RESOURCE_METADATA_PATH, authenticateRequest, buildProtectedResourceMetadata, getProtectedResourceMetadataUrl, isOauthEnabled, loadOAuthMetadata, + OAUTH_PROTECTED_RESOURCE_METADATA_PATH, } from './oauth.ts' import type { AuthenticatedRequest } from './oauth.ts' import { VERSION } from './version.ts' @@ -26,7 +26,7 @@ import { VERSION } from './version.ts' // Per-session record. Both transport and server must persist for the // session lifetime — storing the server prevents GC from reclaiming it // before subsequent RPC calls. -interface Session { +export interface Session { transport: StreamableHTTPServerTransport server: Server lastActivity: number diff --git a/lib/tool-alerts.ts b/lib/tool-alerts.ts index 97ca9fe0..cb5ed3c0 100644 --- a/lib/tool-alerts.ts +++ b/lib/tool-alerts.ts @@ -6,14 +6,14 @@ import { fetchAlerts } from './alerts.ts' import { logger } from './logger.ts' import { AUTH_REQUIRED_MSG, - SOCKET_API_BASE_URL, authRequiredResult, resolveScopedAuthToken, + SOCKET_API_BASE_URL, } from './server.ts' import type { ToolSpec } from './tool-types.ts' import { VERSION } from './version.ts' -interface AlertsArgs { +export interface AlertsArgs { org_slug: string severity?: string | undefined status?: 'open' | 'cleared' | undefined diff --git a/lib/tool-organizations.ts b/lib/tool-organizations.ts index 308a6e5c..b08f1c19 100644 --- a/lib/tool-organizations.ts +++ b/lib/tool-organizations.ts @@ -6,9 +6,9 @@ import { logger } from './logger.ts' import { fetchOrganizations } from './organizations.ts' import { AUTH_REQUIRED_MSG, - SOCKET_API_BASE_URL, authRequiredResult, resolveScopedAuthToken, + SOCKET_API_BASE_URL, } from './server.ts' import type { ToolSpec } from './tool-types.ts' import { VERSION } from './version.ts' diff --git a/lib/tool-package-files.ts b/lib/tool-package-files.ts index f1f300de..a7d92625 100644 --- a/lib/tool-package-files.ts +++ b/lib/tool-package-files.ts @@ -9,15 +9,15 @@ import { debug, logger } from './logger.ts' import { buildPurl } from './purl.ts' import { AUTH_REQUIRED_MSG, - SOCKET_API_BASE_URL, authRequiredResult, resolveScopedAuthToken, + SOCKET_API_BASE_URL, } from './server.ts' import type { ToolSpec } from './tool-types.ts' const INTERNAL_USER_AGENT = getSocketInternalUserAgent() -interface PackageFilesArgs { +export interface PackageFilesArgs { ecosystem?: string | undefined depname: string version: string @@ -25,12 +25,12 @@ interface PackageFilesArgs { platform?: string | undefined } -interface PackageFileContentsArgs { +export interface PackageFileContentsArgs { hash: string path?: string | undefined } -interface PackageFileGrepArgs { +export interface PackageFileGrepArgs { hash: string pattern: string caseInsensitive?: boolean | undefined diff --git a/lib/tool-threat-feed.ts b/lib/tool-threat-feed.ts index 47133036..9eac0f3a 100644 --- a/lib/tool-threat-feed.ts +++ b/lib/tool-threat-feed.ts @@ -5,15 +5,15 @@ import { errorMessage } from '@socketsecurity/lib/errors' import { logger } from './logger.ts' import { AUTH_REQUIRED_MSG, - SOCKET_API_BASE_URL, authRequiredResult, resolveScopedAuthToken, + SOCKET_API_BASE_URL, } from './server.ts' import { fetchThreatFeed } from './threat-feed.ts' import type { ToolSpec } from './tool-types.ts' import { VERSION } from './version.ts' -interface ThreatFeedArgs { +export interface ThreatFeedArgs { org_slug: string filter?: string | undefined ecosystem?: string | undefined diff --git a/mock-client/debug-client.ts b/mock-client/debug-client.ts index ae638fc3..fb863b7b 100644 --- a/mock-client/debug-client.ts +++ b/mock-client/debug-client.ts @@ -7,7 +7,7 @@ import { getDefaultLogger } from '@socketsecurity/lib/logger/default' const logger = getDefaultLogger() // Simple JSON-RPC client for testing MCP server -class SimpleJSONRPCClient { +export class SimpleJSONRPCClient { private spawned: ReturnType private rl: readline.Interface private requestId = 1 From 6202b5461f977e37f4a8f6190acf345ac9654cbc Mon Sep 17 00:00:00 2001 From: John Tuckner Date: Wed, 10 Jun 2026 12:36:41 -0500 Subject: [PATCH 07/10] style: mark socket-gate stdio writes with process-stdio lint marker --- hooks/socket-gate/index.mts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hooks/socket-gate/index.mts b/hooks/socket-gate/index.mts index 23e69a25..8e07daad 100644 --- a/hooks/socket-gate/index.mts +++ b/hooks/socket-gate/index.mts @@ -184,7 +184,7 @@ export function outputAllow(): void { permissionDecision: 'allow', }, }) - process.stdout.write(payload) // socket-hook: allow console + process.stdout.write(payload) // socket-lint: allow process-stdio } export function outputDeny(reason: string): void { @@ -195,7 +195,7 @@ export function outputDeny(reason: string): void { permissionDecisionReason: reason, }, }) - process.stdout.write(payload) // socket-hook: allow console + process.stdout.write(payload) // socket-lint: allow process-stdio } export function parseSupplyChainScore(text: string): number | undefined { @@ -274,7 +274,7 @@ async function main(): Promise { // not a hard gate — see the file header). Surface the error on stderr so // the failure is observable; stdout stays the allow/deny IPC channel. const errLine = `socket-gate: check failed for ${target.ecosystem}/${target.name}, failing open: ${errorMessage(e)}\n` - process.stderr.write(errLine) // socket-hook: allow console + process.stderr.write(errLine) // socket-lint: allow process-stdio outputAllow() } } From ade04524dc90e146366b5eefba4d24a120b3027b Mon Sep 17 00:00:00 2001 From: John Tuckner Date: Wed, 10 Jun 2026 14:23:55 -0500 Subject: [PATCH 08/10] chore(deps): pin untracked to soaked 1.6.0 and sync lockfile --- pnpm-lock.yaml | 152 ++++++++++++++++++++++---------------------- pnpm-workspace.yaml | 2 +- 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d19267d6..481afaeb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -25,8 +25,8 @@ catalogs: specifier: 4.1.6 version: 4.1.6 rolldown: - specifier: 1.0.3 - version: 1.0.3 + specifier: 1.1.0 + version: 1.1.0 shell-quote: specifier: 1.8.4 version: 1.8.4 @@ -34,8 +34,8 @@ catalogs: specifier: 19.11.0 version: 19.11.0 untracked: - specifier: 1.6.1 - version: 1.6.1 + specifier: 1.6.0 + version: 1.6.0 vitest: specifier: 4.1.6 version: 4.1.6 @@ -119,7 +119,7 @@ importers: version: 1.63.0 rolldown: specifier: 'catalog:' - version: 1.0.3 + version: 1.1.0 shell-quote: specifier: 'catalog:' version: 1.8.4 @@ -128,7 +128,7 @@ importers: version: 19.11.0 untracked: specifier: 'catalog:' - version: 1.6.1 + version: 1.6.0 vitest: specifier: 'catalog:' version: 4.1.6(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(vite@8.0.14(@types/node@24.12.4)(jiti@2.7.0)(yaml@2.8.4)) @@ -313,8 +313,8 @@ packages: '@oxc-project/types@0.132.0': resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} - '@oxc-project/types@0.133.0': - resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + '@oxc-project/types@0.134.0': + resolution: {integrity: sha512-T0xuRRKrQFmocH8y+jGfpmSkGcheaJExY9lEihmR1Gm2aH+75B8CzgU2rABRQSzzDxLjZ15Sc0bRVLj5lVeNXQ==} '@oxfmt/binding-android-arm-eabi@0.48.0': resolution: {integrity: sha512-uwqk+/KhQvBIpULD8SMM/zAafMRC/+DV/xsEQjkkIsJ/kLmEI/2bxonVowcYTiXqqZ/a0FEW8DPkZY3VvwELDA==} @@ -619,8 +619,8 @@ packages: cpu: [arm64] os: [android] - '@rolldown/binding-android-arm64@1.0.3': - resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + '@rolldown/binding-android-arm64@1.1.0': + resolution: {integrity: sha512-gCYzGOSkYY6Z034suzd20euvds7lPzMEEla62DJGE/ZAlR4OMBnNbvnBSsIGUCAr52gaWMsloGxP4tVGtN5aCA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] @@ -631,8 +631,8 @@ packages: cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-arm64@1.0.3': - resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + '@rolldown/binding-darwin-arm64@1.1.0': + resolution: {integrity: sha512-JQBD77MNgu+4Z6RAyg69acugdrhhVoWesr3l47zohYZ2YV2fwkWMArkN/2p4l6Ei+Sno7W5q+UsKdVWq5Ens0w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] @@ -643,8 +643,8 @@ packages: cpu: [x64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.3': - resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + '@rolldown/binding-darwin-x64@1.1.0': + resolution: {integrity: sha512-p/8cXUTK4Sob604e+xxPhVSbDFf29E6J0l/xESM9rdCfn3aDai3nEs6TnMHUsdD5aNlFz0+gDbiGlozLKGa2YA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] @@ -655,8 +655,8 @@ packages: cpu: [x64] os: [freebsd] - '@rolldown/binding-freebsd-x64@1.0.3': - resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + '@rolldown/binding-freebsd-x64@1.1.0': + resolution: {integrity: sha512-KbtOSlVv6fElujiZWMcC3aQYhEwLVVf073RcwlSmpGQvIsKZFUqc0ef4sjUuurRwfbiI6JJXji9DQn+86hawmQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] @@ -667,8 +667,8 @@ packages: cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': - resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + '@rolldown/binding-linux-arm-gnueabihf@1.1.0': + resolution: {integrity: sha512-9fZ9i0o0/MQaw7om6Z6TsT7tfCk0jtbEFtC+aPqZL5RNsGWNcHvn6EHgL3dAprjq+AZzPTAQjg2JtpJaMt+6pg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] @@ -680,8 +680,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-gnu@1.0.3': - resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + '@rolldown/binding-linux-arm64-gnu@1.1.0': + resolution: {integrity: sha512-+tog7T66i+yFyIuuAnjL6xmW182W/qTBOUt6BtQ6lBIM1Eikh/fSMz4HGgvuCp5uU0zuIVWng7kDYthjCMOHcg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] @@ -694,8 +694,8 @@ packages: os: [linux] libc: [musl] - '@rolldown/binding-linux-arm64-musl@1.0.3': - resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + '@rolldown/binding-linux-arm64-musl@1.1.0': + resolution: {integrity: sha512-4b7yruLIIj/oZ3GpcLOvxcLCLDMraohn3IhQfN2hBP4w9UekG0DTIajWguJosRGfySf/+h/NwRUiMKoCpxCrqQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] @@ -708,8 +708,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-ppc64-gnu@1.0.3': - resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + '@rolldown/binding-linux-ppc64-gnu@1.1.0': + resolution: {integrity: sha512-QRDOVZd0bhQ5jLsUsCC3dUxDWdTSVY9WMznowZgCGOrZfLLgctWpelhUASEiBwsXfat/JwYnVd1EaxMhqyT+UQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] @@ -722,8 +722,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.0.3': - resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + '@rolldown/binding-linux-s390x-gnu@1.1.0': + resolution: {integrity: sha512-ypxT+Hq76NFG7woFbNbySnGEajFuYuIXeKz/jfCU+lXUoxfi3zLE6OG/ZQNeK3RpZSYJlAe2bokpsQ046CaieQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] @@ -736,8 +736,8 @@ packages: os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.3': - resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + '@rolldown/binding-linux-x64-gnu@1.1.0': + resolution: {integrity: sha512-IdovCmfROFmpTLahdecTDFL74aLERVYN68F/mLZjfVh6LfoplPfI6deyHNMTcVujbokDV5k05XrFO22zfv+qjg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] @@ -750,8 +750,8 @@ packages: os: [linux] libc: [musl] - '@rolldown/binding-linux-x64-musl@1.0.3': - resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + '@rolldown/binding-linux-x64-musl@1.1.0': + resolution: {integrity: sha512-pcA8xlFp2tyk9T2R6Fi/rPe3bQ1MA+sSMDNUU5Ogu80GHOatkE4P8YCreGAvZErm5Ho2YRXnyvNrWiRncfVysQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] @@ -763,8 +763,8 @@ packages: cpu: [arm64] os: [openharmony] - '@rolldown/binding-openharmony-arm64@1.0.3': - resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + '@rolldown/binding-openharmony-arm64@1.1.0': + resolution: {integrity: sha512-4+fexHayrLCWpriPh4c6dNvL4an34DEZCG7zOM/FD5QNF6h8DT+bDXzyB/kfC8lDJbaFb7jKShtnjDQFXVQEjg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] @@ -774,8 +774,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-wasm32-wasi@1.0.3': - resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} + '@rolldown/binding-wasm32-wasi@1.1.0': + resolution: {integrity: sha512-SbL++MNmOw6QamrwIGDMSSfM4ceTzFr+RjbOExJSLLBinScU4WI5OdA413h1qwPw2yH7lVF1+H4svQ+6mSXKTQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] @@ -785,8 +785,8 @@ packages: cpu: [arm64] os: [win32] - '@rolldown/binding-win32-arm64-msvc@1.0.3': - resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + '@rolldown/binding-win32-arm64-msvc@1.1.0': + resolution: {integrity: sha512-+xTE6XC7wBgk0VKRXGG+QAnyW5S9b8vfsFpiMjf0waQTmSQSU8onsH/beyZ8X4aXVveJnotiy7VDjLOaW8bTrg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] @@ -797,8 +797,8 @@ packages: cpu: [x64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.3': - resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + '@rolldown/binding-win32-x64-msvc@1.1.0': + resolution: {integrity: sha512-Ogji1TQNqH3ACLnYr+1Ns1nyrJ0CO2P585u9Hsh02pXvtFiFpgtgT2b3P4PnCOU86VVCvqtAeCN4OftMT8KU4w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1825,8 +1825,8 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rolldown@1.0.3: - resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + rolldown@1.1.0: + resolution: {integrity: sha512-zpMvlJhs5PkXRTtKc0CaLBVI9AR/VDiJFpM+kx//hgToEca7FgMlGjaRIisXBcb19T76LswgmKECSQ96hjWr5A==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -2035,8 +2035,8 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - untracked@1.6.1: - resolution: {integrity: sha512-ECzmcyT4BcWAqplpHvK5dIGzPfclTIO4X7oyvnAGNOD3+AR49yk9Qoq42OKJR6nX1dTOKsVgrSv2/jjoyYDZ4Q==} + untracked@1.6.0: + resolution: {integrity: sha512-rFv+kRCCSjt3x8JBNSd5RlhOJEYzNlZV4sVJkZf6UKP5Srj3VlvnHpkd4JbFQfgz/da/E1gRtVQsHqdhTgjfww==} engines: {node: '>= 6'} hasBin: true @@ -2456,7 +2456,7 @@ snapshots: '@oxc-project/types@0.132.0': {} - '@oxc-project/types@0.133.0': {} + '@oxc-project/types@0.134.0': {} '@oxfmt/binding-android-arm-eabi@0.48.0': optional: true @@ -2625,73 +2625,73 @@ snapshots: '@rolldown/binding-android-arm64@1.0.2': optional: true - '@rolldown/binding-android-arm64@1.0.3': + '@rolldown/binding-android-arm64@1.1.0': optional: true '@rolldown/binding-darwin-arm64@1.0.2': optional: true - '@rolldown/binding-darwin-arm64@1.0.3': + '@rolldown/binding-darwin-arm64@1.1.0': optional: true '@rolldown/binding-darwin-x64@1.0.2': optional: true - '@rolldown/binding-darwin-x64@1.0.3': + '@rolldown/binding-darwin-x64@1.1.0': optional: true '@rolldown/binding-freebsd-x64@1.0.2': optional: true - '@rolldown/binding-freebsd-x64@1.0.3': + '@rolldown/binding-freebsd-x64@1.1.0': optional: true '@rolldown/binding-linux-arm-gnueabihf@1.0.2': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + '@rolldown/binding-linux-arm-gnueabihf@1.1.0': optional: true '@rolldown/binding-linux-arm64-gnu@1.0.2': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.3': + '@rolldown/binding-linux-arm64-gnu@1.1.0': optional: true '@rolldown/binding-linux-arm64-musl@1.0.2': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.3': + '@rolldown/binding-linux-arm64-musl@1.1.0': optional: true '@rolldown/binding-linux-ppc64-gnu@1.0.2': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.3': + '@rolldown/binding-linux-ppc64-gnu@1.1.0': optional: true '@rolldown/binding-linux-s390x-gnu@1.0.2': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.3': + '@rolldown/binding-linux-s390x-gnu@1.1.0': optional: true '@rolldown/binding-linux-x64-gnu@1.0.2': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.3': + '@rolldown/binding-linux-x64-gnu@1.1.0': optional: true '@rolldown/binding-linux-x64-musl@1.0.2': optional: true - '@rolldown/binding-linux-x64-musl@1.0.3': + '@rolldown/binding-linux-x64-musl@1.1.0': optional: true '@rolldown/binding-openharmony-arm64@1.0.2': optional: true - '@rolldown/binding-openharmony-arm64@1.0.3': + '@rolldown/binding-openharmony-arm64@1.1.0': optional: true '@rolldown/binding-wasm32-wasi@1.0.2': @@ -2701,7 +2701,7 @@ snapshots: '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-wasm32-wasi@1.0.3': + '@rolldown/binding-wasm32-wasi@1.1.0': dependencies: '@emnapi/core': 1.10.0 '@emnapi/runtime': 1.10.0 @@ -2711,13 +2711,13 @@ snapshots: '@rolldown/binding-win32-arm64-msvc@1.0.2': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.3': + '@rolldown/binding-win32-arm64-msvc@1.1.0': optional: true '@rolldown/binding-win32-x64-msvc@1.0.2': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.3': + '@rolldown/binding-win32-x64-msvc@1.1.0': optional: true '@rolldown/pluginutils@1.0.1': {} @@ -3721,26 +3721,26 @@ snapshots: '@rolldown/binding-win32-arm64-msvc': 1.0.2 '@rolldown/binding-win32-x64-msvc': 1.0.2 - rolldown@1.0.3: + rolldown@1.1.0: dependencies: - '@oxc-project/types': 0.133.0 + '@oxc-project/types': 0.134.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.3 - '@rolldown/binding-darwin-arm64': 1.0.3 - '@rolldown/binding-darwin-x64': 1.0.3 - '@rolldown/binding-freebsd-x64': 1.0.3 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 - '@rolldown/binding-linux-arm64-gnu': 1.0.3 - '@rolldown/binding-linux-arm64-musl': 1.0.3 - '@rolldown/binding-linux-ppc64-gnu': 1.0.3 - '@rolldown/binding-linux-s390x-gnu': 1.0.3 - '@rolldown/binding-linux-x64-gnu': 1.0.3 - '@rolldown/binding-linux-x64-musl': 1.0.3 - '@rolldown/binding-openharmony-arm64': 1.0.3 - '@rolldown/binding-wasm32-wasi': 1.0.3 - '@rolldown/binding-win32-arm64-msvc': 1.0.3 - '@rolldown/binding-win32-x64-msvc': 1.0.3 + '@rolldown/binding-android-arm64': 1.1.0 + '@rolldown/binding-darwin-arm64': 1.1.0 + '@rolldown/binding-darwin-x64': 1.1.0 + '@rolldown/binding-freebsd-x64': 1.1.0 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.0 + '@rolldown/binding-linux-arm64-gnu': 1.1.0 + '@rolldown/binding-linux-arm64-musl': 1.1.0 + '@rolldown/binding-linux-ppc64-gnu': 1.1.0 + '@rolldown/binding-linux-s390x-gnu': 1.1.0 + '@rolldown/binding-linux-x64-gnu': 1.1.0 + '@rolldown/binding-linux-x64-musl': 1.1.0 + '@rolldown/binding-openharmony-arm64': 1.1.0 + '@rolldown/binding-wasm32-wasi': 1.1.0 + '@rolldown/binding-win32-arm64-msvc': 1.1.0 + '@rolldown/binding-win32-x64-msvc': 1.1.0 router@2.2.0: dependencies: @@ -3973,7 +3973,7 @@ snapshots: unpipe@1.0.0: {} - untracked@1.6.1: + untracked@1.6.0: dependencies: joycon: 3.1.1 lodash: 4.18.1 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 47420d01..7a92058a 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -38,7 +38,7 @@ catalog: 'rolldown': 1.1.0 'shell-quote': 1.8.4 'taze': 19.11.0 - 'untracked': 1.6.1 + 'untracked': 1.6.0 'vitest': 4.1.6 enablePrePostScripts: true From 911edcd42d172d8bdabeaa3c06470bad2e8a3cba Mon Sep 17 00:00:00 2001 From: John Tuckner Date: Wed, 10 Jun 2026 14:33:58 -0500 Subject: [PATCH 09/10] chore(deps): declare regjsparser so the oxlint plugin loads --- package.json | 1 + pnpm-lock.yaml | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/package.json b/package.json index 552b8fa1..d5e5bfbc 100644 --- a/package.json +++ b/package.json @@ -85,6 +85,7 @@ "npm-run-all2": "^8.0.4", "oxfmt": "0.48.0", "oxlint": "1.63.0", + "regjsparser": "catalog:", "rolldown": "catalog:", "shell-quote": "catalog:", "taze": "catalog:", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 481afaeb..79c693d5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,6 +24,9 @@ catalogs: '@vitest/coverage-v8': specifier: 4.1.6 version: 4.1.6 + regjsparser: + specifier: 0.13.1 + version: 0.13.1 rolldown: specifier: 1.1.0 version: 1.1.0 @@ -117,6 +120,9 @@ importers: oxlint: specifier: 1.63.0 version: 1.63.0 + regjsparser: + specifier: 'catalog:' + version: 0.13.1 rolldown: specifier: 'catalog:' version: 1.1.0 @@ -1455,6 +1461,11 @@ packages: js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + json-parse-even-better-errors@4.0.0: resolution: {integrity: sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==} engines: {node: ^18.17.0 || >=20.5.0} @@ -1808,6 +1819,10 @@ packages: resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} engines: {node: '>=12'} + regjsparser@0.13.1: + resolution: {integrity: sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==} + hasBin: true + require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -3350,6 +3365,8 @@ snapshots: js-tokens@10.0.0: {} + jsesc@3.1.0: {} + json-parse-even-better-errors@4.0.0: {} json-schema-traverse@1.0.0: {} @@ -3691,6 +3708,10 @@ snapshots: dependencies: rc: 1.2.8 + regjsparser@0.13.1: + dependencies: + jsesc: 3.1.0 + require-directory@2.1.1: {} require-from-string@2.0.2: {} From 8491c3a0f2d2851c4e8bd46f542294efb446878f Mon Sep 17 00:00:00 2001 From: John Tuckner Date: Wed, 10 Jun 2026 14:33:58 -0500 Subject: [PATCH 10/10] style: comment complex regexes and exempt http-server from soft line cap --- hooks/socket-gate/index.mts | 10 +++++----- lib/artifacts.ts | 2 +- lib/http-server.ts | 4 ++++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/hooks/socket-gate/index.mts b/hooks/socket-gate/index.mts index 8e07daad..702882c1 100644 --- a/hooks/socket-gate/index.mts +++ b/hooks/socket-gate/index.mts @@ -45,13 +45,13 @@ export interface HookInput { } const INSTALL_PATTERNS: Array<{ ecosystem: Ecosystem; pattern: RegExp }> = [ - { ecosystem: 'npm', pattern: /\bnpm\s+(?:add|i|install)\s+([^\s-][^\s]*)/i }, + { ecosystem: 'npm', pattern: /\bnpm\s+(?:add|i|install)\s+([^\s-][^\s]*)/i }, // socket-lint: allow uncommented-regex { ecosystem: 'npm', pattern: /\byarn\s+add\s+([^\s-][^\s]*)/i }, { ecosystem: 'npm', pattern: /\bpnpm\s+add\s+([^\s-][^\s]*)/i }, { ecosystem: 'npm', pattern: /\bbun\s+add\s+([^\s-][^\s]*)/i }, { ecosystem: 'pypi', - pattern: /(?:\bpython3?\s+-m\s+)?\bpip3?\s+install\s+([^\s-][^\s]*)/i, + pattern: /(?:\bpython3?\s+-m\s+)?\bpip3?\s+install\s+([^\s-][^\s]*)/i, // socket-lint: allow uncommented-regex }, { ecosystem: 'pypi', pattern: /\buv\s+add\s+([^\s-][^\s]*)/i }, { ecosystem: 'pypi', pattern: /\buv\s+pip\s+install\s+([^\s-][^\s]*)/i }, @@ -59,11 +59,11 @@ const INSTALL_PATTERNS: Array<{ ecosystem: Ecosystem; pattern: RegExp }> = [ { ecosystem: 'pypi', pattern: /\bpipenv\s+install\s+([^\s-][^\s]*)/i }, { ecosystem: 'cargo', - pattern: /\bcargo\s+(?:add|install)\s+([^\s-][^\s]*)/i, + pattern: /\bcargo\s+(?:add|install)\s+([^\s-][^\s]*)/i, // socket-lint: allow uncommented-regex }, { ecosystem: 'gem', pattern: /\bgem\s+install\s+([^\s-][^\s]*)/i }, { ecosystem: 'gem', pattern: /\bbundle\s+add\s+([^\s-][^\s]*)/i }, - { ecosystem: 'golang', pattern: /\bgo\s+(?:get|install)\s+([^\s-][^\s]*)/i }, + { ecosystem: 'golang', pattern: /\bgo\s+(?:get|install)\s+([^\s-][^\s]*)/i }, // socket-lint: allow uncommented-regex { ecosystem: 'nuget', pattern: /\bdotnet\s+add\s+package\s+([^\s-][^\s]*)/i }, { ecosystem: 'nuget', pattern: /\bnuget\s+install\s+([^\s-][^\s]*)/i }, ] @@ -199,7 +199,7 @@ export function outputDeny(reason: string): void { } export function parseSupplyChainScore(text: string): number | undefined { - const match = text.match(/supplyChain:\s*(\d+(?:\.\d+)?)/i) + const match = text.match(/supplyChain:\s*(\d+(?:\.\d+)?)/i) // socket-lint: allow uncommented-regex return match ? Number(match[1]) : undefined } diff --git a/lib/artifacts.ts b/lib/artifacts.ts index 8b7a65fc..189aed25 100644 --- a/lib/artifacts.ts +++ b/lib/artifacts.ts @@ -14,7 +14,7 @@ export type PlatformPattern = RegExp const PLATFORM_PATTERNS: Record = { 'darwin-arm64': [/macosx.*arm64/i], 'darwin-x64': [/macosx.*x86_64/i], - 'linux-arm64': [/(linux|manylinux).*(aarch64|arm64)/i], + 'linux-arm64': [/(linux|manylinux).*(aarch64|arm64)/i], // socket-lint: allow uncommented-regex 'linux-x64': [/(linux|manylinux).*x86_64/i], 'win32-ia32': [/win.*win32/i], 'win32-x64': [/win.*(amd64|x86_64)/i], diff --git a/lib/http-server.ts b/lib/http-server.ts index 7b564ae3..3f3f335c 100644 --- a/lib/http-server.ts +++ b/lib/http-server.ts @@ -1,3 +1,7 @@ +// max-file-lines: transport — HTTP transport module: session lifecycle, +// request routing (GET/POST/DELETE), and the post-body size guard are one +// cohesive unit that reads top-to-bottom; splitting would scatter the +// request path across files. import type { Server } from '@modelcontextprotocol/sdk/server/index.js' import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js' import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'