workflow-agent-cli 2.1.0 → 2.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.
@@ -5,7 +5,7 @@ import {
5
5
  loadConfig,
6
6
  validateConfig,
7
7
  validateScopeName
8
- } from "../chunk-B27W7GWP.js";
8
+ } from "../chunk-IPMSSOXR.js";
9
9
  export {
10
10
  DEFAULT_RESERVED_SCOPE_NAMES,
11
11
  WorkflowConfigSchema,
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  validateBranchName,
6
6
  validateCommitMessage,
7
7
  validatePRTitle
8
- } from "./chunk-X2NQJ2ZY.js";
8
+ } from "./chunk-NMHWD2GA.js";
9
9
  import {
10
10
  DEFAULT_RESERVED_SCOPE_NAMES,
11
11
  WorkflowConfigSchema,
@@ -13,7 +13,7 @@ import {
13
13
  loadConfig,
14
14
  validateConfig,
15
15
  validateScopeName
16
- } from "./chunk-B27W7GWP.js";
16
+ } from "./chunk-IPMSSOXR.js";
17
17
  export {
18
18
  DEFAULT_RESERVED_SCOPE_NAMES,
19
19
  WorkflowConfigSchema,
@@ -48,7 +48,9 @@ function addScriptsToPackageJson() {
48
48
  return;
49
49
  }
50
50
  let addedCount = 0;
51
- for (const [scriptName, scriptCommand] of Object.entries(WORKFLOW_SCRIPTS)) {
51
+ for (const [scriptName, scriptCommand] of Object.entries(
52
+ WORKFLOW_SCRIPTS
53
+ )) {
52
54
  if (!packageJson.scripts[scriptName]) {
53
55
  packageJson.scripts[scriptName] = scriptCommand;
54
56
  addedCount++;
@@ -64,7 +66,9 @@ function addScriptsToPackageJson() {
64
66
  Object.keys(WORKFLOW_SCRIPTS).forEach((scriptName) => {
65
67
  console.log(` - ${scriptName}`);
66
68
  });
67
- console.log("\nRun them with: npm run workflow:init (or pnpm run workflow:init)\n");
69
+ console.log(
70
+ "\nRun them with: npm run workflow:init (or pnpm run workflow:init)\n"
71
+ );
68
72
  }
69
73
  } catch (error) {
70
74
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/scripts/postinstall.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * Post-install script that automatically adds workflow scripts to package.json\n * when installed as a local dependency (not global)\n */\n\nimport { readFileSync, writeFileSync, existsSync } from 'fs';\nimport { join } from 'path';\n\nconst WORKFLOW_SCRIPTS = {\n 'workflow:init': 'workflow-agent init',\n 'workflow:validate': 'workflow-agent validate',\n 'workflow:suggest': 'workflow-agent suggest',\n 'workflow:doctor': 'workflow-agent doctor',\n};\n\nfunction isGlobalInstall(): boolean {\n // Check if we're being installed globally\n const installPath = process.env.npm_config_global;\n return installPath === 'true';\n}\n\nfunction findProjectRoot(): string | null {\n // When installed as a dependency, npm/pnpm runs postinstall from the package directory\n // which is inside node_modules/@hawkinside_out/workflow-agent\n // We need to find the project root (the directory containing node_modules)\n \n let currentDir = process.cwd();\n \n // Check if we're inside node_modules\n if (currentDir.includes('node_modules')) {\n // Split on 'node_modules' and take everything before it\n // This handles both node_modules/@scope/package and node_modules/package\n const parts = currentDir.split('node_modules');\n if (parts.length > 0 && parts[0]) {\n // Remove trailing slash\n return parts[0].replace(/\\/$/, '');\n }\n }\n \n // If not in node_modules, we're probably in a monorepo workspace during development\n // Don't modify package.json in this case\n return null;\n}\n\nfunction addScriptsToPackageJson(): void {\n try {\n // Don't run for global installs\n if (isGlobalInstall()) {\n return;\n }\n\n const projectRoot = findProjectRoot();\n if (!projectRoot) {\n return;\n }\n\n const packageJsonPath = join(projectRoot, 'package.json');\n \n if (!existsSync(packageJsonPath)) {\n return;\n }\n\n // Read existing package.json\n const packageJsonContent = readFileSync(packageJsonPath, 'utf-8');\n const packageJson = JSON.parse(packageJsonContent);\n\n // Initialize scripts object if it doesn't exist\n if (!packageJson.scripts) {\n packageJson.scripts = {};\n }\n\n // Check if any workflow scripts already exist\n const hasWorkflowScripts = Object.keys(WORKFLOW_SCRIPTS).some(\n (scriptName) => packageJson.scripts[scriptName]\n );\n\n if (hasWorkflowScripts) {\n // Scripts already exist, don't overwrite\n return;\n }\n\n // Add workflow scripts\n let addedCount = 0;\n for (const [scriptName, scriptCommand] of Object.entries(WORKFLOW_SCRIPTS)) {\n if (!packageJson.scripts[scriptName]) {\n packageJson.scripts[scriptName] = scriptCommand;\n addedCount++;\n }\n }\n\n if (addedCount > 0) {\n // Write back to package.json with proper formatting\n writeFileSync(\n packageJsonPath,\n JSON.stringify(packageJson, null, 2) + '\\n',\n 'utf-8'\n );\n\n console.log('\\n✓ Added workflow scripts to package.json:');\n Object.keys(WORKFLOW_SCRIPTS).forEach((scriptName) => {\n console.log(` - ${scriptName}`);\n });\n console.log('\\nRun them with: npm run workflow:init (or pnpm run workflow:init)\\n');\n }\n } catch (error) {\n // Silently fail - this is a nice-to-have feature\n // We don't want to break the installation if something goes wrong\n }\n}\n\n// Run the script\naddScriptsToPackageJson();\n"],"mappings":";;;AAOA,SAAS,cAAc,eAAe,kBAAkB;AACxD,SAAS,YAAY;AAErB,IAAM,mBAAmB;AAAA,EACvB,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,mBAAmB;AACrB;AAEA,SAAS,kBAA2B;AAElC,QAAM,cAAc,QAAQ,IAAI;AAChC,SAAO,gBAAgB;AACzB;AAEA,SAAS,kBAAiC;AAKxC,MAAI,aAAa,QAAQ,IAAI;AAG7B,MAAI,WAAW,SAAS,cAAc,GAAG;AAGvC,UAAM,QAAQ,WAAW,MAAM,cAAc;AAC7C,QAAI,MAAM,SAAS,KAAK,MAAM,CAAC,GAAG;AAEhC,aAAO,MAAM,CAAC,EAAE,QAAQ,OAAO,EAAE;AAAA,IACnC;AAAA,EACF;AAIA,SAAO;AACT;AAEA,SAAS,0BAAgC;AACvC,MAAI;AAEF,QAAI,gBAAgB,GAAG;AACrB;AAAA,IACF;AAEA,UAAM,cAAc,gBAAgB;AACpC,QAAI,CAAC,aAAa;AAChB;AAAA,IACF;AAEA,UAAM,kBAAkB,KAAK,aAAa,cAAc;AAExD,QAAI,CAAC,WAAW,eAAe,GAAG;AAChC;AAAA,IACF;AAGA,UAAM,qBAAqB,aAAa,iBAAiB,OAAO;AAChE,UAAM,cAAc,KAAK,MAAM,kBAAkB;AAGjD,QAAI,CAAC,YAAY,SAAS;AACxB,kBAAY,UAAU,CAAC;AAAA,IACzB;AAGA,UAAM,qBAAqB,OAAO,KAAK,gBAAgB,EAAE;AAAA,MACvD,CAAC,eAAe,YAAY,QAAQ,UAAU;AAAA,IAChD;AAEA,QAAI,oBAAoB;AAEtB;AAAA,IACF;AAGA,QAAI,aAAa;AACjB,eAAW,CAAC,YAAY,aAAa,KAAK,OAAO,QAAQ,gBAAgB,GAAG;AAC1E,UAAI,CAAC,YAAY,QAAQ,UAAU,GAAG;AACpC,oBAAY,QAAQ,UAAU,IAAI;AAClC;AAAA,MACF;AAAA,IACF;AAEA,QAAI,aAAa,GAAG;AAElB;AAAA,QACE;AAAA,QACA,KAAK,UAAU,aAAa,MAAM,CAAC,IAAI;AAAA,QACvC;AAAA,MACF;AAEA,cAAQ,IAAI,kDAA6C;AACzD,aAAO,KAAK,gBAAgB,EAAE,QAAQ,CAAC,eAAe;AACpD,gBAAQ,IAAI,OAAO,UAAU,EAAE;AAAA,MACjC,CAAC;AACD,cAAQ,IAAI,sEAAsE;AAAA,IACpF;AAAA,EACF,SAAS,OAAO;AAAA,EAGhB;AACF;AAGA,wBAAwB;","names":[]}
1
+ {"version":3,"sources":["../../src/scripts/postinstall.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * Post-install script that automatically adds workflow scripts to package.json\n * when installed as a local dependency (not global)\n */\n\nimport { readFileSync, writeFileSync, existsSync } from \"fs\";\nimport { join } from \"path\";\n\nconst WORKFLOW_SCRIPTS = {\n \"workflow:init\": \"workflow-agent init\",\n \"workflow:validate\": \"workflow-agent validate\",\n \"workflow:suggest\": \"workflow-agent suggest\",\n \"workflow:doctor\": \"workflow-agent doctor\",\n};\n\nfunction isGlobalInstall(): boolean {\n // Check if we're being installed globally\n const installPath = process.env.npm_config_global;\n return installPath === \"true\";\n}\n\nfunction findProjectRoot(): string | null {\n // When installed as a dependency, npm/pnpm runs postinstall from the package directory\n // which is inside node_modules/@hawkinside_out/workflow-agent\n // We need to find the project root (the directory containing node_modules)\n\n let currentDir = process.cwd();\n\n // Check if we're inside node_modules\n if (currentDir.includes(\"node_modules\")) {\n // Split on 'node_modules' and take everything before it\n // This handles both node_modules/@scope/package and node_modules/package\n const parts = currentDir.split(\"node_modules\");\n if (parts.length > 0 && parts[0]) {\n // Remove trailing slash\n return parts[0].replace(/\\/$/, \"\");\n }\n }\n\n // If not in node_modules, we're probably in a monorepo workspace during development\n // Don't modify package.json in this case\n return null;\n}\n\nfunction addScriptsToPackageJson(): void {\n try {\n // Don't run for global installs\n if (isGlobalInstall()) {\n return;\n }\n\n const projectRoot = findProjectRoot();\n if (!projectRoot) {\n return;\n }\n\n const packageJsonPath = join(projectRoot, \"package.json\");\n\n if (!existsSync(packageJsonPath)) {\n return;\n }\n\n // Read existing package.json\n const packageJsonContent = readFileSync(packageJsonPath, \"utf-8\");\n const packageJson = JSON.parse(packageJsonContent);\n\n // Initialize scripts object if it doesn't exist\n if (!packageJson.scripts) {\n packageJson.scripts = {};\n }\n\n // Check if any workflow scripts already exist\n const hasWorkflowScripts = Object.keys(WORKFLOW_SCRIPTS).some(\n (scriptName) => packageJson.scripts[scriptName],\n );\n\n if (hasWorkflowScripts) {\n // Scripts already exist, don't overwrite\n return;\n }\n\n // Add workflow scripts\n let addedCount = 0;\n for (const [scriptName, scriptCommand] of Object.entries(\n WORKFLOW_SCRIPTS,\n )) {\n if (!packageJson.scripts[scriptName]) {\n packageJson.scripts[scriptName] = scriptCommand;\n addedCount++;\n }\n }\n\n if (addedCount > 0) {\n // Write back to package.json with proper formatting\n writeFileSync(\n packageJsonPath,\n JSON.stringify(packageJson, null, 2) + \"\\n\",\n \"utf-8\",\n );\n\n console.log(\"\\n✓ Added workflow scripts to package.json:\");\n Object.keys(WORKFLOW_SCRIPTS).forEach((scriptName) => {\n console.log(` - ${scriptName}`);\n });\n console.log(\n \"\\nRun them with: npm run workflow:init (or pnpm run workflow:init)\\n\",\n );\n }\n } catch (error) {\n // Silently fail - this is a nice-to-have feature\n // We don't want to break the installation if something goes wrong\n }\n}\n\n// Run the script\naddScriptsToPackageJson();\n"],"mappings":";;;AAOA,SAAS,cAAc,eAAe,kBAAkB;AACxD,SAAS,YAAY;AAErB,IAAM,mBAAmB;AAAA,EACvB,iBAAiB;AAAA,EACjB,qBAAqB;AAAA,EACrB,oBAAoB;AAAA,EACpB,mBAAmB;AACrB;AAEA,SAAS,kBAA2B;AAElC,QAAM,cAAc,QAAQ,IAAI;AAChC,SAAO,gBAAgB;AACzB;AAEA,SAAS,kBAAiC;AAKxC,MAAI,aAAa,QAAQ,IAAI;AAG7B,MAAI,WAAW,SAAS,cAAc,GAAG;AAGvC,UAAM,QAAQ,WAAW,MAAM,cAAc;AAC7C,QAAI,MAAM,SAAS,KAAK,MAAM,CAAC,GAAG;AAEhC,aAAO,MAAM,CAAC,EAAE,QAAQ,OAAO,EAAE;AAAA,IACnC;AAAA,EACF;AAIA,SAAO;AACT;AAEA,SAAS,0BAAgC;AACvC,MAAI;AAEF,QAAI,gBAAgB,GAAG;AACrB;AAAA,IACF;AAEA,UAAM,cAAc,gBAAgB;AACpC,QAAI,CAAC,aAAa;AAChB;AAAA,IACF;AAEA,UAAM,kBAAkB,KAAK,aAAa,cAAc;AAExD,QAAI,CAAC,WAAW,eAAe,GAAG;AAChC;AAAA,IACF;AAGA,UAAM,qBAAqB,aAAa,iBAAiB,OAAO;AAChE,UAAM,cAAc,KAAK,MAAM,kBAAkB;AAGjD,QAAI,CAAC,YAAY,SAAS;AACxB,kBAAY,UAAU,CAAC;AAAA,IACzB;AAGA,UAAM,qBAAqB,OAAO,KAAK,gBAAgB,EAAE;AAAA,MACvD,CAAC,eAAe,YAAY,QAAQ,UAAU;AAAA,IAChD;AAEA,QAAI,oBAAoB;AAEtB;AAAA,IACF;AAGA,QAAI,aAAa;AACjB,eAAW,CAAC,YAAY,aAAa,KAAK,OAAO;AAAA,MAC/C;AAAA,IACF,GAAG;AACD,UAAI,CAAC,YAAY,QAAQ,UAAU,GAAG;AACpC,oBAAY,QAAQ,UAAU,IAAI;AAClC;AAAA,MACF;AAAA,IACF;AAEA,QAAI,aAAa,GAAG;AAElB;AAAA,QACE;AAAA,QACA,KAAK,UAAU,aAAa,MAAM,CAAC,IAAI;AAAA,QACvC;AAAA,MACF;AAEA,cAAQ,IAAI,kDAA6C;AACzD,aAAO,KAAK,gBAAgB,EAAE,QAAQ,CAAC,eAAe;AACpD,gBAAQ,IAAI,OAAO,UAAU,EAAE;AAAA,MACjC,CAAC;AACD,cAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AAAA,EAGhB;AACF;AAGA,wBAAwB;","names":[]}
@@ -5,7 +5,7 @@ import {
5
5
  validateBranchName,
6
6
  validateCommitMessage,
7
7
  validatePRTitle
8
- } from "../chunk-X2NQJ2ZY.js";
8
+ } from "../chunk-NMHWD2GA.js";
9
9
  export {
10
10
  discoverCustomScopes,
11
11
  getAllScopes,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workflow-agent-cli",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "A self-evolving workflow management system for AI agent development",
5
5
  "keywords": [
6
6
  "workflow",
@@ -41,6 +41,19 @@
41
41
  "templates",
42
42
  "README.md"
43
43
  ],
44
+ "scripts": {
45
+ "build": "tsup",
46
+ "dev": "tsup --watch",
47
+ "test": "vitest run",
48
+ "test:watch": "vitest",
49
+ "test:coverage": "vitest run --coverage",
50
+ "test:unit": "vitest run --exclude 'src/**/*.e2e.test.ts'",
51
+ "test:e2e": "vitest run 'src/**/*.e2e.test.ts'",
52
+ "lint": "exit 0",
53
+ "typecheck": "tsc --noEmit",
54
+ "clean": "rm -rf dist",
55
+ "postinstall": "node dist/scripts/postinstall.js || true"
56
+ },
44
57
  "dependencies": {
45
58
  "@clack/prompts": "^0.7.0",
46
59
  "@hawkinside_out/workflow-improvement-tracker": "^1.0.0",
@@ -69,18 +82,5 @@
69
82
  },
70
83
  "publishConfig": {
71
84
  "access": "public"
72
- },
73
- "scripts": {
74
- "build": "tsup",
75
- "dev": "tsup --watch",
76
- "test": "vitest run",
77
- "test:watch": "vitest",
78
- "test:coverage": "vitest run --coverage",
79
- "test:unit": "vitest run --exclude 'src/**/*.e2e.test.ts'",
80
- "test:e2e": "vitest run 'src/**/*.e2e.test.ts'",
81
- "lint": "eslint src",
82
- "typecheck": "tsc --noEmit",
83
- "clean": "rm -rf dist",
84
- "postinstall": "node dist/scripts/postinstall.js || true"
85
85
  }
86
- }
86
+ }
@@ -144,6 +144,176 @@ Any decisions, blockers, or context for future reference.
144
144
 
145
145
  > ⚠️ **IMPORTANT**: Never push directly to `main`. Always push to your feature branch and create a PR.
146
146
 
147
+ ---
148
+
149
+ ## 🚨 MANDATORY PRE-COMMIT CHECKLIST - ZERO EXCEPTIONS
150
+
151
+ > **CRITICAL RULE**: This is a "one-and-done" service commitment. The following pre-commit checks are MANDATORY before ANY commit and push. There are ZERO EXCEPTIONS to this rule.
152
+
153
+ ### Auto-Setup Guarantee
154
+
155
+ **If ANY mandatory check tool is not configured** (missing config files, scripts, or dependencies), Agent MUST automatically set them up based on industry best practices BEFORE running checks.
156
+
157
+ 👉 **Complete auto-setup documentation**: [../../docs/AUTO_SETUP_TOOLS.md](../../docs/AUTO_SETUP_TOOLS.md)
158
+
159
+ ### The Rule
160
+
161
+ **Before EVERY commit and push, Agent MUST:**
162
+
163
+ 1. ✅ **Run all pre-commit checks** (listed below)
164
+ 2. 🔧 **Fix ALL errors encountered** automatically
165
+ 3. 🔄 **Re-run checks** until all pass
166
+ 4. ✅ **Only then commit and push**
167
+
168
+ ### Pre-Commit Execution Sequence
169
+
170
+ Execute these commands in this exact order. If ANY command fails, fix the errors and restart from step 1:
171
+
172
+ #### Step 1: Type Check
173
+
174
+ ```bash
175
+ pnpm typecheck
176
+ ```
177
+
178
+ **If errors occur:**
179
+
180
+ - Fix all TypeScript type errors
181
+ - Remove any `any` types
182
+ - Ensure proper type imports
183
+ - Re-run until clean
184
+
185
+ #### Step 2: Lint Check
186
+
187
+ ```bash
188
+ pnpm lint
189
+ ```
190
+
191
+ **If errors occur:**
192
+
193
+ - Fix all ESLint errors
194
+ - Address all warnings
195
+ - Ensure import ordering is correct
196
+ - Re-run until clean
197
+
198
+ #### Step 3: Format Check
199
+
200
+ ```bash
201
+ pnpm format
202
+ ```
203
+
204
+ **This command auto-fixes, then verify:**
205
+
206
+ - All files are properly formatted
207
+ - No formatting inconsistencies remain
208
+
209
+ #### Step 4: Unit Tests
210
+
211
+ ```bash
212
+ pnpm test
213
+ ```
214
+
215
+ **If tests fail:**
216
+
217
+ - Fix failing test logic
218
+ - Update test expectations if changes are intentional
219
+ - Add missing test coverage for new code
220
+ - Re-run until all tests pass
221
+
222
+ #### Step 5: Build Verification
223
+
224
+ ```bash
225
+ pnpm build
226
+ ```
227
+
228
+ **If build fails:**
229
+
230
+ - Fix compilation errors
231
+ - Resolve module resolution issues
232
+ - Ensure all imports are valid
233
+ - Re-run until build succeeds
234
+
235
+ ### Automated Pre-Commit Check Script
236
+
237
+ Agent should execute this comprehensive check:
238
+
239
+ ```bash
240
+ #!/bin/bash
241
+ # Pre-commit validation - ALL must pass
242
+
243
+ echo "🔍 Running pre-commit checks..."
244
+
245
+ echo "📘 Step 1/5: Type checking..."
246
+ pnpm typecheck || { echo "❌ Type check failed. Fix errors and retry."; exit 1; }
247
+
248
+ echo "🔍 Step 2/5: Linting..."
249
+ pnpm lint || { echo "❌ Lint check failed. Fix errors and retry."; exit 1; }
250
+
251
+ echo "✨ Step 3/5: Formatting..."
252
+ pnpm format || { echo "❌ Format check failed. Fix errors and retry."; exit 1; }
253
+
254
+ echo "🧪 Step 4/5: Unit tests..."
255
+ pnpm test || { echo "❌ Tests failed. Fix errors and retry."; exit 1; }
256
+
257
+ echo "🏗️ Step 5/5: Build verification..."
258
+ pnpm build || { echo "❌ Build failed. Fix errors and retry."; exit 1; }
259
+
260
+ echo "✅ All pre-commit checks passed! Ready to commit."
261
+ ```
262
+
263
+ ### Agent Workflow for Commits
264
+
265
+ When Agent is ready to commit, follow this EXACT workflow:
266
+
267
+ 1. **Stage changes**: `git add .`
268
+
269
+ 2. **Run pre-commit checks**: Execute all 5 steps above
270
+
271
+ 3. **If ANY check fails**:
272
+ - Analyze the error output
273
+ - Fix the errors in the codebase
274
+ - Commit the fixes
275
+ - Return to step 2 (re-run ALL checks)
276
+
277
+ 4. **When ALL checks pass**:
278
+ - Commit with proper message: `git commit -m "<type>(<scope>): <description>"`
279
+ - Push to branch: `git push origin <branch-name>`
280
+
281
+ 5. **Verification**: After push, confirm:
282
+ - GitHub Actions pipeline is triggered
283
+ - All CI checks are passing
284
+ - No pipeline failures
285
+
286
+ ### Error Handling Protocol
287
+
288
+ **When errors are encountered:**
289
+
290
+ | Error Type | Agent Action |
291
+ | ------------- | ------------------------------------------------------------ |
292
+ | Type errors | Analyze and fix type definitions, imports, and usage |
293
+ | Lint errors | Apply auto-fix where possible, manual fix for complex issues |
294
+ | Format errors | Re-run `pnpm format` (usually auto-fixes) |
295
+ | Test failures | Update test logic, fix implementation, or update snapshots |
296
+ | Build errors | Fix compilation issues, resolve imports, check dependencies |
297
+
298
+ **After fixing errors:**
299
+
300
+ - ✅ Commit the fixes separately if needed
301
+ - 🔄 Re-run the COMPLETE pre-commit checklist from step 1
302
+ - ⚠️ Never skip steps or assume fixes worked without verification
303
+
304
+ ### Accountability
305
+
306
+ This workflow ensures:
307
+
308
+ - ✅ **Zero regressions** reach the main branch
309
+ - ✅ **All code is production-ready** before merging
310
+ - ✅ **CI/CD pipelines always pass** (no surprises)
311
+ - ✅ **"One-and-done"** - customers receive working code, first time
312
+
313
+ > 🔒 **ENFORCEMENT**: This rule has ZERO EXCEPTIONS. Agent will not commit or push code that fails any of these checks. Period.
314
+
315
+ ---
316
+
147
317
  ### Auto-Cleanup Rules
148
318
 
149
319
  | Trigger | Action |
@@ -350,15 +520,15 @@ Every component story file MUST include:
350
520
  **Story Template:**
351
521
 
352
522
  ```tsx
353
- import type { Meta, StoryObj } from '@storybook/nextjs-vite';
354
- import { ComponentName } from './ui/component-name';
355
- import { mockFeatureFlags } from '@/lib/feature-flags';
523
+ import type { Meta, StoryObj } from "@storybook/nextjs-vite";
524
+ import { ComponentName } from "./ui/component-name";
525
+ import { mockFeatureFlags } from "@/lib/feature-flags";
356
526
 
357
527
  const meta: Meta<typeof ComponentName> = {
358
- title: 'Category/ComponentName',
528
+ title: "Category/ComponentName",
359
529
  component: ComponentName,
360
- tags: ['autodocs'],
361
- parameters: { layout: 'centered' },
530
+ tags: ["autodocs"],
531
+ parameters: { layout: "centered" },
362
532
  decorators: [
363
533
  (Story) => {
364
534
  mockFeatureFlags({ FEATURE_FLAG: true });
@@ -501,28 +671,28 @@ Imports MUST follow this exact order, with blank lines between groups:
501
671
 
502
672
  ```typescript
503
673
  // 1. Directive (MUST be first line if present)
504
- 'use server';
674
+ "use server";
505
675
  // OR
506
- 'use client';
676
+ "use client";
507
677
 
508
678
  // 2. React imports
509
- import React, { useState, useEffect, useCallback } from 'react';
679
+ import React, { useState, useEffect, useCallback } from "react";
510
680
 
511
681
  // 3. External library imports (alphabetical)
512
- import { useDrag } from 'react-dnd';
513
- import { QueryClient } from '@tanstack/react-query';
514
- import { z } from 'zod';
682
+ import { useDrag } from "react-dnd";
683
+ import { QueryClient } from "@tanstack/react-query";
684
+ import { z } from "zod";
515
685
 
516
686
  // 4. Internal absolute imports with @/ prefix (alphabetical by path)
517
- import { createServerClient } from '@/lib/supabase/server';
518
- import { verifyBoardAccess } from '@/utils/authorization.server';
519
- import type { Task, Sprint } from '@/types';
520
- import { useAuth } from '@/app/providers';
687
+ import { createServerClient } from "@/lib/supabase/server";
688
+ import { verifyBoardAccess } from "@/utils/authorization.server";
689
+ import type { Task, Sprint } from "@/types";
690
+ import { useAuth } from "@/app/providers";
521
691
 
522
692
  // 5. Relative imports (parent directories first, then siblings)
523
- import { Button } from '../ui/button';
524
- import { TaskCard } from './TaskCard';
525
- import type { LocalType } from './types';
693
+ import { Button } from "../ui/button";
694
+ import { TaskCard } from "./TaskCard";
695
+ import type { LocalType } from "./types";
526
696
  ```
527
697
 
528
698
  ### Naming Conventions
@@ -548,27 +718,31 @@ import type { LocalType } from './types';
548
718
 
549
719
  ```typescript
550
720
  export async function getEntity(
551
- id: string
721
+ id: string,
552
722
  ): Promise<{ data: Entity | null; error: string | null }> {
553
723
  try {
554
724
  // 1. Verify access FIRST
555
725
  const access = await verifyEntityAccess(id);
556
726
  if (!access.hasAccess) {
557
- return { data: null, error: access.error || 'Access denied' };
727
+ return { data: null, error: access.error || "Access denied" };
558
728
  }
559
729
 
560
730
  const supabase = await createServerClient();
561
- const { data, error } = await supabase.from('entities').select('*').eq('id', id).single();
731
+ const { data, error } = await supabase
732
+ .from("entities")
733
+ .select("*")
734
+ .eq("id", id)
735
+ .single();
562
736
 
563
737
  if (error) {
564
- console.error('Error fetching entity:', error);
738
+ console.error("Error fetching entity:", error);
565
739
  return { data: null, error: error.message };
566
740
  }
567
741
 
568
742
  return { data: transformEntity(data), error: null };
569
743
  } catch (err) {
570
- console.error('Unexpected error:', err);
571
- return { data: null, error: 'An unexpected error occurred' };
744
+ console.error("Unexpected error:", err);
745
+ return { data: null, error: "An unexpected error occurred" };
572
746
  }
573
747
  }
574
748
  ```
@@ -583,10 +757,10 @@ const handleSubmit = async () => {
583
757
  toast.error(error);
584
758
  return;
585
759
  }
586
- toast.success('Created successfully');
760
+ toast.success("Created successfully");
587
761
  onSuccess?.(data);
588
762
  } catch (err) {
589
- toast.error('An unexpected error occurred');
763
+ toast.error("An unexpected error occurred");
590
764
  }
591
765
  };
592
766
  ```
@@ -612,12 +786,12 @@ const handleSubmit = async () => {
612
786
  5. **Never expose sensitive data** - filter fields before returning
613
787
 
614
788
  ```typescript
615
- 'use server';
789
+ "use server";
616
790
 
617
- import { createServerClient } from '@/lib/supabase/server';
618
- import { verifyBoardAccess } from '@/utils/authorization.server';
619
- import { revalidatePath } from 'next/cache';
620
- import type { Task } from '@/types';
791
+ import { createServerClient } from "@/lib/supabase/server";
792
+ import { verifyBoardAccess } from "@/utils/authorization.server";
793
+ import { revalidatePath } from "next/cache";
794
+ import type { Task } from "@/types";
621
795
 
622
796
  interface TaskRow {
623
797
  id: string;
@@ -636,17 +810,20 @@ function transformTask(row: TaskRow): Task {
636
810
  }
637
811
 
638
812
  export async function getTasks(
639
- boardId: string
813
+ boardId: string,
640
814
  ): Promise<{ data: Task[] | null; error: string | null }> {
641
815
  // 1. Authorization FIRST
642
816
  const access = await verifyBoardAccess(boardId);
643
817
  if (!access.hasAccess) {
644
- return { data: null, error: access.error || 'Access denied' };
818
+ return { data: null, error: access.error || "Access denied" };
645
819
  }
646
820
 
647
821
  // 2. Fetch data
648
822
  const supabase = await createServerClient();
649
- const { data, error } = await supabase.from('tasks').select('*').eq('board_id', boardId);
823
+ const { data, error } = await supabase
824
+ .from("tasks")
825
+ .select("*")
826
+ .eq("board_id", boardId);
650
827
 
651
828
  if (error) {
652
829
  return { data: null, error: error.message };
@@ -717,12 +894,15 @@ export function TaskCard({ task, onEdit, readOnly = false }: TaskCardProps) {
717
894
 
718
895
  ```typescript
719
896
  // Server action
720
- import { verifyBoardAccess, requireContributorAccess } from '@/utils/authorization.server';
897
+ import {
898
+ verifyBoardAccess,
899
+ requireContributorAccess,
900
+ } from "@/utils/authorization.server";
721
901
 
722
902
  export async function createTask(boardId: string, data: CreateTaskData) {
723
903
  const boardAccess = await verifyBoardAccess(boardId);
724
904
  if (!boardAccess.hasAccess) {
725
- return { data: null, error: 'Access denied' };
905
+ return { data: null, error: "Access denied" };
726
906
  }
727
907
 
728
908
  // For write operations, also check role
@@ -853,16 +1033,23 @@ When creating a PR, use Agent to automatically fill out the PR description:
853
1033
 
854
1034
  Before creating a PR, Agent must verify:
855
1035
 
1036
+ - [ ] **🚨 MANDATORY PRE-COMMIT CHECKLIST completed** - See section above (ZERO EXCEPTIONS)
1037
+ - [ ] ✅ Type check passed (`pnpm typecheck`)
1038
+ - [ ] ✅ Lint check passed (`pnpm lint`)
1039
+ - [ ] ✅ Format check passed (`pnpm format`)
1040
+ - [ ] ✅ Unit tests passed (`pnpm test`)
1041
+ - [ ] ✅ Build verification passed (`pnpm build`)
856
1042
  - [ ] All required files for the change type have been touched
857
1043
  - [ ] No `any` types introduced
858
1044
  - [ ] Authorization added for new data access
859
1045
  - [ ] Types updated in `types/index.ts`
860
- - [ ] Unit tests added/updated and passing (`pnpm test`)
861
- - [ ] E2E tests pass for affected flows (`pnpm test:e2e`)
1046
+ - [ ] E2E tests pass for affected flows (`pnpm test:e2e`) if applicable
862
1047
  - [ ] No unapproved new libraries added
863
1048
  - [ ] Import order follows the standard
864
1049
  - [ ] `data-testid` attributes added for testable elements
865
1050
 
1051
+ > ⚠️ **NOTE**: The mandatory pre-commit checklist MUST be completed before even considering a PR. If any pre-commit check fails, the code is not ready for PR.
1052
+
866
1053
  ---
867
1054
 
868
1055
  ## Quick Reference: Path Aliases
@@ -269,11 +269,12 @@ import {
269
269
  FormDialogSection,
270
270
  FormDialogField,
271
271
  useFormDialog,
272
- } from '@/components/FormDialog';
272
+ } from "@/components/FormDialog";
273
273
 
274
274
  function CreateSprintDialog() {
275
- const { isOpen, isSubmitting, setIsSubmitting, open, close } = useFormDialog();
276
- const [name, setName] = useState('');
275
+ const { isOpen, isSubmitting, setIsSubmitting, open, close } =
276
+ useFormDialog();
277
+ const [name, setName] = useState("");
277
278
 
278
279
  const handleSubmit = async (e: React.FormEvent) => {
279
280
  e.preventDefault();
@@ -359,8 +360,13 @@ Use sections to group related fields:
359
360
  Use `FormDialogField` error prop for validation:
360
361
 
361
362
  ```tsx
362
- <FormDialogField label="Email" required error={errors.email?.message} htmlFor="email">
363
- <Input id="email" {...register('email')} />
363
+ <FormDialogField
364
+ label="Email"
365
+ required
366
+ error={errors.email?.message}
367
+ htmlFor="email"
368
+ >
369
+ <Input id="email" {...register("email")} />
364
370
  </FormDialogField>
365
371
  ```
366
372
 
@@ -418,14 +424,14 @@ components/
418
424
  #### Behavioral Tests
419
425
 
420
426
  ```typescript
421
- describe('StatusBadge', () => {
422
- it('should render without crashing', () => {});
423
- it('should render all status variants', () => {});
424
- it('should apply correct colors for each status', () => {});
425
- it('should respect size prop', () => {});
426
- it('should apply custom className', () => {});
427
- it('should handle feature flag disabled state', () => {});
428
- it('should handle feature flag enabled state', () => {});
427
+ describe("StatusBadge", () => {
428
+ it("should render without crashing", () => {});
429
+ it("should render all status variants", () => {});
430
+ it("should apply correct colors for each status", () => {});
431
+ it("should respect size prop", () => {});
432
+ it("should apply custom className", () => {});
433
+ it("should handle feature flag disabled state", () => {});
434
+ it("should handle feature flag enabled state", () => {});
429
435
  });
430
436
  ```
431
437
 
@@ -510,19 +516,19 @@ function TaskRow({ task }) {
510
516
  ### Testing with Flags
511
517
 
512
518
  ```typescript
513
- import { mockFeatureFlag, clearFeatureFlagMocks } from '@/lib/feature-flags';
519
+ import { mockFeatureFlag, clearFeatureFlagMocks } from "@/lib/feature-flags";
514
520
 
515
- describe('Component with feature flag', () => {
521
+ describe("Component with feature flag", () => {
516
522
  afterEach(() => {
517
523
  clearFeatureFlagMocks();
518
524
  });
519
525
 
520
- it('should render new component when flag enabled', () => {
526
+ it("should render new component when flag enabled", () => {
521
527
  mockFeatureFlag(FeatureFlag.STATUS_BADGE, true);
522
528
  // test new behavior
523
529
  });
524
530
 
525
- it('should render fallback when flag disabled', () => {
531
+ it("should render fallback when flag disabled", () => {
526
532
  mockFeatureFlag(FeatureFlag.STATUS_BADGE, false);
527
533
  // test fallback behavior
528
534
  });
@@ -137,11 +137,11 @@ describe('{{presetName}} Scope Preset', () => {
137
137
  ## tsup.config.ts Template
138
138
 
139
139
  ```typescript
140
- import { defineConfig } from 'tsup';
140
+ import { defineConfig } from "tsup";
141
141
 
142
142
  export default defineConfig({
143
- entry: ['src/index.ts'],
144
- format: ['esm'],
143
+ entry: ["src/index.ts"],
144
+ format: ["esm"],
145
145
  dts: true,
146
146
  clean: true,
147
147
  sourcemap: true,
@@ -153,6 +153,7 @@ export default defineConfig({
153
153
  To create a custom scope package using these templates:
154
154
 
155
155
  1. **Use the CLI** (recommended):
156
+
156
157
  ```bash
157
158
  workflow scope:create
158
159
  ```
@@ -180,7 +181,7 @@ Each scope in `{{scopeDefinitions}}` must match:
180
181
  name: string; // lowercase, alphanumeric, hyphens, max 32 chars
181
182
  description: string; // min 10 characters
182
183
  emoji?: string; // optional emoji
183
- category?: 'auth' | 'features' | 'infrastructure' | 'documentation' |
184
+ category?: 'auth' | 'features' | 'infrastructure' | 'documentation' |
184
185
  'testing' | 'performance' | 'other';
185
186
  }
186
187
  ```