@cogito.ai/cli 0.3.2 → 0.3.4

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.
@@ -3,10 +3,6 @@
3
3
  "title": "Welcome to AgentDock Web Template",
4
4
  "description": "A Next.js scaffold with four-layer architecture."
5
5
  },
6
- "hello": {
7
- "title": "Hello Feature",
8
- "greeting": "Hello, {name}!"
9
- },
10
6
  "auth": {
11
7
  "loginTitle": "Welcome back",
12
8
  "loginSubtitle": "Sign in to your account",
@@ -1,38 +1,34 @@
1
1
  {
2
2
  "home": {
3
- "title": "home.title",
4
- "description": "home.description"
5
- },
6
- "hello": {
7
- "title": "hello.title",
8
- "greeting": "hello.greeting"
3
+ "title": "欢迎使用 AgentDock Web 模板",
4
+ "description": "基于四层架构的 Next.js 脚手架。"
9
5
  },
10
6
  "auth": {
11
- "loginTitle": "auth.loginTitle",
12
- "loginSubtitle": "auth.loginSubtitle",
13
- "signupTitle": "auth.signupTitle",
14
- "signupSubtitle": "auth.signupSubtitle",
15
- "emailLabel": "auth.emailLabel",
16
- "emailPlaceholder": "auth.emailPlaceholder",
17
- "emailHelperText": "auth.emailHelperText",
18
- "passwordLabel": "auth.passwordLabel",
19
- "passwordPlaceholder": "auth.passwordPlaceholder",
20
- "confirmPasswordLabel": "auth.confirmPasswordLabel",
21
- "confirmPasswordPlaceholder": "auth.confirmPasswordPlaceholder",
22
- "signInButton": "auth.signInButton",
23
- "signUpButton": "auth.signUpButton",
24
- "signOutButton": "auth.signOutButton",
25
- "githubButton": "auth.githubButton",
26
- "noAccountText": "auth.noAccountText",
27
- "signUpLink": "auth.signUpLink",
28
- "hasAccountText": "auth.hasAccountText",
29
- "signInLink": "auth.signInLink",
30
- "orContinueWith": "auth.orContinueWith",
31
- "verifyEmailTitle": "auth.verifyEmailTitle",
32
- "verifyEmailMessage": "auth.verifyEmailMessage",
33
- "dashboardTitle": "auth.dashboardTitle",
34
- "dashboardWelcome": "auth.dashboardWelcome",
35
- "errorInvalidCredentials": "auth.errorInvalidCredentials",
36
- "errorGeneric": "auth.errorGeneric"
7
+ "loginTitle": "欢迎回来",
8
+ "loginSubtitle": "登录您的账号",
9
+ "signupTitle": "创建账号",
10
+ "signupSubtitle": "输入您的信息以开始使用",
11
+ "emailLabel": "邮箱",
12
+ "emailPlaceholder": "you@example.com",
13
+ "emailHelperText": "请使用真实邮箱地址 — 注册后需要验证。",
14
+ "passwordLabel": "密码",
15
+ "passwordPlaceholder": "••••••••",
16
+ "confirmPasswordLabel": "确认密码",
17
+ "confirmPasswordPlaceholder": "••••••••",
18
+ "signInButton": "登录",
19
+ "signUpButton": "创建账号",
20
+ "signOutButton": "退出登录",
21
+ "githubButton": "使用 GitHub 登录",
22
+ "noAccountText": "还没有账号?",
23
+ "signUpLink": "立即注册",
24
+ "hasAccountText": "已有账号?",
25
+ "signInLink": "立即登录",
26
+ "orContinueWith": "或使用以下方式",
27
+ "verifyEmailTitle": "请验证您的邮箱",
28
+ "verifyEmailMessage": "我们已发送验证链接至 {email},请点击链接完成注册。",
29
+ "dashboardTitle": "控制台",
30
+ "dashboardWelcome": "欢迎,{email}",
31
+ "errorInvalidCredentials": "邮箱或密码错误。",
32
+ "errorGeneric": "出现错误,请稍后重试。"
37
33
  }
38
34
  }
@@ -74,5 +74,6 @@ export default async function middleware(request: NextRequest) {
74
74
 
75
75
  export const config = {
76
76
  // Match all pathnames except Next.js internals, static files, and auth callback.
77
- matcher: ['/((?!_next|_vercel|auth/callback|.*\\..*).*)'],
77
+ // The explicit '/' entry ensures the root redirect to the default locale always fires.
78
+ matcher: ['/', '/((?!_next|_vercel|auth/callback|.*\\..*).*)'],
78
79
  }
@@ -1,4 +1,4 @@
1
- import { useTranslations } from 'next-intl'
1
+ import { getTranslations } from 'next-intl/server'
2
2
  import { getServerClient } from '@/infra/db/client'
3
3
  import { signOut } from '@/features/auth'
4
4
  import { Button } from '@/components/ui/button'
@@ -9,7 +9,7 @@ export default async function DashboardPage({
9
9
  params: Promise<{ locale: string }>
10
10
  }) {
11
11
  const { locale } = await params
12
- const t = useTranslations('auth')
12
+ const t = await getTranslations({ locale, namespace: 'auth' })
13
13
  const supabase = await getServerClient()
14
14
  const {
15
15
  data: { user },
@@ -1,7 +1,9 @@
1
1
  import type { Metadata } from 'next'
2
2
  import { NextIntlClientProvider } from 'next-intl'
3
3
  import { getMessages } from 'next-intl/server'
4
+ import { ThemeProvider } from 'next-themes'
4
5
  import { notFound } from 'next/navigation'
6
+ import { Toaster } from '@/components/ui/sonner'
5
7
  import { isLocale } from '@/i18n/config'
6
8
  import './globals.css'
7
9
 
@@ -26,9 +28,14 @@ export default async function LocaleLayout({
26
28
  const messages = await getMessages()
27
29
 
28
30
  return (
29
- <html lang={locale}>
30
- <body>
31
- <NextIntlClientProvider messages={messages}>{children}</NextIntlClientProvider>
31
+ <html lang={locale} suppressHydrationWarning>
32
+ <body className="min-h-screen bg-background font-sans antialiased">
33
+ <ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
34
+ <NextIntlClientProvider messages={messages}>
35
+ {children}
36
+ </NextIntlClientProvider>
37
+ <Toaster />
38
+ </ThemeProvider>
32
39
  </body>
33
40
  </html>
34
41
  )
@@ -10,7 +10,7 @@ import type { NextRequest, NextResponse } from 'next/server'
10
10
  * ```ts
11
11
  * // In a Server Component or Server Action:
12
12
  * const supabase = await getServerClient();
13
- * const { data } = await supabase.from('greetings').select('*');
13
+ * const { data } = await supabase.from('profiles').select('*');
14
14
  * ```
15
15
  *
16
16
  * Requires env vars: NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY
@@ -2,16 +2,16 @@
2
2
  * Drizzle extension point — not implemented in Supabase MVP stage.
3
3
  *
4
4
  * When the team decides to adopt Drizzle ORM, implement the schema here.
5
- * The IGreetingRepository interface in src/core/repositories/ does not need
6
- * to change only the implementation in SupabaseGreetingRepository.ts.
5
+ * Define your tables using `pgTable` from `drizzle-orm/pg-core` and export
6
+ * them so that `infra/db` implementations can reference the typed schema.
7
7
  *
8
- * Example future implementation:
8
+ * Example:
9
9
  *
10
10
  * import { pgTable, text, timestamp } from "drizzle-orm/pg-core";
11
11
  *
12
- * export const greetings = pgTable("greetings", {
12
+ * export const profiles = pgTable("profiles", {
13
13
  * id: text("id").primaryKey(),
14
- * name: text("name").notNull(),
14
+ * email: text("email").notNull(),
15
15
  * createdAt: timestamp("created_at").notNull().defaultNow(),
16
16
  * });
17
17
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cogito.ai/cli",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "type": "module",
5
5
  "description": "AgentDock CLI – scaffold projects for humans and AI agents",
6
6
  "publishConfig": {
@@ -1,45 +0,0 @@
1
- import { getTranslations } from 'next-intl/server'
2
- import { greet } from '@/features/hello'
3
- import type { Greeting } from '@/core/types/greeting'
4
-
5
- async function loadRecentGreetings(): Promise<Greeting[]> {
6
- // Gracefully skip DB access when Supabase is not configured.
7
- if (!process.env.NEXT_PUBLIC_SUPABASE_URL || !process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY) {
8
- return []
9
- }
10
-
11
- try {
12
- const { SupabaseGreetingRepository } = await import('@/infra/db/SupabaseGreetingRepository')
13
- const repo = new SupabaseGreetingRepository()
14
- return await repo.findRecent()
15
- } catch {
16
- return []
17
- }
18
- }
19
-
20
- export default async function HelloPage() {
21
- const t = await getTranslations('hello')
22
- const greeting = greet('World')
23
- const recentGreetings = await loadRecentGreetings()
24
-
25
- return (
26
- <main className="flex min-h-screen flex-col items-center justify-center p-24">
27
- <h1 className="text-4xl font-bold">{t('title')}</h1>
28
- <p className="mt-4 text-xl text-gray-700">{greeting}</p>
29
- <p className="mt-2 text-gray-500">{t('greeting', { name: 'World' })}</p>
30
-
31
- {recentGreetings.length > 0 && (
32
- <section className="mt-8">
33
- <h2 className="text-lg font-semibold">Recent greetings</h2>
34
- <ul className="mt-2 space-y-1">
35
- {recentGreetings.map((g) => (
36
- <li key={g.id} className="text-sm text-gray-600">
37
- {g.name} — {g.createdAt}
38
- </li>
39
- ))}
40
- </ul>
41
- </section>
42
- )}
43
- </main>
44
- )
45
- }
@@ -1,14 +0,0 @@
1
- import type { Greeting } from '../types/greeting'
2
-
3
- /**
4
- * Repository interface for Greeting persistence.
5
- * Uses domain types only — no Supabase types leak through.
6
- * Implement this in src/infra/db/ to swap storage backends.
7
- */
8
- export interface IGreetingRepository {
9
- /** Persist a new greeting and return the saved record. */
10
- save(name: string): Promise<Greeting>
11
-
12
- /** Return the most recent greeting records. */
13
- findRecent(): Promise<Greeting[]>
14
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Greeting — domain type.
3
- * No Supabase types here; this is pure domain model.
4
- */
5
- export interface Greeting {
6
- id: string
7
- name: string
8
- createdAt: string
9
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * Contract for the `hello` feature.
3
- *
4
- * Defines the public API boundary: input/output types and the exported function signature.
5
- * Only symbols declared here may be exported from `index.ts`.
6
- */
7
-
8
- /** Input accepted by the hello feature. */
9
- export interface HelloInput {
10
- name: string
11
- }
12
-
13
- /** Output returned by the hello feature. */
14
- export interface HelloOutput {
15
- greeting: string
16
- }
@@ -1,16 +0,0 @@
1
- import { describe, it, expect } from 'vitest'
2
- import { greet } from './index'
3
-
4
- describe('hello feature — greet()', () => {
5
- it('returns a greeting with the provided name', () => {
6
- expect(greet('Alice')).toBe('Hello, Alice!')
7
- })
8
-
9
- it("returns a greeting with 'World' when name is an empty string", () => {
10
- expect(greet('')).toBe('Hello, World!')
11
- })
12
-
13
- it("returns a greeting with 'World' when name is only whitespace", () => {
14
- expect(greet(' ')).toBe('Hello, World!')
15
- })
16
- })
@@ -1,5 +0,0 @@
1
- /**
2
- * Public API for the `hello` feature.
3
- * Only exports declared in __contract__.ts are exposed here.
4
- */
5
- export { greet } from './service'
@@ -1,12 +0,0 @@
1
- /**
2
- * Hello feature — pure business logic, no side effects.
3
- */
4
-
5
- /**
6
- * Returns a greeting string for the given name.
7
- * Falls back to "World" when name is empty.
8
- */
9
- export function greet(name: string): string {
10
- const target = name.trim() || 'World'
11
- return `Hello, ${target}!`
12
- }
@@ -1,58 +0,0 @@
1
- import type { IGreetingRepository } from '@/core/repositories/IGreetingRepository'
2
- import type { Greeting } from '@/core/types/greeting'
3
- import { getServerClient } from './client'
4
-
5
- /**
6
- * Supabase implementation of IGreetingRepository.
7
- * Operates on the `greetings` table.
8
- *
9
- * Table schema (create in Supabase SQL editor):
10
- * ```sql
11
- * create table greetings (
12
- * id uuid primary key default gen_random_uuid(),
13
- * name text not null,
14
- * created_at timestamptz not null default now()
15
- * );
16
- * ```
17
- */
18
- export class SupabaseGreetingRepository implements IGreetingRepository {
19
- async save(name: string): Promise<Greeting> {
20
- const supabase = await getServerClient()
21
-
22
- const { data, error } = await supabase
23
- .from('greetings')
24
- .insert({ name })
25
- .select('id, name, created_at')
26
- .single()
27
-
28
- if (error !== null || data === null) {
29
- throw new Error(`Failed to save greeting: ${error?.message ?? 'unknown'}`)
30
- }
31
-
32
- return {
33
- id: data.id as string,
34
- name: data.name as string,
35
- createdAt: (data.created_at as string) ?? new Date().toISOString(),
36
- }
37
- }
38
-
39
- async findRecent(): Promise<Greeting[]> {
40
- const supabase = await getServerClient()
41
-
42
- const { data, error } = await supabase
43
- .from('greetings')
44
- .select('id, name, created_at')
45
- .order('created_at', { ascending: false })
46
- .limit(10)
47
-
48
- if (error !== null) {
49
- throw new Error(`Failed to fetch greetings: ${error.message}`)
50
- }
51
-
52
- return (data ?? []).map((row) => ({
53
- id: row.id as string,
54
- name: row.name as string,
55
- createdAt: (row.created_at as string) ?? '',
56
- }))
57
- }
58
- }