@cogito.ai/cli 0.2.0

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.
Files changed (40) hide show
  1. package/LICENSE +23 -0
  2. package/dist/index.js +17870 -0
  3. package/dist/registry.json +26 -0
  4. package/dist/templates/web-nextjs/.env.example +22 -0
  5. package/dist/templates/web-nextjs/.github/copilot-instructions.md +43 -0
  6. package/dist/templates/web-nextjs/AGENTS.md +46 -0
  7. package/dist/templates/web-nextjs/README.md +204 -0
  8. package/dist/templates/web-nextjs/eslint.config.js +12 -0
  9. package/dist/templates/web-nextjs/messages/en.json +10 -0
  10. package/dist/templates/web-nextjs/messages/zh.json +10 -0
  11. package/dist/templates/web-nextjs/middleware.ts +34 -0
  12. package/dist/templates/web-nextjs/next-env.d.ts +6 -0
  13. package/dist/templates/web-nextjs/next.config.ts +8 -0
  14. package/dist/templates/web-nextjs/openspec/changes/.gitkeep +0 -0
  15. package/dist/templates/web-nextjs/openspec/changes/archive/.gitkeep +0 -0
  16. package/dist/templates/web-nextjs/openspec/config.yaml +28 -0
  17. package/dist/templates/web-nextjs/openspec/specs/.gitkeep +0 -0
  18. package/dist/templates/web-nextjs/package.json +37 -0
  19. package/dist/templates/web-nextjs/src/app/[locale]/globals.css +3 -0
  20. package/dist/templates/web-nextjs/src/app/[locale]/hello/page.tsx +45 -0
  21. package/dist/templates/web-nextjs/src/app/[locale]/layout.tsx +37 -0
  22. package/dist/templates/web-nextjs/src/app/[locale]/page.tsx +12 -0
  23. package/dist/templates/web-nextjs/src/core/repositories/.gitkeep +2 -0
  24. package/dist/templates/web-nextjs/src/core/repositories/IGreetingRepository.ts +14 -0
  25. package/dist/templates/web-nextjs/src/core/types/.gitkeep +3 -0
  26. package/dist/templates/web-nextjs/src/core/types/greeting.ts +9 -0
  27. package/dist/templates/web-nextjs/src/features/_experiments/.gitkeep +2 -0
  28. package/dist/templates/web-nextjs/src/features/hello/__contract__.ts +16 -0
  29. package/dist/templates/web-nextjs/src/features/hello/hello.test.ts +16 -0
  30. package/dist/templates/web-nextjs/src/features/hello/index.ts +5 -0
  31. package/dist/templates/web-nextjs/src/features/hello/service.ts +12 -0
  32. package/dist/templates/web-nextjs/src/i18n/request.ts +11 -0
  33. package/dist/templates/web-nextjs/src/infra/db/.gitkeep +3 -0
  34. package/dist/templates/web-nextjs/src/infra/db/SupabaseGreetingRepository.ts +58 -0
  35. package/dist/templates/web-nextjs/src/infra/db/client.ts +55 -0
  36. package/dist/templates/web-nextjs/src/infra/db/schema.ts +19 -0
  37. package/dist/templates/web-nextjs/tailwind.config.ts +11 -0
  38. package/dist/templates/web-nextjs/tsconfig.json +22 -0
  39. package/dist/templates/web-nextjs/vitest.config.ts +16 -0
  40. package/package.json +37 -0
