Merge pull request #3858 from jeremymcs/fix/audit-remediations

fix: harden command execution and remediate audit findings
This commit is contained in:
Jeremy McSpadden 2026-04-09 08:02:08 -05:00 committed by GitHub
commit b75c81074d
15 changed files with 342 additions and 221 deletions

View file

@ -96,41 +96,47 @@ jobs:
Be generous in your assessment — only flag clear violations. Ambiguous cases should be marked as aligned.
Do NOT flag issues/PRs that are legitimately reporting bugs or requesting features, even if they could be better written.`;
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'x-api-key': process.env.ANTHROPIC_API_KEY,
'content-type': 'application/json',
'anthropic-version': '2023-06-01'
},
body: JSON.stringify({
model: 'claude-haiku-4-5-20251001',
max_tokens: 1024,
messages: [{ role: 'user', content: prompt }]
})
});
if (!response.ok) {
const err = await response.text();
core.setFailed(`Anthropic API error: ${response.status} ${err}`);
return;
}
const data = await response.json();
const text = data.content[0].text;
// Extract JSON from response (handle markdown code blocks)
const jsonMatch = text.match(/\{[\s\S]*\}/);
if (!jsonMatch) {
core.setFailed(`Could not parse Claude response: ${text}`);
if (!process.env.ANTHROPIC_API_KEY) {
core.warning('Skipping AI triage because ANTHROPIC_API_KEY is not configured.');
return;
}
let result;
try {
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'x-api-key': process.env.ANTHROPIC_API_KEY,
'content-type': 'application/json',
'anthropic-version': '2023-06-01'
},
body: JSON.stringify({
model: 'claude-haiku-4-5-20251001',
max_tokens: 1024,
messages: [{ role: 'user', content: prompt }]
}),
signal: AbortSignal.timeout(20000)
});
if (!response.ok) {
const err = await response.text();
core.warning(`Skipping AI triage after Anthropic API error: ${response.status} ${err}`);
return;
}
const data = await response.json();
const text = data.content?.[0]?.text ?? '';
// Extract JSON from response (handle markdown code blocks)
const jsonMatch = text.match(/\{[\s\S]*\}/);
if (!jsonMatch) {
core.warning(`Skipping AI triage because the model response was not parseable JSON: ${text}`);
return;
}
result = JSON.parse(jsonMatch[0]);
} catch (e) {
core.setFailed(`JSON parse error: ${e.message}\nRaw text: ${text}`);
core.warning(`Skipping AI triage after unexpected failure: ${e.message}`);
return;
}
core.info(`Triage result: ${JSON.stringify(result, null, 2)}`);

139
package-lock.json generated
View file

@ -846,13 +846,13 @@
}
},
"node_modules/@aws-sdk/xml-builder": {
"version": "3.972.10",
"resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.10.tgz",
"integrity": "sha512-OnejAIVD+CxzyAUrVic7lG+3QRltyja9LoNqCE/1YVs8ichoTbJlVSaZ9iSMcnHLyzrSNtvaOGjSDRP+d/ouFA==",
"version": "3.972.17",
"resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.17.tgz",
"integrity": "sha512-Ra7hjqAZf1OXRRMueB13qex7mFJRDK/pgCvdSFemXBT8KCGnQDPoKzHY1SjN+TjJVmnpSF14W5tJ1vDamFu+Gg==",
"license": "Apache-2.0",
"dependencies": {
"@smithy/types": "^4.13.0",
"fast-xml-parser": "5.4.1",
"@smithy/types": "^4.14.0",
"fast-xml-parser": "5.5.8",
"tslib": "^2.6.2"
},
"engines": {
@ -1245,9 +1245,9 @@
}
},
"node_modules/@discordjs/builders": {
"version": "1.14.0",
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.14.0.tgz",
"integrity": "sha512-7pVKxVWkeLUtrTo9nTYkjRcJk0Hlms6lYervXAD7E7+K5lil9ms2JrEB1TalMiHvQMh7h1HJZ4fCJa0/vHpl4w==",
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.14.1.tgz",
"integrity": "sha512-gSKkhXLqs96TCzk66VZuHHl8z2bQMJFGwrXC0f33ngK+FLNau4hU1PYny3DNJfNdSH+gVMzE85/d5FQ2BpcNwQ==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/formatters": "^0.6.2",
@ -2002,9 +2002,9 @@
"link": true
},
"node_modules/@hono/node-server": {
"version": "1.19.11",
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz",
"integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==",
"version": "1.19.13",
"resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.13.tgz",
"integrity": "sha512-TsQLe4i2gvoTtrHje625ngThGBySOgSK3Xo2XRYOdqGN1teR8+I7vchQC46uLJi8OF62YTYA3AhSpumtkhsaKQ==",
"license": "MIT",
"engines": {
"node": ">=18.14.1"
@ -3694,9 +3694,9 @@
}
},
"node_modules/@smithy/types": {
"version": "4.13.1",
"resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.13.1.tgz",
"integrity": "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g==",
"version": "4.14.0",
"resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.0.tgz",
"integrity": "sha512-OWgntFLW88kx2qvf/c/67Vno1yuXm/f9M7QFAtVkkO29IJXGBIg0ycEaBTH0kvCtwmvZxRujrgP5a86RvsXJAQ==",
"license": "Apache-2.0",
"dependencies": {
"tslib": "^2.6.2"
@ -4616,9 +4616,9 @@
}
},
"node_modules/basic-ftp": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz",
"integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.1.tgz",
"integrity": "sha512-0yaL8JdxTknKDILitVpfYfV2Ob6yb3udX/hK97M7I3jOeznBNxQPtVvTUtnhUkyHlxFWyr5Lvknmgzoc7jf+1Q==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
@ -4679,9 +4679,9 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
"license": "MIT",
"dependencies": {
"balanced-match": "^4.0.2"
@ -5216,24 +5216,24 @@
]
},
"node_modules/discord.js": {
"version": "14.25.1",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.25.1.tgz",
"integrity": "sha512-2l0gsPOLPs5t6GFZfQZKnL1OJNYFcuC/ETWsW4VtKVD/tg4ICa9x+jb9bkPffkMdRpRpuUaO/fKkHCBeiCKh8g==",
"version": "14.26.2",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.26.2.tgz",
"integrity": "sha512-feShi+gULJ6R2MAA4/KkCFnkJcuVrROJrKk4czplzq8gE1oqhqgOy9K0Scu44B8oGeWKe04egquzf+ia6VtXAw==",
"license": "Apache-2.0",
"dependencies": {
"@discordjs/builders": "^1.13.0",
"@discordjs/builders": "^1.14.1",
"@discordjs/collection": "1.5.3",
"@discordjs/formatters": "^0.6.2",
"@discordjs/rest": "^2.6.0",
"@discordjs/rest": "^2.6.1",
"@discordjs/util": "^1.2.0",
"@discordjs/ws": "^1.2.3",
"@sapphire/snowflake": "3.5.3",
"discord-api-types": "^0.38.33",
"discord-api-types": "^0.38.40",
"fast-deep-equal": "3.1.3",
"lodash.snakecase": "4.1.1",
"magic-bytes.js": "^1.10.0",
"magic-bytes.js": "^1.13.0",
"tslib": "^2.6.3",
"undici": "6.21.3"
"undici": "6.24.1"
},
"engines": {
"node": ">=18"
@ -5243,9 +5243,9 @@
}
},
"node_modules/discord.js/node_modules/undici": {
"version": "6.21.3",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.21.3.tgz",
"integrity": "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==",
"version": "6.24.1",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz",
"integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==",
"license": "MIT",
"engines": {
"node": ">=18.17"
@ -5281,9 +5281,9 @@
"license": "MIT"
},
"node_modules/electron": {
"version": "41.0.3",
"resolved": "https://registry.npmjs.org/electron/-/electron-41.0.3.tgz",
"integrity": "sha512-IDjx8liW1q+r7+MOip5W1Eo1eMwJzVObmYrd9yz2dPCkS7XlgLq3qPVMR80TpiROFp73iY30kTzMdpA6fEVs3A==",
"version": "41.2.0",
"resolved": "https://registry.npmjs.org/electron/-/electron-41.2.0.tgz",
"integrity": "sha512-0OKLiymqfV0WK68RBXqAm3Myad2TpI5wwxLCBEUcH5Nugo3YfSk7p1Js/AL9266qTz5xZioUnxt9hG8FFwax0g==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@ -5703,9 +5703,9 @@
"license": "BSD-3-Clause"
},
"node_modules/fast-xml-builder": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.2.tgz",
"integrity": "sha512-NJAmiuVaJEjVa7TjLZKlYd7RqmzOC91EtPFXHvlTcqBVo50Qh7XV5IwvXi1c7NRz2Q/majGX9YLcwJtWgHjtkA==",
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz",
"integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==",
"funding": [
{
"type": "github",
@ -5718,9 +5718,9 @@
}
},
"node_modules/fast-xml-parser": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.4.1.tgz",
"integrity": "sha512-BQ30U1mKkvXQXXkAGcuyUA/GA26oEB7NzOtsxCDtyu62sjGw5QraKFhx2Em3WQNjPw9PG6MQ9yuIIgkSDfGu5A==",
"version": "5.5.8",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.8.tgz",
"integrity": "sha512-Z7Fh2nVQSb2d+poDViM063ix2ZGt9jmY1nWhPfHBOK2Hgnb/OW3P4Et3P/81SEej0J7QbWtJqxO05h8QYfK7LQ==",
"funding": [
{
"type": "github",
@ -5729,8 +5729,9 @@
],
"license": "MIT",
"dependencies": {
"fast-xml-builder": "^1.0.0",
"strnum": "^2.1.2"
"fast-xml-builder": "^1.1.4",
"path-expression-matcher": "^1.2.0",
"strnum": "^2.2.0"
},
"bin": {
"fxparser": "src/cli/cli.js"
@ -5788,9 +5789,9 @@
}
},
"node_modules/file-type": {
"version": "21.3.1",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.1.tgz",
"integrity": "sha512-SrzXX46I/zsRDjTb82eucsGg0ODq2NpGDp4HcsFKApPy8P8vACjpJRDoGGMfEzhFC0ry61ajd7f72J3603anBA==",
"version": "21.3.4",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-21.3.4.tgz",
"integrity": "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==",
"license": "MIT",
"dependencies": {
"@tokenizer/inflate": "^0.4.1",
@ -6262,9 +6263,9 @@
}
},
"node_modules/hono": {
"version": "4.12.8",
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.8.tgz",
"integrity": "sha512-VJCEvtrezO1IAR+kqEYnxUOoStaQPGrCmX3j4wDTNOcD1uRPFpGlwQUIW8niPuvHXaTUxeOUl5MMDGrl+tmO9A==",
"version": "4.12.12",
"resolved": "https://registry.npmjs.org/hono/-/hono-4.12.12.tgz",
"integrity": "sha512-p1JfQMKaceuCbpJKAPKVqyqviZdS0eUxH9v82oWo1kb9xjQ5wA6iP3FNVAPDFlz5/p7d45lO+BpSk1tuSZMF4Q==",
"license": "MIT",
"engines": {
"node": ">=16.9.0"
@ -6923,9 +6924,9 @@
}
},
"node_modules/lodash": {
"version": "4.17.23",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
"version": "4.18.1",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"license": "MIT"
},
"node_modules/lodash.snakecase": {
@ -7389,9 +7390,9 @@
}
},
"node_modules/path-expression-matcher": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.1.3.tgz",
"integrity": "sha512-qdVgY8KXmVdJZRSS1JdEPOKPdTiEK/pi0RkcT2sw1RhXxohdujUlJFPuS1TSkevZ9vzd3ZlL7ULl1MHGTApKzQ==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.4.0.tgz",
"integrity": "sha512-s4DQMxIdhj3jLFWd9LxHOplj4p9yQ4ffMGowFf3cpEgrrJjEhN0V5nxw4Ye1EViAGDoL4/1AeO6qHpqYPOzE4Q==",
"funding": [
{
"type": "github",
@ -7429,9 +7430,9 @@
}
},
"node_modules/path-to-regexp": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
"integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
"version": "8.4.2",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz",
"integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==",
"license": "MIT",
"funding": {
"type": "opencollective",
@ -7451,9 +7452,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"license": "MIT",
"engines": {
"node": ">=12"
@ -8301,9 +8302,9 @@
}
},
"node_modules/strnum": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.0.tgz",
"integrity": "sha512-Y7Bj8XyJxnPAORMZj/xltsfo55uOiyHcU2tnAVzHUnSJR/KsEX+9RoDeXEnsXtl/CX4fAcrt64gZ13aGaWPeBg==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.3.tgz",
"integrity": "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==",
"funding": [
{
"type": "github",
@ -8603,9 +8604,9 @@
}
},
"node_modules/vite": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
"version": "7.3.2",
"resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz",
"integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
"dev": true,
"license": "MIT",
"peer": true,
@ -9299,9 +9300,9 @@
"license": "ISC"
},
"node_modules/yaml": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
"integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
"license": "ISC",
"bin": {
"yaml": "bin.mjs"

View file

@ -413,12 +413,14 @@ export function initResources(agentDir: string): void {
const currentVersion = getBundledGsdVersion()
const manifest = readManagedResourceManifest(agentDir)
const extensionsDir = join(agentDir, 'extensions')
// Always prune root-level extension files that were removed from the bundle.
// This is cheap (a few existence checks + at most one rmSync) and must run
// unconditionally so that stale files left by a previous version are cleaned
// up even when the version/hash match causes the full sync to be skipped.
pruneRemovedBundledExtensions(manifest, agentDir)
pruneStaleSiblingFiles(bundledExtensionsDir, extensionsDir)
// Ensure ~/.gsd/agent/node_modules symlinks to GSD's node_modules on EVERY
// launch, not just during resource syncs. A stale/broken symlink makes ALL
@ -435,7 +437,7 @@ export function initResources(agentDir: string): void {
if (manifest && manifest.gsdVersion === currentVersion) {
// Version matches — check content fingerprint for same-version staleness.
const currentHash = computeResourceFingerprint()
const hasStaleExtensionFiles = hasStaleCompiledExtensionSiblings(join(agentDir, 'extensions'))
const hasStaleExtensionFiles = hasStaleCompiledExtensionSiblings(extensionsDir, bundledExtensionsDir)
if (manifest.contentHash && manifest.contentHash === currentHash && !hasStaleExtensionFiles) {
return
}
@ -571,12 +573,26 @@ function migrateSkillsToEcosystemDir(agentDir: string): void {
}
}
export function hasStaleCompiledExtensionSiblings(extensionsDir: string): boolean {
export function hasStaleCompiledExtensionSiblings(extensionsDir: string, sourceDir: string = bundledExtensionsDir): boolean {
if (!existsSync(extensionsDir)) return false
const sourceFiles = existsSync(sourceDir)
? new Set(
readdirSync(sourceDir, { withFileTypes: true })
.filter((entry) => entry.isFile())
.map((entry) => entry.name),
)
: new Set<string>()
for (const entry of readdirSync(extensionsDir, { withFileTypes: true })) {
if (!entry.isFile() || !entry.name.endsWith('.ts')) continue
const jsName = entry.name.replace(/\.ts$/, '.js')
if (existsSync(join(extensionsDir, jsName))) {
if (!entry.isFile()) continue
if (!entry.name.endsWith('.ts') && !entry.name.endsWith('.js')) continue
const siblingName = entry.name.endsWith('.ts')
? entry.name.replace(/\.ts$/, '.js')
: entry.name.replace(/\.js$/, '.ts')
if (!existsSync(join(extensionsDir, siblingName))) continue
if (sourceFiles.has(entry.name) && sourceFiles.has(siblingName)) continue
if (sourceFiles.has(entry.name) || sourceFiles.has(siblingName)) {
return true
}
}

View file

@ -47,6 +47,14 @@ function shellEscapeSingle(value: string): string {
return `'${value.replace(/'/g, `'\\''`)}'`;
}
function isSafeEnvVarKey(key: string): boolean {
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(key);
}
function isSupportedDeploymentEnvironment(env: string): boolean {
return env === "development" || env === "preview" || env === "production";
}
function hydrateProcessEnv(key: string, value: string): void {
// Make newly collected secrets immediately visible to the current session.
// Some extensions read process.env directly and do not reload .env on every call.
@ -330,12 +338,22 @@ async function applySecrets(
if ((destination === "vercel" || destination === "convex") && opts.exec) {
const env = opts.environment ?? "development";
if (!isSupportedDeploymentEnvironment(env)) {
errors.push(`environment: unsupported target environment "${env}"`);
return { applied, errors };
}
for (const { key, value } of provided) {
if (!isSafeEnvVarKey(key)) {
errors.push(`${key}: invalid environment variable name`);
continue;
}
const cmd = destination === "vercel"
? `printf %s ${shellEscapeSingle(value)} | vercel env add ${key} ${env}`
: `npx convex env set ${key} ${shellEscapeSingle(value)}`;
: "";
try {
const result = await opts.exec("sh", ["-c", cmd]);
const result = destination === "vercel"
? await opts.exec("sh", ["-c", cmd])
: await opts.exec("npx", ["convex", "env", "set", key, value]);
if (result.code !== 0) {
errors.push(`${key}: ${result.stderr.slice(0, 200)}`);
} else {

View file

@ -249,11 +249,6 @@ export function extractEntityKey(
? { type: "slice", id: p["sliceId"] }
: null;
case "complete_milestone":
return typeof p["milestoneId"] === "string"
? { type: "milestone", id: p["milestoneId"] }
: null;
case "plan_slice":
return typeof p["sliceId"] === "string"
? { type: "slice_plan", id: p["sliceId"] }

View file

@ -124,8 +124,9 @@ export function worktreeBranchName(name: string): string {
* nativeWorktreeRemove --force) to prevent #2365-style data loss.
*/
export function isInsideWorktreesDir(basePath: string, targetPath: string): boolean {
const wtDir = resolve(worktreesDir(basePath));
const resolved = resolve(targetPath);
const wtDirPath = worktreesDir(basePath);
const wtDir = existsSync(wtDirPath) ? realpathSync(wtDirPath) : resolve(wtDirPath);
const resolved = existsSync(targetPath) ? realpathSync(targetPath) : resolve(targetPath);
// The resolved path must start with the worktrees dir followed by a separator,
// not merely be a prefix match (e.g. ".gsd/worktrees-extra" must not match).
return resolved === wtDir || resolved.startsWith(wtDir + sep);
@ -517,6 +518,9 @@ export function removeWorktree(
rmSync(wtInternalDir, { recursive: true, force: true });
}
rmSync(resolvedWtPath, { recursive: true, force: true });
if (wtPath !== resolvedWtPath && existsSync(wtPath)) {
rmSync(wtPath, { recursive: true, force: true });
}
} catch {
logWarning(
"reconcile",

View file

@ -350,6 +350,7 @@ test("assembled lifecycle: boot → onboard → prompt → streaming text → to
onboarding.configureOnboardingServiceForTests({
authStorage,
getEnvApiKey: () => undefined,
validateApiKey: async () => ({ ok: true, message: "openai credentials validated" }),
});
@ -694,6 +695,7 @@ test("assembled settings controls keep retry visibility and daily-use mutations
authStorage: AuthStorage.inMemory({
anthropic: { type: "api_key", key: "sk-test-assembled-settings" },
} as any),
getEnvApiKey: () => undefined,
});
t.after(async () => {
@ -964,6 +966,7 @@ test("assembled slash-command behavior keeps built-ins safe while preserving GSD
authStorage: AuthStorage.inMemory({
anthropic: { type: "api_key", key: "sk-test-assembled-slash" },
} as any),
getEnvApiKey: () => undefined,
});
t.after(async () => {

View file

@ -301,6 +301,7 @@ test("successful browser onboarding restarts the stale bridge child and unlocks
const harness = configureBridgeRuntime(fixture, authStorage);
onboarding.configureOnboardingServiceForTests({
authStorage,
getEnvApiKey: () => undefined,
validateApiKey: async () => ({ ok: true, message: "openai credentials validated" }),
});
@ -368,6 +369,7 @@ test("refresh failures keep the workspace locked and expose the failed bridge-re
const harness = configureBridgeRuntime(fixture, authStorage, { failRestart: true });
onboarding.configureOnboardingServiceForTests({
authStorage,
getEnvApiKey: () => undefined,
validateApiKey: async () => ({ ok: true, message: "openai credentials validated" }),
});

View file

@ -13,6 +13,52 @@ const packagedWebHostPath = join(projectRoot, "dist", "web", "standalone", "serv
let runtimeArtifactsReady = false
const SANITIZED_PROVIDER_ENV_KEYS = [
"ANTHROPIC_OAUTH_TOKEN",
"ANTHROPIC_API_KEY",
"OPENAI_API_KEY",
"AZURE_OPENAI_API_KEY",
"GEMINI_API_KEY",
"GROQ_API_KEY",
"CEREBRAS_API_KEY",
"XAI_API_KEY",
"OPENROUTER_API_KEY",
"AI_GATEWAY_API_KEY",
"ZAI_API_KEY",
"MISTRAL_API_KEY",
"MINIMAX_API_KEY",
"MINIMAX_CN_API_KEY",
"HF_TOKEN",
"OPENCODE_API_KEY",
"KIMI_API_KEY",
"ALIBABA_API_KEY",
"COPILOT_GITHUB_TOKEN",
"GH_TOKEN",
"GITHUB_TOKEN",
"GOOGLE_APPLICATION_CREDENTIALS",
"GOOGLE_CLOUD_PROJECT",
"GCLOUD_PROJECT",
"GOOGLE_CLOUD_LOCATION",
"AWS_PROFILE",
"AWS_ACCESS_KEY_ID",
"AWS_SECRET_ACCESS_KEY",
"AWS_BEARER_TOKEN_BEDROCK",
"AWS_CONTAINER_CREDENTIALS_RELATIVE_URI",
"AWS_CONTAINER_CREDENTIALS_FULL_URI",
"AWS_WEB_IDENTITY_TOKEN_FILE",
] as const
function buildSanitizedRuntimeEnv(overrides?: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
const env: NodeJS.ProcessEnv = { ...process.env }
for (const key of SANITIZED_PROVIDER_ENV_KEYS) {
env[key] = ""
}
return {
...env,
...overrides,
}
}
type RuntimeEndpoint = "boot" | "events"
type RuntimeRequestDiagnostic = {
@ -147,12 +193,11 @@ export async function launchPackagedWebHost(options: {
{
cwd: options.launchCwd,
env: {
...process.env,
...buildSanitizedRuntimeEnv(options.env),
HOME: options.tempHome,
PATH: `${fakeBin}:${process.env.PATH || ""}`,
CI: "1",
FORCE_COLOR: "0",
...options.env,
},
stdio: ["ignore", "pipe", "pipe"],
},

View file

@ -53,18 +53,24 @@ test("hasStaleCompiledExtensionSiblings only flags top-level .ts/.js sibling pai
const { hasStaleCompiledExtensionSiblings } = await import("../resource-loader.ts");
const tmp = mkdtempSync(join(tmpdir(), "gsd-resource-loader-"));
const extensionsDir = join(tmp, "extensions");
const bundledDir = join(tmp, "bundled");
t.after(() => { rmSync(tmp, { recursive: true, force: true }); });
mkdirSync(bundledDir, { recursive: true });
mkdirSync(join(extensionsDir, "gsd"), { recursive: true });
writeFileSync(join(extensionsDir, "gsd", "index.ts"), "export {};\n");
assert.equal(hasStaleCompiledExtensionSiblings(extensionsDir), false);
assert.equal(hasStaleCompiledExtensionSiblings(extensionsDir, bundledDir), false);
writeFileSync(join(bundledDir, "ask-user-questions.js"), "export {};\n");
writeFileSync(join(extensionsDir, "ask-user-questions.js"), "export {};\n");
assert.equal(hasStaleCompiledExtensionSiblings(extensionsDir), false);
assert.equal(hasStaleCompiledExtensionSiblings(extensionsDir, bundledDir), false);
writeFileSync(join(extensionsDir, "ask-user-questions.ts"), "export {};\n");
assert.equal(hasStaleCompiledExtensionSiblings(extensionsDir), true);
assert.equal(hasStaleCompiledExtensionSiblings(extensionsDir, bundledDir), true);
writeFileSync(join(bundledDir, "ask-user-questions.ts"), "export {};\n");
assert.equal(hasStaleCompiledExtensionSiblings(extensionsDir, bundledDir), false);
});
test("buildResourceLoader excludes duplicate top-level pi extensions when bundled resources use .js", async (t) => {
@ -148,16 +154,30 @@ test("initResources prunes stale top-level extension siblings next to bundled co
const staleSiblingPath = bundledPath.endsWith(".js")
? bundledTsPath
: bundledJsPath;
const siblingWasBundled = existsSync(staleSiblingPath);
const staleContent = "export {};\n";
assert.equal(existsSync(bundledPath), true, "bundled top-level extension should exist");
// Simulate a stale opposite-format sibling left from a previous sync/build mismatch.
writeFileSync(staleSiblingPath, "export {};\n");
writeFileSync(staleSiblingPath, staleContent);
assert.equal(existsSync(staleSiblingPath), true);
// Force a full resync so this test exercises the prune/copy path rather than
// the early-return manifest fast path.
const manifestPath = join(fakeAgentDir, "managed-resources.json");
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
manifest.contentHash = "force-resync";
writeFileSync(manifestPath, JSON.stringify(manifest));
initResources(fakeAgentDir);
assert.equal(existsSync(staleSiblingPath), false, "stale top-level sibling should be removed during sync");
if (siblingWasBundled) {
assert.equal(existsSync(staleSiblingPath), true, "bundled sibling should be restored during sync");
assert.notEqual(readFileSync(staleSiblingPath, "utf-8"), staleContent, "bundled sibling should overwrite stale contents");
} else {
assert.equal(existsSync(staleSiblingPath), false, "stale top-level sibling should be removed during sync");
}
assert.equal(existsSync(bundledPath), true, "bundled extension should remain after cleanup");
});

View file

@ -231,7 +231,9 @@ function resolveOnboardingLockReason(
function hasStoredCredentialValue(authStorage: AuthStorageInstance, providerId: string): boolean {
return authStorage.getCredentialsForProvider(providerId).some((credential) => {
if (credential.type === "oauth") return true;
if (credential.type === "oauth") {
return typeof credential.access === "string" && credential.access.trim().length > 0;
}
return typeof credential.key === "string" && credential.key.trim().length > 0;
});
}
@ -247,9 +249,6 @@ function resolveCredentialSource(
if (getEnvApiKeyFn(providerId)) {
return "environment";
}
if (authStorage.getCredentialsForProvider(providerId).length > 0) {
return "runtime";
}
return null;
}

View file

@ -1,12 +1,12 @@
{
"name": "gsd-2",
"version": "0.1.0",
"version": "0.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "gsd-2",
"version": "0.1.0",
"version": "0.3.0",
"license": "MIT",
"devDependencies": {
"@types/vscode": "^1.95.0",
@ -955,9 +955,9 @@
"license": "BSD-2-Clause"
},
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1808,9 +1808,9 @@
}
},
"node_modules/glob/node_modules/brace-expansion": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -2352,9 +2352,9 @@
}
},
"node_modules/lodash": {
"version": "4.17.23",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
"version": "4.18.1",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"dev": true,
"license": "MIT"
},
@ -2903,9 +2903,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true,
"license": "MIT",
"engines": {

View file

@ -1,5 +1,5 @@
import * as vscode from "vscode";
import { exec } from "node:child_process";
import { execFile } from "node:child_process";
import type { GsdChangeTracker } from "./change-tracker.js";
/**
@ -31,11 +31,11 @@ export class GsdGitIntegration implements vscode.Disposable {
});
if (!message) return;
try {
// Stage the modified files
await this.git(`add ${files.map((f) => `"${f}"`).join(" ")}`);
// Commit
await this.git(`commit -m "${message.replace(/"/g, '\\"')}"`);
try {
// Stage the modified files
await this.git(["add", ...files]);
// Commit
await this.git(["commit", "-m", message]);
// Accept all changes (clear tracking since they're committed)
this.tracker.acceptAll();
@ -62,8 +62,8 @@ export class GsdGitIntegration implements vscode.Disposable {
});
if (!branchName) return;
try {
await this.git(`checkout -b "${branchName}"`);
try {
await this.git(["checkout", "-b", branchName]);
vscode.window.showInformationMessage(`Created and switched to branch: ${branchName}`);
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
@ -81,11 +81,11 @@ export class GsdGitIntegration implements vscode.Disposable {
return;
}
try {
const diff = await this.git("diff");
if (!diff.trim()) {
// Files may be untracked — show status instead
const status = await this.git("status --short");
try {
const diff = await this.git(["diff"]);
if (!diff.trim()) {
// Files may be untracked — show status instead
const status = await this.git(["status", "--short"]);
const channel = vscode.window.createOutputChannel("GSD Git Diff");
channel.appendLine("# Agent-modified files (unstaged):");
channel.appendLine(status);
@ -108,9 +108,9 @@ export class GsdGitIntegration implements vscode.Disposable {
}
}
private git(args: string): Promise<string> {
private git(args: string[]): Promise<string> {
return new Promise((resolve, reject) => {
exec(`git ${args}`, { cwd: this.cwd, maxBuffer: 10 * 1024 * 1024 }, (err, stdout, stderr) => {
execFile("git", args, { cwd: this.cwd, maxBuffer: 10 * 1024 * 1024 }, (err, stdout, stderr) => {
if (err) {
reject(new Error(stderr.trim() || err.message));
} else {

148
web/package-lock.json generated
View file

@ -52,7 +52,7 @@
"input-otp": "1.4.2",
"lucide-react": "^0.564.0",
"motion": "^12.36.0",
"next": "16.1.6",
"next": "16.2.3",
"next-themes": "^0.4.6",
"node-pty": "^1.1.0",
"react": "19.2.4",
@ -77,7 +77,7 @@
"@types/react-dom": "19.2.3",
"esbuild": "^0.27.4",
"eslint": "^9.38.0",
"eslint-config-next": "16.1.6",
"eslint-config-next": "16.2.3",
"postcss": "^8.5",
"tailwindcss": "^4.2.0",
"tw-animate-css": "1.3.3",
@ -2181,15 +2181,15 @@
}
},
"node_modules/@next/env": {
"version": "16.1.6",
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.6.tgz",
"integrity": "sha512-N1ySLuZjnAtN3kFnwhAwPvZah8RJxKasD7x1f8shFqhncnWZn4JMfg37diLNuoHsLAlrDfM3g4mawVdtAG8XLQ==",
"version": "16.2.3",
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.3.tgz",
"integrity": "sha512-ZWXyj4uNu4GCWQw9cjRxWlbD+33mcDszIo9iQxFnBX3Wmgq9ulaSJcl6VhuWx5pCWqqD+9W6Wfz7N0lM5lYPMA==",
"license": "MIT"
},
"node_modules/@next/eslint-plugin-next": {
"version": "16.1.6",
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.1.6.tgz",
"integrity": "sha512-/Qq3PTagA6+nYVfryAtQ7/9FEr/6YVyvOtl6rZnGsbReGLf0jZU6gkpr1FuChAQpvV46a78p4cmHOVP8mbfSMQ==",
"version": "16.2.3",
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-16.2.3.tgz",
"integrity": "sha512-nE/b9mht28XJxjTwKs/yk7w4XTaU3t40UHVAky6cjiijdP/SEy3hGsnQMPxmXPTpC7W4/97okm6fngKnvCqVaA==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -2197,9 +2197,9 @@
}
},
"node_modules/@next/swc-darwin-arm64": {
"version": "16.1.6",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.1.6.tgz",
"integrity": "sha512-wTzYulosJr/6nFnqGW7FrG3jfUUlEf8UjGA0/pyypJl42ExdVgC6xJgcXQ+V8QFn6niSG2Pb8+MIG1mZr2vczw==",
"version": "16.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.3.tgz",
"integrity": "sha512-u37KDKTKQ+OQLvY+z7SNXixwo4Q2/IAJFDzU1fYe66IbCE51aDSAzkNDkWmLN0yjTUh4BKBd+hb69jYn6qqqSg==",
"cpu": [
"arm64"
],
@ -2213,9 +2213,9 @@
}
},
"node_modules/@next/swc-darwin-x64": {
"version": "16.1.6",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.1.6.tgz",
"integrity": "sha512-BLFPYPDO+MNJsiDWbeVzqvYd4NyuRrEYVB5k2N3JfWncuHAy2IVwMAOlVQDFjj+krkWzhY2apvmekMkfQR0CUQ==",
"version": "16.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.3.tgz",
"integrity": "sha512-gHjL/qy6Q6CG3176FWbAKyKh9IfntKZTB3RY/YOJdDFpHGsUDXVH38U4mMNpHVGXmeYW4wj22dMp1lTfmu/bTQ==",
"cpu": [
"x64"
],
@ -2229,12 +2229,15 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
"version": "16.1.6",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.1.6.tgz",
"integrity": "sha512-OJYkCd5pj/QloBvoEcJ2XiMnlJkRv9idWA/j0ugSuA34gMT6f5b7vOiCQHVRpvStoZUknhl6/UxOXL4OwtdaBw==",
"version": "16.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.3.tgz",
"integrity": "sha512-U6vtblPtU/P14Y/b/n9ZY0GOxbbIhTFuaFR7F4/uMBidCi2nSdaOFhA0Go81L61Zd6527+yvuX44T4ksnf8T+Q==",
"cpu": [
"arm64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@ -2245,12 +2248,15 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
"version": "16.1.6",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.1.6.tgz",
"integrity": "sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==",
"version": "16.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.3.tgz",
"integrity": "sha512-/YV0LgjHUmfhQpn9bVoGc4x4nan64pkhWR5wyEV8yCOfwwrH630KpvRg86olQHTwHIn1z59uh6JwKvHq1h4QEw==",
"cpu": [
"arm64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@ -2261,12 +2267,15 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
"version": "16.1.6",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.1.6.tgz",
"integrity": "sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==",
"version": "16.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.3.tgz",
"integrity": "sha512-/HiWEcp+WMZ7VajuiMEFGZ6cg0+aYZPqCJD3YJEfpVWQsKYSjXQG06vJP6F1rdA03COD9Fef4aODs3YxKx+RDQ==",
"cpu": [
"x64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@ -2277,12 +2286,15 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
"version": "16.1.6",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.1.6.tgz",
"integrity": "sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==",
"version": "16.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.3.tgz",
"integrity": "sha512-Kt44hGJfZSefebhk/7nIdivoDr3Ugp5+oNz9VvF3GUtfxutucUIHfIO0ZYO8QlOPDQloUVQn4NVC/9JvHRk9hw==",
"cpu": [
"x64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@ -2293,9 +2305,9 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
"version": "16.1.6",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.1.6.tgz",
"integrity": "sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==",
"version": "16.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.3.tgz",
"integrity": "sha512-O2NZ9ie3Tq6xj5Z5CSwBT3+aWAMW2PIZ4egUi9MaWLkwaehgtB7YZjPm+UpcNpKOme0IQuqDcor7BsW6QBiQBw==",
"cpu": [
"arm64"
],
@ -2309,9 +2321,9 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
"version": "16.1.6",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.1.6.tgz",
"integrity": "sha512-NRfO39AIrzBnixKbjuo2YiYhB6o9d8v/ymU9m/Xk8cyVk+k7XylniXkHwjs4s70wedVffc6bQNbufk5v0xEm0A==",
"version": "16.2.3",
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.3.tgz",
"integrity": "sha512-Ibm29/GgB/ab5n7XKqlStkm54qqZE8v2FnijUPBgrd67FWrac45o/RsNlaOWjme/B5UqeWt/8KM4aWBwA1D2Kw==",
"cpu": [
"x64"
],
@ -4882,9 +4894,9 @@
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -5731,9 +5743,9 @@
}
},
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
"integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -6785,13 +6797,13 @@
}
},
"node_modules/eslint-config-next": {
"version": "16.1.6",
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.1.6.tgz",
"integrity": "sha512-vKq40io2B0XtkkNDYyleATwblNt8xuh3FWp8SpSz3pt7P01OkBFlKsJZ2mWt5WsCySlDQLckb1zMY9yE9Qy0LA==",
"version": "16.2.3",
"resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-16.2.3.tgz",
"integrity": "sha512-Dnkrylzjof/Az7iNoIQJqD18zTxQZcngir19KJaiRsMnnjpQSVoa6aEg/1Q4hQC+cW90uTlgQYadwL1CYNwFWA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@next/eslint-plugin-next": "16.1.6",
"@next/eslint-plugin-next": "16.2.3",
"eslint-import-resolver-node": "^0.3.6",
"eslint-import-resolver-typescript": "^3.5.2",
"eslint-plugin-import": "^2.32.0",
@ -7324,9 +7336,9 @@
}
},
"node_modules/flatted": {
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.1.tgz",
"integrity": "sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==",
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"dev": true,
"license": "ISC"
},
@ -8764,9 +8776,9 @@
}
},
"node_modules/lodash": {
"version": "4.17.23",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
"integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
"version": "4.18.1",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
"license": "MIT"
},
"node_modules/lodash.merge": {
@ -9828,14 +9840,14 @@
"license": "MIT"
},
"node_modules/next": {
"version": "16.1.6",
"resolved": "https://registry.npmjs.org/next/-/next-16.1.6.tgz",
"integrity": "sha512-hkyRkcu5x/41KoqnROkfTm2pZVbKxvbZRuNvKXLRXxs3VfyO0WhY50TQS40EuKO9SW3rBj/sF3WbVwDACeMZyw==",
"version": "16.2.3",
"resolved": "https://registry.npmjs.org/next/-/next-16.2.3.tgz",
"integrity": "sha512-9V3zV4oZFza3PVev5/poB9g0dEafVcgNyQ8eTRop8GvxZjV2G15FC5ARuG1eFD42QgeYkzJBJzHghNP8Ad9xtA==",
"license": "MIT",
"dependencies": {
"@next/env": "16.1.6",
"@next/env": "16.2.3",
"@swc/helpers": "0.5.15",
"baseline-browser-mapping": "^2.8.3",
"baseline-browser-mapping": "^2.9.19",
"caniuse-lite": "^1.0.30001579",
"postcss": "8.4.31",
"styled-jsx": "5.1.6"
@ -9847,15 +9859,15 @@
"node": ">=20.9.0"
},
"optionalDependencies": {
"@next/swc-darwin-arm64": "16.1.6",
"@next/swc-darwin-x64": "16.1.6",
"@next/swc-linux-arm64-gnu": "16.1.6",
"@next/swc-linux-arm64-musl": "16.1.6",
"@next/swc-linux-x64-gnu": "16.1.6",
"@next/swc-linux-x64-musl": "16.1.6",
"@next/swc-win32-arm64-msvc": "16.1.6",
"@next/swc-win32-x64-msvc": "16.1.6",
"sharp": "^0.34.4"
"@next/swc-darwin-arm64": "16.2.3",
"@next/swc-darwin-x64": "16.2.3",
"@next/swc-linux-arm64-gnu": "16.2.3",
"@next/swc-linux-arm64-musl": "16.2.3",
"@next/swc-linux-x64-gnu": "16.2.3",
"@next/swc-linux-x64-musl": "16.2.3",
"@next/swc-win32-arm64-msvc": "16.2.3",
"@next/swc-win32-x64-msvc": "16.2.3",
"sharp": "^0.34.5"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
@ -10248,9 +10260,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true,
"license": "MIT",
"engines": {
@ -11453,9 +11465,9 @@
}
},
"node_modules/tinyglobby/node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {

View file

@ -55,7 +55,7 @@
"input-otp": "1.4.2",
"lucide-react": "^0.564.0",
"motion": "^12.36.0",
"next": "16.1.6",
"next": "16.2.3",
"next-themes": "^0.4.6",
"node-pty": "^1.1.0",
"react": "19.2.4",
@ -80,7 +80,7 @@
"@types/react-dom": "19.2.3",
"esbuild": "^0.27.4",
"eslint": "^9.38.0",
"eslint-config-next": "16.1.6",
"eslint-config-next": "16.2.3",
"postcss": "^8.5",
"tailwindcss": "^4.2.0",
"tw-animate-css": "1.3.3",