build(runtime): require Node 24 toolchain
This commit is contained in:
parent
5355570f2c
commit
58a0eb603d
23 changed files with 336 additions and 418 deletions
52
.dockerignore
Normal file
52
.dockerignore
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
# Dependencies installed inside the image
|
||||||
|
node_modules/
|
||||||
|
landing/node_modules/
|
||||||
|
|
||||||
|
# Local build output
|
||||||
|
dist/
|
||||||
|
dist-electron/
|
||||||
|
dist-standalone/
|
||||||
|
out/
|
||||||
|
release/
|
||||||
|
coverage/
|
||||||
|
landing/.nuxt/
|
||||||
|
landing/.output/
|
||||||
|
electron.vite.config.*.mjs
|
||||||
|
|
||||||
|
# Runtime and local caches
|
||||||
|
.git/
|
||||||
|
.pnpm-store/
|
||||||
|
.runtime-download/
|
||||||
|
resources/runtime/*
|
||||||
|
!resources/runtime/.gitkeep
|
||||||
|
.eslintcache
|
||||||
|
.eslintcache-fast
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Local-only data
|
||||||
|
.claude/
|
||||||
|
.home/
|
||||||
|
.serena/
|
||||||
|
.playwright-mcp/
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
|
||||||
|
# OS and editor noise
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Local scratch artifacts
|
||||||
|
notification_example/
|
||||||
|
temp/
|
||||||
|
eslint-fix/
|
||||||
|
remotion/*
|
||||||
|
.tmp-*
|
||||||
|
agent-teams-reference-fix-*.png
|
||||||
|
ORCHESTRATOR_RELEASE_RUNBOOK.local.md
|
||||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
|
@ -64,7 +64,7 @@ jobs:
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version-file: .node-version
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Restore pnpm node-gyp executable bit
|
- name: Restore pnpm node-gyp executable bit
|
||||||
|
|
@ -102,7 +102,7 @@ jobs:
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version-file: .node-version
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Restore pnpm node-gyp executable bit
|
- name: Restore pnpm node-gyp executable bit
|
||||||
|
|
@ -136,7 +136,7 @@ jobs:
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version-file: .node-version
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
|
|
||||||
2
.github/workflows/codex-runtime-smoke.yml
vendored
2
.github/workflows/codex-runtime-smoke.yml
vendored
|
|
@ -58,7 +58,7 @@ jobs:
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version-file: .node-version
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
|
|
|
||||||
2
.github/workflows/landing.yml
vendored
2
.github/workflows/landing.yml
vendored
|
|
@ -23,7 +23,7 @@ jobs:
|
||||||
|
|
||||||
- uses: actions/setup-node@v6
|
- uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version-file: .node-version
|
||||||
cache: npm
|
cache: npm
|
||||||
cache-dependency-path: landing/package-lock.json
|
cache-dependency-path: landing/package-lock.json
|
||||||
|
|
||||||
|
|
|
||||||
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
|
|
@ -42,7 +42,7 @@ jobs:
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version-file: .node-version
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Restore pnpm node-gyp executable bit
|
- name: Restore pnpm node-gyp executable bit
|
||||||
|
|
@ -334,7 +334,7 @@ jobs:
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version-file: .node-version
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Setup Python for node-gyp
|
- name: Setup Python for node-gyp
|
||||||
|
|
@ -455,7 +455,7 @@ jobs:
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version-file: .node-version
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Setup Python for node-gyp
|
- name: Setup Python for node-gyp
|
||||||
|
|
@ -577,7 +577,7 @@ jobs:
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: 22
|
node-version-file: .node-version
|
||||||
cache: pnpm
|
cache: pnpm
|
||||||
|
|
||||||
- name: Setup Python for node-gyp
|
- name: Setup Python for node-gyp
|
||||||
|
|
|
||||||
1
.node-version
Normal file
1
.node-version
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
24.16.0
|
||||||
1
.npmrc
Normal file
1
.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
engine-strict=true
|
||||||
1
.nvmrc
Normal file
1
.nvmrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
24.16.0
|
||||||
|
|
@ -14,6 +14,6 @@
|
||||||
"test:watch": "vitest --config vitest.config.js"
|
"test:watch": "vitest --config vitest.config.js"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20"
|
"node": ">=24.16.0 <25"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,35 +8,55 @@
|
||||||
# Run: docker run -p 3456:3456 -v ~/.claude:/data/.claude:ro agent-teams-ai
|
# Run: docker run -p 3456:3456 -v ~/.claude:/data/.claude:ro agent-teams-ai
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
FROM node:20-slim AS builder
|
ARG NODE_VERSION=24.16.0
|
||||||
|
|
||||||
|
FROM node:${NODE_VERSION}-slim AS base
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Enable corepack for pnpm
|
# Enable corepack for pnpm
|
||||||
RUN corepack enable
|
RUN corepack enable
|
||||||
|
|
||||||
|
FROM base AS builder
|
||||||
|
|
||||||
|
# Native dependencies such as node-pty may need source builds on slim images.
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends python3 make g++ \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Install dependencies first (better layer caching)
|
# Install dependencies first (better layer caching)
|
||||||
COPY package.json pnpm-lock.yaml ./
|
COPY package.json pnpm-lock.yaml ./
|
||||||
|
COPY patches ./patches
|
||||||
RUN pnpm install --frozen-lockfile
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
# Copy source and build
|
# Copy source and build
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN pnpm standalone:build
|
RUN AGENT_TEAMS_DISABLE_SOURCEMAPS=1 pnpm standalone:build
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Production stage — minimal image with only the built output
|
# Production dependencies stage
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
FROM node:20-slim
|
FROM base AS prod-deps
|
||||||
|
|
||||||
WORKDIR /app
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y --no-install-recommends python3 make g++ \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Enable corepack for pnpm
|
# Install production-only dependencies
|
||||||
RUN corepack enable
|
|
||||||
|
|
||||||
# Copy package files and install production-only dependencies
|
|
||||||
# (fastify, @fastify/cors, @fastify/static are externalized from the bundle)
|
# (fastify, @fastify/cors, @fastify/static are externalized from the bundle)
|
||||||
COPY --from=builder /app/package.json /app/pnpm-lock.yaml ./
|
COPY package.json pnpm-lock.yaml ./
|
||||||
RUN pnpm install --frozen-lockfile --prod
|
COPY patches ./patches
|
||||||
|
RUN pnpm install --frozen-lockfile --prod --ignore-scripts \
|
||||||
|
&& pnpm rebuild node-pty cpu-features ssh2
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Production stage - minimal image with only runtime dependencies and built output
|
||||||
|
# =============================================================================
|
||||||
|
FROM base
|
||||||
|
|
||||||
|
COPY --from=prod-deps /app/package.json /app/pnpm-lock.yaml ./
|
||||||
|
COPY --from=prod-deps /app/node_modules ./node_modules
|
||||||
|
COPY --from=builder /app/agent-teams-controller ./agent-teams-controller
|
||||||
|
|
||||||
# Copy built standalone server and renderer output
|
# Copy built standalone server and renderer output
|
||||||
COPY --from=builder /app/dist-standalone ./dist-standalone
|
COPY --from=builder /app/dist-standalone ./dist-standalone
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import type { Plugin } from 'vite'
|
||||||
// `vite build --config docker/vite.standalone.config.ts`, so __dirname
|
// `vite build --config docker/vite.standalone.config.ts`, so __dirname
|
||||||
// is docker/. All paths must resolve relative to the repo root.
|
// is docker/. All paths must resolve relative to the repo root.
|
||||||
const ROOT = resolve(__dirname, '..')
|
const ROOT = resolve(__dirname, '..')
|
||||||
|
const sourceMapsEnabled = process.env.AGENT_TEAMS_DISABLE_SOURCEMAPS !== '1'
|
||||||
|
|
||||||
// Node.js built-in modules that should be externalized
|
// Node.js built-in modules that should be externalized
|
||||||
const nodeBuiltins = new Set([
|
const nodeBuiltins = new Set([
|
||||||
|
|
@ -35,11 +36,13 @@ function nativeModuleStub(): Plugin {
|
||||||
const STUB_ID = '\0native-stub'
|
const STUB_ID = '\0native-stub'
|
||||||
return {
|
return {
|
||||||
name: 'native-module-stub',
|
name: 'native-module-stub',
|
||||||
|
enforce: 'pre',
|
||||||
resolveId(source) {
|
resolveId(source) {
|
||||||
if (source.endsWith('.node')) return STUB_ID
|
if (source.endsWith('.node')) return STUB_ID
|
||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
load(id) {
|
load(id) {
|
||||||
|
if (id.endsWith('.node')) return 'export default {}'
|
||||||
if (id === STUB_ID) return 'export default {}'
|
if (id === STUB_ID) return 'export default {}'
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
@ -63,6 +66,8 @@ export const ipcMain = { handle: noop, on: noop, removeHandler: noop };
|
||||||
export const shell = { openPath: noop, openExternal: noop };
|
export const shell = { openPath: noop, openExternal: noop };
|
||||||
export const dialog = { showOpenDialog: async () => ({ canceled: true, filePaths: [] }) };
|
export const dialog = { showOpenDialog: async () => ({ canceled: true, filePaths: [] }) };
|
||||||
export const Notification = class { show() {} };
|
export const Notification = class { show() {} };
|
||||||
|
export const nativeImage = { createFromPath: () => proxyObj, createEmpty: () => proxyObj };
|
||||||
|
export const net = { fetch: globalThis.fetch };
|
||||||
export const safeStorage = { isEncryptionAvailable: () => false, encryptString: noop, decryptString: () => '' };
|
export const safeStorage = { isEncryptionAvailable: () => false, encryptString: noop, decryptString: () => '' };
|
||||||
export const screen = proxyObj;
|
export const screen = proxyObj;
|
||||||
export default proxyObj;
|
export default proxyObj;
|
||||||
|
|
@ -87,6 +92,7 @@ export default defineConfig({
|
||||||
plugins: [nativeModuleStub(), electronStub()],
|
plugins: [nativeModuleStub(), electronStub()],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
|
'@features': resolve(ROOT, 'src/features'),
|
||||||
'@main': resolve(ROOT, 'src/main'),
|
'@main': resolve(ROOT, 'src/main'),
|
||||||
'@shared': resolve(ROOT, 'src/shared'),
|
'@shared': resolve(ROOT, 'src/shared'),
|
||||||
'@preload': resolve(ROOT, 'src/preload')
|
'@preload': resolve(ROOT, 'src/preload')
|
||||||
|
|
@ -99,7 +105,7 @@ export default defineConfig({
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
outDir: 'dist-standalone',
|
outDir: 'dist-standalone',
|
||||||
target: 'node20',
|
target: 'node24',
|
||||||
ssr: true,
|
ssr: true,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: {
|
input: {
|
||||||
|
|
@ -119,6 +125,6 @@ export default defineConfig({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
minify: false,
|
minify: false,
|
||||||
sourcemap: true
|
sourcemap: sourceMapsEnabled
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,8 @@ const sentrySourceMapTargets = {
|
||||||
},
|
},
|
||||||
} as const
|
} as const
|
||||||
|
|
||||||
|
const sourceMapSetting = process.env.AGENT_TEAMS_DISABLE_SOURCEMAPS === '1' ? false : 'hidden'
|
||||||
|
|
||||||
// Sentry source map upload - only active in CI when SENTRY_AUTH_TOKEN is set.
|
// Sentry source map upload - only active in CI when SENTRY_AUTH_TOKEN is set.
|
||||||
function createSentryPlugins(target: keyof typeof sentrySourceMapTargets): Plugin[] {
|
function createSentryPlugins(target: keyof typeof sentrySourceMapTargets): Plugin[] {
|
||||||
if (!process.env.SENTRY_AUTH_TOKEN) return []
|
if (!process.env.SENTRY_AUTH_TOKEN) return []
|
||||||
|
|
@ -98,7 +100,7 @@ export default defineConfig({
|
||||||
commonjsOptions: {
|
commonjsOptions: {
|
||||||
strictRequires: [/node_modules\/.*ssh2\//],
|
strictRequires: [/node_modules\/.*ssh2\//],
|
||||||
},
|
},
|
||||||
sourcemap: 'hidden',
|
sourcemap: sourceMapSetting,
|
||||||
outDir: 'dist-electron/main',
|
outDir: 'dist-electron/main',
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: {
|
input: {
|
||||||
|
|
@ -169,7 +171,7 @@ export default defineConfig({
|
||||||
},
|
},
|
||||||
plugins: [react(), ...createSentryPlugins('renderer')],
|
plugins: [react(), ...createSentryPlugins('renderer')],
|
||||||
build: {
|
build: {
|
||||||
sourcemap: 'hidden',
|
sourcemap: sourceMapSetting,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: {
|
input: {
|
||||||
index: resolve(__dirname, 'src/renderer/index.html')
|
index: resolve(__dirname, 'src/renderer/index.html')
|
||||||
|
|
|
||||||
1
landing/.npmrc
Normal file
1
landing/.npmrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
engine-strict=true
|
||||||
3
landing/package-lock.json
generated
3
landing/package-lock.json
generated
|
|
@ -35,6 +35,9 @@
|
||||||
"vitepress": "2.0.0-alpha.17",
|
"vitepress": "2.0.0-alpha.17",
|
||||||
"vitepress-codeblock-collapse": "^1.0.0",
|
"vitepress-codeblock-collapse": "^1.0.0",
|
||||||
"vitepress-plugin-llms": "^1.12.2"
|
"vitepress-plugin-llms": "^1.12.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=24.16.0 <25"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@alloc/quick-lru": {
|
"node_modules/@alloc/quick-lru": {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
"name": "agent-teams-landing",
|
"name": "agent-teams-landing",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=24.16.0 <25"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "nuxt dev",
|
"dev": "nuxt dev",
|
||||||
"build": "nuxt build",
|
"build": "nuxt build",
|
||||||
|
|
|
||||||
|
|
@ -41,13 +41,13 @@
|
||||||
"zod": "^4.3.6"
|
"zod": "^4.3.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^24.12.4",
|
||||||
"tsup": "^8.5.1",
|
"tsup": "^8.5.1",
|
||||||
"tsx": "^4.21.0",
|
"tsx": "^4.21.0",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"vitest": "^3.1.4",
|
"vitest": "^3.1.4"
|
||||||
"@types/node": "^22.15.18"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20"
|
"node": ">=24.16.0 <25"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { defineConfig } from 'tsup';
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
entry: ['src/index.ts'],
|
entry: ['src/index.ts'],
|
||||||
format: ['esm'],
|
format: ['esm'],
|
||||||
target: 'node20',
|
target: 'node24',
|
||||||
platform: 'node',
|
platform: 'node',
|
||||||
outDir: 'dist',
|
outDir: 'dist',
|
||||||
clean: true,
|
clean: true,
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,9 @@
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/777genius/agent-teams-ai/issues"
|
"url": "https://github.com/777genius/agent-teams-ai/issues"
|
||||||
},
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=24.16.0 <25"
|
||||||
|
},
|
||||||
"main": "dist-electron/main/index.cjs",
|
"main": "dist-electron/main/index.cjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node ./scripts/dev-with-runtime.mjs",
|
"dev": "node ./scripts/dev-with-runtime.mjs",
|
||||||
|
|
@ -83,7 +86,7 @@
|
||||||
"test:coverage": "vitest run --coverage",
|
"test:coverage": "vitest run --coverage",
|
||||||
"test:coverage:critical": "vitest run --coverage --config vitest.critical.config.ts",
|
"test:coverage:critical": "vitest run --coverage --config vitest.critical.config.ts",
|
||||||
"standalone": "tsx src/main/standalone.ts",
|
"standalone": "tsx src/main/standalone.ts",
|
||||||
"standalone:build": "electron-vite build && vite build --config docker/vite.standalone.config.ts",
|
"standalone:build": "node --max-old-space-size=8192 ./node_modules/electron-vite/bin/electron-vite.js build && node --max-old-space-size=8192 ./node_modules/vite/bin/vite.js build --config docker/vite.standalone.config.ts",
|
||||||
"standalone:start": "node dist-standalone/index.cjs",
|
"standalone:start": "node dist-standalone/index.cjs",
|
||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"postinstall": "electron-rebuild -f -o node-pty,ssh2,cpu-features || echo 'native Electron rebuild failed (terminal/ssh features may be degraded)'"
|
"postinstall": "electron-rebuild -f -o node-pty,ssh2,cpu-features || echo 'native Electron rebuild failed (terminal/ssh features may be degraded)'"
|
||||||
|
|
@ -212,7 +215,7 @@
|
||||||
"@tailwindcss/typography": "^0.5.19",
|
"@tailwindcss/typography": "^0.5.19",
|
||||||
"@types/hast": "^3.0.4",
|
"@types/hast": "^3.0.4",
|
||||||
"@types/mdast": "^4.0.4",
|
"@types/mdast": "^4.0.4",
|
||||||
"@types/node": "^25.0.7",
|
"@types/node": "^24.12.4",
|
||||||
"@types/pidusage": "2.0.5",
|
"@types/pidusage": "2.0.5",
|
||||||
"@types/react": "^19.0.0",
|
"@types/react": "^19.0.0",
|
||||||
"@types/react-dom": "^19.0.0",
|
"@types/react-dom": "^19.0.0",
|
||||||
|
|
@ -388,7 +391,7 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319",
|
"packageManager": "pnpm@10.33.4+sha512.1c67b3b359b2d408119ba1ed289f34b8fc3c6873412bec6fd264fbdc82489e510fcbecb9ce9d22dae7f3b76269d8441046014bdca53b9979cd7a561ad631b800",
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"@hono/node-server@1": "1.19.13",
|
"@hono/node-server@1": "1.19.13",
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=24.16.0 <25"
|
||||||
|
},
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"types": "src/index.ts",
|
"types": "src/index.ts",
|
||||||
"exports": {
|
"exports": {
|
||||||
|
|
|
||||||
544
pnpm-lock.yaml
544
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -47,7 +47,10 @@ const MCP_CONFIG_PREFIX = 'agent-teams-mcp-';
|
||||||
const MCP_CONFIG_REMOVE_RETRY_DELAYS_MS = [25, 75, 150] as const;
|
const MCP_CONFIG_REMOVE_RETRY_DELAYS_MS = [25, 75, 150] as const;
|
||||||
const NODE_RUNTIME_PROBE_TIMEOUT_MS = 5_000;
|
const NODE_RUNTIME_PROBE_TIMEOUT_MS = 5_000;
|
||||||
const ELECTRON_NODE_RUNTIME_PROBE_TIMEOUT_MS = 5_000;
|
const ELECTRON_NODE_RUNTIME_PROBE_TIMEOUT_MS = 5_000;
|
||||||
const MIN_MCP_NODE_MAJOR_VERSION = 20;
|
// The packaged Electron runtime can lag the source toolchain patch version,
|
||||||
|
// so MCP launch validation pins the Node 24 runtime line, not .node-version.
|
||||||
|
const MIN_MCP_NODE_MAJOR_VERSION = 24;
|
||||||
|
const MAX_MCP_NODE_MAJOR_VERSION = 25;
|
||||||
const NODE_RUNTIME_PROBE_SCRIPT =
|
const NODE_RUNTIME_PROBE_SCRIPT =
|
||||||
'process.stdout.write(JSON.stringify({execPath:process.execPath,version:process.versions.node}))';
|
'process.stdout.write(JSON.stringify({execPath:process.execPath,version:process.versions.node}))';
|
||||||
/**
|
/**
|
||||||
|
|
@ -335,9 +338,9 @@ function parseNodeRuntimeProbeMetadata(stdout: string, command: string): NodeRun
|
||||||
|
|
||||||
function assertSupportedMcpNodeRuntime(command: string, metadata: NodeRuntimeProbeMetadata): void {
|
function assertSupportedMcpNodeRuntime(command: string, metadata: NodeRuntimeProbeMetadata): void {
|
||||||
const major = parseNodeMajorVersion(metadata.version);
|
const major = parseNodeMajorVersion(metadata.version);
|
||||||
if (major === null || major < MIN_MCP_NODE_MAJOR_VERSION) {
|
if (major === null || major < MIN_MCP_NODE_MAJOR_VERSION || major >= MAX_MCP_NODE_MAJOR_VERSION) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`${command} resolved ${metadata.path} with Node.js ${metadata.version}; Agent Teams MCP requires Node.js ${MIN_MCP_NODE_MAJOR_VERSION}+`
|
`${command} resolved ${metadata.path} with Node.js ${metadata.version}; Agent Teams MCP requires Node.js 24.x`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -392,21 +395,16 @@ async function probePackagedElectronNodeRuntime(
|
||||||
|
|
||||||
emitProgress(options, 'electron-node-runtime', 'Checking bundled Electron Node runtime...');
|
emitProgress(options, 'electron-node-runtime', 'Checking bundled Electron Node runtime...');
|
||||||
try {
|
try {
|
||||||
const { stdout } = await execCli(
|
const { stdout } = await execCli(process.execPath.trim(), ['-e', NODE_RUNTIME_PROBE_SCRIPT], {
|
||||||
process.execPath.trim(),
|
encoding: 'utf-8',
|
||||||
['-e', 'process.stdout.write("agent-teams-electron-node-ok")'],
|
timeout: ELECTRON_NODE_RUNTIME_PROBE_TIMEOUT_MS,
|
||||||
{
|
env: {
|
||||||
encoding: 'utf-8',
|
...process.env,
|
||||||
timeout: ELECTRON_NODE_RUNTIME_PROBE_TIMEOUT_MS,
|
...getPackagedElectronNodeEnv(),
|
||||||
env: {
|
},
|
||||||
...process.env,
|
});
|
||||||
...getPackagedElectronNodeEnv(),
|
const metadata = parseNodeRuntimeProbeMetadata(stdout, process.execPath.trim());
|
||||||
},
|
assertSupportedMcpNodeRuntime(process.execPath.trim(), metadata);
|
||||||
}
|
|
||||||
);
|
|
||||||
if (stdout.trim() !== 'agent-teams-electron-node-ok') {
|
|
||||||
throw new Error('Electron Node runtime probe did not return the expected marker');
|
|
||||||
}
|
|
||||||
_packagedElectronNodeRuntimeProbe = { ok: true };
|
_packagedElectronNodeRuntimeProbe = { ok: true };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
_packagedElectronNodeRuntimeProbe = { ok: false, error };
|
_packagedElectronNodeRuntimeProbe = { ok: false, error };
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,7 @@ vi.mock('@features/codex-runtime-installer/main', () => ({
|
||||||
import { resolveVerifiedOpenCodeRuntimeBinaryPath } from '../../../../src/main/services/infrastructure/OpenCodeRuntimeInstallerService';
|
import { resolveVerifiedOpenCodeRuntimeBinaryPath } from '../../../../src/main/services/infrastructure/OpenCodeRuntimeInstallerService';
|
||||||
import { ensureOpenCodeBridgeRuntimeBinaryEnv } from '../../../../src/main/services/runtime/openCodeBridgeRuntimeEnv';
|
import { ensureOpenCodeBridgeRuntimeBinaryEnv } from '../../../../src/main/services/runtime/openCodeBridgeRuntimeEnv';
|
||||||
import { buildProviderAwareCliEnv } from '../../../../src/main/services/runtime/providerAwareCliEnv';
|
import { buildProviderAwareCliEnv } from '../../../../src/main/services/runtime/providerAwareCliEnv';
|
||||||
|
import { clearResolvedNodePathForTests } from '../../../../src/main/services/team/TeamMcpConfigBuilder';
|
||||||
import { execCli } from '../../../../src/main/utils/childProcess';
|
import { execCli } from '../../../../src/main/utils/childProcess';
|
||||||
import { setAppDataBasePath } from '../../../../src/main/utils/pathDecoder';
|
import { setAppDataBasePath } from '../../../../src/main/utils/pathDecoder';
|
||||||
import { clearShellEnvCache } from '../../../../src/main/utils/shellEnv';
|
import { clearShellEnvCache } from '../../../../src/main/utils/shellEnv';
|
||||||
|
|
@ -72,6 +73,7 @@ describePosix('OpenCode packaged-runtime preflight integration', () => {
|
||||||
tempDir = await mkdtemp(path.join(os.tmpdir(), 'opencode-prod-preflight-'));
|
tempDir = await mkdtemp(path.join(os.tmpdir(), 'opencode-prod-preflight-'));
|
||||||
setAppDataBasePath(path.join(tempDir, 'app-data'));
|
setAppDataBasePath(path.join(tempDir, 'app-data'));
|
||||||
clearShellEnvCache();
|
clearShellEnvCache();
|
||||||
|
clearResolvedNodePathForTests();
|
||||||
|
|
||||||
originalPath = process.env.PATH;
|
originalPath = process.env.PATH;
|
||||||
originalShell = process.env.SHELL;
|
originalShell = process.env.SHELL;
|
||||||
|
|
@ -142,7 +144,7 @@ describePosix('OpenCode packaged-runtime preflight integration', () => {
|
||||||
[
|
[
|
||||||
'#!/bin/sh',
|
'#!/bin/sh',
|
||||||
'if [ "$1" = "-e" ]; then',
|
'if [ "$1" = "-e" ]; then',
|
||||||
' printf "{\\"execPath\\":\\"%s\\",\\"version\\":\\"%s\\"}" "$FAKE_NODE_PATH" "22.0.0"',
|
' printf "{\\"execPath\\":\\"%s\\",\\"version\\":\\"%s\\"}" "$FAKE_NODE_PATH" "24.16.0"',
|
||||||
' exit 0',
|
' exit 0',
|
||||||
'fi',
|
'fi',
|
||||||
'echo "unexpected node args: $*" >&2',
|
'echo "unexpected node args: $*" >&2',
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ const hoisted = vi.hoisted(() => ({
|
||||||
version: '9.9.9-test',
|
version: '9.9.9-test',
|
||||||
},
|
},
|
||||||
execCliMock: vi.fn<ExecCliMock>(async () => ({
|
execCliMock: vi.fn<ExecCliMock>(async () => ({
|
||||||
stdout: JSON.stringify({ execPath: '/mock/node', version: '20.11.0' }),
|
stdout: JSON.stringify({ execPath: '/mock/node', version: '24.16.0' }),
|
||||||
stderr: '',
|
stderr: '',
|
||||||
})),
|
})),
|
||||||
cachedShellEnv: null as NodeJS.ProcessEnv | null,
|
cachedShellEnv: null as NodeJS.ProcessEnv | null,
|
||||||
|
|
@ -68,7 +68,7 @@ import {
|
||||||
} from '@main/services/team/TeamMcpConfigBuilder';
|
} from '@main/services/team/TeamMcpConfigBuilder';
|
||||||
import { setAppDataBasePath, setClaudeBasePathOverride } from '@main/utils/pathDecoder';
|
import { setAppDataBasePath, setClaudeBasePathOverride } from '@main/utils/pathDecoder';
|
||||||
|
|
||||||
function nodeRuntimeProbeStdout(execPath: string, version = '20.11.0'): string {
|
function nodeRuntimeProbeStdout(execPath: string, version = '24.16.0'): string {
|
||||||
return JSON.stringify({ execPath, version });
|
return JSON.stringify({ execPath, version });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -385,7 +385,7 @@ describe('TeamMcpConfigBuilder', () => {
|
||||||
createPackagedServerBundle(resourcesDir, '// packaged server');
|
createPackagedServerBundle(resourcesDir, '// packaged server');
|
||||||
setResourcesPath(resourcesDir);
|
setResourcesPath(resourcesDir);
|
||||||
hoisted.execCliMock.mockResolvedValue({
|
hoisted.execCliMock.mockResolvedValue({
|
||||||
stdout: 'agent-teams-electron-node-ok',
|
stdout: nodeRuntimeProbeStdout(electronBinary, '24.15.0'),
|
||||||
stderr: '',
|
stderr: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -418,7 +418,7 @@ describe('TeamMcpConfigBuilder', () => {
|
||||||
expect(hoisted.execCliMock).toHaveBeenCalledTimes(1);
|
expect(hoisted.execCliMock).toHaveBeenCalledTimes(1);
|
||||||
expect(hoisted.execCliMock).toHaveBeenCalledWith(
|
expect(hoisted.execCliMock).toHaveBeenCalledWith(
|
||||||
electronBinary,
|
electronBinary,
|
||||||
['-e', 'process.stdout.write("agent-teams-electron-node-ok")'],
|
['-e', expect.stringContaining('process.versions.node')],
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
env: expect.objectContaining({ ELECTRON_RUN_AS_NODE: '1' }),
|
env: expect.objectContaining({ ELECTRON_RUN_AS_NODE: '1' }),
|
||||||
})
|
})
|
||||||
|
|
@ -528,11 +528,11 @@ describe('TeamMcpConfigBuilder', () => {
|
||||||
if (env?.PATH?.split(path.delimiter)[0] === '/strict-shell-node-bin') {
|
if (env?.PATH?.split(path.delimiter)[0] === '/strict-shell-node-bin') {
|
||||||
expect(command).toBe('node');
|
expect(command).toBe('node');
|
||||||
return {
|
return {
|
||||||
stdout: nodeRuntimeProbeStdout('/strict-shell-node-bin/node', '20.11.0'),
|
stdout: nodeRuntimeProbeStdout('/strict-shell-node-bin/node', '24.16.0'),
|
||||||
stderr: '',
|
stderr: '',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return { stdout: nodeRuntimeProbeStdout('/usr/bin/node', '18.19.0'), stderr: '' };
|
return { stdout: nodeRuntimeProbeStdout('/usr/bin/node', '22.21.1'), stderr: '' };
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue