Compare commits

..
Author SHA1 Message Date
dayuan.jiang ab33dae69d fix(mcp-server): read npm 12's pack output in the package check
The publish workflow installs the latest npm, and npm 12 prints
`npm pack --json` as an object keyed by package name instead of a list,
so check-package failed and 0.3.0 was not published. Accept both.
2026-10-05 22:43:05 +09:00
6 changed files with 1731 additions and 1142 deletions
+22 -25
View File
@@ -77,7 +77,6 @@ export default function ExamplePanel({
minimal?: boolean
}) {
const dict = useDictionary()
const isSelfHosted = process.env.NEXT_PUBLIC_SELFHOSTED === "true"
const handleReplicateFlowchart = async () => {
setInput("Replicate this flowchart.")
@@ -126,31 +125,29 @@ export default function ExamplePanel({
<div className={minimal ? "" : "py-6 px-2 animate-fade-in"}>
{!minimal && (
<>
{/* MCP Server Notice, hidden on self-hosted deployments */}
{!isSelfHosted && (
<a
href="https://github.com/DayuanJiang/next-ai-draw-io/tree/main/packages/mcp-server"
target="_blank"
rel="noopener noreferrer"
className="block mb-4 p-3 rounded-xl bg-gradient-to-r from-purple-500/10 to-blue-500/10 border border-purple-500/20 hover:border-purple-500/40 transition-colors group"
>
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-purple-500/20 flex items-center justify-center shrink-0">
<Terminal className="w-4 h-4 text-purple-500" />
</div>
<div className="min-w-0">
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-foreground group-hover:text-purple-500 transition-colors">
{dict.examples.mcpServer}
</span>
</div>
<p className="text-xs text-muted-foreground">
{dict.examples.mcpDescription}
</p>
</div>
{/* MCP Server Notice */}
<a
href="https://github.com/DayuanJiang/next-ai-draw-io/tree/main/packages/mcp-server"
target="_blank"
rel="noopener noreferrer"
className="block mb-4 p-3 rounded-xl bg-gradient-to-r from-purple-500/10 to-blue-500/10 border border-purple-500/20 hover:border-purple-500/40 transition-colors group"
>
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-purple-500/20 flex items-center justify-center shrink-0">
<Terminal className="w-4 h-4 text-purple-500" />
</div>
</a>
)}
<div className="min-w-0">
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-foreground group-hover:text-purple-500 transition-colors">
{dict.examples.mcpServer}
</span>
</div>
<p className="text-xs text-muted-foreground">
{dict.examples.mcpDescription}
</p>
</div>
</div>
</a>
{/* Welcome section */}
<div className="text-center mb-6">
+1 -2
View File
@@ -1,6 +1,6 @@
# AI Provider Configuration
# AI_PROVIDER: Which provider to use
# Options: bedrock, openai, anthropic, google, vertexai, azure, ollama, openrouter, aihubmix, deepseek, siliconflow, sglang, gateway, edgeone, doubao, modelscope, glm, qwen, qiniu, kimi, minimax, novita, mimo, atlascloud
# Options: bedrock, openai, anthropic, google, vertexai, azure, ollama, openrouter, aihubmix, deepseek, siliconflow, gateway, novita
# Default: bedrock
AI_PROVIDER=bedrock
@@ -168,7 +168,6 @@ AI_MODEL=global.anthropic.claude-sonnet-4-5-20250929-v1:0
# which triggers the client UI to display messages suggesting self-hosting or sponsorship.
# This switch allows self-hosted users to provide custom messages in response to a 429 code,
# in messageTokenSelfHosted, messageApiSelfHosted, and tipSelfHosted translation strings.
# It also turns off the MCP server advertisement in the chat examples.
# NEXT_PUBLIC_SELFHOSTED=true
# Minimax Configuration (Optional)
+1 -6
View File
@@ -125,12 +125,7 @@ let writableCache: boolean | null = null
export function isSettingsWritable(): boolean {
if (writableCache !== null) return writableCache
try {
const filePath = getSettingsPath()
if (fs.existsSync(filePath) && !fs.statSync(filePath).isFile()) {
writableCache = false
return writableCache
}
const dir = path.dirname(filePath)
const dir = path.dirname(getSettingsPath())
fs.mkdirSync(dir, { recursive: true })
fs.accessSync(dir, fs.constants.W_OK)
writableCache = true
+1689 -1090
View File
File diff suppressed because it is too large Load Diff
+14 -13
View File
@@ -31,15 +31,15 @@
"test:e2e": "playwright test"
},
"dependencies": {
"@ai-sdk/amazon-bedrock": "^5.0.0",
"@ai-sdk/anthropic": "^4.0.0",
"@ai-sdk/azure": "^4.0.0",
"@ai-sdk/deepseek": "^3.0.0",
"@ai-sdk/google": "^4.0.0",
"@ai-sdk/google-vertex": "^5.0.0",
"@ai-sdk/openai": "^4.0.0",
"@ai-sdk/openai-compatible": "^3.0.0",
"@ai-sdk/react": "^4.0.0",
"@ai-sdk/amazon-bedrock": "^4.0.191",
"@ai-sdk/anthropic": "^3.0.127",
"@ai-sdk/azure": "^3.0.133",
"@ai-sdk/deepseek": "^2.0.71",
"@ai-sdk/google": "^3.0.130",
"@ai-sdk/google-vertex": "^4.0.210",
"@ai-sdk/openai": "^3.0.124",
"@ai-sdk/openai-compatible": "^2.0.81",
"@ai-sdk/react": "^3.0.303",
"@aihubmix/ai-sdk-provider": "^2.2.1",
"@aws-sdk/client-dynamodb": "^3.957.0",
"@aws-sdk/credential-providers": "^3.943.0",
@@ -50,7 +50,7 @@
"@langfuse/tracing": "^4.4.9",
"@next/third-parties": "^16.0.6",
"@opennextjs/cloudflare": "^1.17.1",
"@openrouter/ai-sdk-provider": "^3.0.0",
"@openrouter/ai-sdk-provider": "^2.10.0",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/exporter-trace-otlp-http": "^0.222.0",
"@opentelemetry/sdk-trace-node": "^2.2.0",
@@ -66,7 +66,8 @@
"@radix-ui/react-tooltip": "^1.1.8",
"@radix-ui/react-use-controllable-state": "^1.2.2",
"@xmldom/xmldom": "^0.9.8",
"ai": "^7.0.0",
"ai": "^6.0.300",
"base-64": "^1.0.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
@@ -77,7 +78,7 @@
"nanoid": "^5.0.0",
"negotiator": "^1.0.0",
"next": "^16.0.7",
"ollama-ai-provider-v2": "^4.0.0",
"ollama-ai-provider-v2": "^3.6.0",
"pako": "^2.1.0",
"prism-react-renderer": "^2.4.1",
"react": "^19.1.2",
@@ -144,7 +145,7 @@
},
"overrides": {
"@openrouter/ai-sdk-provider": {
"ai": "^7.0.0"
"ai": "^6.0.1"
}
}
}
+4 -6
View File
@@ -154,9 +154,9 @@ describe("isSettingsWritable", () => {
expect(isSettingsWritable()).toBe(true)
})
it("returns false when the settings path is a directory", () => {
it("returns false for an unwritable path", () => {
_resetForTests()
process.env.SETTINGS_FILE = tmpDir
process.env.SETTINGS_FILE = "/nonexistent-root-dir/settings.json"
expect(isSettingsWritable()).toBe(false)
})
})
@@ -170,9 +170,7 @@ describe("settings file on disk", () => {
version: 1,
values: { TEST_ADMIN_VAR: "secret" },
})
if (process.platform !== "win32") {
const mode = fs.statSync(filePath).mode & 0o777
expect(mode).toBe(0o600)
}
const mode = fs.statSync(filePath).mode & 0o777
expect(mode).toBe(0o600)
})
})