@codebakers/cli 1.2.1 → 1.3.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.
@@ -0,0 +1,81 @@
1
+ export declare const PACKAGE_JSON: {
2
+ name: string;
3
+ version: string;
4
+ private: boolean;
5
+ scripts: {
6
+ dev: string;
7
+ build: string;
8
+ start: string;
9
+ lint: string;
10
+ "db:generate": string;
11
+ "db:push": string;
12
+ "db:studio": string;
13
+ };
14
+ dependencies: {
15
+ next: string;
16
+ react: string;
17
+ "react-dom": string;
18
+ "@supabase/supabase-js": string;
19
+ "@supabase/ssr": string;
20
+ "drizzle-orm": string;
21
+ postgres: string;
22
+ zod: string;
23
+ "react-hook-form": string;
24
+ "@hookform/resolvers": string;
25
+ "lucide-react": string;
26
+ clsx: string;
27
+ "tailwind-merge": string;
28
+ };
29
+ devDependencies: {
30
+ "@types/node": string;
31
+ "@types/react": string;
32
+ "@types/react-dom": string;
33
+ typescript: string;
34
+ tailwindcss: string;
35
+ postcss: string;
36
+ autoprefixer: string;
37
+ "drizzle-kit": string;
38
+ eslint: string;
39
+ "eslint-config-next": string;
40
+ };
41
+ };
42
+ export declare const ENV_EXAMPLE = "# Supabase\nNEXT_PUBLIC_SUPABASE_URL=your-supabase-url\nNEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key\nSUPABASE_SERVICE_ROLE_KEY=your-service-role-key\n\n# Database (from Supabase connection string)\nDATABASE_URL=postgresql://postgres:[password]@db.[project-ref].supabase.co:5432/postgres\n";
43
+ export declare const DRIZZLE_CONFIG = "import { defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n schema: \"./src/db/schema.ts\",\n out: \"./src/db/migrations\",\n dialect: \"postgresql\",\n dbCredentials: {\n url: process.env.DATABASE_URL!,\n },\n});\n";
44
+ export declare const DB_SCHEMA = "import { pgTable, text, timestamp, uuid, boolean } from \"drizzle-orm/pg-core\";\n\n// Users table (synced with Supabase Auth)\nexport const users = pgTable(\"users\", {\n id: uuid(\"id\").primaryKey().notNull(),\n email: text(\"email\").notNull().unique(),\n name: text(\"name\"),\n avatarUrl: text(\"avatar_url\"),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n});\n\n// Example: Add your tables here following this pattern\n// export const posts = pgTable(\"posts\", {\n// id: uuid(\"id\").primaryKey().defaultRandom(),\n// title: text(\"title\").notNull(),\n// content: text(\"content\"),\n// authorId: uuid(\"author_id\").references(() => users.id),\n// published: boolean(\"published\").default(false),\n// createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n// });\n";
45
+ export declare const DB_INDEX = "import { drizzle } from \"drizzle-orm/postgres-js\";\nimport postgres from \"postgres\";\nimport * as schema from \"./schema\";\n\nconst connectionString = process.env.DATABASE_URL!;\n\nconst client = postgres(connectionString, { prepare: false });\nexport const db = drizzle(client, { schema });\n\nexport type DB = typeof db;\n";
46
+ export declare const SUPABASE_SERVER = "import { createServerClient } from \"@supabase/ssr\";\nimport { cookies } from \"next/headers\";\n\nexport async function createClient() {\n const cookieStore = await cookies();\n\n return createServerClient(\n process.env.NEXT_PUBLIC_SUPABASE_URL!,\n process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,\n {\n cookies: {\n getAll() {\n return cookieStore.getAll();\n },\n setAll(cookiesToSet) {\n try {\n cookiesToSet.forEach(({ name, value, options }) =>\n cookieStore.set(name, value, options)\n );\n } catch {\n // The `setAll` method was called from a Server Component.\n // This can be ignored if you have middleware refreshing user sessions.\n }\n },\n },\n }\n );\n}\n";
47
+ export declare const SUPABASE_CLIENT = "import { createBrowserClient } from \"@supabase/ssr\";\n\nexport function createClient() {\n return createBrowserClient(\n process.env.NEXT_PUBLIC_SUPABASE_URL!,\n process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!\n );\n}\n";
48
+ export declare const SUPABASE_MIDDLEWARE = "import { createServerClient } from \"@supabase/ssr\";\nimport { NextResponse, type NextRequest } from \"next/server\";\n\nexport async function updateSession(request: NextRequest) {\n let supabaseResponse = NextResponse.next({\n request,\n });\n\n const supabase = createServerClient(\n process.env.NEXT_PUBLIC_SUPABASE_URL!,\n process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,\n {\n cookies: {\n getAll() {\n return request.cookies.getAll();\n },\n setAll(cookiesToSet) {\n cookiesToSet.forEach(({ name, value }) =>\n request.cookies.set(name, value)\n );\n supabaseResponse = NextResponse.next({\n request,\n });\n cookiesToSet.forEach(({ name, value, options }) =>\n supabaseResponse.cookies.set(name, value, options)\n );\n },\n },\n }\n );\n\n // This will refresh session if expired\n await supabase.auth.getUser();\n\n return supabaseResponse;\n}\n";
49
+ export declare const MIDDLEWARE = "import { type NextRequest } from \"next/server\";\nimport { updateSession } from \"@/lib/supabase/middleware\";\n\nexport async function middleware(request: NextRequest) {\n return await updateSession(request);\n}\n\nexport const config = {\n matcher: [\n /*\n * Match all request paths except for:\n * - _next/static (static files)\n * - _next/image (image optimization)\n * - favicon.ico\n * - public files\n */\n \"/((?!_next/static|_next/image|favicon.ico|.*\\\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)\",\n ],\n};\n";
50
+ export declare const TAILWIND_CONFIG = "import type { Config } from \"tailwindcss\";\n\nconst config: Config = {\n content: [\n \"./src/pages/**/*.{js,ts,jsx,tsx,mdx}\",\n \"./src/components/**/*.{js,ts,jsx,tsx,mdx}\",\n \"./src/app/**/*.{js,ts,jsx,tsx,mdx}\",\n ],\n theme: {\n extend: {},\n },\n plugins: [],\n};\nexport default config;\n";
51
+ export declare const POSTCSS_CONFIG = "module.exports = {\n plugins: {\n tailwindcss: {},\n autoprefixer: {},\n },\n};\n";
52
+ export declare const TSCONFIG: {
53
+ compilerOptions: {
54
+ lib: string[];
55
+ allowJs: boolean;
56
+ skipLibCheck: boolean;
57
+ strict: boolean;
58
+ noEmit: boolean;
59
+ esModuleInterop: boolean;
60
+ module: string;
61
+ moduleResolution: string;
62
+ resolveJsonModule: boolean;
63
+ isolatedModules: boolean;
64
+ jsx: string;
65
+ incremental: boolean;
66
+ plugins: {
67
+ name: string;
68
+ }[];
69
+ paths: {
70
+ "@/*": string[];
71
+ };
72
+ };
73
+ include: string[];
74
+ exclude: string[];
75
+ };
76
+ export declare const NEXT_CONFIG = "import type { NextConfig } from \"next\";\n\nconst nextConfig: NextConfig = {\n /* config options here */\n};\n\nexport default nextConfig;\n";
77
+ export declare const GLOBALS_CSS = "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n:root {\n --background: #ffffff;\n --foreground: #171717;\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --background: #0a0a0a;\n --foreground: #ededed;\n }\n}\n\nbody {\n color: var(--foreground);\n background: var(--background);\n font-family: Arial, Helvetica, sans-serif;\n}\n";
78
+ export declare const LAYOUT_TSX = "import type { Metadata } from \"next\";\nimport \"./globals.css\";\n\nexport const metadata: Metadata = {\n title: \"My App\",\n description: \"Built with CodeBakers patterns\",\n};\n\nexport default function RootLayout({\n children,\n}: Readonly<{\n children: React.ReactNode;\n}>) {\n return (\n <html lang=\"en\">\n <body>{children}</body>\n </html>\n );\n}\n";
79
+ export declare const PAGE_TSX = "export default function Home() {\n return (\n <main className=\"flex min-h-screen flex-col items-center justify-center p-24\">\n <h1 className=\"text-4xl font-bold mb-4\">Welcome to Your App</h1>\n <p className=\"text-gray-600 mb-8\">Built with CodeBakers patterns</p>\n <div className=\"flex gap-4\">\n <a\n href=\"/login\"\n className=\"px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition\"\n >\n Get Started\n </a>\n <a\n href=\"/docs\"\n className=\"px-6 py-3 border border-gray-300 rounded-lg hover:bg-gray-50 transition\"\n >\n Documentation\n </a>\n </div>\n </main>\n );\n}\n";
80
+ export declare const UTILS_CN = "import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n";
81
+ export declare const GITIGNORE = "# Dependencies\nnode_modules\n.pnpm-debug.log*\n\n# Next.js\n.next/\nout/\n\n# Production\nbuild\ndist\n\n# Misc\n.DS_Store\n*.pem\n\n# Debug\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n\n# Local env files\n.env\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\n# Vercel\n.vercel\n\n# TypeScript\n*.tsbuildinfo\nnext-env.d.ts\n\n# IDE\n.idea\n.vscode/*\n!.vscode/settings.json\n";
@@ -0,0 +1,356 @@
1
+ "use strict";
2
+ // Next.js + Supabase + Drizzle project template
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.GITIGNORE = exports.UTILS_CN = exports.PAGE_TSX = exports.LAYOUT_TSX = exports.GLOBALS_CSS = exports.NEXT_CONFIG = exports.TSCONFIG = exports.POSTCSS_CONFIG = exports.TAILWIND_CONFIG = exports.MIDDLEWARE = exports.SUPABASE_MIDDLEWARE = exports.SUPABASE_CLIENT = exports.SUPABASE_SERVER = exports.DB_INDEX = exports.DB_SCHEMA = exports.DRIZZLE_CONFIG = exports.ENV_EXAMPLE = exports.PACKAGE_JSON = void 0;
5
+ exports.PACKAGE_JSON = {
6
+ name: "my-project",
7
+ version: "0.1.0",
8
+ private: true,
9
+ scripts: {
10
+ "dev": "next dev",
11
+ "build": "next build",
12
+ "start": "next start",
13
+ "lint": "next lint",
14
+ "db:generate": "drizzle-kit generate",
15
+ "db:push": "drizzle-kit push",
16
+ "db:studio": "drizzle-kit studio"
17
+ },
18
+ dependencies: {
19
+ "next": "15.1.0",
20
+ "react": "^19.0.0",
21
+ "react-dom": "^19.0.0",
22
+ "@supabase/supabase-js": "^2.47.10",
23
+ "@supabase/ssr": "^0.5.2",
24
+ "drizzle-orm": "^0.38.2",
25
+ "postgres": "^3.4.5",
26
+ "zod": "^3.24.1",
27
+ "react-hook-form": "^7.54.1",
28
+ "@hookform/resolvers": "^3.9.1",
29
+ "lucide-react": "^0.468.0",
30
+ "clsx": "^2.1.1",
31
+ "tailwind-merge": "^2.6.0"
32
+ },
33
+ devDependencies: {
34
+ "@types/node": "^22.10.2",
35
+ "@types/react": "^19.0.1",
36
+ "@types/react-dom": "^19.0.1",
37
+ "typescript": "^5.7.2",
38
+ "tailwindcss": "^3.4.17",
39
+ "postcss": "^8.4.49",
40
+ "autoprefixer": "^10.4.20",
41
+ "drizzle-kit": "^0.30.1",
42
+ "eslint": "^9.17.0",
43
+ "eslint-config-next": "15.1.0"
44
+ }
45
+ };
46
+ exports.ENV_EXAMPLE = `# Supabase
47
+ NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
48
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
49
+ SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
50
+
51
+ # Database (from Supabase connection string)
52
+ DATABASE_URL=postgresql://postgres:[password]@db.[project-ref].supabase.co:5432/postgres
53
+ `;
54
+ exports.DRIZZLE_CONFIG = `import { defineConfig } from "drizzle-kit";
55
+
56
+ export default defineConfig({
57
+ schema: "./src/db/schema.ts",
58
+ out: "./src/db/migrations",
59
+ dialect: "postgresql",
60
+ dbCredentials: {
61
+ url: process.env.DATABASE_URL!,
62
+ },
63
+ });
64
+ `;
65
+ exports.DB_SCHEMA = `import { pgTable, text, timestamp, uuid, boolean } from "drizzle-orm/pg-core";
66
+
67
+ // Users table (synced with Supabase Auth)
68
+ export const users = pgTable("users", {
69
+ id: uuid("id").primaryKey().notNull(),
70
+ email: text("email").notNull().unique(),
71
+ name: text("name"),
72
+ avatarUrl: text("avatar_url"),
73
+ createdAt: timestamp("created_at").defaultNow().notNull(),
74
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
75
+ });
76
+
77
+ // Example: Add your tables here following this pattern
78
+ // export const posts = pgTable("posts", {
79
+ // id: uuid("id").primaryKey().defaultRandom(),
80
+ // title: text("title").notNull(),
81
+ // content: text("content"),
82
+ // authorId: uuid("author_id").references(() => users.id),
83
+ // published: boolean("published").default(false),
84
+ // createdAt: timestamp("created_at").defaultNow().notNull(),
85
+ // });
86
+ `;
87
+ exports.DB_INDEX = `import { drizzle } from "drizzle-orm/postgres-js";
88
+ import postgres from "postgres";
89
+ import * as schema from "./schema";
90
+
91
+ const connectionString = process.env.DATABASE_URL!;
92
+
93
+ const client = postgres(connectionString, { prepare: false });
94
+ export const db = drizzle(client, { schema });
95
+
96
+ export type DB = typeof db;
97
+ `;
98
+ exports.SUPABASE_SERVER = `import { createServerClient } from "@supabase/ssr";
99
+ import { cookies } from "next/headers";
100
+
101
+ export async function createClient() {
102
+ const cookieStore = await cookies();
103
+
104
+ return createServerClient(
105
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
106
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
107
+ {
108
+ cookies: {
109
+ getAll() {
110
+ return cookieStore.getAll();
111
+ },
112
+ setAll(cookiesToSet) {
113
+ try {
114
+ cookiesToSet.forEach(({ name, value, options }) =>
115
+ cookieStore.set(name, value, options)
116
+ );
117
+ } catch {
118
+ // The \`setAll\` method was called from a Server Component.
119
+ // This can be ignored if you have middleware refreshing user sessions.
120
+ }
121
+ },
122
+ },
123
+ }
124
+ );
125
+ }
126
+ `;
127
+ exports.SUPABASE_CLIENT = `import { createBrowserClient } from "@supabase/ssr";
128
+
129
+ export function createClient() {
130
+ return createBrowserClient(
131
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
132
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
133
+ );
134
+ }
135
+ `;
136
+ exports.SUPABASE_MIDDLEWARE = `import { createServerClient } from "@supabase/ssr";
137
+ import { NextResponse, type NextRequest } from "next/server";
138
+
139
+ export async function updateSession(request: NextRequest) {
140
+ let supabaseResponse = NextResponse.next({
141
+ request,
142
+ });
143
+
144
+ const supabase = createServerClient(
145
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
146
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
147
+ {
148
+ cookies: {
149
+ getAll() {
150
+ return request.cookies.getAll();
151
+ },
152
+ setAll(cookiesToSet) {
153
+ cookiesToSet.forEach(({ name, value }) =>
154
+ request.cookies.set(name, value)
155
+ );
156
+ supabaseResponse = NextResponse.next({
157
+ request,
158
+ });
159
+ cookiesToSet.forEach(({ name, value, options }) =>
160
+ supabaseResponse.cookies.set(name, value, options)
161
+ );
162
+ },
163
+ },
164
+ }
165
+ );
166
+
167
+ // This will refresh session if expired
168
+ await supabase.auth.getUser();
169
+
170
+ return supabaseResponse;
171
+ }
172
+ `;
173
+ exports.MIDDLEWARE = `import { type NextRequest } from "next/server";
174
+ import { updateSession } from "@/lib/supabase/middleware";
175
+
176
+ export async function middleware(request: NextRequest) {
177
+ return await updateSession(request);
178
+ }
179
+
180
+ export const config = {
181
+ matcher: [
182
+ /*
183
+ * Match all request paths except for:
184
+ * - _next/static (static files)
185
+ * - _next/image (image optimization)
186
+ * - favicon.ico
187
+ * - public files
188
+ */
189
+ "/((?!_next/static|_next/image|favicon.ico|.*\\\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
190
+ ],
191
+ };
192
+ `;
193
+ exports.TAILWIND_CONFIG = `import type { Config } from "tailwindcss";
194
+
195
+ const config: Config = {
196
+ content: [
197
+ "./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
198
+ "./src/components/**/*.{js,ts,jsx,tsx,mdx}",
199
+ "./src/app/**/*.{js,ts,jsx,tsx,mdx}",
200
+ ],
201
+ theme: {
202
+ extend: {},
203
+ },
204
+ plugins: [],
205
+ };
206
+ export default config;
207
+ `;
208
+ exports.POSTCSS_CONFIG = `module.exports = {
209
+ plugins: {
210
+ tailwindcss: {},
211
+ autoprefixer: {},
212
+ },
213
+ };
214
+ `;
215
+ exports.TSCONFIG = {
216
+ compilerOptions: {
217
+ lib: ["dom", "dom.iterable", "esnext"],
218
+ allowJs: true,
219
+ skipLibCheck: true,
220
+ strict: true,
221
+ noEmit: true,
222
+ esModuleInterop: true,
223
+ module: "esnext",
224
+ moduleResolution: "bundler",
225
+ resolveJsonModule: true,
226
+ isolatedModules: true,
227
+ jsx: "preserve",
228
+ incremental: true,
229
+ plugins: [{ name: "next" }],
230
+ paths: {
231
+ "@/*": ["./src/*"]
232
+ }
233
+ },
234
+ include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
235
+ exclude: ["node_modules"]
236
+ };
237
+ exports.NEXT_CONFIG = `import type { NextConfig } from "next";
238
+
239
+ const nextConfig: NextConfig = {
240
+ /* config options here */
241
+ };
242
+
243
+ export default nextConfig;
244
+ `;
245
+ exports.GLOBALS_CSS = `@tailwind base;
246
+ @tailwind components;
247
+ @tailwind utilities;
248
+
249
+ :root {
250
+ --background: #ffffff;
251
+ --foreground: #171717;
252
+ }
253
+
254
+ @media (prefers-color-scheme: dark) {
255
+ :root {
256
+ --background: #0a0a0a;
257
+ --foreground: #ededed;
258
+ }
259
+ }
260
+
261
+ body {
262
+ color: var(--foreground);
263
+ background: var(--background);
264
+ font-family: Arial, Helvetica, sans-serif;
265
+ }
266
+ `;
267
+ exports.LAYOUT_TSX = `import type { Metadata } from "next";
268
+ import "./globals.css";
269
+
270
+ export const metadata: Metadata = {
271
+ title: "My App",
272
+ description: "Built with CodeBakers patterns",
273
+ };
274
+
275
+ export default function RootLayout({
276
+ children,
277
+ }: Readonly<{
278
+ children: React.ReactNode;
279
+ }>) {
280
+ return (
281
+ <html lang="en">
282
+ <body>{children}</body>
283
+ </html>
284
+ );
285
+ }
286
+ `;
287
+ exports.PAGE_TSX = `export default function Home() {
288
+ return (
289
+ <main className="flex min-h-screen flex-col items-center justify-center p-24">
290
+ <h1 className="text-4xl font-bold mb-4">Welcome to Your App</h1>
291
+ <p className="text-gray-600 mb-8">Built with CodeBakers patterns</p>
292
+ <div className="flex gap-4">
293
+ <a
294
+ href="/login"
295
+ className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition"
296
+ >
297
+ Get Started
298
+ </a>
299
+ <a
300
+ href="/docs"
301
+ className="px-6 py-3 border border-gray-300 rounded-lg hover:bg-gray-50 transition"
302
+ >
303
+ Documentation
304
+ </a>
305
+ </div>
306
+ </main>
307
+ );
308
+ }
309
+ `;
310
+ exports.UTILS_CN = `import { clsx, type ClassValue } from "clsx";
311
+ import { twMerge } from "tailwind-merge";
312
+
313
+ export function cn(...inputs: ClassValue[]) {
314
+ return twMerge(clsx(inputs));
315
+ }
316
+ `;
317
+ exports.GITIGNORE = `# Dependencies
318
+ node_modules
319
+ .pnpm-debug.log*
320
+
321
+ # Next.js
322
+ .next/
323
+ out/
324
+
325
+ # Production
326
+ build
327
+ dist
328
+
329
+ # Misc
330
+ .DS_Store
331
+ *.pem
332
+
333
+ # Debug
334
+ npm-debug.log*
335
+ yarn-debug.log*
336
+ yarn-error.log*
337
+
338
+ # Local env files
339
+ .env
340
+ .env.local
341
+ .env.development.local
342
+ .env.test.local
343
+ .env.production.local
344
+
345
+ # Vercel
346
+ .vercel
347
+
348
+ # TypeScript
349
+ *.tsbuildinfo
350
+ next-env.d.ts
351
+
352
+ # IDE
353
+ .idea
354
+ .vscode/*
355
+ !.vscode/settings.json
356
+ `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codebakers/cli",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "CodeBakers CLI - Production patterns for AI-assisted development",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -4,71 +4,40 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync, copyFileSync } from
4
4
  import { join } from 'path';
