diff --git a/.claude/hooks/check-new-deps/package.json b/.claude/hooks/check-new-deps/package.json
index ebfb39ac1..96d04649b 100644
--- a/.claude/hooks/check-new-deps/package.json
+++ b/.claude/hooks/check-new-deps/package.json
@@ -10,9 +10,9 @@
"test": "node --test test/*.test.mts"
},
"dependencies": {
- "@socketregistry/packageurl-js": "1.4.2",
- "@socketsecurity/lib": "5.18.2",
- "@socketsecurity/sdk": "4.0.1"
+ "@socketregistry/packageurl-js": "catalog:",
+ "@socketsecurity/lib": "catalog:",
+ "@socketsecurity/sdk": "catalog:"
},
"devDependencies": {
"@types/node": "24.9.2"
diff --git a/.claude/hooks/setup-security-tools/package.json b/.claude/hooks/setup-security-tools/package.json
index af78c9855..f8ecc76cb 100644
--- a/.claude/hooks/setup-security-tools/package.json
+++ b/.claude/hooks/setup-security-tools/package.json
@@ -4,6 +4,6 @@
"type": "module",
"main": "./index.mts",
"dependencies": {
- "@socketsecurity/lib": "5.18.2"
+ "@socketsecurity/lib": "catalog:"
}
}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 254a4c98c..931edecca 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -109,7 +109,7 @@ jobs:
export default { text, view, renderToString, renderToStringWithWidth, printComponent, eprintComponent, getTerminalSize, TuiRenderer, init }
CODE
- - uses: SocketDev/socket-registry/.github/actions/setup-and-install@bbe46386c0a2bc6baefd02916234956a38e622d5 # main
+ - uses: SocketDev/socket-registry/.github/actions/setup-and-install@3362af95fadd1e325cb48e9ad6daff21c112bd72 # main
with:
checkout: 'false'
@@ -168,7 +168,7 @@ jobs:
export default { text, view, renderToString, renderToStringWithWidth, printComponent, eprintComponent, getTerminalSize, TuiRenderer, init }
CODE
- - uses: SocketDev/socket-registry/.github/actions/setup-and-install@bbe46386c0a2bc6baefd02916234956a38e622d5 # main
+ - uses: SocketDev/socket-registry/.github/actions/setup-and-install@3362af95fadd1e325cb48e9ad6daff21c112bd72 # main
with:
checkout: 'false'
@@ -234,7 +234,7 @@ jobs:
export default { text, view, renderToString, renderToStringWithWidth, printComponent, eprintComponent, getTerminalSize, TuiRenderer, init }
CODE
- - uses: SocketDev/socket-registry/.github/actions/setup-and-install@bbe46386c0a2bc6baefd02916234956a38e622d5 # main
+ - uses: SocketDev/socket-registry/.github/actions/setup-and-install@3362af95fadd1e325cb48e9ad6daff21c112bd72 # main
with:
checkout: 'false'
node-version: ${{ matrix.node-version }}
@@ -310,7 +310,7 @@ jobs:
export default { text, view, renderToString, renderToStringWithWidth, printComponent, eprintComponent, getTerminalSize, TuiRenderer, init }
CODE
- - uses: SocketDev/socket-registry/.github/actions/setup-and-install@bbe46386c0a2bc6baefd02916234956a38e622d5 # main
+ - uses: SocketDev/socket-registry/.github/actions/setup-and-install@3362af95fadd1e325cb48e9ad6daff21c112bd72 # main
with:
checkout: 'false'
node-version: ${{ matrix.node-version }}
diff --git a/.github/workflows/provenance.yml b/.github/workflows/provenance.yml
index 456ee6e4d..0a7fa2bf7 100644
--- a/.github/workflows/provenance.yml
+++ b/.github/workflows/provenance.yml
@@ -51,7 +51,7 @@ jobs:
with:
persist-credentials: false
- - uses: SocketDev/socket-registry/.github/actions/setup-and-install@bbe46386c0a2bc6baefd02916234956a38e622d5 # main
+ - uses: SocketDev/socket-registry/.github/actions/setup-and-install@3362af95fadd1e325cb48e9ad6daff21c112bd72 # main
with:
checkout: 'false'
@@ -91,7 +91,7 @@ jobs:
with:
persist-credentials: false
- - uses: SocketDev/socket-registry/.github/actions/setup-and-install@bbe46386c0a2bc6baefd02916234956a38e622d5 # main
+ - uses: SocketDev/socket-registry/.github/actions/setup-and-install@3362af95fadd1e325cb48e9ad6daff21c112bd72 # main
with:
checkout: 'false'
registry-url: 'https://registry.npmjs.org'
@@ -141,7 +141,7 @@ jobs:
with:
persist-credentials: false
- - uses: SocketDev/socket-registry/.github/actions/setup-and-install@bbe46386c0a2bc6baefd02916234956a38e622d5 # main
+ - uses: SocketDev/socket-registry/.github/actions/setup-and-install@3362af95fadd1e325cb48e9ad6daff21c112bd72 # main
with:
checkout: 'false'
registry-url: 'https://registry.npmjs.org'
diff --git a/.github/workflows/weekly-update.yml b/.github/workflows/weekly-update.yml
index 6a48ea19f..90ce34463 100644
--- a/.github/workflows/weekly-update.yml
+++ b/.github/workflows/weekly-update.yml
@@ -1,360 +1,20 @@
-name: 🔄 Weekly Dependency Update
+name: 🔄 Weekly Update
on:
schedule:
- # Run weekly on Monday at 9 AM UTC
- cron: '0 9 * * 1'
workflow_dispatch:
- inputs:
- dry-run:
- description: 'Check for updates without creating PR'
- required: false
- type: boolean
- default: false
permissions:
contents: read
jobs:
- check-updates:
- name: Check for dependency updates
- runs-on: ubuntu-latest
- permissions:
- contents: read
- outputs:
- has-updates: ${{ steps.check.outputs.has-updates }}
- steps:
- - name: Checkout repository
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- persist-credentials: false
-
- - uses: SocketDev/socket-registry/.github/actions/setup-and-install@bbe46386c0a2bc6baefd02916234956a38e622d5 # main
- with:
- checkout: 'false'
-
- - name: Check for npm updates
- id: check
- shell: bash
- run: |
- echo "Checking for npm package updates..."
- HAS_UPDATES=false
- NPM_UPDATES=$(pnpm outdated 2>/dev/null || true)
- if [ -n "$NPM_UPDATES" ] && ! echo "$NPM_UPDATES" | grep -q "No outdated"; then
- echo "npm packages have updates available"
- HAS_UPDATES=true
- fi
- echo "has-updates=$HAS_UPDATES" >> $GITHUB_OUTPUT
-
- apply-updates:
- name: Apply updates with Claude Code
- needs: check-updates
- if: needs.check-updates.outputs.has-updates == 'true' && inputs.dry-run != true
- runs-on: ubuntu-latest
- permissions:
- actions: write # Trigger CI workflow via workflow_dispatch
- contents: write # Push update branch
- pull-requests: write # Create PR
- steps:
- - name: Checkout repository
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- with:
- fetch-depth: 0
- persist-credentials: false
-
- - uses: SocketDev/socket-registry/.github/actions/setup-and-install@bbe46386c0a2bc6baefd02916234956a38e622d5 # main
- with:
- checkout: 'false'
-
- - name: Create update branch
- id: branch
- env:
- GH_TOKEN: ${{ github.token }}
- GITHUB_REPO: ${{ github.repository }}
- run: |
- BRANCH_NAME="weekly-update-$(date +%Y%m%d)"
- git remote set-url origin "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPO}.git"
- # Branch from HEAD~1 so the PR is behind main, making the
- # "Update branch" button available to trigger enterprise checks.
- git checkout -b "$BRANCH_NAME" HEAD~1
- echo "branch=$BRANCH_NAME" >> $GITHUB_OUTPUT
-
- - uses: SocketDev/socket-registry/.github/actions/setup-git-signing@bbe46386c0a2bc6baefd02916234956a38e622d5 # main
- with:
- gpg-private-key: ${{ secrets.BOT_GPG_PRIVATE_KEY }}
-
- - name: Update dependencies (haiku — fast, cheap)
- id: update
- timeout-minutes: 10
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- GITHUB_ACTIONS: 'true'
- run: |
- if [ -z "$ANTHROPIC_API_KEY" ]; then
- echo "ANTHROPIC_API_KEY not set - skipping automated update"
- echo "success=false" >> $GITHUB_OUTPUT
- exit 0
- fi
-
- set +e
- pnpm exec claude --print \
- --allowedTools "Bash(pnpm:*)" "Bash(git add:*)" "Bash(git commit:*)" "Bash(git status:*)" "Bash(git diff:*)" "Bash(git log:*)" "Bash(git rev-parse:*)" "Read" "Write" "Edit" "Glob" "Grep" \
- --model haiku \
- --max-turns 15 \
- "$(cat <<'PROMPT'
- /updating
-
-
- You are an automated CI agent in a weekly dependency update workflow.
- Git is configured with GPG signing. A branch has been created for you.
-
-
-
- Update all dependencies to their latest versions.
- Create one atomic commit per dependency update with a conventional commit message.
- Leave all changes local — the workflow handles pushing and PR creation.
- Do not run builds or tests — the next step handles that.
-
-
-
- Each updated dependency has its own commit.
- The lockfile is consistent with package.json changes.
- No uncommitted changes remain in the working tree.
-
- PROMPT
- )" \
- 2>&1 | tee claude-update.log
- CLAUDE_EXIT=${PIPESTATUS[0]}
- set -e
-
- if [ "$CLAUDE_EXIT" -eq 0 ]; then
- echo "success=true" >> $GITHUB_OUTPUT
- else
- echo "success=false" >> $GITHUB_OUTPUT
- fi
-
- - name: Run tests
- id: tests
- if: steps.update.outputs.success == 'true'
- run: |
- set +e
- pnpm build 2>&1 | tee build.log
- BUILD_EXIT=${PIPESTATUS[0]}
-
- pnpm test 2>&1 | tee test.log
- TEST_EXIT=${PIPESTATUS[0]}
- set -e
-
- if [ "$BUILD_EXIT" -eq 0 ] && [ "$TEST_EXIT" -eq 0 ]; then
- echo "tests-passed=true" >> $GITHUB_OUTPUT
- else
- echo "tests-passed=false" >> $GITHUB_OUTPUT
- fi
-
- - name: Fix test failures (sonnet — smarter, escalated)
- id: claude
- if: steps.update.outputs.success == 'true' && steps.tests.outputs.tests-passed == 'false'
- timeout-minutes: 15
- env:
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
- GITHUB_ACTIONS: 'true'
- run: |
- FAILURE_LOG="$(cat build.log test.log 2>/dev/null)"
-
- set +e
- pnpm exec claude --print \
- --allowedTools "Bash(pnpm:*)" "Bash(git add:*)" "Bash(git commit:*)" "Bash(git status:*)" "Bash(git diff:*)" "Bash(git log:*)" "Bash(git rev-parse:*)" "Read" "Write" "Edit" "Glob" "Grep" \
- --model sonnet \
- --max-turns 25 \
- "$(cat <
- You are an automated CI agent in a weekly dependency update workflow.
- Git is configured with GPG signing. A branch has been created for you.
- Dependencies were updated in the previous step but build/tests failed.
-
-
-
- $FAILURE_LOG
-
-
-
- The dependency updates above caused build or test failures.
- Diagnose the failures from the logs and fix the code so it builds and tests pass.
- Create one atomic commit per fix with a conventional commit message.
- Run pnpm build && pnpm test to verify your fixes.
- Leave all changes local — the workflow handles pushing and PR creation.
-
-
-
- pnpm build succeeds.
- pnpm test succeeds.
- Each fix has its own commit.
- No uncommitted changes remain in the working tree.
-
- PROMPT
- )" \
- 2>&1 | tee claude-fix.log
- CLAUDE_EXIT=${PIPESTATUS[0]}
- set -e
-
- if [ "$CLAUDE_EXIT" -eq 0 ]; then
- echo "success=true" >> $GITHUB_OUTPUT
- else
- echo "success=false" >> $GITHUB_OUTPUT
- fi
-
- - name: Set final status
- id: final
- if: always()
- env:
- UPDATE_SUCCESS: ${{ steps.update.outputs.success }}
- TESTS_PASSED: ${{ steps.tests.outputs.tests-passed }}
- FIX_SUCCESS: ${{ steps.claude.outputs.success }}
- run: |
- if [ "$UPDATE_SUCCESS" = "true" ] && [ "$TESTS_PASSED" = "true" ]; then
- echo "success=true" >> $GITHUB_OUTPUT
- elif [ "$UPDATE_SUCCESS" = "true" ] && [ "$FIX_SUCCESS" = "true" ]; then
- echo "success=true" >> $GITHUB_OUTPUT
- else
- echo "success=false" >> $GITHUB_OUTPUT
- fi
-
- - name: Validate changes
- id: validate
- if: steps.final.outputs.success == 'true'
- run: |
- UNEXPECTED=""
- for file in $(git diff --name-only origin/main..HEAD); do
- case "$file" in
- package.json|*/package.json|pnpm-lock.yaml|*/pnpm-lock.yaml|.npmrc|pnpm-workspace.yaml) ;;
- src/*|test/*) ;;
- *.ts|*.mts|*.js|*.mjs) ;;
- *) UNEXPECTED="$UNEXPECTED $file" ;;
- esac
- done
- if [ -n "$UNEXPECTED" ]; then
- echo "::error::Unexpected files modified by Claude:$UNEXPECTED"
- echo "valid=false" >> $GITHUB_OUTPUT
- else
- echo "valid=true" >> $GITHUB_OUTPUT
- fi
-
- - name: Check for changes
- id: changes
- run: |
- if [ -n "$(git status --porcelain)" ] || [ "$(git rev-list --count HEAD ^origin/main)" -gt 0 ]; then
- echo "has-changes=true" >> $GITHUB_OUTPUT
- else
- echo "has-changes=false" >> $GITHUB_OUTPUT
- fi
-
- - name: Push branch
- if: steps.final.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true'
- env:
- BRANCH_NAME: ${{ steps.branch.outputs.branch }}
- run: git push origin "$BRANCH_NAME"
-
- - name: Create Pull Request
- if: steps.final.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true'
- env:
- GH_TOKEN: ${{ github.token }}
- BRANCH_NAME: ${{ steps.branch.outputs.branch }}
- run: |
- COMMITS=$(git log --oneline origin/main..HEAD)
- COMMIT_COUNT=$(git rev-list --count origin/main..HEAD)
-
- PR_BODY="## Weekly Dependency Update"$'\n\n'
- PR_BODY+="Automated weekly update of npm packages."$'\n\n'
- PR_BODY+="---"$'\n\n'
- PR_BODY+="### Commits (${COMMIT_COUNT})"$'\n\n'
- PR_BODY+=""$'\n'
- PR_BODY+="View commit history
"$'\n\n'
- PR_BODY+="\`\`\`"$'\n'
- PR_BODY+="${COMMITS}"$'\n'
- PR_BODY+="\`\`\`"$'\n\n'
- PR_BODY+=" "$'\n\n'
- PR_BODY+="---"$'\n\n'
- PR_BODY+="Generated by [weekly-update.yml](.github/workflows/weekly-update.yml)"
-
- gh pr create \
- --title "chore(deps): weekly dependency update ($(date +%Y-%m-%d))" \
- --body "$PR_BODY" \
- --draft \
- --head "$BRANCH_NAME" \
- --base main
-
- # Pushes made with GITHUB_TOKEN don't trigger other workflows.
- # Use workflow_dispatch to directly trigger CI on the PR branch.
- - name: Trigger CI checks
- if: steps.final.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true'
- env:
- GH_TOKEN: ${{ github.token }}
- BRANCH_NAME: ${{ steps.branch.outputs.branch }}
- run: gh workflow run ci.yml --ref "$BRANCH_NAME"
-
- - name: Add job summary
- if: steps.final.outputs.success == 'true' && steps.validate.outputs.valid == 'true' && steps.changes.outputs.has-changes == 'true'
- env:
- GH_TOKEN: ${{ github.token }}
- BRANCH_NAME: ${{ steps.branch.outputs.branch }}
- run: |
- COMMIT_COUNT=$(git rev-list --count origin/main..HEAD)
- pr_number=$(gh pr list --head "$BRANCH_NAME" --json number --jq '.[0].number' || echo "")
- pr_url="https://github.com/${{ github.repository }}/pull/${pr_number}"
-
- cat >> "$GITHUB_STEP_SUMMARY" < **Note:** Enterprise required workflows (e.g. Audit GHA Workflows) won't trigger
- > automatically on bot PRs. Click **"Update branch"** on the PR to trigger them,
- > or push an empty commit to the branch:
- >
- > \`\`\`sh
- > git fetch origin ${BRANCH_NAME} && git checkout ${BRANCH_NAME}
- > git commit --allow-empty -m "chore: trigger enterprise checks"
- > git push origin ${BRANCH_NAME}
- > \`\`\`
- EOF
-
- - name: Upload Claude output
- if: always()
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
- with:
- name: claude-output-${{ github.run_id }}
- path: |
- claude-update.log
- claude-fix.log
- build.log
- test.log
- retention-days: 7
-
- - uses: SocketDev/socket-registry/.github/actions/cleanup-git-signing@bbe46386c0a2bc6baefd02916234956a38e622d5 # main
- if: always()
-
- notify:
- name: Notify results
- needs: [check-updates, apply-updates]
- if: always()
- runs-on: ubuntu-latest
- permissions:
- contents: read
- steps:
- - name: Report status
- env:
- HAS_UPDATES: ${{ needs.check-updates.outputs.has-updates }}
- DRY_RUN: ${{ inputs.dry-run }}
- run: |
- if [ "$HAS_UPDATES" = "true" ]; then
- if [ "$DRY_RUN" = "true" ]; then
- echo "Updates available (dry-run mode - no PR created)"
- else
- echo "Weekly update workflow completed"
- echo "Check the PRs tab for the automated update PR"
- fi
- else
- echo "All dependencies are up to date - no action needed!"
- fi
+ weekly-update:
+ uses: SocketDev/socket-registry/.github/workflows/weekly-update.yml@3362af95fadd1e325cb48e9ad6daff21c112bd72 # main
+ with:
+ test-setup-script: 'pnpm run build'
+ test-script: 'pnpm test'
+ secrets:
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
+ BOT_GPG_PRIVATE_KEY: ${{ secrets.BOT_GPG_PRIVATE_KEY }}
+ SOCKET_API_KEY: ${{ secrets.SOCKET_API_KEY }}
diff --git a/package.json b/package.json
index 92f2fe2ec..343dfa218 100644
--- a/package.json
+++ b/package.json
@@ -1,11 +1,11 @@
{
"name": "socket-cli-monorepo",
"version": "0.0.0",
- "packageManager": "pnpm@11.0.0-rc.0",
+ "packageManager": "pnpm@11.0.0-rc.2",
"private": true,
"engines": {
"node": ">=25.9.0",
- "pnpm": ">=11.0.0-rc.0"
+ "pnpm": ">=11.0.0-rc.2"
},
"scripts": {
"// Build": "",
diff --git a/packages/cli/src/utils/coana/spawn.mts b/packages/cli/src/utils/coana/spawn.mts
index 9f9c8f6cb..27ec0c393 100644
--- a/packages/cli/src/utils/coana/spawn.mts
+++ b/packages/cli/src/utils/coana/spawn.mts
@@ -12,6 +12,7 @@ import { spawnNode } from '../spawn/spawn-node.mjs'
import type { IpcObject } from '../ipc.mts'
import type { CResult } from '../../types.mjs'
+import type { StdioOptions } from 'node:child_process'
import type { SpawnExtra, SpawnOptions } from '@socketsecurity/lib/spawn'
export type CoanaSpawnOptions = SpawnOptions & {
@@ -70,7 +71,8 @@ export async function spawnCoana(
...mixinsEnv,
...spawnEnv,
},
- stdio: spawnExtra?.['stdio'] || 'inherit',
+ stdio:
+ (spawnExtra?.['stdio'] as StdioOptions | undefined) ?? 'inherit',
},
)
diff --git a/packages/cli/src/utils/dlx/spawn.mts b/packages/cli/src/utils/dlx/spawn.mts
index 7cf7364e9..994cd276c 100644
--- a/packages/cli/src/utils/dlx/spawn.mts
+++ b/packages/cli/src/utils/dlx/spawn.mts
@@ -69,6 +69,7 @@ import { getDefaultApiToken, getDefaultProxyUrl } from '../socket/sdk.mjs'
import type { IpcObject } from '../ipc.mts'
import type { CResult } from '../../types.mjs'
import type { ExternalTool } from './vfs-extract.mjs'
+import type { StdioOptions } from 'node:child_process'
import type {
SpawnExtra,
SpawnOptions,
@@ -390,7 +391,7 @@ export async function spawnCoanaDlx(
const spawnPromise = spawn(spawnCommand, spawnArgs, {
...dlxOptions,
env: finalEnv,
- stdio: spawnExtra?.['stdio'] || 'inherit',
+ stdio: (spawnExtra?.['stdio'] as StdioOptions | undefined) ?? 'inherit',
})
const output = await spawnPromise
@@ -469,7 +470,7 @@ export async function spawnCdxgenDlx(
...process.env,
...spawnEnv,
},
- stdio: spawnExtra?.['stdio'] || 'inherit',
+ stdio: (spawnExtra?.['stdio'] as StdioOptions | undefined) ?? 'inherit',
})
return {
@@ -519,7 +520,7 @@ export async function spawnSfwDlx(
...process.env,
...spawnEnv,
},
- stdio: spawnExtra?.['stdio'] || 'inherit',
+ stdio: (spawnExtra?.['stdio'] as StdioOptions | undefined) ?? 'inherit',
})
return {
@@ -572,7 +573,7 @@ export async function spawnSocketPatchDlx(
...process.env,
...spawnEnv,
},
- stdio: spawnExtra?.['stdio'] || 'inherit',
+ stdio: (spawnExtra?.['stdio'] as StdioOptions | undefined) ?? 'inherit',
})
return {
@@ -590,7 +591,7 @@ export async function spawnSocketPatchDlx(
...process.env,
...spawnEnv,
},
- stdio: spawnExtra?.['stdio'] || 'inherit',
+ stdio: (spawnExtra?.['stdio'] as StdioOptions | undefined) ?? 'inherit',
})
return {
@@ -672,7 +673,7 @@ async function spawnToolVfs(
...process.env,
...spawnEnv,
},
- stdio: spawnExtra?.['stdio'] || 'inherit',
+ stdio: (spawnExtra?.['stdio'] as StdioOptions | undefined) ?? 'inherit',
})
return {
@@ -1657,7 +1658,7 @@ async function spawnTrivyDlx(
...process.env,
...spawnEnv,
},
- stdio: spawnExtra?.['stdio'] || 'inherit',
+ stdio: (spawnExtra?.['stdio'] as StdioOptions | undefined) ?? 'inherit',
})
return {
@@ -1719,7 +1720,7 @@ async function spawnTrufflehogDlx(
...process.env,
...spawnEnv,
},
- stdio: spawnExtra?.['stdio'] || 'inherit',
+ stdio: (spawnExtra?.['stdio'] as StdioOptions | undefined) ?? 'inherit',
})
return {
@@ -1781,7 +1782,7 @@ async function spawnOpengrepDlx(
...process.env,
...spawnEnv,
},
- stdio: spawnExtra?.['stdio'] || 'inherit',
+ stdio: (spawnExtra?.['stdio'] as StdioOptions | undefined) ?? 'inherit',
})
return {
diff --git a/packages/cli/src/utils/spawn/spawn-node.mts b/packages/cli/src/utils/spawn/spawn-node.mts
index 7ae68b952..6c3bdb357 100644
--- a/packages/cli/src/utils/spawn/spawn-node.mts
+++ b/packages/cli/src/utils/spawn/spawn-node.mts
@@ -33,6 +33,22 @@ import type {
SpawnExtra,
} from '@socketsecurity/lib/spawn'
+/**
+ * Narrows a spawned process to the shape required by
+ * `sendBootstrapHandshake` (i.e. `.send` is a callable, not undefined).
+ * The typeof-on-a-property guard can't flow to the parent object, so
+ * we need an explicit assertion function.
+ */
+function assertHasSend(
+ proc: T,
+): asserts proc is T & { send: (message: unknown) => void } {
+ if (typeof proc.send !== 'function') {
+ throw new TypeError(
+ 'spawn-node: expected IPC channel on child process (send is undefined)',
+ )
+ }
+}
+
/**
* Ensures stdio configuration includes IPC channel for process communication.
* Converts various stdio formats to include 'ipc' as the fourth element.
@@ -117,6 +133,10 @@ export function spawnNode(
extra,
)
+ // `ensureIpcInStdio` above guarantees an IPC channel in stdio, so
+ // `.send` should always be a function here. Narrow explicitly via an
+ // assertion function so the call site doesn't need a structural cast.
+ assertHasSend(spawnResult.process)
sendBootstrapHandshake(
spawnResult.process,
// Always send IPC handshake with bootstrap indicators + custom data.
diff --git a/packages/cli/src/utils/validation/ipc.mts b/packages/cli/src/utils/validation/ipc.mts
index af1249715..a96dbda42 100644
--- a/packages/cli/src/utils/validation/ipc.mts
+++ b/packages/cli/src/utils/validation/ipc.mts
@@ -7,7 +7,23 @@
import { randomBytes } from 'node:crypto'
-import type { IpcHandshake, IpcMessage, IpcStub } from '@socketsecurity/lib/ipc'
+import type { IpcStub } from '@socketsecurity/lib/ipc'
+
+export interface IpcMessage {
+ data: T
+ id: string
+ timestamp: number
+ type: string
+}
+
+export interface IpcHandshake extends IpcMessage<{
+ apiToken?: string | undefined
+ appName: string
+ pid: number
+ version: string
+}> {
+ type: 'handshake'
+}
/**
* Check if a value is a valid IPC message.
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 19cc1e347..16de2d988 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -438,7 +438,7 @@ overrides:
'@octokit/graphql': 9.0.1
'@octokit/request-error': 7.0.0
'@sigstore/sign': 4.1.0
- '@socketsecurity/lib': 5.18.2
+ '@socketsecurity/lib': 5.21.0
aggregate-error: npm:@socketregistry/aggregate-error@^1.0.15
ansi-regex: 6.2.2
brace-expansion: 5.0.5
@@ -577,8 +577,8 @@ importers:
specifier: 'catalog:'
version: 3.0.1
'@socketsecurity/lib':
- specifier: 5.18.2
- version: 5.18.2(typescript@5.9.3)
+ specifier: 5.21.0
+ version: 5.21.0(typescript@5.9.3)
'@socketsecurity/registry':
specifier: 'catalog:'
version: 2.0.2(typescript@5.9.3)
@@ -754,6 +754,28 @@ importers:
specifier: 'catalog:'
version: 4.1.8
+ .claude/hooks/check-new-deps:
+ dependencies:
+ '@socketregistry/packageurl-js':
+ specifier: 'catalog:'
+ version: 1.4.2
+ '@socketsecurity/lib':
+ specifier: 5.21.0
+ version: 5.21.0(typescript@5.9.3)
+ '@socketsecurity/sdk':
+ specifier: 'catalog:'
+ version: 4.0.1
+ devDependencies:
+ '@types/node':
+ specifier: 24.9.2
+ version: 24.9.2
+
+ .claude/hooks/setup-security-tools:
+ dependencies:
+ '@socketsecurity/lib':
+ specifier: 5.21.0
+ version: 5.21.0(typescript@5.9.3)
+
packages/build-infra:
dependencies:
'@babel/parser':
@@ -763,8 +785,8 @@ importers:
specifier: 'catalog:'
version: 7.28.4
'@socketsecurity/lib':
- specifier: 5.18.2
- version: 5.18.2(typescript@5.9.3)
+ specifier: 5.21.0
+ version: 5.21.0(typescript@5.9.3)
magic-string:
specifier: 'catalog:'
version: 0.30.19
@@ -820,8 +842,8 @@ importers:
specifier: 'catalog:'
version: 3.0.1
'@socketsecurity/lib':
- specifier: 5.18.2
- version: 5.18.2(typescript@5.9.3)
+ specifier: 5.21.0
+ version: 5.21.0(typescript@5.9.3)
'@socketsecurity/registry':
specifier: 'catalog:'
version: 2.0.2(typescript@5.9.3)
@@ -940,8 +962,8 @@ importers:
packages/package-builder:
dependencies:
'@socketsecurity/lib':
- specifier: 5.18.2
- version: 5.18.2(typescript@5.9.3)
+ specifier: 5.21.0
+ version: 5.21.0(typescript@5.9.3)
build-infra:
specifier: workspace:*
version: link:../build-infra
@@ -2378,8 +2400,8 @@ packages:
resolution: {integrity: sha512-kLKdSqi4W7SDSm5z+wYnfVRnZCVhxzbzuKcdOZSrcHoEGOT4Gl844uzoaML+f5eiQMxY+nISiETwRph/aXrIaQ==}
engines: {node: 18.20.7 || ^20.18.3 || >=22.14.0}
- '@socketsecurity/lib@5.18.2':
- resolution: {integrity: sha512-h6aGfphQ9jdVjUMGIKJcsIvT6BmzBo0OD20HzeK+6KQJi2HupfCUzIH26vDPxf+aYVmrX0/hKJDYI5sXfTGx9A==}
+ '@socketsecurity/lib@5.21.0':
+ resolution: {integrity: sha512-cSqdq2kOBSuH3u8rfDhViCrN7IJPqzAvzklUYrEFhohUgJkky0+YYQ/gbSwRehZDGY8mqv+6lKGrt4OKWnNsdQ==}
engines: {node: '>=22', pnpm: '>=11.0.0-rc.0'}
peerDependencies:
typescript: '>=5.0.0'
@@ -2457,9 +2479,6 @@ packages:
'@types/node@24.9.2':
resolution: {integrity: sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==}
- '@types/node@25.5.2':
- resolution: {integrity: sha512-tO4ZIRKNC+MDWV4qKVZe3Ql/woTnmHDr5JD8UI5hn2pwBrHEwOEMZK7WlNb5RKB6EoJ02gwmQS9OrjuFnZYdpg==}
-
'@types/normalize-package-data@2.4.4':
resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
@@ -4390,9 +4409,6 @@ packages:
undici-types@7.16.0:
resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
- undici-types@7.18.2:
- resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==}
-
unicorn-magic@0.3.0:
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
engines: {node: '>=18'}
@@ -5870,7 +5886,7 @@ snapshots:
pony-cause: 2.1.11
yaml: 2.8.1
- '@socketsecurity/lib@5.18.2(typescript@5.9.3)':
+ '@socketsecurity/lib@5.21.0(typescript@5.9.3)':
optionalDependencies:
typescript: 5.9.3
@@ -5893,7 +5909,7 @@ snapshots:
'@types/adm-zip@0.5.7':
dependencies:
- '@types/node': 25.5.2
+ '@types/node': 24.9.2
'@types/braces@3.0.5': {}
@@ -5927,7 +5943,7 @@ snapshots:
'@types/node-fetch@2.6.13':
dependencies:
- '@types/node': 25.5.2
+ '@types/node': 24.9.2
form-data: 4.0.5
'@types/node@18.19.130':
@@ -5938,17 +5954,13 @@ snapshots:
dependencies:
undici-types: 7.16.0
- '@types/node@25.5.2':
- dependencies:
- undici-types: 7.18.2
-
'@types/normalize-package-data@2.4.4': {}
'@types/npm-package-arg@6.1.4': {}
'@types/npm-registry-fetch@8.0.9':
dependencies:
- '@types/node': 25.5.2
+ '@types/node': 24.9.2
'@types/node-fetch': 2.6.13
'@types/npm-package-arg': 6.1.4
'@types/npmlog': 7.0.0
@@ -5971,7 +5983,7 @@ snapshots:
'@types/npmlog@7.0.0':
dependencies:
- '@types/node': 25.5.2
+ '@types/node': 24.9.2
'@types/pacote@11.1.8':
dependencies:
@@ -5986,7 +5998,7 @@ snapshots:
'@types/ssri@7.1.5':
dependencies:
- '@types/node': 25.5.2
+ '@types/node': 24.9.2
'@types/which@3.0.4': {}
@@ -8024,8 +8036,6 @@ snapshots:
undici-types@7.16.0: {}
- undici-types@7.18.2: {}
-
unicorn-magic@0.3.0: {}
universal-user-agent@7.0.3: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index a3d319646..158c941d4 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,11 +1,8 @@
-resolutionMode: highest
-trustPolicy: no-downgrade
-trustPolicyExclude:
- - undici@6.21.3
packages:
- packages/*
- '!packages/package-builder/build'
+ - .claude/hooks/*
# Packages allowed to run build scripts (pnpm v11 strictDepBuilds default).
allowBuilds:
@@ -45,7 +42,7 @@ catalog:
'@socketregistry/packageurl-js': 1.4.2
'@socketregistry/yocto-spinner': 1.0.25
'@socketsecurity/config': 3.0.1
- '@socketsecurity/lib': 5.18.2
+ '@socketsecurity/lib': 5.21.0
'@socketsecurity/registry': 2.0.2
'@socketsecurity/sdk': 4.0.1
'@types/adm-zip': 0.5.7
@@ -153,8 +150,6 @@ catalog:
# pnpm v11 reads settings from this file; only auth/registry go in .npmrc.
ignoreScripts: true
linkWorkspacePackages: false
-saveExact: true
-strictPeerDependencies: true
# Wait 7 days (10080 minutes) before installing newly published packages.
minimumReleaseAge: 10080
@@ -223,3 +218,9 @@ patchedDependencies:
execa@2.1.0: patches/execa@2.1.0.patch
execa@5.1.1: patches/execa@5.1.1.patch
node-gyp@12.2.0: patches/node-gyp@12.2.0.patch
+resolutionMode: highest
+saveExact: true
+strictPeerDependencies: true
+trustPolicy: no-downgrade
+trustPolicyExclude:
+ - undici@6.21.3
diff --git a/scripts/check.mts b/scripts/check.mts
index 4f844beba..b2115b5b7 100644
--- a/scripts/check.mts
+++ b/scripts/check.mts
@@ -14,7 +14,8 @@ import { WIN32 } from '@socketsecurity/lib/constants/platform'
import { getChangedFiles, getStagedFiles } from '@socketsecurity/lib/git'
import { getDefaultLogger } from '@socketsecurity/lib/logger'
import { spawn } from '@socketsecurity/lib/spawn'
-import { printFooter, printHeader } from '@socketsecurity/lib/stdio/header'
+import { printFooter } from '@socketsecurity/lib/stdio/footer'
+import { printHeader } from '@socketsecurity/lib/stdio/header'
import {
getAffectedPackages,
diff --git a/scripts/type.mts b/scripts/type.mts
index 9e5d103ce..c5dbf1338 100644
--- a/scripts/type.mts
+++ b/scripts/type.mts
@@ -12,7 +12,8 @@ import { parseArgs } from '@socketsecurity/lib/argv/parse'
import { WIN32 } from '@socketsecurity/lib/constants/platform'
import { getDefaultLogger } from '@socketsecurity/lib/logger'
import { spawn } from '@socketsecurity/lib/spawn'
-import { printFooter, printHeader } from '@socketsecurity/lib/stdio/header'
+import { printFooter } from '@socketsecurity/lib/stdio/footer'
+import { printHeader } from '@socketsecurity/lib/stdio/header'
import { getPackagesWithScript } from './utils/monorepo-helper.mts'