ci: move deployment to new sveltekit app
This commit is contained in:
@@ -1 +0,0 @@
|
||||
.vercel
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 MiB |
@@ -1,30 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Rubber Duck - Voice Activity Detector</title>
|
||||
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>🦆</text></svg>" />
|
||||
<link rel="stylesheet" href="style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div id="duck-wrapper">
|
||||
<div id="duck-indicator" class="silent">
|
||||
<svg viewBox="0 0 100 100" class="duck-icon">
|
||||
<path d="M35 60 Q20 55 15 45 Q10 35 20 30 Q25 28 30 30 Q28 20 35 15 Q42 10 50 15 Q55 12 60 18 Q65 15 68 22 Q75 25 78 32 Q85 35 82 45 Q80 50 75 52 Q80 58 75 65 Q70 72 60 70 Q55 75 45 75 Q40 72 35 70 Z" fill="#FFD700" stroke="#DAA520" stroke-width="2"/>
|
||||
<circle cx="45" cy="38" r="5" fill="#333"/>
|
||||
<path d="M38 28 Q42 25 46 28" fill="none" stroke="#333" stroke-width="2" stroke-linecap="round"/>
|
||||
<ellipse cx="68" cy="45" rx="10" ry="6" fill="#FF8C00" opacity="0.6"/>
|
||||
</svg>
|
||||
<div id="glow-ring"></div>
|
||||
</div>
|
||||
</div>
|
||||
<p id="status-text">Click "Start" to begin</p>
|
||||
<button id="toggle-btn" class="btn">Start</button>
|
||||
<p id="error-text" class="error hidden"></p>
|
||||
<p class="hint">Grant microphone access to start voice detection</p>
|
||||
</div>
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,121 +0,0 @@
|
||||
const indicator = document.getElementById('duck-indicator')
|
||||
const statusText = document.getElementById('status-text')
|
||||
const toggleBtn = document.getElementById('toggle-btn')
|
||||
const errorText = document.getElementById('error-text')
|
||||
|
||||
let detector = null
|
||||
|
||||
class SmartVoiceDetector {
|
||||
constructor(options = {}) {
|
||||
this.threshold = options.threshold ?? -50
|
||||
this.silenceDelay = options.silenceDelay ?? 700
|
||||
this.onSpeechStart = options.onSpeechStart || (() => {})
|
||||
this.onSpeechEnd = options.onSpeechEnd || (() => {})
|
||||
|
||||
this.isSpeaking = false
|
||||
this.timeout = null
|
||||
this.audioContext = null
|
||||
this.running = false
|
||||
}
|
||||
|
||||
async start() {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
|
||||
this.audioContext = new AudioContext()
|
||||
const source = this.audioContext.createMediaStreamSource(stream)
|
||||
const analyser = this.audioContext.createAnalyser()
|
||||
|
||||
analyser.fftSize = 1024
|
||||
analyser.smoothingTimeConstant = 0.4
|
||||
source.connect(analyser)
|
||||
|
||||
const bufferLength = analyser.frequencyBinCount
|
||||
const dataArray = new Float32Array(bufferLength)
|
||||
|
||||
const sampleRate = this.audioContext.sampleRate
|
||||
const minHz = 85
|
||||
const maxHz = 3000
|
||||
const minIndex = Math.floor(minHz / (sampleRate / analyser.fftSize))
|
||||
const maxIndex = Math.ceil(maxHz / (sampleRate / analyser.fftSize))
|
||||
|
||||
this.running = true
|
||||
const check = () => {
|
||||
if (!this.running) return
|
||||
|
||||
analyser.getFloatFrequencyData(dataArray)
|
||||
|
||||
let maxVolume = -Infinity
|
||||
for (let i = minIndex; i <= maxIndex; i++) {
|
||||
if (dataArray[i] > maxVolume) maxVolume = dataArray[i]
|
||||
}
|
||||
|
||||
if (maxVolume > this.threshold) {
|
||||
if (!this.isSpeaking) {
|
||||
this.isSpeaking = true
|
||||
this.onSpeechStart()
|
||||
}
|
||||
clearTimeout(this.timeout)
|
||||
this.timeout = null
|
||||
} else if (this.isSpeaking && !this.timeout) {
|
||||
this.timeout = setTimeout(() => {
|
||||
this.isSpeaking = false
|
||||
this.onSpeechEnd()
|
||||
}, this.silenceDelay)
|
||||
}
|
||||
|
||||
requestAnimationFrame(check)
|
||||
}
|
||||
|
||||
check()
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.running = false
|
||||
if (this.audioContext) {
|
||||
this.audioContext.close()
|
||||
this.audioContext = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toggleBtn.addEventListener('click', async () => {
|
||||
if (detector) {
|
||||
detector.stop()
|
||||
detector = null
|
||||
statusText.textContent = 'Stopped'
|
||||
toggleBtn.textContent = 'Start'
|
||||
indicator.classList.remove('speaking')
|
||||
indicator.classList.add('silent')
|
||||
return
|
||||
}
|
||||
|
||||
toggleBtn.disabled = true
|
||||
statusText.textContent = 'Starting...'
|
||||
|
||||
try {
|
||||
detector = new SmartVoiceDetector({
|
||||
threshold: -50,
|
||||
onSpeechStart: () => {
|
||||
indicator.classList.remove('silent')
|
||||
indicator.classList.add('speaking')
|
||||
statusText.textContent = 'Voice detected'
|
||||
},
|
||||
onSpeechEnd: () => {
|
||||
indicator.classList.remove('speaking')
|
||||
indicator.classList.add('silent')
|
||||
statusText.textContent = 'Listening...'
|
||||
},
|
||||
})
|
||||
|
||||
await detector.start()
|
||||
statusText.textContent = 'Listening...'
|
||||
toggleBtn.textContent = 'Stop'
|
||||
toggleBtn.disabled = false
|
||||
} catch (err) {
|
||||
console.error('Mic error:', err)
|
||||
errorText.textContent = err.message || String(err)
|
||||
errorText.classList.remove('hidden')
|
||||
statusText.textContent = 'Error'
|
||||
toggleBtn.textContent = 'Retry'
|
||||
toggleBtn.disabled = false
|
||||
}
|
||||
})
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"name": "rubber-duck",
|
||||
"version": "0.0.1",
|
||||
"description": "Best debug tool - rubber duck",
|
||||
"keywords": [
|
||||
"rubber",
|
||||
"duck",
|
||||
"debug",
|
||||
"tool",
|
||||
"fun"
|
||||
],
|
||||
"homepage": "https://github.com/Ku6epXBOCTuK/rubber-duck#readme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Ku6epXBOCTuK/rubber-duck/issues"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Ku6epXBOCTuK/rubber-duck.git"
|
||||
},
|
||||
"license": "MIT",
|
||||
"author": "Ku6epXBOCTuK",
|
||||
"type": "module",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite": "^8.0.11"
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: #1a1a2e;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#duck-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#duck-indicator {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
transition: filter 0.3s ease;
|
||||
}
|
||||
|
||||
.duck-icon {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
#glow-ring {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
#duck-indicator.silent #glow-ring {
|
||||
background: radial-gradient(circle, rgba(255, 50, 50, 0.3) 0%, transparent 70%);
|
||||
box-shadow: 0 0 40px 10px rgba(255, 50, 50, 0.2), inset 0 0 40px 10px rgba(255, 50, 50, 0.05);
|
||||
}
|
||||
|
||||
#duck-indicator.speaking #glow-ring {
|
||||
background: radial-gradient(circle, rgba(50, 255, 50, 0.4) 0%, transparent 70%);
|
||||
box-shadow: 0 0 60px 20px rgba(50, 255, 50, 0.3), inset 0 0 60px 20px rgba(50, 255, 50, 0.1);
|
||||
animation: pulse 1.2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { transform: scale(1); opacity: 1; }
|
||||
50% { transform: scale(1.08); opacity: 0.85; }
|
||||
}
|
||||
|
||||
#status-text {
|
||||
margin-top: 20px;
|
||||
font-size: 1.2rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin-top: 16px;
|
||||
padding: 10px 28px;
|
||||
font-size: 1rem;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
background: #16213e;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #0f3460;
|
||||
}
|
||||
|
||||
.hint {
|
||||
margin-top: 24px;
|
||||
font-size: 0.85rem;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.error {
|
||||
margin-top: 12px;
|
||||
color: #ff6b6b;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { defineConfig } from 'vite'
|
||||
|
||||
export default defineConfig({
|
||||
assetsInlineLimit: 0,
|
||||
})
|
||||
@@ -1,43 +0,0 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.*
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/versions
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# env files (can opt-in for committing if needed)
|
||||
.env*
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
.vercel
|
||||
@@ -1,9 +0,0 @@
|
||||
<!-- BEGIN:nextjs-agent-rules -->
|
||||
|
||||
# This is NOT the Next.js you know
|
||||
|
||||
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.
|
||||
|
||||
This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.
|
||||
|
||||
<!-- END:nextjs-agent-rules -->
|
||||
@@ -1 +0,0 @@
|
||||
@AGENTS.md
|
||||
@@ -1,45 +0,0 @@
|
||||
# Rubber Duck MCP
|
||||
|
||||
MCP-сервер для техники «резиновая уточка»: когда ИИ застревает в логическом цикле или склонен к
|
||||
галлюцинациям, он вызывает инструмент `quack()`, чтобы сформулировать мысль и продолжить.
|
||||
|
||||
Сервер работает в режиме **Streamable HTTP** (stateless), развёртывается на Vercel, использует
|
||||
`mcp-handler` v2 + `@modelcontextprotocol/server` v2.
|
||||
|
||||
## Эндпоинт
|
||||
|
||||
```
|
||||
POST /api/mcp
|
||||
```
|
||||
|
||||
Подключите этот URL как MCP-сервер (тип Streamable HTTP) в Cursor, Claude Desktop и других клиентах.
|
||||
|
||||
## Инструменты
|
||||
|
||||
- `quack` — возвращает кряк. Опциональный параметр `mood`: `happy | confused | excited | sleepy`.
|
||||
|
||||
## Запуск
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm dev # http://localhost:3000
|
||||
pnpm build
|
||||
pnpm start
|
||||
```
|
||||
|
||||
## Проверка
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:3000/api/mcp \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Accept: application/json, text/event-stream" \
|
||||
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"quack","arguments":{"mood":"happy"}}}'
|
||||
```
|
||||
|
||||
## Деплой на Vercel
|
||||
|
||||
```bash
|
||||
vercel --prod
|
||||
```
|
||||
|
||||
(`rootDirectory` проекта — `apps/mcp`.)
|
||||
@@ -1,21 +0,0 @@
|
||||
import { createMcpHandler } from "mcp-handler";
|
||||
import { registerDuckTools } from "@/lib/mcp";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
|
||||
const post = createMcpHandler(
|
||||
async (server) => {
|
||||
registerDuckTools(server);
|
||||
},
|
||||
{
|
||||
serverInfo: { name: "rubber-duck-mcp", version: "1.0.0" },
|
||||
},
|
||||
);
|
||||
|
||||
export async function GET(req: Request) {
|
||||
return post(req);
|
||||
}
|
||||
|
||||
export async function POST(req: Request) {
|
||||
return post(req);
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 25 KiB |
@@ -1,49 +0,0 @@
|
||||
:root {
|
||||
--background: #ffffff;
|
||||
--foreground: #171717;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: #0a0a0a;
|
||||
--foreground: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
max-width: 100vw;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: var(--foreground);
|
||||
background: var(--background);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
html {
|
||||
color-scheme: dark;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import type { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Rubber Duck MCP",
|
||||
description: "MCP server for rubber duck debugging — quack() to articulate your thinking.",
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
export default function Home() {
|
||||
return (
|
||||
<main style={{ fontFamily: "system-ui, sans-serif", maxWidth: 640, margin: "0 auto", padding: "3rem 1rem" }}>
|
||||
<h1>Rubber Duck MCP</h1>
|
||||
<p>
|
||||
MCP-сервер для техники «резиновая уточка»: когда ИИ застревает, он вызывает инструмент{" "}
|
||||
<code>quack()</code>, чтобы сформулировать мысль и продолжить. Сервер работает в режиме
|
||||
Streamable HTTP и предназначен для подключения в Cursor, Claude Desktop и других MCP-клиентах.
|
||||
</p>
|
||||
<h2>Эндпоинт</h2>
|
||||
<p>
|
||||
<code>/api/mcp</code> — подключите этот URL как MCP-сервер (тип Streamable HTTP).
|
||||
</p>
|
||||
<h2>Инструменты</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<code>quack</code> — возвращает кряк. Опциональный параметр <code>mood</code>:{" "}
|
||||
<code>happy | confused | excited | sleepy</code>.
|
||||
</li>
|
||||
</ul>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import type { McpServer } from "@modelcontextprotocol/server";
|
||||
import { z } from "zod";
|
||||
|
||||
const QUACKS = {
|
||||
happy: ["QUACK! 🎉", "Quack quack! 😄", "QUAAACK! 🦆✨"],
|
||||
confused: ["Qu...ack?", "Quack? 🤔", "Quaaack...?"],
|
||||
excited: ["QUACK QUACK QUACK!", "QUAAACK!! 🔥", "Quack! Quack! Quack!"],
|
||||
sleepy: ["quack... 😴", "quaack... 💤", "quack. *yawn*"],
|
||||
default: ["Quack!", "Quack quack!", "QUACK!", "Quaaack!", "Quack. 🦆"],
|
||||
} as const;
|
||||
|
||||
const MOODS = ["happy", "confused", "excited", "sleepy"] as const;
|
||||
|
||||
function randomFrom<T>(arr: readonly T[]): T {
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
}
|
||||
|
||||
export function registerDuckTools(server: McpServer): void {
|
||||
server.registerTool(
|
||||
"quack",
|
||||
{
|
||||
title: "Quack",
|
||||
description:
|
||||
"Rubber duck quacks. Use when you're stuck, looping, or hallucinating. " +
|
||||
"The act of calling forces you to articulate your current thinking out loud.",
|
||||
inputSchema: z.object({
|
||||
mood: z
|
||||
.enum(MOODS)
|
||||
.optional()
|
||||
.describe("Mood of the duck. Omit for a random quack."),
|
||||
}),
|
||||
},
|
||||
async ({ mood }) => {
|
||||
const text = mood ? randomFrom(QUACKS[mood]) : randomFrom(QUACKS.default);
|
||||
return { content: [{ type: "text", text }] };
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
/* config options here */
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"name": "mcp",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/server": "^2.0.0",
|
||||
"mcp-handler": "^2.1.1",
|
||||
"next": "16.3.3",
|
||||
"react": "19.2.8",
|
||||
"react-dom": "19.2.8",
|
||||
"zod": "^4.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"packageManager": "pnpm@11.20.0"
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2017",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".next/types/**/*.ts",
|
||||
".next/dev/types/**/*.ts",
|
||||
"**/*.mts"
|
||||
],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
+23
-23
@@ -1,23 +1,23 @@
|
||||
node_modules
|
||||
|
||||
# Output
|
||||
.output
|
||||
.vercel
|
||||
.netlify
|
||||
.wrangler
|
||||
/.svelte-kit
|
||||
/build
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Env
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
# Vite
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
node_modules
|
||||
|
||||
# Output
|
||||
.output
|
||||
.vercel
|
||||
.netlify
|
||||
.wrangler
|
||||
/.svelte-kit
|
||||
/build
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Env
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.test
|
||||
|
||||
# Vite
|
||||
vite.config.js.timestamp-*
|
||||
vite.config.ts.timestamp-*
|
||||
|
||||
+4
-7
@@ -3,13 +3,10 @@
|
||||
"version": "1.0.0",
|
||||
"description": "Rubber duck debugging - frontend + MCP server monorepo",
|
||||
"scripts": {
|
||||
"dev": "pnpm --dir apps/frontend dev",
|
||||
"build-frontend": "pnpm --dir apps/frontend build",
|
||||
"build-mcp": "pnpm --dir apps/mcp build",
|
||||
"dev-mcp": "pnpm --dir apps/mcp dev",
|
||||
"typecheck-mcp": "pnpm --dir apps/mcp exec tsc --noEmit",
|
||||
"deploy-mcp": "vercel --cwd apps/mcp --prod --yes",
|
||||
"deploy-frontend": "vercel --cwd apps/frontend --prod --yes",
|
||||
"dev": "pnpm --dir apps/web dev",
|
||||
"build": "pnpm --dir apps/web build",
|
||||
"deploy": "vercel --cwd apps/web --prod --yes",
|
||||
"typecheck": "pnpm --dir apps/eval run typecheck && pnpm --dir apps/web run typecheck",
|
||||
"eval:run": "pnpm --dir apps/eval run run",
|
||||
"eval:review": "pnpm --dir apps/eval run review",
|
||||
"eval:sync": "node scripts/sync-report.mjs",
|
||||
|
||||
Generated
+19
-68
@@ -223,46 +223,6 @@ importers:
|
||||
specifier: ^5.9.3
|
||||
version: 5.9.3
|
||||
|
||||
apps/frontend:
|
||||
devDependencies:
|
||||
vite:
|
||||
specifier: ^8.0.11
|
||||
version: 8.2.2(@types/node@20.19.43)(esbuild@0.28.2)(tsx@4.23.13)
|
||||
|
||||
apps/mcp:
|
||||
dependencies:
|
||||
'@modelcontextprotocol/server':
|
||||
specifier: ^2.0.0
|
||||
version: 2.0.0
|
||||
mcp-handler:
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1(@modelcontextprotocol/server@2.0.0)(next@16.3.3(@types/node@20.19.43)(react-dom@19.2.8(react@19.2.8))(react@19.2.8))
|
||||
next:
|
||||
specifier: 16.3.3
|
||||
version: 16.3.3(@types/node@20.19.43)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)
|
||||
react:
|
||||
specifier: 19.2.8
|
||||
version: 19.2.8
|
||||
react-dom:
|
||||
specifier: 19.2.8
|
||||
version: 19.2.8(react@19.2.8)
|
||||
zod:
|
||||
specifier: ^4.5.4
|
||||
version: 4.5.4
|
||||
devDependencies:
|
||||
'@types/node':
|
||||
specifier: ^20
|
||||
version: 20.19.43
|
||||
'@types/react':
|
||||
specifier: ^19
|
||||
version: 19.2.18
|
||||
'@types/react-dom':
|
||||
specifier: ^19
|
||||
version: 19.2.5(@types/react@19.2.18)
|
||||
typescript:
|
||||
specifier: ^5
|
||||
version: 5.9.3
|
||||
|
||||
apps/web:
|
||||
dependencies:
|
||||
'@duck/types':
|
||||
@@ -887,14 +847,6 @@ packages:
|
||||
'@types/node@20.19.43':
|
||||
resolution: {integrity: sha512-6oYBAi5ikg4Pl+kGsoYtawUMBT2zZMCvPNF7pVLnHZfd1zf38DRiWn/gT01RYCdUqkv7Fhr+C9ot4/tb+2sVvA==}
|
||||
|
||||
'@types/react-dom@19.2.5':
|
||||
resolution: {integrity: sha512-fMPwH9v7r/pp43yUd2/Mbiex5KouJwwR3dzHkhLREUC6764VyDsqxhAxv6OFEYR1RhjOyD1naqba8ECDBe7ZQg==}
|
||||
peerDependencies:
|
||||
'@types/react': ^19.2.0
|
||||
|
||||
'@types/react@19.2.18':
|
||||
resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==}
|
||||
|
||||
'@vercel/nft@1.11.0':
|
||||
resolution: {integrity: sha512-m1QFg+U+3yPOnP1xSYJ73UIRxLOXdts1JOhiOiyPYqEsALgrXFFINvgUaD6R6iNvaBFAjHllBCbkfx4FuOdpaA==}
|
||||
engines: {node: '>=20'}
|
||||
@@ -979,9 +931,6 @@ packages:
|
||||
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
csstype@3.2.3:
|
||||
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
|
||||
|
||||
debug@4.4.3:
|
||||
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
|
||||
engines: {node: '>=6.0'}
|
||||
@@ -1663,7 +1612,8 @@ snapshots:
|
||||
'@modelcontextprotocol/core': 2.0.0
|
||||
zod: 4.5.4
|
||||
|
||||
'@next/env@16.3.3': {}
|
||||
'@next/env@16.3.3':
|
||||
optional: true
|
||||
|
||||
'@next/swc-darwin-arm64@16.3.3':
|
||||
optional: true
|
||||
@@ -1796,6 +1746,7 @@ snapshots:
|
||||
'@swc/helpers@0.5.23':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@types/cookie@0.6.0': {}
|
||||
|
||||
@@ -1805,14 +1756,6 @@ snapshots:
|
||||
dependencies:
|
||||
undici-types: 6.21.0
|
||||
|
||||
'@types/react-dom@19.2.5(@types/react@19.2.18)':
|
||||
dependencies:
|
||||
'@types/react': 19.2.18
|
||||
|
||||
'@types/react@19.2.18':
|
||||
dependencies:
|
||||
csstype: 3.2.3
|
||||
|
||||
'@vercel/nft@1.11.0':
|
||||
dependencies:
|
||||
'@mapbox/node-pre-gyp': 2.0.3
|
||||
@@ -1850,7 +1793,8 @@ snapshots:
|
||||
|
||||
balanced-match@4.0.4: {}
|
||||
|
||||
baseline-browser-mapping@2.11.20: {}
|
||||
baseline-browser-mapping@2.11.20:
|
||||
optional: true
|
||||
|
||||
bindings@1.5.0:
|
||||
dependencies:
|
||||
@@ -1860,7 +1804,8 @@ snapshots:
|
||||
dependencies:
|
||||
balanced-match: 4.0.4
|
||||
|
||||
caniuse-lite@1.0.30001810: {}
|
||||
caniuse-lite@1.0.30001810:
|
||||
optional: true
|
||||
|
||||
chalk@5.6.2: {}
|
||||
|
||||
@@ -1870,7 +1815,8 @@ snapshots:
|
||||
|
||||
chownr@3.0.0: {}
|
||||
|
||||
client-only@0.0.1: {}
|
||||
client-only@0.0.1:
|
||||
optional: true
|
||||
|
||||
clsx@2.1.1: {}
|
||||
|
||||
@@ -1880,8 +1826,6 @@ snapshots:
|
||||
|
||||
cookie@0.6.0: {}
|
||||
|
||||
csstype@3.2.3: {}
|
||||
|
||||
debug@4.4.3:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
@@ -2070,6 +2014,7 @@ snapshots:
|
||||
- '@babel/core'
|
||||
- '@types/node'
|
||||
- babel-plugin-macros
|
||||
optional: true
|
||||
|
||||
node-fetch@2.7.0:
|
||||
dependencies:
|
||||
@@ -2097,6 +2042,7 @@ snapshots:
|
||||
nanoid: 3.3.18
|
||||
picocolors: 1.1.1
|
||||
source-map-js: 1.2.1
|
||||
optional: true
|
||||
|
||||
postcss@8.5.26:
|
||||
dependencies:
|
||||
@@ -2108,8 +2054,10 @@ snapshots:
|
||||
dependencies:
|
||||
react: 19.2.8
|
||||
scheduler: 0.27.0
|
||||
optional: true
|
||||
|
||||
react@19.2.8: {}
|
||||
react@19.2.8:
|
||||
optional: true
|
||||
|
||||
readdirp@4.1.2: {}
|
||||
|
||||
@@ -2140,7 +2088,8 @@ snapshots:
|
||||
dependencies:
|
||||
mri: 1.2.0
|
||||
|
||||
scheduler@0.27.0: {}
|
||||
scheduler@0.27.0:
|
||||
optional: true
|
||||
|
||||
semver@7.8.5: {}
|
||||
|
||||
@@ -2192,6 +2141,7 @@ snapshots:
|
||||
dependencies:
|
||||
client-only: 0.0.1
|
||||
react: 19.2.8
|
||||
optional: true
|
||||
|
||||
svelte-check@4.7.6(picomatch@4.0.7)(svelte@5.57.0)(typescript@6.0.3):
|
||||
dependencies:
|
||||
@@ -2243,7 +2193,8 @@ snapshots:
|
||||
|
||||
tr46@0.0.3: {}
|
||||
|
||||
tslib@2.8.1: {}
|
||||
tslib@2.8.1:
|
||||
optional: true
|
||||
|
||||
tsx@4.23.13:
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user