5
5
  import { homedir } from 'os';
6
6
 
7
- // Enhanced hook with pre-flight checks and self-review automation
7
+ // Enhanced hook with visible feedback and concise instructions
8
8
  const HOOK_TEMPLATE = {
9
9
  hooks: {
10
10
  UserPromptSubmit: [
11
11
  {
12
12
  type: "command",
13
- command: `echo '════════════════════════════════════════════════════════════════
14
- 🚀 CODEBAKERS ZERO-FRICTION PROTOCOL
15
- ════════════════════════════════════════════════════════════════
16
-
17
- AUTOMATIC WORKFLOW - Execute silently, output only the acknowledgment:
18
-
19
- ▸ PHASE 1: CONTEXT LOAD
20
- Read these files (if they exist):
21
- - CLAUDE.md → Router & module instructions
22
- - PRD.md → What we are building (requirements!)
23
- - PROJECT-CONTEXT.md → Codebase knowledge
24
- - PROJECT-STATE.md → What is in progress
25
- - DECISIONS.md → Past architectural choices
26
-
27
- ▸ PHASE 2: PRE-FLIGHT CHECK (before writing code)
28
- □ What existing code does this touch?
29
- □ Is similar code in the codebase? (copy that pattern!)
30
- □ Whats the data model?
31
- □ What are the error cases?
32
- □ Is someone else working on this? (check In Progress)
33
-
34
- If PROJECT-CONTEXT.md is empty/stale, SCAN PROJECT FIRST:
35
- - Read package.json
36
- - Check file structure
37
- - Find existing patterns
38
- - Update PROJECT-CONTEXT.md
39
-
40
- ▸ PHASE 3: ACKNOWLEDGE & EXECUTE
41
- Output: 📋 CodeBakers | [Type] | Modules: [list]
42
- Then: Follow patterns from .claude/ folder EXACTLY
43
-
44
- ▸ PHASE 4: SELF-REVIEW (before saying done)
45
- □ TypeScript compiles? (npx tsc --noEmit)
46
- □ Imports resolve?
47
- □ Error handling exists?
48
- □ Matches existing patterns?
49
- □ Tests written?
50
-
51
- If ANY fails → FIX before responding
52
-
53
- ▸ PHASE 5: UPDATE STATE
54
- - Update PROJECT-STATE.md (move to Completed)
55
- - Add to DECISIONS.md if architectural choice made
56
-
57
- ════════════════════════════════════════════════════════════════
58
- 🔄 MULTI-AGENT MODE
59
- ════════════════════════════════════════════════════════════════
60
- - Check PROJECT-STATE.md "In Progress" - dont duplicate work
61
- - Add YOUR task to In Progress when starting
62
- - If conflict → STOP and ask user
63
-
64
- ════════════════════════════════════════════════════════════════
65
- 💡 REMEMBER: Check existing code FIRST. Copy patterns. Validate.
66
- ════════════════════════════════════════════════════════════════'`
13
+ command: `echo '[CodeBakers] Loading project context...'`
14
+ }
15
+ ],
16
+ PostToolUse: [
17
+ {
18
+ type: "command",
19
+ matcher: "Write|Edit",
20
+ command: `echo '[CodeBakers] Code written - remember to self-review before marking done'`
67
21
  }
68
22
  ]
69
23
  }
70
24
  };
