farmwork 1.0.0 โ†’ 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/init.js CHANGED
@@ -1,15 +1,12 @@
1
1
  import inquirer from "inquirer";
2
- import chalk from "chalk";
3
- import ora from "ora";
4
2
  import fs from "fs-extra";
5
3
  import path from "path";
6
4
  import { fileURLToPath } from "url";
5
+ import { farmTerm, emojis } from "./terminal.js";
7
6
 
8
7
  const __filename = fileURLToPath(import.meta.url);
9
8
  const __dirname = path.dirname(__filename);
10
- const TEMPLATES_DIR = path.join(__dirname, "..", "templates");
11
9
 
12
- // Try to detect package.json info
13
10
  function detectPackageJson() {
14
11
  try {
15
12
  const pkgPath = path.join(process.cwd(), "package.json");
@@ -32,19 +29,19 @@ const QUESTIONS = [
32
29
  {
33
30
  type: "input",
34
31
  name: "projectName",
35
- message: "Project name:",
32
+ message: "๐ŸŒฑ Project name:",
36
33
  default: path.basename(process.cwd()),
37
34
  },
38
35
  {
39
36
  type: "list",
40
37
  name: "packageManager",
41
- message: "Package manager:",
38
+ message: "๐Ÿงบ Package manager:",
42
39
  choices: ["npm", "yarn", "pnpm", "bun"],
43
40
  },
44
41
  {
45
42
  type: "input",
46
43
  name: "testCommand",
47
- message: "Test command:",
44
+ message: "๐Ÿฅ’ Test command:",
48
45
  default: (answers) => {
49
46
  const { scripts } = detectPackageJson();
50
47
  const pm = answers.packageManager;
@@ -56,7 +53,7 @@ const QUESTIONS = [
56
53
  {
57
54
  type: "input",
58
55
  name: "buildCommand",
59
- message: "Build command:",
56
+ message: "๐ŸŒฝ Build command:",
60
57
  default: (answers) => {
61
58
  const { scripts } = detectPackageJson();
62
59
  const pm = answers.packageManager;
@@ -67,7 +64,7 @@ const QUESTIONS = [
67
64
  {
68
65
  type: "input",
69
66
  name: "lintCommand",
70
- message: "Lint command:",
67
+ message: "๐Ÿฆ‰ Lint command:",
71
68
  default: (answers) => {
72
69
  const { scripts } = detectPackageJson();
73
70
  const pm = answers.packageManager;
@@ -78,13 +75,13 @@ const QUESTIONS = [
78
75
  {
79
76
  type: "confirm",
80
77
  name: "includeStorybook",
81
- message: "Include Storybook support? (React/Vue component docs)",
78
+ message: "๐Ÿ„ Include Storybook support?",
82
79
  default: () => detectPackageJson().hasStorybook,
83
80
  },
84
81
  {
85
82
  type: "confirm",
86
83
  name: "includeI18n",
87
- message: "Include i18n support? (multi-language translations)",
84
+ message: "๐ŸŒป Include i18n support?",
88
85
  default: false,
89
86
  },
90
87
  ];
@@ -93,27 +90,27 @@ const STORYBOOK_QUESTIONS = [
93
90
  {
94
91
  type: "input",
95
92
  name: "storybookUrl",
96
- message: "Storybook URL (e.g., storybook.yoursite.com):",
93
+ message: "๐ŸŒฟ Storybook URL:",
97
94
  default: "storybook.example.com",
98
95
  },
99
96
  {
100
97
  type: "input",
101
98
  name: "netlifyAuthToken",
102
- message: "Netlify Auth Token (from netlify.com/user/applications):",
99
+ message: "๐Ÿ—๏ธ Netlify Auth Token:",
103
100
  validate: (input) =>
104
101
  input.length > 0 || "Auth token is required for deployment",
105
102
  },
106
103
  {
107
104
  type: "input",
108
105
  name: "netlifySiteId",
109
- message: "Netlify Site ID (from site settings):",
106
+ message: "๐Ÿท๏ธ Netlify Site ID:",
110
107
  validate: (input) =>
111
108
  input.length > 0 || "Site ID is required for deployment",
112
109
  },
113
110
  {
114
111
  type: "confirm",
115
112
  name: "passwordProtect",
116
- message: "Password protect Storybook? (Recommended for private components)",
113
+ message: "๐Ÿ• Password protect Storybook?",
117
114
  default: true,
118
115
  },
119
116
  ];
@@ -121,38 +118,99 @@ const STORYBOOK_QUESTIONS = [
121
118
  export async function init(options) {
122
119
  const cwd = process.cwd();
123
120
 
124
- console.log(chalk.cyan("\n๐ŸŒฝ Farmwork Initialization\n"));
121
+ // Show animated logo
122
+ await farmTerm.logoAnimated();
123
+
124
+ // Check if farmwork is already installed
125
+ const claudeDir = path.join(cwd, ".claude");
126
+ const farmworkConfig = path.join(cwd, ".farmwork.json");
127
+ const claudeMd = path.join(cwd, "CLAUDE.md");
128
+
129
+ const isAlreadyInstalled =
130
+ fs.existsSync(claudeDir) &&
131
+ (fs.existsSync(farmworkConfig) || fs.existsSync(claudeMd));
132
+
133
+ if (isAlreadyInstalled && !options.force) {
134
+ farmTerm.warn("Farmwork is already installed in this project!");
135
+ farmTerm.nl();
136
+
137
+ // Show what's detected
138
+ farmTerm.gray(" Detected:\n");
139
+ if (fs.existsSync(claudeDir)) farmTerm.gray(" โ€ข .claude/ directory\n");
140
+ if (fs.existsSync(claudeMd)) farmTerm.gray(" โ€ข CLAUDE.md\n");
141
+ if (fs.existsSync(farmworkConfig)) farmTerm.gray(" โ€ข .farmwork.json\n");
142
+ farmTerm.nl();
143
+
144
+ const { continueInit } = await inquirer.prompt([
145
+ {
146
+ type: "list",
147
+ name: "continueInit",
148
+ message: "What would you like to do?",
149
+ choices: [
150
+ {
151
+ name: "๐Ÿด Re-initialize (will backup existing files)",
152
+ value: "reinit",
153
+ },
154
+ { name: "๐Ÿฎ Run doctor instead (check health)", value: "doctor" },
155
+ { name: "๐ŸŒพ Run status instead (view metrics)", value: "status" },
156
+ { name: "๐Ÿ” Exit", value: "exit" },
157
+ ],
158
+ },
159
+ ]);
160
+
161
+ if (continueInit === "exit") {
162
+ farmTerm.info("No changes made. Your farm is safe! ๐ŸŒพ\n");
163
+ return;
164
+ }
165
+
166
+ if (continueInit === "doctor") {
167
+ farmTerm.nl();
168
+ const { doctor } = await import("./doctor.js");
169
+ await doctor();
170
+ return;
171
+ }
172
+
173
+ if (continueInit === "status") {
174
+ farmTerm.nl();
175
+ const { status } = await import("./status.js");
176
+ await status();
177
+ return;
178
+ }
179
+
180
+ // continueInit === "reinit" - proceed with force
181
+ options.force = true;
182
+ farmTerm.nl();
183
+ }
184
+
185
+ farmTerm.header("FARMWORK INITIALIZATION", "primary");
186
+ farmTerm.info(
187
+ "Let's set up your farm! Answer a few questions to get started.\n",
188
+ );
125
189
 
126
190
  const answers = await inquirer.prompt(QUESTIONS);
127
191
 
128
- // Ask Storybook deployment questions if Storybook is enabled
192
+ // Storybook configuration
129
193
  if (answers.includeStorybook) {
130
- console.log(chalk.cyan("\n๐Ÿ‡ Storybook Deployment Configuration\n"));
131
- console.log(
132
- chalk.gray(
133
- "We recommend deploying Storybook to Netlify with password protection.",
134
- ),
194
+ farmTerm.nl();
195
+ farmTerm.section("Storybook Deployment", "๐Ÿ„");
196
+ farmTerm.gray(
197
+ " We recommend deploying Storybook to Netlify with password protection.\n",
135
198
  );
136
- console.log(
137
- chalk.gray(
138
- "This keeps your component documentation private while accessible to your team.\n",
139
- ),
199
+ farmTerm.gray(
200
+ " This keeps your component docs private but accessible to your team.\n\n",
140
201
  );
141
202
 
142
203
  const storybookAnswers = await inquirer.prompt(STORYBOOK_QUESTIONS);
143
204
  Object.assign(answers, storybookAnswers);
144
205
 
145
206
  if (answers.passwordProtect) {
146
- console.log(
147
- chalk.yellow("\n๐Ÿ‹ Remember to enable password protection in Netlify:"),
148
- );
149
- console.log(
150
- chalk.gray(" Site settings โ†’ Access control โ†’ Password protection"),
151
- );
207
+ farmTerm.nl();
208
+ farmTerm.warn("Remember to enable password protection in Netlify:");
209
+ farmTerm.gray(" Site settings โ†’ Access control โ†’ Password protection\n");
152
210
  }
153
211
  }
154
212
 
155
- // Check for existing files that would be overwritten
213
+ // Check for existing files
156
214
  const existingFiles = [];
157
215
  const filesToCheck = [
158
216
  {
@@ -170,11 +228,6 @@ export async function init(options) {
170
228
  name: ".farmwork.json",
171
229
  backup: null,
172
230
  },
173
- {
174
- path: path.join(cwd, ".claude", "settings.json"),
175
- name: ".claude/settings.json",
176
- backup: ".claude/OLD_settings.json",
177
- },
178
231
  {
179
232
  path: path.join(cwd, ".claude", "commands"),
180
233
  name: ".claude/commands/",
@@ -204,17 +257,23 @@ export async function init(options) {
204
257
  let didBackupClaudeMd = false;
205
258
 
206
259
  if (existingFiles.length > 0 && !options.force) {
207
- console.log(chalk.yellow("\n๐Ÿ‹ The following files/folders already exist:"));
260
+ farmTerm.nl();
261
+ farmTerm.warn("The following files/folders already exist:");
262
+ farmTerm.nl();
263
+
208
264
  for (const file of existingFiles) {
209
265
  if (file.isDir) {
210
- console.log(chalk.gray(` - ${file.name}`) + chalk.dim(" (will add new files)"));
266
+ farmTerm.gray(` ${file.name}`);
267
+ farmTerm.cyan(" (will add new files)\n");
211
268
  } else if (file.backup) {
212
- console.log(chalk.gray(` - ${file.name}`) + chalk.dim(` (will backup to ${file.backup})`));
269
+ farmTerm.gray(` ${file.name}`);
270
+ farmTerm.yellow(` โ†’ ${file.backup}\n`);
213
271
  } else {
214
- console.log(chalk.gray(` - ${file.name}`) + chalk.dim(" (will overwrite)"));
272
+ farmTerm.gray(` ${file.name}`);
273
+ farmTerm.red(" (will overwrite)\n");
215
274
  }
216
275
  }
217
- console.log("");
276
+ farmTerm.nl();
218
277
 
219
278
  const { overwriteChoice } = await inquirer.prompt([
220
279
  {
@@ -223,290 +282,223 @@ export async function init(options) {
223
282
  message: "How would you like to proceed?",
224
283
  choices: [
225
284
  {
226
- name: "Continue (backup files, add to existing folders)",
285
+ name: "๐ŸŒฑ Continue (backup files, add to existing folders)",
227
286
  value: "overwrite",
228
287
  },
229
- { name: "Cancel installation", value: "cancel" },
288
+ { name: "๐Ÿ” Cancel installation", value: "cancel" },
230
289
  ],
231
290
  },
232
291
  ]);
233
292
 
234
293
  if (overwriteChoice === "cancel") {
235
- console.log(chalk.gray("\nInstallation cancelled."));
294
+ farmTerm.nl();
295
+ farmTerm.gray(" Installation cancelled.\n\n");
236
296
  process.exit(0);
237
297
  }
238
298
 
239
- // Backup files that have backup paths
240
- console.log("");
299
+ // Backup files
300
+ farmTerm.nl();
241
301
  for (const file of existingFiles) {
242
302
  if (file.backup) {
243
303
  const backupPath = path.join(cwd, file.backup);
244
304
  await fs.copy(file.path, backupPath);
245
- console.log(chalk.gray(` Backed up ${file.name} โ†’ ${file.backup}`));
305
+ farmTerm.status(`Backed up ${file.name} โ†’ ${file.backup}`, "pass");
246
306
  if (file.name === "CLAUDE.md") {
247
307
  didBackupClaudeMd = true;
248
308
  }
249
309
  }
250
310
  }
251
- console.log("");
252
311
  }
253
312
 
254
- // Store for use in final output
255
313
  answers._didBackupClaudeMd = didBackupClaudeMd;
256
314
 
257
- const spinner = ora("Creating Farmwork structure...").start();
315
+ // Planting animation
316
+ farmTerm.nl();
317
+ farmTerm.section("Planting Your Farm", emojis.seedling);
258
318
 
259
319
  try {
260
- // Create folder structure
261
- await fs.ensureDir(path.join(cwd, "_AUDIT"));
262
- await fs.ensureDir(path.join(cwd, "_PLANS"));
263
- await fs.ensureDir(path.join(cwd, ".claude", "commands"));
264
- await fs.ensureDir(path.join(cwd, ".claude", "agents"));
265
-
266
- spinner.text = "Creating CLAUDE.md...";
267
- await createClaudeMd(cwd, answers);
268
-
269
- spinner.text = "Creating FARMHOUSE.md...";
270
- await createFarmhouseMd(cwd, answers);
271
-
272
- spinner.text = "Creating audit documents...";
273
- await createAuditDocs(cwd, answers);
274
-
275
- spinner.text = "Creating justfile...";
276
- await createJustfile(cwd, answers);
277
-
278
- spinner.text = "Creating core agents...";
279
- await createAgents(cwd, answers);
280
-
281
- spinner.text = "Creating core commands...";
282
- await createCommands(cwd, answers);
320
+ // Create folder structure with animations
321
+ const steps = [
322
+ {
323
+ name: "Creating directories",
324
+ fn: async () => {
325
+ await fs.ensureDir(path.join(cwd, "_AUDIT"));
326
+ await fs.ensureDir(path.join(cwd, "_PLANS"));
327
+ await fs.ensureDir(path.join(cwd, ".claude", "commands"));
328
+ await fs.ensureDir(path.join(cwd, ".claude", "agents"));
329
+ },
330
+ },
331
+ { name: "Planting CLAUDE.md", fn: () => createClaudeMd(cwd, answers) },
332
+ {
333
+ name: "Building FARMHOUSE.md",
334
+ fn: () => createFarmhouseMd(cwd, answers),
335
+ },
336
+ {
337
+ name: "Creating audit documents",
338
+ fn: () => createAuditDocs(cwd, answers),
339
+ },
340
+ { name: "Laying out justfile", fn: () => createJustfile(cwd, answers) },
341
+ { name: "Training agents", fn: () => createAgents(cwd, answers) },
342
+ { name: "Setting up commands", fn: () => createCommands(cwd, answers) },
343
+ { name: "Configuring settings", fn: () => createSettings(cwd, answers) },
344
+ {
345
+ name: "Writing .farmwork.json",
346
+ fn: () => createProduceConfig(cwd, answers),
347
+ },
348
+ ];
283
349
 
284
- spinner.text = "Creating settings...";
285
- await createSettings(cwd, answers);
350
+ for (const step of steps) {
351
+ await farmTerm.spin(step.name, step.fn);
352
+ }
286
353
 
287
- spinner.text = "Creating .farmwork.json...";
288
- await createProduceConfig(cwd, answers);
354
+ // Install dependencies
355
+ farmTerm.nl();
356
+ farmTerm.section("Installing Tools", emojis.horse);
289
357
 
290
- // Check and install just if needed
291
- spinner.text = "Checking for just command runner...";
292
- try {
358
+ // Check and install just
359
+ await farmTerm.spin("Checking for just command runner", async () => {
293
360
  const { execSync } = await import("child_process");
294
361
  try {
295
362
  execSync("which just", { stdio: "ignore" });
296
363
  } catch {
297
- spinner.text = "Installing just...";
298
364
  try {
299
- // Try brew first (macOS), then cargo
300
365
  try {
301
- execSync("brew install just", { stdio: "inherit" });
302
- console.log(
303
- chalk.green("\n๐ŸŒฑ Just installed successfully via Homebrew"),
304
- );
366
+ execSync("brew install just", { stdio: "pipe" });
305
367
  } catch {
306
- execSync("cargo install just", { stdio: "inherit" });
307
- console.log(
308
- chalk.green("\n๐ŸŒฑ Just installed successfully via Cargo"),
309
- );
368
+ execSync("cargo install just", { stdio: "pipe" });
310
369
  }
311
370
  } catch {
312
- console.log(
313
- chalk.yellow("\n๐Ÿ‹ Could not install just automatically."),
314
- );
315
- console.log(chalk.gray(" Install manually: brew install just"));
316
- console.log(chalk.gray(" Or see: https://github.com/casey/just"));
371
+ farmTerm.warn("Could not install just automatically.");
372
+ farmTerm.gray(" Install manually: brew install just\n");
317
373
  }
318
374
  }
319
- } catch (e) {
320
- // Silently continue if check fails
321
- }
375
+ });
322
376
 
323
- spinner.text = "Setting up beads issue tracking...";
324
- try {
377
+ // Check and install beads
378
+ await farmTerm.spin("Setting up beads issue tracking", async () => {
325
379
  const { execSync } = await import("child_process");
326
-
327
- // Check if bd is installed
328
380
  try {
329
381
  execSync("which bd", { stdio: "ignore" });
330
382
  } catch {
331
- // bd not found, try to install it (npm first, then brew, then cargo)
332
- spinner.text = "Installing beads (bd)...";
333
383
  let installed = false;
334
-
335
- // Try npm first (most common)
336
384
  try {
337
- execSync("npm install -g @beads/bd", { stdio: "inherit" });
338
- console.log(chalk.green("\n๐ŸŒฑ Beads installed successfully via npm"));
385
+ execSync("npm install -g @beads/bd", { stdio: "pipe" });
339
386
  installed = true;
340
387
  } catch {
341
- // Try homebrew
342
388
  try {
343
- execSync("brew install steveyegge/beads/bd", { stdio: "inherit" });
344
- console.log(
345
- chalk.green("\n๐ŸŒฑ Beads installed successfully via Homebrew"),
346
- );
389
+ execSync("brew install steveyegge/beads/bd", { stdio: "pipe" });
347
390
  installed = true;
348
391
  } catch {
349
- // Try cargo as last resort
350
392
  try {
351
- execSync("cargo install beads", { stdio: "inherit" });
352
- console.log(
353
- chalk.green("\n๐ŸŒฑ Beads installed successfully via Cargo"),
354
- );
393
+ execSync("cargo install beads", { stdio: "pipe" });
355
394
  installed = true;
356
395
  } catch {
357
396
  // All methods failed
358
397
  }
359
398
  }
360
399
  }
361
-
362
400
  if (!installed) {
363
- console.log(
364
- chalk.yellow("\n๐Ÿ‹ Could not install beads automatically."),
365
- );
366
- console.log(
367
- chalk.gray(" Install manually: npm install -g @beads/bd"),
368
- );
369
- console.log(chalk.gray(" Or: brew install steveyegge/beads/bd"));
370
- console.log(
371
- chalk.gray(" Or see: https://github.com/steveyegge/beads"),
372
- );
401
+ farmTerm.warn("Could not install beads automatically.");
402
+ farmTerm.gray(" Install manually: npm install -g @beads/bd\n");
373
403
  }
374
404
  }
375
405
 
376
- // Initialize beads in the project
377
- spinner.text = "Initializing beads...";
406
+ // Initialize beads
378
407
  try {
379
408
  execSync("bd init", { cwd, stdio: "ignore" });
380
409
  } catch {
381
- // bd init might fail if already initialized or not installed
410
+ // bd init might fail if already initialized
382
411
  }
383
412
 
384
- // Clean up beads-generated agent files (we use CLAUDE.md instead)
385
- spinner.text = "Cleaning up beads defaults...";
413
+ // Clean up beads-generated files
386
414
  const beadsAgentFiles = ["AGENTS.md", "@AGENTS.md"];
387
415
  for (const file of beadsAgentFiles) {
388
- const filePath = path.join(cwd, file);
389
416
  try {
390
- await fs.remove(filePath);
417
+ await fs.remove(path.join(cwd, file));
391
418
  } catch {
392
- // File doesn't exist, ignore
419
+ // File doesn't exist
393
420
  }
394
421
  }
395
- } catch (e) {
396
- console.log(
397
- chalk.yellow(
398
- "\n๐Ÿ‹ Could not set up beads. Install with: cargo install beads",
399
- ),
400
- );
401
- }
402
-
403
- spinner.succeed(chalk.green("Farmwork initialized!"));
404
-
405
- console.log(chalk.cyan("\n๐ŸŒฑ Created structure:"));
406
- console.log(` ${chalk.green("๐ŸŒฑ")} _AUDIT/`);
407
- console.log(` ${chalk.green("๐ŸŒฑ")} _PLANS/`);
408
- console.log(` ${chalk.green("๐ŸŒฑ")} .claude/commands/`);
409
- console.log(` ${chalk.green("๐ŸŒฑ")} .claude/agents/`);
410
- console.log(` ${chalk.green("๐ŸŒฑ")} CLAUDE.md`);
411
- console.log(` ${chalk.green("๐ŸŒฑ")} justfile`);
412
- console.log(` ${chalk.green("๐ŸŒฑ")} .farmwork.json`);
413
-
414
- console.log(chalk.cyan("\n๐Ÿฅ• Next steps:"));
415
- console.log(
416
- ` 1. Run ${chalk.yellow("just --list")} to see available commands`,
417
- );
418
- console.log(
419
- ` 2. Say ${chalk.yellow('"till the land"')} to Claude to audit your setup`,
420
- );
421
- console.log(
422
- ` 3. Say ${chalk.yellow('"make a plan for <feature>"')} to start planning`,
422
+ });
423
+
424
+ // Success!
425
+ farmTerm.nl();
426
+ farmTerm.divider("โ•", 50);
427
+ farmTerm.success("Farmwork initialized successfully!");
428
+
429
+ // Show created structure
430
+ farmTerm.section("Created Structure", emojis.corn);
431
+ await farmTerm.planting(
432
+ [
433
+ "_AUDIT/",
434
+ "_PLANS/",
435
+ ".claude/commands/",
436
+ ".claude/agents/",
437
+ "CLAUDE.md",
438
+ "justfile",
439
+ ".farmwork.json",
440
+ ],
441
+ "Files planted",
423
442
  );
424
443
 
425
- console.log(chalk.cyan("\n๐ŸŒพ Now let Claude Code get comfortable!"));
426
- console.log(chalk.gray(" Copy and paste this prompt to Claude Code:\n"));
427
- console.log(
428
- chalk.white(
429
- " โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”",
430
- ),
431
- );
432
- console.log(
433
- chalk.white(" โ”‚") +
434
- chalk.yellow(
435
- " Hey Claude, I am using the Farmwork framework, please go through the ",
436
- ) +
437
- chalk.white("โ”‚"),
438
- );
439
- console.log(
440
- chalk.white(" โ”‚") +
441
- chalk.yellow(
442
- " justfile and create project-specific commands, and go through my app ",
443
- ) +
444
- chalk.white("โ”‚"),
445
- );
446
- console.log(
447
- chalk.white(" โ”‚") +
448
- chalk.yellow(
449
- " and suggest any project-specific subagents that would work well. ",
450
- ) +
451
- chalk.white("โ”‚"),
452
- );
453
- console.log(
454
- chalk.white(
455
- " โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜",
456
- ),
444
+ // Next steps
445
+ farmTerm.section("Next Steps", emojis.carrot);
446
+ farmTerm.nl();
447
+ farmTerm.white(" 1. ");
448
+ farmTerm.yellow("just --list");
449
+ farmTerm.gray(" โ†’ See available commands\n");
450
+ farmTerm.white(" 2. ");
451
+ farmTerm.yellow('"open the farm"');
452
+ farmTerm.gray(" โ†’ Audit your setup\n");
453
+ farmTerm.white(" 3. ");
454
+ farmTerm.yellow('"make a plan for <feature>"');
455
+ farmTerm.gray(" โ†’ Start planning\n");
456
+
457
+ // Claude prompt box
458
+ farmTerm.nl();
459
+ farmTerm.section("Get Claude Comfortable", emojis.wheat);
460
+ farmTerm.gray(" Copy and paste this prompt to Claude Code:\n\n");
461
+
462
+ farmTerm.box(
463
+ "Prompt for Claude",
464
+ [
465
+ "Hey Claude, I am using the Farmwork framework,",
466
+ "please go through the justfile and create",
467
+ "project-specific commands, and go through my",
468
+ "app and suggest project-specific subagents",
469
+ "that would work well.",
470
+ ],
471
+ "secondary",
457
472
  );
458
473
 
459
474
  // Show merge prompt if we backed up CLAUDE.md
460
475
  if (answers._didBackupClaudeMd) {
461
- console.log(chalk.cyan("\n๐Ÿฅฌ Merge your old instructions!"));
462
- console.log(
463
- chalk.gray(
464
- " Your old CLAUDE.md was backed up. Use this prompt to merge:\n",
465
- ),
466
- );
467
- console.log(
468
- chalk.white(
469
- " โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”",
470
- ),
471
- );
472
- console.log(
473
- chalk.white(" โ”‚") +
474
- chalk.yellow(
475
- " Hey Claude, look at my CLAUDE.md file and merge the project-specific ",
476
- ) +
477
- chalk.white("โ”‚"),
476
+ farmTerm.nl();
477
+ farmTerm.section("Merge Your Old Instructions", "๐Ÿฅฌ");
478
+ farmTerm.gray(
479
+ " Your old CLAUDE.md was backed up. Use this prompt to merge:\n\n",
478
480
  );
479
- console.log(
480
- chalk.white(" โ”‚") +
481
- chalk.yellow(
482
- " instructions from OLD_CLAUDE.md into it, so I have one file with all ",
483
- ) +
484
- chalk.white("โ”‚"),
485
- );
486
- console.log(
487
- chalk.white(" โ”‚") +
488
- chalk.yellow(
489
- " the Farmwork framework instructions plus my original project setup. ",
490
- ) +
491
- chalk.white("โ”‚"),
492
- );
493
- console.log(
494
- chalk.white(" โ”‚") +
495
- chalk.yellow(
496
- " Then delete OLD_CLAUDE.md when done. Same for OLD_justfile. Thank you. ",
497
- ) +
498
- chalk.white("โ”‚"),
499
- );
500
- console.log(
501
- chalk.white(
502
- " โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜",
503
- ),
481
+
482
+ farmTerm.box(
483
+ "Merge Prompt",
484
+ [
485
+ "Hey Claude, look at my CLAUDE.md file and",
486
+ "merge the project-specific instructions from",
487
+ "OLD_CLAUDE.md into it, so I have one file",
488
+ "with all the Farmwork instructions plus my",
489
+ "original project setup. Then delete the OLD",
490
+ "files when done.",
491
+ ],
492
+ "accent",
504
493
  );
505
494
  }
506
495
 
507
- console.log("");
496
+ // Final tractor drive
497
+ farmTerm.nl();
498
+ await farmTerm.tractorAnimation("Your farm is ready!", 1500);
499
+ farmTerm.nl();
508
500
  } catch (error) {
509
- spinner.fail(chalk.red("Failed to initialize Farmwork"));
501
+ farmTerm.error("Failed to initialize Farmwork");
510
502
  console.error(error);
511
503
  process.exit(1);
512
504
  }
@@ -548,11 +540,10 @@ Run these in order for a complete development cycle:
548
540
 
549
541
  | Phrase | Action |
550
542
  |--------|--------|
551
- | **till the land** | Audit systems, update \`_AUDIT/FARMHOUSE.md\` with current metrics |
552
- | **inspect the farm** | Full inspection: code review, cleanup, performance, security, code quality |
553
- | **go to market** | i18n scan + translator for missing translations |
554
- | **harvest crops** | Execute \`/push\` (lint, test, build, commit, push) |
555
- | **open the farm** | Full audit cycle (everything except push), then ask to proceed |
543
+ | **open the farm** | Audit systems, update \`_AUDIT/FARMHOUSE.md\` with current metrics |
544
+ | **count the herd** | Full inspection + dry run: code review, cleanup, performance, security, code quality, accessibility |
545
+ | **go to market** | i18n scan + accessibility audit for missing translations and a11y issues |
546
+ | **close the farm** | Execute \`/push\` (lint, test, build, commit, push) |
556
547
 
557
548
  ---
558
549
 
@@ -567,28 +558,30 @@ Run these in order for a complete development cycle:
567
558
 
568
559
  ### Farmwork Phrase Details
569
560
 
570
- **till the land**
561
+ **open the farm**
571
562
  1. Launch \`the-farmer\` agent to audit all systems
572
563
  2. Run \`bd list --status closed | wc -l\` to get total completed issues
573
564
  3. Updates \`_AUDIT/FARMHOUSE.md\` with current metrics
574
565
 
575
- **inspect the farm** (Full Inspection)
576
- Runs all inspection agents in parallel:
566
+ **count the herd** (Full Audit Cycle)
567
+ Runs all inspection agents in parallel, then dry run quality gates. No push.
568
+
577
569
  1. **Code Review & Cleanup** - \`code-reviewer\` + \`unused-code-cleaner\`
578
- 2. **Performance Audit** - Tests + \`performance-auditor\`, updates \`_AUDIT/PERFORMANCE.md\`
570
+ 2. **Performance Audit** - \`performance-auditor\`, updates \`_AUDIT/PERFORMANCE.md\`
579
571
  3. **Security Audit** - \`security-auditor\` for OWASP Top 10, updates \`_AUDIT/SECURITY.md\`
580
572
  4. **Code Quality** - \`code-smell-auditor\` for DRY violations, updates \`_AUDIT/CODE_QUALITY.md\`
581
- 5. **Summary Report** - Consolidate findings
573
+ 5. **Accessibility** - \`accessibility-auditor\` for WCAG 2.1, updates \`_AUDIT/ACCESSIBILITY.md\`
574
+ 6. **Dry Run** - lint, tests, build (but NOT commit/push)
575
+ 7. **Summary Report** - Consolidate findings, ask user next steps
582
576
 
583
- **harvest crops**
584
- - Invoke the \`push\` skill immediately
577
+ **go to market**
578
+ 1. Scan for hardcoded text not using i18n
579
+ 2. Launch \`i18n-locale-translator\` agent
580
+ 3. Launch \`accessibility-auditor\` for WCAG 2.1 compliance
581
+ 4. Updates \`_AUDIT/ACCESSIBILITY.md\`
585
582
 
586
- **open the farm** (Full Audit Cycle)
587
- 1. **Till the Land** - Run \`the-farmer\` agent
588
- 2. **Inspect the Farm** - Full inspection (code review, cleanup, performance, security, code quality)
589
- 3. **Dry Run Harvest** - Run lint, tests, build (but NOT commit/push)
590
- 4. **Summary Report** - Present consolidated findings
591
- 5. **Ask User** - Ready to harvest (push)?
583
+ **close the farm**
584
+ - Invoke the \`push\` skill immediately
592
585
 
593
586
  ---
594
587
 
@@ -645,7 +638,7 @@ async function createFarmhouseMd(cwd, answers) {
645
638
  const content = `# Farmwork Farmhouse
646
639
 
647
640
  > Central command for the Farmwork agentic harness.
648
- > Updated automatically by \`the-farmer\` agent during \`/push\` or via "till the land" phrase.
641
+ > Updated automatically by \`the-farmer\` agent during \`/push\` or via "open the farm" phrase.
649
642
 
650
643
  **Last Updated:** ${today}
651
644
  **Score:** 5.0/10
@@ -658,7 +651,7 @@ async function createFarmhouseMd(cwd, answers) {
658
651
  | Metric | Count |
659
652
  |--------|-------|
660
653
  | Commands | 1 |
661
- | Agents | 4 |
654
+ | Agents | 10 |
662
655
  | Justfile Recipes | 10 |
663
656
  | Unit Tests | 0 |
664
657
  | E2E Tests | 0 |
@@ -676,7 +669,7 @@ All Claude Code commands and agents are documented, phrase triggers are tested a
676
669
 
677
670
  | Command | Description |
678
671
  |---------|-------------|
679
- | \`/push\` | Clean, lint, test, build, commit, push |
672
+ | \`/push\` | Clean, lint, test, build, commit, push, update metrics |
680
673
 
681
674
  ---
682
675
 
@@ -688,6 +681,12 @@ All Claude Code commands and agents are documented, phrase triggers are tested a
688
681
  | \`code-reviewer\` | Quality & security code review |
689
682
  | \`security-auditor\` | OWASP vulnerability scanning |
690
683
  | \`performance-auditor\` | Performance anti-patterns |
684
+ | \`code-smell-auditor\` | DRY violations, complexity, naming |
685
+ | \`accessibility-auditor\` | WCAG 2.1 compliance, alt text, contrast |
686
+ | \`unused-code-cleaner\` | Detect and remove dead code |
687
+ | \`code-cleaner\` | Remove comments and console.logs |
688
+ | \`i18n-locale-translator\` | Translate UI text to locales |
689
+ | \`storybook-maintainer\` | Create/update Storybook stories |
691
690
 
692
691
  ---
693
692
 
@@ -697,11 +696,10 @@ All Claude Code commands and agents are documented, phrase triggers are tested a
697
696
 
698
697
  | Phrase | Action |
699
698
  |--------|--------|
700
- | \`till the land\` | Audit systems, update FARMHOUSE.md |
701
- | \`inspect the farm\` | Full inspection: code review, cleanup, performance, security, code quality |
702
- | \`go to market\` | i18n scan + translator |
703
- | \`harvest crops\` | Execute /push |
704
- | \`open the farm\` | Full audit cycle |
699
+ | \`open the farm\` | Audit systems, update FARMHOUSE.md |
700
+ | \`count the herd\` | Full inspection + dry run (no push) |
701
+ | \`go to market\` | i18n scan + accessibility audit |
702
+ | \`close the farm\` | Execute /push |
705
703
 
706
704
  ### Plan Phrases
707
705
 
@@ -755,6 +753,11 @@ async function createAuditDocs(cwd, answers) {
755
753
  title: "Performance Audit",
756
754
  description: "Performance metrics and optimization tracking",
757
755
  },
756
+ {
757
+ name: "ACCESSIBILITY.md",
758
+ title: "Accessibility Audit",
759
+ description: "WCAG 2.1 Level AA compliance tracking",
760
+ },
758
761
  {
759
762
  name: "CODE_QUALITY.md",
760
763
  title: "Code Quality Audit",
@@ -948,8 +951,8 @@ Reports findings with severity (CRITICAL, HIGH, MEDIUM, LOW) and remediation ste
948
951
  "security-auditor.md": `---
949
952
  name: security-auditor
950
953
  description: OWASP security vulnerability scanning
951
- tools: Read, Grep, Glob
952
- model: sonnet
954
+ tools: Read, Grep, Glob, Edit
955
+ model: haiku
953
956
  ---
954
957
 
955
958
  # Security Auditor Agent
@@ -967,8 +970,8 @@ Updates \`_AUDIT/SECURITY.md\` with results.
967
970
  "performance-auditor.md": `---
968
971
  name: performance-auditor
969
972
  description: Find memory leaks, unnecessary re-renders, and anti-patterns
970
- tools: Read, Grep, Glob
971
- model: sonnet
973
+ tools: Read, Grep, Glob, Edit
974
+ model: haiku
972
975
  ---
973
976
 
974
977
  # Performance Auditor Agent
@@ -982,6 +985,118 @@ Scans for performance anti-patterns:
982
985
 
983
986
  Reports findings with impact assessment.
984
987
  Updates \`_AUDIT/PERFORMANCE.md\` with results.
988
+ `,
989
+ "code-smell-auditor.md": `---
990
+ name: code-smell-auditor
991
+ description: Detect DRY violations, complexity issues, naming problems, and technical debt
992
+ tools: Read, Grep, Glob, Edit
993
+ model: haiku
994
+ ---
995
+
996
+ # Code Smell Auditor Agent
997
+
998
+ Scans for code quality issues:
999
+ - DRY violations (duplicated code)
1000
+ - Complexity issues (functions > 50 lines, deep nesting)
1001
+ - Naming issues (misleading names, abbreviations)
1002
+ - Magic values (hardcoded numbers/strings)
1003
+ - Technical debt (TODO, FIXME, HACK comments)
1004
+
1005
+ Reports code health as GOOD / FAIR / NEEDS ATTENTION.
1006
+ Updates \`_AUDIT/CODE_QUALITY.md\` with results.
1007
+ `,
1008
+ "accessibility-auditor.md": `---
1009
+ name: accessibility-auditor
1010
+ description: WCAG 2.1 accessibility auditing for React/Next.js applications
1011
+ tools: Read, Grep, Glob, Edit
1012
+ model: haiku
1013
+ ---
1014
+
1015
+ # Accessibility Auditor Agent
1016
+
1017
+ Scans for WCAG 2.1 Level AA compliance issues:
1018
+ - Missing or inadequate alt text on images
1019
+ - Color contrast issues
1020
+ - Keyboard navigation problems
1021
+ - Missing ARIA labels and roles
1022
+ - Form accessibility (labels, error messages)
1023
+ - Focus management issues
1024
+
1025
+ Reports findings by severity (CRITICAL, HIGH, MEDIUM, LOW).
1026
+ Updates \`_AUDIT/ACCESSIBILITY.md\` with results.
1027
+ `,
1028
+ "unused-code-cleaner.md": `---
1029
+ name: unused-code-cleaner
1030
+ description: Detect and remove unused code (imports, functions, variables)
1031
+ tools: Read, Write, Edit, Bash, Grep, Glob
1032
+ model: haiku
1033
+ ---
1034
+
1035
+ # Unused Code Cleaner Agent
1036
+
1037
+ Detects and removes unused code:
1038
+ - Unused imports
1039
+ - Unused functions and classes
1040
+ - Unused variables
1041
+ - Dead code paths
1042
+ - Console.log statements (optional)
1043
+ - Comments (preserves JSDoc)
1044
+
1045
+ Use after refactoring, when removing features, or before production deployment.
1046
+ `,
1047
+ "code-cleaner.md": `---
1048
+ name: code-cleaner
1049
+ description: Fast removal of comments, console.logs, and debug code while preserving JSDoc
1050
+ tools: Read, Edit, Glob, Grep
1051
+ model: haiku
1052
+ ---
1053
+
1054
+ # Code Cleaner Agent
1055
+
1056
+ Fast cleanup of TypeScript/JavaScript files:
1057
+
1058
+ ## Removes
1059
+ - Line comments (\`//\`)
1060
+ - Block comments (\`/* */\`)
1061
+ - \`console.log\` statements
1062
+
1063
+ ## Preserves
1064
+ - JSDoc comments (\`/** */\`)
1065
+ - \`console.error\`, \`console.warn\`, \`console.info\`
1066
+ `,
1067
+ "i18n-locale-translator.md": `---
1068
+ name: i18n-locale-translator
1069
+ description: Translate UI text content into English (en) and Japanese (jp) using i18n locale system
1070
+ tools: Read, Write, Edit, Glob, Grep
1071
+ model: sonnet
1072
+ ---
1073
+
1074
+ # i18n Locale Translator Agent
1075
+
1076
+ Handles internationalization tasks:
1077
+ - Extract hardcoded text from components
1078
+ - Create translation keys in locale files
1079
+ - Translate content to English and Japanese
1080
+ - Update components to use translation hooks
1081
+
1082
+ Use when adding new features or internationalizing existing hardcoded text.
1083
+ `,
1084
+ "storybook-maintainer.md": `---
1085
+ name: storybook-maintainer
1086
+ description: Create and update Storybook stories for UI components
1087
+ tools: Read, Write, Edit, Glob, Grep
1088
+ model: haiku
1089
+ ---
1090
+
1091
+ # Storybook Maintainer Agent
1092
+
1093
+ Manages Storybook stories for UI components:
1094
+ - Analyze component props and variants
1095
+ - Create comprehensive story files
1096
+ - Document component usage
1097
+ - Add controls for interactive props
1098
+
1099
+ Use when adding new components or when existing components change significantly.
985
1100
  `,
986
1101
  };
987
1102
 
@@ -993,93 +1108,129 @@ Updates \`_AUDIT/PERFORMANCE.md\` with results.
993
1108
  async function createCommands(cwd, answers) {
994
1109
  const pm = answers.packageManager || "npm";
995
1110
 
996
- // Build Storybook deployment steps if enabled
997
1111
  const storybookSteps = answers.includeStorybook
998
1112
  ? `
999
1113
 
1000
- ### Step 6: Build & Deploy Storybook
1114
+ ### Step 9: Deploy Storybook to Netlify
1001
1115
 
1002
- Build Storybook for production:
1003
- \`\`\`bash
1004
- ${pm} run build-storybook
1005
- \`\`\`
1006
-
1007
- Deploy to Netlify (requires NETLIFY_AUTH_TOKEN and NETLIFY_STORYBOOK_SITE_ID in .claude/settings.local.json):
1116
+ Deploy the Storybook documentation site:
1008
1117
  \`\`\`bash
1009
1118
  npx netlify deploy --dir=storybook-static --site=$NETLIFY_STORYBOOK_SITE_ID --prod
1010
1119
  \`\`\`
1011
1120
 
1121
+ Note: Requires \`NETLIFY_AUTH_TOKEN\` and \`NETLIFY_STORYBOOK_SITE_ID\` in \`.claude/settings.local.json\`.
1122
+ If not configured, skip this step and inform the user to add the env vars.
1123
+
1012
1124
  Storybook URL: https://${answers.storybookUrl || "storybook.example.com"}
1013
1125
  ${answers.passwordProtect ? "**Note:** This Storybook is password protected." : ""}
1014
1126
  `
1015
1127
  : "";
1016
1128
 
1017
- const finalStep = answers.includeStorybook
1018
- ? "### Step 7: Report Success"
1019
- : "### Step 6: Report Success";
1020
- const reportContent = answers.includeStorybook
1021
- ? `
1022
- Show summary:
1023
- - Files changed
1024
- - Commit hash
1025
- - Push status
1026
- - Storybook deploy status
1027
- `
1028
- : `
1029
- Show summary:
1030
- - Files changed
1031
- - Commit hash
1032
- - Push status
1033
- `;
1034
-
1035
1129
  const pushCommand = `---
1036
- description: Clean, lint, test, build, commit, and push${answers.includeStorybook ? " (+ deploy Storybook)" : ""}
1037
- allowed-tools: Bash(git:*), Bash(${pm}:*), Bash(npx:*)
1130
+ description: Clean, stage, lint, test, build, commit, push, and update metrics
1131
+ argument-hint: [optional: commit message override]
1132
+ allowed-tools: Bash(find:*), Bash(git:*), Bash(${pm}:*), Bash(npx:*)${answers.includeStorybook ? ", Bash(npx netlify:*)" : ""}, Task
1038
1133
  ---
1039
1134
 
1040
1135
  # Push Command
1041
1136
 
1042
- Run quality gates, commit changes, and push to remote.${answers.includeStorybook ? " Then deploy Storybook." : ""}
1137
+ Run code cleanup, all quality gates, commit changes, and push to remote.
1043
1138
 
1044
1139
  ## Workflow
1045
1140
 
1046
1141
  Execute these steps in order. **Stop immediately if any step fails.**
1047
1142
 
1048
- ### Step 1: Stage All Changes
1143
+ ### Step 1: Clean Up System Files
1144
+ Remove any .DS_Store files from the repository:
1049
1145
  \`\`\`bash
1050
- git add -A
1146
+ find . -name '.DS_Store' -type f -delete
1147
+ \`\`\`
1148
+
1149
+ ### Step 2: Sync Packages
1150
+ Clean and reinstall node_modules to ensure package-lock.json stays in sync:
1151
+ \`\`\`bash
1152
+ rm -rf node_modules && ${pm} install
1051
1153
  \`\`\`
1154
+ This prevents \`${pm} ci\` failures in CI/CD due to lock file drift.
1052
1155
 
1053
- ### Step 2: Check for Changes
1054
- Run \`git status\` to verify there are staged changes. If nothing to commit, stop.
1156
+ If package-lock.json was modified, it will be staged in the next step.
1055
1157
 
1056
- ### Step 3: Run Quality Gates
1158
+ ### Step 3: Stage All Changes
1159
+ \`\`\`bash
1160
+ git add -A
1161
+ \`\`\`
1057
1162
 
1058
- 1. **Lint**: \`${answers.lintCommand}\`
1059
- 2. **Tests**: \`${answers.testCommand}\`
1060
- 3. **Build**: \`${answers.buildCommand}\`
1163
+ ### Step 4: Check for Changes
1164
+ Run \`git status\` to verify there are staged changes. If nothing to commit, inform the user and stop.
1061
1165
 
1062
- ### Step 4: Generate Commit Message
1166
+ ### Step 5: Clean Code
1063
1167
 
1064
- Analyze staged changes and generate a concise commit message:
1065
- - Starts with a type (feat, fix, refactor, docs, style, test, chore)
1066
- - Summarizes the "why" not the "what"
1067
- - 1-2 sentences maximum
1168
+ Run the code-cleaner agent on staged TypeScript files to remove comments and console.logs.
1068
1169
 
1069
- ### Step 5: Commit and Push
1170
+ This removes:
1171
+ - Line comments (\`//\`) and block comments (\`/* */\`)
1172
+ - \`console.log\` statements
1070
1173
 
1071
- Create the commit with footer:
1174
+ It preserves:
1175
+ - JSDoc comments (\`/** */\`)
1176
+ - \`console.error\`, \`console.warn\`, \`console.info\`
1072
1177
 
1178
+ After cleaning, re-stage the modified files:
1179
+ \`\`\`bash
1180
+ git add -A
1073
1181
  \`\`\`
1074
- ๐ŸŒฝ Generated with [Claude Code](https://claude.com/claude-code)
1075
1182
 
1076
- Co-Authored-By: Claude <noreply@anthropic.com>
1183
+ ### Step 6: Run Quality Gates (in order)
1184
+
1185
+ Run each check. If any fails, stop and report which check failed:
1186
+
1187
+ 1. **Lint**: \`${answers.lintCommand}\`${answers.includeStorybook ? `\n2. **Storybook**: \`${pm} run build-storybook\`` : ""}
1188
+ ${answers.includeStorybook ? "3" : "2"}. **Unit Tests**: \`${answers.testCommand}\`
1189
+ ${answers.includeStorybook ? "4" : "3"}. **Build**: \`${answers.buildCommand}\`
1190
+
1191
+ ### Step 7: Generate Commit Message
1192
+
1193
+ If \`$ARGUMENTS\` is provided, use it as the commit message.
1194
+
1195
+ Otherwise, analyze the staged changes:
1196
+ 1. Run \`git diff --cached --stat\` to see changed files
1197
+ 2. Run \`git diff --cached\` to see actual changes
1198
+ 3. Run \`git log -5 --oneline\` to match the repository's commit style
1199
+ 4. Generate a concise, descriptive commit message that:
1200
+ - Starts with a type (feat, fix, refactor, docs, style, test, chore)
1201
+ - Summarizes the "why" not the "what"
1202
+ - Is 1-2 sentences maximum
1203
+
1204
+ ### Step 8: Commit and Push
1205
+
1206
+ Create the commit with the message, including the standard footer:
1207
+
1208
+ \`\`\`
1209
+ ๐ŸŒฝ Generated with FARMWORK
1077
1210
  \`\`\`
1078
1211
 
1079
- Then push: \`git push\`
1212
+ Then push to remote:
1213
+ \`\`\`bash
1214
+ git push
1215
+ \`\`\`
1080
1216
  ${storybookSteps}
1081
- ${finalStep}
1082
- ${reportContent}`;
1217
+ ### Step 10: Update Farmhouse Metrics
1218
+
1219
+ Run the-farmer agent to update \`_AUDIT/FARMHOUSE.md\` with current metrics:
1220
+ - Commands and agents inventory
1221
+ - Test counts (unit, e2e)
1222
+ - Completed issues count
1223
+
1224
+ This keeps the harness documentation in sync with the codebase.
1225
+
1226
+ ### Step 11: Report Success
1227
+
1228
+ Show a summary:
1229
+ - Files changed
1230
+ - Commit hash
1231
+ - Push status${answers.includeStorybook ? "\n- Storybook deploy status (if deployed)" : ""}
1232
+ - Harness metrics updated
1233
+ `;
1083
1234
 
1084
1235
  await fs.writeFile(
1085
1236
  path.join(cwd, ".claude", "commands", "push.md"),
@@ -1088,20 +1239,6 @@ ${reportContent}`;
1088
1239
  }
1089
1240
 
1090
1241
  async function createSettings(cwd, answers) {
1091
- const settings = {
1092
- permissions: {
1093
- allow: [],
1094
- deny: [],
1095
- ask: [],
1096
- },
1097
- };
1098
-
1099
- await fs.writeFile(
1100
- path.join(cwd, ".claude", "settings.json"),
1101
- JSON.stringify(settings, null, 2),
1102
- );
1103
-
1104
- // Create local settings for sensitive data (gitignored)
1105
1242
  if (answers.includeStorybook && answers.netlifyAuthToken) {
1106
1243
  const localSettings = {
1107
1244
  env: {
@@ -1115,7 +1252,6 @@ async function createSettings(cwd, answers) {
1115
1252
  JSON.stringify(localSettings, null, 2),
1116
1253
  );
1117
1254
 
1118
- // Ensure settings.local.json is gitignored
1119
1255
  const gitignorePath = path.join(cwd, ".gitignore");
1120
1256
  let gitignoreContent = "";
1121
1257
  try {
@@ -1155,10 +1291,9 @@ async function createProduceConfig(cwd, answers) {
1155
1291
  storybook: answers.includeStorybook || false,
1156
1292
  i18n: answers.includeI18n || false,
1157
1293
  },
1158
- audits: ["FARMHOUSE", "SECURITY", "PERFORMANCE", "CODE_QUALITY", "TESTS"],
1294
+ audits: ["FARMHOUSE", "SECURITY", "PERFORMANCE", "ACCESSIBILITY", "CODE_QUALITY", "TESTS"],
1159
1295
  };
1160
1296
 
1161
- // Add Storybook configuration if enabled
1162
1297
  if (answers.includeStorybook) {
1163
1298
  config.storybook = {
1164
1299
  url: answers.storybookUrl || null,