start-vibing-stacks 1.6.0 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -5,7 +5,8 @@
5
5
  * Multi-stack AI-powered development workflow for Claude Code.
6
6
  * Detects project stack, validates requirements, and configures agents.
7
7
  */
8
- import { basename } from 'path';
8
+ import { existsSync, readFileSync } from 'fs';
9
+ import { join, basename } from 'path';
9
10
  import inquirer from 'inquirer';
10
11
  import chalk from 'chalk';
11
12
  import * as ui from './ui.js';
@@ -66,6 +67,54 @@ async function main() {
66
67
  console.log(ui.LOGO);
67
68
  const projectDir = process.cwd();
68
69
  const projectName = basename(projectDir);
70
+ // ─── Quick Resume: Skip setup if already configured ─────────────────────
71
+ const activeProjectPath = join(projectDir, '.claude', 'config', 'active-project.json');
72
+ if (existsSync(activeProjectPath) && !FLAGS.force) {
73
+ try {
74
+ const existing = JSON.parse(readFileSync(activeProjectPath, 'utf8'));
75
+ ui.success(`Project already configured: ${existing.name || projectName}`);
76
+ ui.info(`Stack: ${existing.stack} | Framework: ${existing.framework} | DB: ${existing.database}`);
77
+ console.log('');
78
+ const { action } = await inquirer.prompt([
79
+ {
80
+ type: 'list',
81
+ name: 'action',
82
+ message: 'What do you want to do?',
83
+ choices: [
84
+ { name: '🚀 Launch Claude Code', value: 'launch' },
85
+ { name: '🔄 Reconfigure project (fresh setup)', value: 'reconfig' },
86
+ { name: '❌ Exit', value: 'exit' },
87
+ ],
88
+ },
89
+ ]);
90
+ if (action === 'launch') {
91
+ if (!FLAGS.noClaude) {
92
+ console.log(chalk.dim('\n Launching Claude Code...\n'));
93
+ const { execSync: run } = await import('child_process');
94
+ try {
95
+ run('claude --dangerously-skip-permissions', {
96
+ cwd: projectDir,
97
+ stdio: 'inherit',
98
+ env: { ...process.env },
99
+ });
100
+ }
101
+ catch {
102
+ ui.info('Claude Code session ended.');
103
+ }
104
+ }
105
+ process.exit(0);
106
+ }
107
+ if (action === 'exit') {
108
+ process.exit(0);
109
+ }
110
+ // action === 'reconfig' → continue with full setup below
111
+ ui.info('Reconfiguring project...');
112
+ console.log('');
113
+ }
114
+ catch {
115
+ // Corrupted config, continue with fresh setup
116
+ }
117
+ }
69
118
  // ─── Step 1: Detect Project ─────────────────────────────────────────────
70
119
  ui.header('🔍 Scanning project directory...');
71
120
  const detection = detectProject(projectDir);
package/dist/setup.js CHANGED
@@ -176,7 +176,7 @@ export async function setupProject(projectDir, config, options = {}) {
176
176
  hooks: [
177
177
  {
178
178
  type: 'command',
179
- command: 'npx tsx .claude/hooks/run-hook.ts user-prompt-submit',
179
+ command: 'bash .claude/hooks/run-hook.sh user-prompt-submit',
180
180
  timeout: 10,
181
181
  },
182
182
  ],
@@ -187,7 +187,7 @@ export async function setupProject(projectDir, config, options = {}) {
187
187
  hooks: [
188
188
  {
189
189
  type: 'command',
190
- command: 'npx tsx .claude/hooks/run-hook.ts stop-validator',
190
+ command: 'bash .claude/hooks/run-hook.sh stop-validator',
191
191
  timeout: 30,
192
192
  },
193
193
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "start-vibing-stacks",
3
- "version": "1.6.0",
3
+ "version": "1.7.1",
4
4
  "description": "AI-powered multi-stack dev workflow for Claude Code. Supports PHP, Node.js, Python and more.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,88 @@
1
+ # Hook Development — Claude Code Hooks
2
+
3
+ **ALWAYS invoke when creating or modifying Claude Code hooks.**
4
+
5
+ ## Hook Types
6
+
7
+ | Event | When | Use Case |
8
+ |-------|------|----------|
9
+ | `UserPromptSubmit` | Before prompt is sent | Inject workflow, validate input |
10
+ | `Stop` | Before task completion | Validate state, block if dirty |
11
+ | `PreToolUse` | Before tool execution | Approve/block dangerous tools |
12
+ | `PostToolUse` | After tool execution | Log, validate output |
13
+
14
+ ## File Structure
15
+
16
+ ```
17
+ .claude/hooks/
18
+ ├── run-hook.sh # Entry point (bash → bun/tsx fallback)
19
+ ├── user-prompt-submit.ts # Prompt injection
20
+ └── stop-validator.ts # Task completion gate
21
+ ```
22
+
23
+ ## Hook Input (stdin JSON)
24
+
25
+ ```typescript
26
+ // UserPromptSubmit
27
+ interface PromptInput {
28
+ user_prompt: string;
29
+ session_id: string;
30
+ }
31
+
32
+ // Stop
33
+ interface StopInput {
34
+ stop_hook_active?: boolean; // Cycle detection
35
+ transcript?: string;
36
+ }
37
+ ```
38
+
39
+ ## Hook Output (stdout JSON)
40
+
41
+ ```typescript
42
+ // UserPromptSubmit — inject system message
43
+ { "continue": true, "systemMessage": "WORKFLOW: ..." }
44
+
45
+ // Stop — approve or block
46
+ { "continue": false, "decision": "approve", "reason": "All checks passed" }
47
+ { "continue": true, "decision": "block", "reason": "Uncommitted files" }
48
+ ```
49
+
50
+ ## Template: Stop Validator
51
+
52
+ ```typescript
53
+ #!/usr/bin/env node
54
+ import { execSync } from 'child_process';
55
+
56
+ function cmd(c: string): string {
57
+ try { return execSync(c, { encoding: 'utf8' }).trim(); } catch { return ''; }
58
+ }
59
+
60
+ const branch = cmd('git rev-parse --abbrev-ref HEAD');
61
+ const dirty = cmd('git status --porcelain');
62
+
63
+ const result = (!dirty && (branch === 'main' || branch === 'master'))
64
+ ? { continue: false, decision: 'approve', reason: 'Clean main branch' }
65
+ : { continue: true, decision: 'block', reason: `Branch: ${branch}, dirty: ${!!dirty}` };
66
+
67
+ console.log(JSON.stringify(result));
68
+ ```
69
+
70
+ ## settings.json Registration
71
+
72
+ ```json
73
+ {
74
+ "hooks": {
75
+ "Stop": [{ "hooks": [{ "type": "command", "command": "bash .claude/hooks/run-hook.sh stop-validator", "timeout": 30 }] }],
76
+ "UserPromptSubmit": [{ "matcher": "", "hooks": [{ "type": "command", "command": "bash .claude/hooks/run-hook.sh user-prompt-submit", "timeout": 10 }] }]
77
+ }
78
+ }
79
+ ```
80
+
81
+ ## Rules
82
+
83
+ 1. **Always use `run-hook.sh` as entry** — handles bun/tsx fallback
84
+ 2. **Read stdin with timeout** — hooks must not hang
85
+ 3. **Exit 0 always** — non-zero kills the session
86
+ 4. **Output valid JSON to stdout** — Claude Code parses it
87
+ 5. **Cycle detection** — check `stop_hook_active` flag in Stop hooks
88
+ 6. **Keep hooks fast** — timeout applies (10s for prompt, 30s for stop)
@@ -0,0 +1,92 @@
1
+ # shadcn/ui — Component Library Patterns
2
+
3
+ **ALWAYS invoke when adding or modifying shadcn/ui components.**
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npx shadcn@latest init
9
+ npx shadcn@latest add button card dialog input
10
+ ```
11
+
12
+ ## Theming
13
+
14
+ ```css
15
+ /* globals.css — CSS variables for theming */
16
+ @layer base {
17
+ :root {
18
+ --background: 0 0% 100%;
19
+ --foreground: 222.2 84% 4.9%;
20
+ --primary: 222.2 47.4% 11.2%;
21
+ --primary-foreground: 210 40% 98%;
22
+ --muted: 210 40% 96.1%;
23
+ --muted-foreground: 215.4 16.3% 46.9%;
24
+ --border: 214.3 31.8% 91.4%;
25
+ --ring: 222.2 84% 4.9%;
26
+ --radius: 0.5rem;
27
+ }
28
+ .dark {
29
+ --background: 222.2 84% 4.9%;
30
+ --foreground: 210 40% 98%;
31
+ --primary: 210 40% 98%;
32
+ --primary-foreground: 222.2 47.4% 11.2%;
33
+ }
34
+ }
35
+ ```
36
+
37
+ ## Component Customization
38
+
39
+ ```tsx
40
+ // CORRECT — extend via className + variants
41
+ import { Button } from '@/components/ui/button';
42
+ <Button variant="outline" size="lg" className="rounded-full">Custom</Button>
43
+
44
+ // WRONG — modify component source for one-off styles
45
+ ```
46
+
47
+ ## Composition Pattern
48
+
49
+ ```tsx
50
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
51
+ import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
52
+
53
+ // Compose primitives, don't create monolithic components
54
+ <Dialog>
55
+ <DialogTrigger asChild>
56
+ <Button variant="outline">Open</Button>
57
+ </DialogTrigger>
58
+ <DialogContent>
59
+ <DialogHeader>
60
+ <DialogTitle>Title</DialogTitle>
61
+ </DialogHeader>
62
+ <Card><CardContent>...</CardContent></Card>
63
+ </DialogContent>
64
+ </Dialog>
65
+ ```
66
+
67
+ ## Form Pattern (with Zod)
68
+
69
+ ```tsx
70
+ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form';
71
+ import { useForm } from 'react-hook-form';
72
+ import { zodResolver } from '@hookform/resolvers/zod';
73
+
74
+ const form = useForm<z.infer<typeof schema>>({ resolver: zodResolver(schema) });
75
+
76
+ <Form {...form}>
77
+ <FormField control={form.control} name="email" render={({ field }) => (
78
+ <FormItem>
79
+ <FormLabel>Email</FormLabel>
80
+ <FormControl><Input {...field} /></FormControl>
81
+ <FormMessage />
82
+ </FormItem>
83
+ )} />
84
+ </Form>
85
+ ```
86
+
87
+ ## FORBIDDEN
88
+
89
+ 1. **Modifying component source for one-off needs** — use className/variants
90
+ 2. **Installing without init** — always `npx shadcn@latest init` first
91
+ 3. **Ignoring dark mode** — all components must work in both themes
92
+ 4. **Skipping accessibility** — shadcn components have built-in a11y, don't break it
@@ -0,0 +1,86 @@
1
+ # Bun Runtime — Fast JavaScript Runtime
2
+
3
+ **ALWAYS invoke when using Bun for scripts, packages, bundling, or testing.**
4
+
5
+ ## Package Management
6
+
7
+ ```bash
8
+ bun install # Install deps (replaces npm install)
9
+ bun add zod # Add dependency
10
+ bun add -D vitest # Add dev dependency
11
+ bun remove lodash # Remove
12
+ bun update # Update all
13
+ ```
14
+
15
+ ## Scripts
16
+
17
+ ```bash
18
+ bun run dev # Run script from package.json
19
+ bun run build
20
+ bun --watch src/index.ts # Watch mode
21
+ ```
22
+
23
+ ## TypeScript (native, no config needed)
24
+
25
+ ```typescript
26
+ // Bun runs .ts files directly — no tsc/tsx needed
27
+ // bun src/index.ts
28
+
29
+ import { serve } from 'bun';
30
+
31
+ serve({
32
+ port: 3000,
33
+ fetch(req) {
34
+ const url = new URL(req.url);
35
+ if (url.pathname === '/api/health') {
36
+ return Response.json({ status: 'ok' });
37
+ }
38
+ return new Response('Not Found', { status: 404 });
39
+ },
40
+ });
41
+ ```
42
+
43
+ ## File I/O (Bun APIs)
44
+
45
+ ```typescript
46
+ // Fast file operations
47
+ const content = await Bun.file('data.json').text();
48
+ const parsed = await Bun.file('data.json').json();
49
+ await Bun.write('output.txt', 'Hello');
50
+
51
+ // Glob
52
+ const glob = new Bun.Glob('**/*.ts');
53
+ for await (const file of glob.scan('.')) { console.log(file); }
54
+ ```
55
+
56
+ ## Testing (built-in)
57
+
58
+ ```typescript
59
+ // *.test.ts — bun test
60
+ import { describe, it, expect } from 'bun:test';
61
+
62
+ describe('math', () => {
63
+ it('adds', () => expect(1 + 1).toBe(2));
64
+ });
65
+ ```
66
+
67
+ ```bash
68
+ bun test # Run all tests
69
+ bun test --coverage # With coverage
70
+ bun test --watch # Watch mode
71
+ ```
72
+
73
+ ## Environment Variables
74
+
75
+ ```typescript
76
+ // .env loaded automatically
77
+ const apiKey = Bun.env['API_KEY']; // Bun.env (recommended)
78
+ const dbUrl = process.env['DATABASE_URL']; // Also works
79
+ ```
80
+
81
+ ## FORBIDDEN
82
+
83
+ 1. **`node` command when `bun` works** — prefer bun for speed
84
+ 2. **`npx` when `bunx` works** — `bunx` is faster
85
+ 3. **Manual .env loading** — Bun loads `.env` automatically
86
+ 4. **CommonJS `require()`** — use ESM `import`
@@ -0,0 +1,77 @@
1
+ # Mongoose Patterns — MongoDB ODM
2
+
3
+ **ALWAYS invoke when writing Mongoose schemas, queries, or aggregations.**
4
+
5
+ ## Schema Pattern
6
+
7
+ ```typescript
8
+ import { Schema, model, type InferSchemaType } from 'mongoose';
9
+
10
+ const userSchema = new Schema({
11
+ name: { type: String, required: true, trim: true, minlength: 2 },
12
+ email: { type: String, required: true, unique: true, lowercase: true, index: true },
13
+ role: { type: String, enum: ['admin', 'user', 'moderator'] as const, default: 'user' },
14
+ profile: {
15
+ avatar: String,
16
+ bio: { type: String, maxlength: 500 },
17
+ },
18
+ tags: [{ type: String, index: true }],
19
+ isActive: { type: Boolean, default: true, index: true },
20
+ }, {
21
+ timestamps: true, // createdAt, updatedAt
22
+ toJSON: { virtuals: true, transform: (_, ret) => { delete ret.__v; return ret; } },
23
+ });
24
+
25
+ // Compound index
26
+ userSchema.index({ email: 1, isActive: 1 });
27
+ // Text index for search
28
+ userSchema.index({ name: 'text', 'profile.bio': 'text' });
29
+
30
+ type IUser = InferSchemaType<typeof userSchema>;
31
+ export const User = model('User', userSchema);
32
+ ```
33
+
34
+ ## Query Patterns
35
+
36
+ ```typescript
37
+ // Pagination
38
+ async function paginate(page: number, limit: number) {
39
+ const [items, total] = await Promise.all([
40
+ User.find({ isActive: true }).skip((page - 1) * limit).limit(limit).lean(),
41
+ User.countDocuments({ isActive: true }),
42
+ ]);
43
+ return { items, total, pages: Math.ceil(total / limit) };
44
+ }
45
+
46
+ // Aggregation
47
+ const stats = await User.aggregate([
48
+ { $match: { isActive: true } },
49
+ { $group: { _id: '$role', count: { $sum: 1 }, avgAge: { $avg: '$age' } } },
50
+ { $sort: { count: -1 } },
51
+ ]);
52
+ ```
53
+
54
+ ## Middleware
55
+
56
+ ```typescript
57
+ // Pre-save: hash password
58
+ userSchema.pre('save', async function (next) {
59
+ if (!this.isModified('password')) return next();
60
+ this.password = await bcrypt.hash(this.password, 12);
61
+ next();
62
+ });
63
+
64
+ // Pre-find: exclude inactive by default
65
+ userSchema.pre(/^find/, function (next) {
66
+ this.where({ isActive: { $ne: false } });
67
+ next();
68
+ });
69
+ ```
70
+
71
+ ## FORBIDDEN
72
+
73
+ 1. **No indexes on queried fields** — always index filter/sort fields
74
+ 2. **`find()` without `.lean()`** for read-only — wastes memory
75
+ 3. **Unbounded queries** — always `.limit()`
76
+ 4. **N+1 queries** — use `.populate()` or aggregation `$lookup`
77
+ 5. **String IDs without casting** — use `new Types.ObjectId(id)`
@@ -0,0 +1,123 @@
1
+ # Next.js App Router — Modern Patterns
2
+
3
+ **ALWAYS invoke when writing Next.js pages, layouts, or server components.**
4
+
5
+ ## File Conventions
6
+
7
+ ```
8
+ app/
9
+ ├── layout.tsx # Root layout (required)
10
+ ├── page.tsx # Home page
11
+ ├── loading.tsx # Loading UI (Suspense boundary)
12
+ ├── error.tsx # Error boundary ('use client')
13
+ ├── not-found.tsx # 404 page
14
+ ├── (auth)/ # Route group (no URL segment)
15
+ │ ├── login/page.tsx
16
+ │ └── register/page.tsx
17
+ ├── dashboard/
18
+ │ ├── layout.tsx # Nested layout
19
+ │ ├── page.tsx
20
+ │ └── [id]/page.tsx # Dynamic route
21
+ └── api/
22
+ └── route.ts # API route handler
23
+ ```
24
+
25
+ ## Server vs Client Components
26
+
27
+ ```tsx
28
+ // DEFAULT: Server Component (no directive needed)
29
+ async function UserList() {
30
+ const users = await db.user.findMany(); // Direct DB access
31
+ return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
32
+ }
33
+
34
+ // CLIENT: Only when needed (interactivity, hooks, browser APIs)
35
+ 'use client';
36
+ function Counter() {
37
+ const [count, setCount] = useState(0);
38
+ return <button onClick={() => setCount(c + 1)}>{count}</button>;
39
+ }
40
+ ```
41
+
42
+ ## Data Fetching
43
+
44
+ ```tsx
45
+ // Server Component — fetch with caching
46
+ async function Page() {
47
+ const data = await fetch('https://api.example.com/data', {
48
+ next: { revalidate: 3600 }, // ISR: revalidate every hour
49
+ });
50
+ return <div>{data}</div>;
51
+ }
52
+
53
+ // Dynamic data (no cache)
54
+ async function Page() {
55
+ const data = await fetch('https://api.example.com/data', {
56
+ cache: 'no-store',
57
+ });
58
+ }
59
+ ```
60
+
61
+ ## Server Actions
62
+
63
+ ```tsx
64
+ // app/actions.ts
65
+ 'use server';
66
+
67
+ import { revalidatePath } from 'next/cache';
68
+
69
+ export async function createUser(formData: FormData) {
70
+ const name = formData.get('name') as string;
71
+ await db.user.create({ data: { name } });
72
+ revalidatePath('/users');
73
+ }
74
+
75
+ // In component
76
+ <form action={createUser}>
77
+ <input name="name" />
78
+ <button type="submit">Create</button>
79
+ </form>
80
+ ```
81
+
82
+ ## Route Handlers (API)
83
+
84
+ ```tsx
85
+ // app/api/users/route.ts
86
+ import { NextRequest, NextResponse } from 'next/server';
87
+
88
+ export async function GET(request: NextRequest) {
89
+ const { searchParams } = new URL(request.url);
90
+ const page = Number(searchParams.get('page') ?? '1');
91
+ const users = await db.user.findMany({ skip: (page - 1) * 20, take: 20 });
92
+ return NextResponse.json(users);
93
+ }
94
+
95
+ export async function POST(request: NextRequest) {
96
+ const body = await request.json();
97
+ const result = schema.safeParse(body);
98
+ if (!result.success) return NextResponse.json(result.error, { status: 400 });
99
+ const user = await db.user.create({ data: result.data });
100
+ return NextResponse.json(user, { status: 201 });
101
+ }
102
+ ```
103
+
104
+ ## Metadata
105
+
106
+ ```tsx
107
+ // Static
108
+ export const metadata = { title: 'Dashboard', description: 'User dashboard' };
109
+
110
+ // Dynamic
111
+ export async function generateMetadata({ params }: { params: { id: string } }) {
112
+ const user = await getUser(params.id);
113
+ return { title: user.name };
114
+ }
115
+ ```
116
+
117
+ ## FORBIDDEN
118
+
119
+ 1. **`'use client'` on server-capable components** — default to server
120
+ 2. **Fetching in client when server fetch works** — use server components
121
+ 3. **`getServerSideProps` / `getStaticProps`** — App Router uses async components
122
+ 4. **API routes for server-only data** — use server components directly
123
+ 5. **Prop drilling through layouts** — use parallel routes or context
@@ -0,0 +1,87 @@
1
+ # tRPC API — End-to-End Type Safety
2
+
3
+ **ALWAYS invoke when building type-safe API routes with tRPC.**
4
+
5
+ ## Structure
6
+
7
+ ```
8
+ server/
9
+ ├── trpc.ts # tRPC init + context
10
+ ├── routers/
11
+ │ ├── _app.ts # Root router (merges all)
12
+ │ ├── user.router.ts
13
+ │ └── post.router.ts
14
+ └── middleware/
15
+ └── auth.ts # Auth middleware
16
+ ```
17
+
18
+ ## Setup
19
+
20
+ ```typescript
21
+ // server/trpc.ts
22
+ import { initTRPC, TRPCError } from '@trpc/server';
23
+ import superjson from 'superjson';
24
+
25
+ const t = initTRPC.context<Context>().create({ transformer: superjson });
26
+
27
+ export const router = t.router;
28
+ export const publicProcedure = t.procedure;
29
+
30
+ export const protectedProcedure = t.procedure.use(async ({ ctx, next }) => {
31
+ if (!ctx.session?.user) throw new TRPCError({ code: 'UNAUTHORIZED' });
32
+ return next({ ctx: { ...ctx, user: ctx.session.user } });
33
+ });
34
+ ```
35
+
36
+ ## Router Pattern
37
+
38
+ ```typescript
39
+ // server/routers/user.router.ts
40
+ import { z } from 'zod';
41
+ import { router, protectedProcedure } from '../trpc';
42
+
43
+ export const userRouter = router({
44
+ me: protectedProcedure.query(async ({ ctx }) => {
45
+ return ctx.db.user.findUnique({ where: { id: ctx.user.id } });
46
+ }),
47
+
48
+ update: protectedProcedure
49
+ .input(z.object({ name: z.string().min(2) }))
50
+ .mutation(async ({ ctx, input }) => {
51
+ return ctx.db.user.update({
52
+ where: { id: ctx.user.id },
53
+ data: input,
54
+ });
55
+ }),
56
+
57
+ list: protectedProcedure
58
+ .input(z.object({ page: z.number().min(1).default(1), limit: z.number().max(100).default(20) }))
59
+ .query(async ({ ctx, input }) => {
60
+ const { page, limit } = input;
61
+ return ctx.db.user.findMany({ skip: (page - 1) * limit, take: limit });
62
+ }),
63
+ });
64
+ ```
65
+
66
+ ## Client Usage (React)
67
+
68
+ ```tsx
69
+ import { trpc } from '@/utils/trpc';
70
+
71
+ function Profile() {
72
+ const { data: user, isLoading } = trpc.user.me.useQuery();
73
+ const updateMutation = trpc.user.update.useMutation({
74
+ onSuccess: () => utils.user.me.invalidate(),
75
+ });
76
+
77
+ if (isLoading) return <Skeleton />;
78
+ return <div>{user?.name}</div>;
79
+ }
80
+ ```
81
+
82
+ ## FORBIDDEN
83
+
84
+ 1. **REST endpoints when tRPC covers it** — use tRPC procedures
85
+ 2. **Unvalidated input** — always use Zod `.input()`
86
+ 3. **Public procedures for auth-required data** — use `protectedProcedure`
87
+ 4. **Direct DB access in client** — always through tRPC procedures