71
25
 
26
+ // Instructions that get injected into the system prompt
27
+ const CODEBAKERS_INSTRUCTIONS = `
28
+ <user-prompt-submit-hook>
29
+ [CodeBakers] Active - Follow these steps for EVERY request:
30
+
31
+ 1. CONTEXT: Read CLAUDE.md, PROJECT-CONTEXT.md, PROJECT-STATE.md
32
+ 2. PRE-FLIGHT: Check existing code patterns before writing new code
33
+ 3. EXECUTE: Use patterns from .claude/ folder
34
+ 4. SELF-REVIEW: Verify TypeScript compiles, imports resolve, error handling exists
35
+ 5. UPDATE: Mark tasks complete in PROJECT-STATE.md
36
+
37
+ Output format: "[CodeBakers] Building [feature] using [patterns]"
38
+ </user-prompt-submit-hook>
39
+ `;
40
+
72
41
  /**
73
42
  * Install the CodeBakers hook into ~/.claude/settings.json
74
43
  */
@@ -117,23 +86,25 @@ export async function installHook(): Promise<void> {
117
86
  }
118
87
  }
119
88
 
120
- // Merge hook into settings
89
+ // Merge hooks into settings
121
90
  settings.hooks = settings.hooks || {};
122
91
  (settings.hooks as Record<string, unknown>).UserPromptSubmit = HOOK_TEMPLATE.hooks.UserPromptSubmit;