@@ -0,0 +1,26 @@
1
+ {
2
+ "version": "1",
3
+ "templates": [
4
+ {
5
+ "id": "web-nextjs",
6
+ "name": "@cogito.ai/template-web-nextjs",
7
+ "description": "Full-stack Next.js 16 starter with Supabase, next-intl, Tailwind CSS and Vitest",
8
+ "minCliVersion": "0.1.0",
9
+ "source": "templates/web-nextjs",
10
+ "resolvedDependencies": {
11
+ "@supabase/ssr": "^0.10.3",
12
+ "next": "16",
13
+ "next-intl": "^4.13.0",
14
+ "react": "19",
15
+ "react-dom": "19",
16
+ "@vitejs/plugin-react": "^6.0.2",
17
+ "tailwindcss": "^4.3.0",
18
+ "typescript": "^6.0.3",
19
+ "vitest": "^4.1.8",
20
+ "@cogito.ai/eslint-config": "^0.2.0",
21
+ "@cogito.ai/tsconfig": "^0.2.0",
22
+ "@fission-ai/openspec": "^1.3.1"
23
+ }
24
+ }
25
+ ]
26
+ }
@@ -0,0 +1,22 @@
1
+ # ──────────────────────────────────────────────────────────────────────────────
2
+ # Supabase
3
+ # Get these from: Supabase Dashboard → Project Settings → API
4
+ # ──────────────────────────────────────────────────────────────────────────────
5
+
6
+ # Project URL — safe to expose in browser
7
+ NEXT_PUBLIC_SUPABASE_URL=https://<project-ref>.supabase.co
8
+
9
+ # Anon key — safe to expose in browser (Row Level Security enforces access)
10
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=<your-anon-key>
11
+
12
+ # Service role key — SERVER ONLY, never expose to browser
13
+ # Used for admin operations that bypass RLS (e.g., seed scripts, cron jobs)
14
+ # Leave empty if not needed
15
+ SUPABASE_SERVICE_ROLE_KEY=<your-service-role-key>
16
+
17
+ # ──────────────────────────────────────────────────────────────────────────────
18
+ # App
19
+ # ──────────────────────────────────────────────────────────────────────────────
20
+
21
+ # Public URL of this app (used for OG image URLs, absolute redirects, etc.)
22
+ NEXT_PUBLIC_APP_URL=http://localhost:3000
@@ -0,0 +1,43 @@
1
+ # AgentDock Web-Next.js Template — Copilot Instructions
2
+
3
+ > Applies to: GitHub Copilot (chat + completions) in any project generated from this template.
4
+
5
+ ## Directory Contract
6
+
7
+ This project enforces a four-layer directory contract. **Before placing any code**, confirm which layer it belongs to:
8
+
9
+ | Layer | Path | Purpose | Rules |
10
+ | --------------- | ---------------------------- | -------------------------------------------------------------- | -------------------------------------------------------------------------- |
11
+ | **core** | `src/core/` | Stable domain layer — types, repository interfaces, pure logic | No framework imports, no DB clients, read-only |
12
+ | **features** | `src/features/` | AI coding zone — business features | Must have `__contract__.ts`; no direct DB access; no cross-feature imports |
13
+ | **infra** | `src/infra/` | Infrastructure — Supabase clients, third-party SDKs | Requires approval; only `core/repositories` implementations live here |
14
+ | **experiments** | `src/features/_experiments/` | Sandbox | Never imported by non-experimental features |
15
+
16
+ ## Layer 2 Architecture Rules (error-level, enforced by ESLint)
17
+
18
+ Four rules are enforced at `error` severity in `src/features/**`. Violations fail `pnpm lint`.
19
+
20
+ 1. **`no-direct-db-in-features`** — Features must not import from `infra/db`. Use repository interfaces from `src/core/repositories/` instead.
21
+ 2. **`require-feature-contract`** — Every feature subdirectory must contain `__contract__.ts` declaring its public API boundary.
22
+ 3. **`no-cross-feature`** — Features must not directly import from sibling feature internals. Import through the feature's `index.ts` only.
23
+ 4. **`no-core-mutation`** — `src/core/` is read-only. Features and infra must not modify core types or interfaces in-place.
24
+
25
+ ## Hard Rules
26
+
27
+ 1. **No secrets** — Never write real API keys, tokens, or passwords. Use placeholders: `YOUR_KEY_HERE`, `process.env.YOUR_VAR`.
28
+ 2. **TypeScript strict** — `strict: true` enforced. No `any`, no `// @ts-ignore` without explanation.
29
+ 3. **Conventional commits** — `type(scope): summary` format required.
30
+ 4. **pnpm only** — Do not use `npm install` or `yarn`. Always `pnpm add`.
31
+ 5. **ESLint config** — Architecture rules come from `packages/eslint-config/features.js` in the AgentDock platform.
32
+
33
+ ## Feature Development Pattern
34
+
35
+ When adding a new feature `src/features/<name>/`:
36
+
37
+ 1. Create `__contract__.ts` first — declare input/output types and public API.
38
+ 2. Create `service.ts` — pure business logic, no side effects.
39
+ 3. Create `index.ts` — only export what `__contract__.ts` declares.
40
+ 4. Create `<name>.test.ts` — Vitest unit tests.
41
+ 5. Create page/component in `src/app/[locale]/` to consume the feature.
42
+
43
+ Reference implementation: `src/features/hello/`.
@@ -0,0 +1,46 @@
1
+ # AgentDock Web-Next.js Template — Agent Execution Boundaries
2
+
3
+ > For AI coding agents (GitHub Copilot CLI, etc.) running in projects generated from this template.
4
+
5
+ ## Generation Assumption
6
+
7
+ - Template source may contain monorepo-only dependency specifiers (for example, workspace links).
8
+ - Scaffold generation MUST rewrite these dependencies to installable versions for the generated standalone project.
9
+
10
+ ## Autonomy Boundaries
11
+
12
+ ### May execute autonomously
13
+
14
+ - `pnpm install`, `pnpm build`, `pnpm check-types`, `pnpm lint`, `pnpm test`
15
+ - Creating / editing files within the current task scope
16
+ - Adding new features inside `src/features/` (following the contract pattern)
17
+ - Adding repository interfaces to `src/core/repositories/`
18
+ - Updating translations in `messages/`
19
+ - Writing or updating tests in `src/**/*.test.ts`
20
+ - Running `openspec` CLI commands (read-only: `list`, `status`, `instructions`, `validate`)
21
+
22
+ ### Must pause and confirm
23
+
24
+ - Any `git push`, `git push --force`, or publishing to a registry
25
+ - Deleting files (including tracked files)
26
+ - Adding new **top-level** directories outside the four-layer contract (`core/`, `features/`, `infra/`, `app/`)
27
+ - Adding new `dependencies` or `devDependencies` to `package.json`
28
+ - Any change to `openspec/config.yaml`
29
+ - Modifying `middleware.ts` (affects routing for all locales)
30
+
31
+ ### Prohibited
32
+
33
+ - Writing real secrets, API keys, or credentials anywhere
34
+ - Running `rm -rf` on tracked directories
35
+ - Bypassing git hooks with `--no-verify`
36
+ - Importing from `src/infra/db/` inside `src/features/**` (violates Layer 2 rules)
37
+ - Creating features without `__contract__.ts` (violates require-feature-contract)
38
+
39
+ ## Acceptance Criteria (before marking a task done)
40
+
41
+ 1. `pnpm lint` — exits 0, no Layer 2 violations in `src/features/`
42
+ 2. ESLint ignores build artifacts (at minimum `.next/**`) so generated files are never linted.
43
+ 3. `pnpm build && pnpm lint` — both exit 0 (lint remains stable after a build).
44
+ 4. `pnpm test` — all unit tests pass
45
+ 5. `pnpm check-types` — TypeScript strict mode, no errors
46
+ 6. New features include `__contract__.ts`, `index.ts`, and at least one test
@@ -0,0 +1,204 @@
1
+ # {{PROJECT_NAME}}
2
+
3
+ > Generated from the [AgentDock](https://github.com/CogitoTech/agentdock) `web-nextjs` template.
4
+
5
+ Full-stack Next.js 16 starter with Supabase, i18n, Tailwind CSS and strict TypeScript.
6
+ Designed for both human developers and AI coding agents.
7
+
8
+ ## Tech Stack
9
+
10
+ | Layer | Technology |
11
+ |-------|-----------|
12
+ | Framework | [Next.js 16](https://nextjs.org) (App Router) |
13
+ | Language | [TypeScript 5+](https://www.typescriptlang.org) (strict mode) |
14
+ | Styling | [Tailwind CSS v4](https://tailwindcss.com) |
15
+ | Database / Auth | [Supabase](https://supabase.com) (`@supabase/ssr`) |
16
+ | i18n | [next-intl](https://next-intl.dev) (en / zh out of the box) |
17
+ | Testing | [Vitest](https://vitest.dev) |
18
+ | Package manager | [pnpm](https://pnpm.io) ≥ 9 |
19
+ | Runtime | Node.js ≥ 18 |
20
+ | Governance | [OpenSpec](https://github.com/fission-ai/openspec) (`@fission-ai/openspec`) |
21
+
22
+ ## Directory Structure
23
+
24
+ ```
25
+ src/
26
+ ├── app/ # Next.js App Router — pages and layouts (per-locale)
27
+ ├── core/ # Domain types + repository interfaces (no framework deps)
28
+ ├── features/ # AI coding zone — one directory per feature
29
+ │ └── hello/ # Reference feature (copy this pattern)
30
+ ├── infra/ # Supabase implementations (requires human review to edit)
31
+ │ └── db/ # Supabase client + repository implementations
32
+ └── i18n/ # next-intl configuration
33
+ messages/ # Translation files (en.json, zh.json)
34
+ openspec/ # Project governance — changes and specs
35
+ ```
36
+
37
+ > **Four-layer contract** is enforced by ESLint Layer 2 rules.
38
+ > Features must not import from `infra/db` directly — use `core/repositories` interfaces.
39
+
40
+ ## Getting Started
41
+
42
+ ### 1. Prerequisites
43
+
44
+ - Node.js ≥ 18
45
+ - pnpm ≥ 9 — `npm install -g pnpm`
46
+ - A [Supabase](https://supabase.com) project (free tier works)
47
+
48
+ ### 2. Install dependencies
49
+
50
+ ```bash
51
+ pnpm install
52
+ ```
53
+
54
+ ### 3. Configure environment variables
55
+
56
+ ```bash
57
+ cp .env.example .env.local
58
+ ```
59
+
60
+ Open `.env.local` and fill in your values:
61
+
62
+ | Variable | Where to find it |
63
+ |----------|-----------------|
64
+ | `NEXT_PUBLIC_SUPABASE_URL` | Supabase Dashboard → Project Settings → API → Project URL |
65
+ | `NEXT_PUBLIC_SUPABASE_ANON_KEY` | Supabase Dashboard → Project Settings → API → anon / public |
66
+ | `SUPABASE_SERVICE_ROLE_KEY` | Supabase Dashboard → Project Settings → API → service_role (server only) |
67
+ | `NEXT_PUBLIC_APP_URL` | `http://localhost:3000` for local dev |
68
+
69
+ ### 4. Start development server
70
+
71
+ ```bash
72
+ pnpm dev
73
+ ```
74
+
75
+ Open [http://localhost:3000](http://localhost:3000) in your browser.
76
+
77
+ ## Development
78
+
79
+ ### Common commands
80
+
81
+ ```bash
82
+ pnpm dev # Start dev server (http://localhost:3000)
83
+ pnpm build # Production build
84
+ pnpm start # Serve production build
85
+ pnpm test # Run Vitest unit tests
86
+ pnpm check-types # TypeScript type check (no emit)
87
+ pnpm lint # ESLint (includes Layer 2 architectural rules)
88
+ ```
89
+
90
+ ### Adding a new feature
91
+
92
+ Features live in `src/features/`. Follow the reference implementation in `src/features/hello/`:
93
+
94
+ ```
95
+ src/features/<your-feature>/
96
+ ├── __contract__.ts # Public API surface (required — export types and functions)
97
+ ├── index.ts # Re-exports from __contract__.ts
98
+ └── *.test.ts # Vitest unit tests
99
+ ```
100
+
101
+ Rules:
102
+ - Features import from `src/core/` (domain interfaces) — never from `src/infra/` directly.
103
+ - Every feature directory **must** have `__contract__.ts` (ESLint enforces this).
104
+ - Add translations to `messages/en.json` and `messages/zh.json`.
105
+
106
+ ### Adding a language
107
+
108
+ 1. Add locale to `src/i18n/routing.ts` and `middleware.ts`.
109
+ 2. Create `messages/<locale>.json` with translated keys.
110
+
111
+ ### Running tests
112
+
113
+ ```bash
114
+ pnpm test # Run all tests once
115
+ pnpm test --watch # Watch mode
116
+ pnpm test --coverage # With coverage report
117
+ ```
118
+
119
+ ## Deployment
120
+
121
+ ### Vercel (recommended)
122
+
123
+ 1. Push your project to GitHub.
124
+ 2. Import the repository in [Vercel](https://vercel.com/new).
125
+ 3. Add all environment variables from `.env.example` in **Project Settings → Environment Variables**.
126
+ 4. Deploy — Vercel auto-detects Next.js.
127
+
128
+ ### Docker / other platforms
129
+
130
+ ```bash
131
+ pnpm build
132
+ pnpm start
133
+ ```
134
+
135
+ Ensure all `NEXT_PUBLIC_*` variables are set at **build time** (they are inlined by Next.js).
136
+ Server-only variables (`SUPABASE_SERVICE_ROLE_KEY`) must be available at **runtime**.
137
+
138
+ ### Supabase: production checklist
139
+
140
+ - [ ] Enable Row Level Security (RLS) on all tables.
141
+ - [ ] Review and tighten RLS policies.
142
+ - [ ] Rotate the `service_role` key if it was ever exposed.
143
+ - [ ] Enable Supabase Auth email confirmation.
144
+
145
+ ## Governance (OpenSpec)
146
+
147
+ This project uses [OpenSpec](https://github.com/fission-ai/openspec) for AI-assisted change governance.
148
+
149
+ ```bash
150
+ openspec list # List all changes
151
+ openspec status --change <name> # Check change artifact status
152
+ openspec instructions apply --change <name> # Get implementation instructions
153
+ ```
154
+
155
+ Changes live in `openspec/changes/`. The four-gate builder workflow:
156
+
157
+ ```
158
+ Human approves roadmap → Human reviews scope → AI codes → Machine gates (lint/types/tests)
159
+ ```
160
+
161
+ See `openspec/config.yaml` for project-specific governance rules.
162
+
163
+ ## Environment Variables Reference
164
+
165
+ | Variable | Required | Exposed to browser | Description |
166
+ |----------|----------|--------------------|-------------|
167
+ | `NEXT_PUBLIC_SUPABASE_URL` | ✅ | ✅ | Supabase project URL |
168
+ | `NEXT_PUBLIC_SUPABASE_ANON_KEY` | ✅ | ✅ | Supabase anon key (RLS protected) |
169
+ | `SUPABASE_SERVICE_ROLE_KEY` | Optional | ❌ | Admin key, bypasses RLS |
170
+ | `NEXT_PUBLIC_APP_URL` | Optional | ✅ | Canonical app URL |
171
+
172
+ > Variables prefixed with `NEXT_PUBLIC_` are bundled into client-side JavaScript.
173
+ > Never put secrets in `NEXT_PUBLIC_*` variables.
174
+
175
+ ## FAQs
176
+
177
+ **Q: pnpm install fails with `ERR_PNPM_FETCH_404` for `@cogito.ai/*`**
178
+ A: The `@cogito.ai/tsconfig` and `@cogito.ai/eslint-config` packages must be published to npm before use. If you generated this project before the packages were published, run `pnpm install` again after they are live at [npmjs.com/@agentdock](https://www.npmjs.com/org/cogito.ai).
179
+
180
+ **Q: How do I add a new Supabase table?**
181
+ A: Create the table in the Supabase Dashboard, then add a repository interface to `src/core/repositories/` and implement it in `src/infra/db/`. Do not call Supabase directly from `src/features/` — use the interface.
182
+
183
+ **Q: How do I disable i18n and use a single language?**
184
+ A: Set a single locale in `src/i18n/routing.ts` and remove the `[locale]` segment handling in `middleware.ts`. Keep `messages/en.json` and remove unused locale files.
185
+
186
+ **Q: TypeScript is strict — how do I handle `!` assertions?**
187
+ A: Prefer explicit checks (`if (!value) throw new Error(...)`) over `!` assertions. If you must use one, add a comment explaining why the value is guaranteed non-null.
188
+
189
+ **Q: Can AI agents work in this project?**
190
+ A: Yes. See `AGENTS.md` for the autonomy boundary contract. AI agents may freely edit `src/features/` but must pause for human review before editing `src/infra/` or `middleware.ts`.
191
+
192
+ ## Contributing
193
+
194
+ This project follows [Conventional Commits](https://www.conventionalcommits.org):
195
+
196
+ ```
197
+ feat(hello): add greeting animation
198
+ fix(i18n): correct zh translation key
199
+ chore: update dependencies
200
+ ```
201
+
202
+ ## License
203
+
204
+ MIT
@@ -0,0 +1,12 @@
1
+ // @ts-check
2
+ const base = require("@cogito.ai/eslint-config/base");
3
+ const features = require("@cogito.ai/eslint-config/features");
4
+
5
+ /** @type {import("eslint").Linter.Config[]} */
6
+ module.exports = [
7
+ {
8
+ ignores: [".next/**"],
9
+ },
10
+ ...base,
11
+ ...features,
12
+ ];
@@ -0,0 +1,10 @@
1
+ {
2
+ "home": {
3
+ "title": "Welcome to AgentDock Web Template",
4
+ "description": "A Next.js scaffold with four-layer architecture."
5
+ },
6
+ "hello": {
7
+ "title": "Hello Feature",
8
+ "greeting": "Hello, {name}!"
9
+ }
10
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "home": {
3
+ "title": "home.title",
4
+ "description": "home.description"
5
+ },
6
+ "hello": {
7
+ "title": "hello.title",
8
+ "greeting": "hello.greeting"
9
+ }
10
+ }
@@ -0,0 +1,34 @@
1
+ import createMiddleware from 'next-intl/middleware'
2
+ import { defineRouting } from 'next-intl/routing'
3
+ import { NextResponse, type NextRequest } from 'next/server'
4
+
5
+ export const routing = defineRouting({
6
+ locales: ['en', 'zh'],
7
+ defaultLocale: 'en',
8
+ })
9
+
10
+ const handleI18nRouting = createMiddleware(routing)
11
+
12
+ export default function middleware(request: NextRequest) {
13
+ const segments = request.nextUrl.pathname.split('/').filter(Boolean)
14
+ const firstSegment = segments[0]
15
+
16
+ if (firstSegment !== undefined) {
17
+ const isLocaleLike = /^[a-z]{2}(?:-[A-Z]{2})?$/.test(firstSegment)
18
+ const isSupportedLocale = routing.locales.includes(firstSegment as 'en' | 'zh')
19
+
20
+ // Normalize unknown locale-like prefixes: /fr/hello -> /en/hello.
21
+ if (isLocaleLike && !isSupportedLocale) {
22
+ const url = request.nextUrl.clone()
23
+ url.pathname = `/${routing.defaultLocale}/${segments.slice(1).join('/')}`.replace(/\/$/, '')
24
+ return NextResponse.redirect(url)
25
+ }
26
+ }
27
+
28
+ return handleI18nRouting(request)
29
+ }
30
+
31
+ export const config = {
32
+ // Match all pathnames except Next.js internals and static files.
33
+ matcher: ['/((?!_next|_vercel|.*\\..*).*)'],
34
+ }
@@ -0,0 +1,6 @@
1
+ /// <reference types="next" />
2
+ /// <reference types="next/image-types/global" />
3
+ import "./.next/types/routes.d.ts";
4
+
5
+ // NOTE: This file should not be edited
6
+ // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
@@ -0,0 +1,8 @@
1
+ import type { NextConfig } from 'next'
2
+ import createNextIntlPlugin from 'next-intl/plugin'
3
+
4
+ const withNextIntl = createNextIntlPlugin('./src/i18n/request.ts')
5
+
6
+ const nextConfig: NextConfig = {}
7
+
8
+ export default withNextIntl(nextConfig)
@@ -0,0 +1,28 @@
1
+ schema: spec-driven
2
+
3
+ # Project context (shown to AI when creating artifacts)
4
+ context: |
5
+ You are working in a project generated from the AgentDock web-nextjs template.
6
+
7
+ Tech stack: Next.js 16 (App Router), React 19, TypeScript 5+ (strict), Tailwind CSS,
8
+ Supabase (@supabase/ssr), next-intl (i18n), Vitest (unit tests), pnpm ≥9, Node ≥18.
9
+
10
+ Four-layer directory contract (enforced by ESLint Layer 2 rules at error severity):
11
+ src/core/ — domain types + repository interfaces (no framework deps, read-only)
12
+ src/features/ — AI coding zone; each feature needs __contract__.ts + index.ts + tests
13
+ src/infra/ — Supabase implementation (requires human approval before editing)
14
+ src/app/ — Next.js App Router pages and layouts
15
+
16
+ Governance rules:
17
+ - Conventional commits: type(scope): summary
18
+ - pnpm only — no npm/yarn
19
+ - TypeScript strict — no any, no @ts-ignore without explanation
20
+ - Features must not import from infra/db directly (use core/repositories interfaces)
21
+ - Every feature directory must have __contract__.ts
22
+
23
+ Reference feature: src/features/hello/ (complete example of the four-layer pattern)
24
+
25
+ # Workflow rules
26
+ rules:
27
+ proposal:
28
+ - "Proposal MUST contain a Non-goals section listing what this change will NOT implement."
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@cogito.ai/template-web-nextjs",
3
+ "version": "0.1.0",
4
+ "description": "Full-stack Next.js 16 starter with Supabase, next-intl, Tailwind CSS and Vitest",
5
+ "private": true,
6
+ "engines": {
7
+ "pnpm": ">=9",
8
+ "node": ">=18"
9
+ },
10
+ "scripts": {
11
+ "dev": "next dev",
12
+ "build": "next build",
13
+ "start": "next start",
14
+ "lint": "eslint .",
15
+ "test": "vitest run",
16
+ "check-types": "tsc --noEmit"
17
+ },
18
+ "dependencies": {
19
+ "@supabase/ssr": "^0.10.3",
20
+ "next": "16",
21
+ "next-intl": "^4.13.0",
22
+ "react": "19",
23
+ "react-dom": "19"
24
+ },
25
+ "devDependencies": {
26
+ "@vitejs/plugin-react": "^6.0.2",
27
+ "tailwindcss": "^4.3.0",
28
+ "typescript": "^6.0.3",
29
+ "vitest": "^4.1.8",
30
+ "@cogito.ai/eslint-config": "workspace:*",
31
+ "@cogito.ai/tsconfig": "workspace:*",
32
+ "@fission-ai/openspec": "^1.3.1"
33
+ },
34
+ "agentdock": {
35
+ "minCliVersion": "0.1.0"
36
+ }
37
+ }
@@ -0,0 +1,3 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
@@ -0,0 +1,45 @@
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
+ }
@@ -0,0 +1,37 @@
1
+ import type { Metadata } from 'next'
2
+ import { NextIntlClientProvider } from 'next-intl'
3
+ import { getMessages } from 'next-intl/server'
4
+ import { notFound } from 'next/navigation'
5
+ import './globals.css'
6
+
7
+ const locales = ['en', 'zh'] as const
8
+ type Locale = (typeof locales)[number]
9
+
10
+ export const metadata: Metadata = {
11
+ title: 'AgentDock Web Template',
12
+ description: 'Generated by AgentDock scaffold platform',
13
+ }
14
+
15
+ export default async function LocaleLayout({
16
+ children,
17
+ params,
18
+ }: {
19
+ children: React.ReactNode
20
+ params: Promise<{ locale: string }>
21
+ }) {
22
+ const { locale } = await params
23
+
24
+ if (!locales.includes(locale as Locale)) {
25
+ notFound()
26
+ }
27
+
28
+ const messages = await getMessages()
29
+
30
+ return (
31
+ <html lang={locale}>
32
+ <body>
33
+ <NextIntlClientProvider messages={messages}>{children}</NextIntlClientProvider>
34
+ </body>
35
+ </html>
36
+ )
37
+ }
@@ -0,0 +1,12 @@
1
+ import { useTranslations } from 'next-intl'
2
+
3
+ export default function HomePage() {
4
+ const t = useTranslations('home')
5
+
6
+ return (
7
+ <main className="flex min-h-screen flex-col items-center justify-center p-24">
8
+ <h1 className="text-4xl font-bold">{t('title')}</h1>
9
+ <p className="mt-4 text-gray-600">{t('description')}</p>
10
+ </main>
11
+ )
12
+ }
@@ -0,0 +1,2 @@
1
+ # src/core/repositories
2
+ # Repository interfaces — pure TypeScript interfaces, no DB dependencies.
@@ -0,0 +1,14 @@
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
+ }
@@ -0,0 +1,3 @@
1
+ # src/core/types
2
+ # Domain types — no framework dependencies.
3
+ # Do not add Supabase, Next.js, or React imports here.
@@ -0,0 +1,9 @@
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
+ }
@@ -0,0 +1,2 @@
1
+ # src/features/_experiments
2
+ # Experimental sandboxes — NOT to be imported by non-_experiments features.