92
+ (settings.hooks as Record<string, unknown>).PostToolUse = HOOK_TEMPLATE.hooks.PostToolUse;
123
93
 
124
94
  // Write back
125
95
  writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
126
96
 
127
97
  spinner.succeed('Hook installed successfully!');
128
98
 
129
- console.log(chalk.white('\n What happens automatically on EVERY message:\n'));
130
- console.log(chalk.gray(' Loads project context (CLAUDE.md, PROJECT-CONTEXT.md)'));
131
- console.log(chalk.gray(' Checks what\'s in progress (PROJECT-STATE.md)'));
132
- console.log(chalk.gray(' ✓ Runs pre-flight checks before coding'));
133
- console.log(chalk.gray(' Copies existing patterns from your codebase'));
134
- console.log(chalk.gray(' ✓ Self-reviews code before outputting'));
135
- console.log(chalk.gray(' ✓ Updates project state when done'));
136
- console.log(chalk.gray(' ✓ Logs architectural decisions\n'));
99
+ console.log(chalk.white('\n You\'ll see [CodeBakers] feedback in terminal:\n'));
100
+ console.log(chalk.cyan(' [CodeBakers] Loading project context...'));
101
+ console.log(chalk.cyan(' [CodeBakers] Code written - remember to self-review\n'));
102
+
103
+ console.log(chalk.white(' What happens automatically:\n'));
104
+ console.log(chalk.gray(' ✓ Loads project context before every response'));
105
+ console.log(chalk.gray(' ✓ Pre-flight checks before writing code'));
106
+ console.log(chalk.gray(' ✓ Self-review reminders after code changes'));
107
+ console.log(chalk.gray(' ✓ Pattern-based development from .claude/ folder\n'));
137
108
 
138
109
  console.log(chalk.yellow(' ⚠️ Restart Claude Code for changes to take effect.\n'));
139
110
  } catch (error) {
@@ -162,13 +133,18 @@ export async function uninstallHook(): Promise<void> {
162
133
 
163
134
  const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
164
135
 
165
- if (!settings.hooks?.UserPromptSubmit) {
166
- spinner.info('No UserPromptSubmit hook found. Nothing to remove.');
136
+ if (!settings.hooks?.UserPromptSubmit && !settings.hooks?.PostToolUse) {
137
+ spinner.info('No CodeBakers hooks found. Nothing to remove.');
167
138
  return;
168
139
  }
169
140
 
170
- // Remove the hook
171
- delete settings.hooks.UserPromptSubmit;
141
+ // Remove both hooks
142
+ if (settings.hooks?.UserPromptSubmit) {
143
+ delete settings.hooks.UserPromptSubmit;
144
+ }
145
+ if (settings.hooks?.PostToolUse) {
146
+ delete settings.hooks.PostToolUse;
147
+ }
172
148
 
173
149
  // Clean up empty hooks object
174
150
  if (Object.keys(settings.hooks).length === 0) {