@delegance/claude-autopilot 5.5.2 → 6.2.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.
Files changed (119) hide show
  1. package/CHANGELOG.md +935 -6
  2. package/README.md +55 -0
  3. package/dist/src/adapters/council/openai.js +12 -6
  4. package/dist/src/adapters/deploy/_http.d.ts +43 -0
  5. package/dist/src/adapters/deploy/_http.js +99 -0
  6. package/dist/src/adapters/deploy/fly.d.ts +206 -0
  7. package/dist/src/adapters/deploy/fly.js +696 -0
  8. package/dist/src/adapters/deploy/index.d.ts +2 -0
  9. package/dist/src/adapters/deploy/index.js +33 -0
  10. package/dist/src/adapters/deploy/render.d.ts +181 -0
  11. package/dist/src/adapters/deploy/render.js +550 -0
  12. package/dist/src/adapters/deploy/types.d.ts +67 -3
  13. package/dist/src/adapters/deploy/vercel.d.ts +17 -1
  14. package/dist/src/adapters/deploy/vercel.js +29 -49
  15. package/dist/src/adapters/pricing.d.ts +36 -0
  16. package/dist/src/adapters/pricing.js +40 -0
  17. package/dist/src/adapters/review-engine/codex.js +10 -7
  18. package/dist/src/cli/autopilot.d.ts +71 -0
  19. package/dist/src/cli/autopilot.js +735 -0
  20. package/dist/src/cli/brainstorm.d.ts +23 -0
  21. package/dist/src/cli/brainstorm.js +131 -0
  22. package/dist/src/cli/costs.d.ts +15 -1
  23. package/dist/src/cli/costs.js +99 -10
  24. package/dist/src/cli/deploy.d.ts +3 -3
  25. package/dist/src/cli/deploy.js +34 -9
  26. package/dist/src/cli/fix.d.ts +18 -0
  27. package/dist/src/cli/fix.js +105 -11
  28. package/dist/src/cli/help-text.d.ts +52 -0
  29. package/dist/src/cli/help-text.js +400 -0
  30. package/dist/src/cli/implement.d.ts +91 -0
  31. package/dist/src/cli/implement.js +196 -0
  32. package/dist/src/cli/index.js +719 -245
  33. package/dist/src/cli/json-envelope.d.ts +187 -0
  34. package/dist/src/cli/json-envelope.js +270 -0
  35. package/dist/src/cli/json-mode.d.ts +33 -0
  36. package/dist/src/cli/json-mode.js +201 -0
  37. package/dist/src/cli/migrate.d.ts +111 -0
  38. package/dist/src/cli/migrate.js +305 -0
  39. package/dist/src/cli/plan.d.ts +81 -0
  40. package/dist/src/cli/plan.js +149 -0
  41. package/dist/src/cli/pr.d.ts +106 -0
  42. package/dist/src/cli/pr.js +191 -19
  43. package/dist/src/cli/preflight.js +26 -0
  44. package/dist/src/cli/review.d.ts +27 -0
  45. package/dist/src/cli/review.js +126 -0
  46. package/dist/src/cli/runs-watch-renderer.d.ts +45 -0
  47. package/dist/src/cli/runs-watch-renderer.js +275 -0
  48. package/dist/src/cli/runs-watch.d.ts +41 -0
  49. package/dist/src/cli/runs-watch.js +395 -0
  50. package/dist/src/cli/runs.d.ts +122 -0
  51. package/dist/src/cli/runs.js +902 -0
  52. package/dist/src/cli/scan.d.ts +93 -0
  53. package/dist/src/cli/scan.js +166 -40
  54. package/dist/src/cli/spec.d.ts +66 -0
  55. package/dist/src/cli/spec.js +132 -0
  56. package/dist/src/cli/validate.d.ts +29 -0
  57. package/dist/src/cli/validate.js +131 -0
  58. package/dist/src/core/config/schema.d.ts +9 -0
  59. package/dist/src/core/config/schema.js +7 -0
  60. package/dist/src/core/config/types.d.ts +11 -0
  61. package/dist/src/core/council/runner.d.ts +10 -1
  62. package/dist/src/core/council/runner.js +25 -3
  63. package/dist/src/core/council/types.d.ts +7 -0
  64. package/dist/src/core/errors.d.ts +1 -1
  65. package/dist/src/core/errors.js +11 -0
  66. package/dist/src/core/logging/redaction.d.ts +13 -0
  67. package/dist/src/core/logging/redaction.js +20 -0
  68. package/dist/src/core/migrate/schema-validator.js +15 -1
  69. package/dist/src/core/phases/static-rules.d.ts +5 -1
  70. package/dist/src/core/phases/static-rules.js +2 -5
  71. package/dist/src/core/run-state/budget.d.ts +88 -0
  72. package/dist/src/core/run-state/budget.js +141 -0
  73. package/dist/src/core/run-state/cli-internal.d.ts +21 -0
  74. package/dist/src/core/run-state/cli-internal.js +174 -0
  75. package/dist/src/core/run-state/events.d.ts +59 -0
  76. package/dist/src/core/run-state/events.js +504 -0
  77. package/dist/src/core/run-state/lock.d.ts +61 -0
  78. package/dist/src/core/run-state/lock.js +206 -0
  79. package/dist/src/core/run-state/phase-context.d.ts +60 -0
  80. package/dist/src/core/run-state/phase-context.js +108 -0
  81. package/dist/src/core/run-state/phase-registry.d.ts +137 -0
  82. package/dist/src/core/run-state/phase-registry.js +162 -0
  83. package/dist/src/core/run-state/phase-runner.d.ts +80 -0
  84. package/dist/src/core/run-state/phase-runner.js +447 -0
  85. package/dist/src/core/run-state/provider-readback.d.ts +130 -0
  86. package/dist/src/core/run-state/provider-readback.js +426 -0
  87. package/dist/src/core/run-state/replay-decision.d.ts +69 -0
  88. package/dist/src/core/run-state/replay-decision.js +144 -0
  89. package/dist/src/core/run-state/resolve-engine.d.ts +100 -0
  90. package/dist/src/core/run-state/resolve-engine.js +190 -0
  91. package/dist/src/core/run-state/resume-preflight.d.ts +66 -0
  92. package/dist/src/core/run-state/resume-preflight.js +116 -0
  93. package/dist/src/core/run-state/run-phase-with-lifecycle.d.ts +73 -0
  94. package/dist/src/core/run-state/run-phase-with-lifecycle.js +186 -0
  95. package/dist/src/core/run-state/runs.d.ts +57 -0
  96. package/dist/src/core/run-state/runs.js +288 -0
  97. package/dist/src/core/run-state/snapshot.d.ts +14 -0
  98. package/dist/src/core/run-state/snapshot.js +114 -0
  99. package/dist/src/core/run-state/state.d.ts +40 -0
  100. package/dist/src/core/run-state/state.js +164 -0
  101. package/dist/src/core/run-state/types.d.ts +278 -0
  102. package/dist/src/core/run-state/types.js +13 -0
  103. package/dist/src/core/run-state/ulid.d.ts +11 -0
  104. package/dist/src/core/run-state/ulid.js +95 -0
  105. package/dist/src/core/schema-alignment/extractor/index.d.ts +1 -1
  106. package/dist/src/core/schema-alignment/extractor/index.js +2 -2
  107. package/dist/src/core/schema-alignment/extractor/prisma.d.ts +13 -1
  108. package/dist/src/core/schema-alignment/extractor/prisma.js +65 -10
  109. package/dist/src/core/schema-alignment/git-history.d.ts +19 -0
  110. package/dist/src/core/schema-alignment/git-history.js +53 -0
  111. package/dist/src/core/static-rules/rules/brand-tokens.js +2 -2
  112. package/dist/src/core/static-rules/rules/schema-alignment.js +14 -4
  113. package/package.json +2 -1
  114. package/scripts/autoregress.ts +1 -1
  115. package/skills/claude-autopilot.md +1 -1
  116. package/skills/make-interfaces-feel-better/SKILL.md +104 -0
  117. package/skills/simplify-ui/SKILL.md +103 -0
  118. package/skills/ui/SKILL.md +117 -0
  119. package/skills/ui-ux-pro-max/SKILL.md +90 -0
@@ -1,18 +1,73 @@
1
- export function extractFromPrisma(content) {
2
- const entities = [];
3
- // Match model blocks: model Name { ... }
4
- const modelRe = /^model\s+(\w+)\s*\{([^}]+)\}/gm;
5
- for (const modelMatch of content.matchAll(modelRe)) {
1
+ const MODEL_RE = /^model\s+(\w+)\s*\{([^}]+)\}/gm;
2
+ const FIELD_RE = /^\s+(\w+)\s+\S/gm;
3
+ function parseModels(content) {
4
+ const models = new Map();
5
+ for (const modelMatch of content.matchAll(MODEL_RE)) {
6
6
  const table = modelMatch[1];
7
- entities.push({ table, operation: 'create_table' });
7
+ const fields = new Set();
8
8
  const body = modelMatch[2];
9
- // Match field lines: fieldName TypeName ...
10
- const fieldRe = /^\s+(\w+)\s+\S/gm;
11
- for (const fieldMatch of body.matchAll(fieldRe)) {
9
+ for (const fieldMatch of body.matchAll(FIELD_RE)) {
12
10
  const column = fieldMatch[1];
13
11
  if (column.startsWith('@') || column === 'id')
14
12
  continue;
15
- entities.push({ table, column, operation: 'add_column' });
13
+ fields.add(column);
14
+ }
15
+ models.set(table, fields);
16
+ }
17
+ return models;
18
+ }
19
+ /**
20
+ * Extract schema entities from a Prisma schema file.
21
+ *
22
+ * When `previousContent` is provided, only the diff (added/removed fields,
23
+ * new/dropped tables) is emitted — this avoids over-reporting when a user
24
+ * touches schema.prisma for any reason (adding one field, editing a comment)
25
+ * and every long-existing field gets re-checked against type/API/UI layers.
26
+ *
27
+ * When `previousContent` is null/undefined, every model and field is emitted
28
+ * — the original "all entities are new" behavior used as a fallback when git
29
+ * history isn't available.
30
+ */
31
+ export function extractFromPrisma(content, previousContent) {
32
+ const current = parseModels(content);
33
+ if (previousContent === undefined || previousContent === null) {
34
+ const entities = [];
35
+ for (const [table, fields] of current) {
36
+ entities.push({ table, operation: 'create_table' });
37
+ for (const column of fields)
38
+ entities.push({ table, column, operation: 'add_column' });
39
+ }
40
+ return entities;
41
+ }
42
+ const previous = parseModels(previousContent);
43
+ const entities = [];
44
+ for (const [table, currentFields] of current) {
45
+ const previousFields = previous.get(table);
46
+ if (!previousFields) {
47
+ // New table — emit create_table + add_column for every field
48
+ entities.push({ table, operation: 'create_table' });
49
+ for (const column of currentFields)
50
+ entities.push({ table, column, operation: 'add_column' });
51
+ continue;
52
+ }
53
+ for (const column of currentFields) {
54
+ if (!previousFields.has(column))
55
+ entities.push({ table, column, operation: 'add_column' });
56
+ }
57
+ for (const column of previousFields) {
58
+ if (!currentFields.has(column))
59
+ entities.push({ table, column, operation: 'drop_column' });
60
+ }
61
+ }
62
+ // Second pass — entirely dropped models. The first loop only iterates
63
+ // `current`, so a model present in `previous` but removed from `current`
64
+ // would never emit any entity, leaving stale references in type/API/UI
65
+ // layers undetected. Caught by Cursor Bugbot on PR #44 (MEDIUM).
66
+ for (const [table, previousFields] of previous) {
67
+ if (current.has(table))
68
+ continue;
69
+ for (const column of previousFields) {
70
+ entities.push({ table, column, operation: 'drop_column' });
16
71
  }
17
72
  }
18
73
  return entities;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Read the previous version of a file from git, comparing against `base`.
3
+ * Returns null if the file has no git history at that ref (untracked,
4
+ * brand-new, not in a repo, or the ref doesn't resolve) — callers should
5
+ * fall back to whole-file extraction in that case.
6
+ *
7
+ * When `base` is omitted, the default is CI-aware (see `resolveDefaultBase`):
8
+ * - GitHub Actions PR build → `origin/<GITHUB_BASE_REF>`
9
+ * - GitLab MR build → `origin/<CI_MERGE_REQUEST_TARGET_BRANCH_NAME>`
10
+ * - everything else → `HEAD~1`
11
+ *
12
+ * Reading from `HEAD` directly is wrong in CI (any post-commit context):
13
+ * `HEAD` IS the current commit, so the diff against the working-tree file
14
+ * is always empty and no schema entities are emitted. Caught by Cursor
15
+ * Bugbot on PR #44 (HIGH); the multi-commit-PR variant of the same bug
16
+ * caught as a MEDIUM follow-up on the rebased commit.
17
+ */
18
+ export declare function getPreviousFileContent(filePath: string, cwd?: string, base?: string): string | null;
19
+ //# sourceMappingURL=git-history.d.ts.map
@@ -0,0 +1,53 @@
1
+ import { spawnSync } from 'node:child_process';
2
+ import * as path from 'node:path';
3
+ /**
4
+ * Resolve the default base ref for git diffs in a CI-aware way.
5
+ *
6
+ * Priority: `GITHUB_BASE_REF` (GitHub Actions PR builds), then
7
+ * `CI_MERGE_REQUEST_TARGET_BRANCH_NAME` (GitLab MR builds), then `HEAD~1`
8
+ * for local / single-commit contexts. Branch-name env vars are prefixed
9
+ * with `origin/` so `git show <ref>:<file>` resolves to the
10
+ * remote-tracking-branch tip (the actual merge base).
11
+ *
12
+ * Caught + extended by Cursor Bugbot follow-up on PR #44 (MEDIUM): a static
13
+ * default of `HEAD~1` is wrong for multi-commit PRs — it points at the
14
+ * previous commit on the branch, not the merge base.
15
+ */
16
+ function resolveDefaultBase() {
17
+ const ghBase = process.env.GITHUB_BASE_REF;
18
+ if (ghBase && ghBase.length > 0)
19
+ return `origin/${ghBase}`;
20
+ const glBase = process.env.CI_MERGE_REQUEST_TARGET_BRANCH_NAME;
21
+ if (glBase && glBase.length > 0)
22
+ return `origin/${glBase}`;
23
+ return 'HEAD~1';
24
+ }
25
+ /**
26
+ * Read the previous version of a file from git, comparing against `base`.
27
+ * Returns null if the file has no git history at that ref (untracked,
28
+ * brand-new, not in a repo, or the ref doesn't resolve) — callers should
29
+ * fall back to whole-file extraction in that case.
30
+ *
31
+ * When `base` is omitted, the default is CI-aware (see `resolveDefaultBase`):
32
+ * - GitHub Actions PR build → `origin/<GITHUB_BASE_REF>`
33
+ * - GitLab MR build → `origin/<CI_MERGE_REQUEST_TARGET_BRANCH_NAME>`
34
+ * - everything else → `HEAD~1`
35
+ *
36
+ * Reading from `HEAD` directly is wrong in CI (any post-commit context):
37
+ * `HEAD` IS the current commit, so the diff against the working-tree file
38
+ * is always empty and no schema entities are emitted. Caught by Cursor
39
+ * Bugbot on PR #44 (HIGH); the multi-commit-PR variant of the same bug
40
+ * caught as a MEDIUM follow-up on the rebased commit.
41
+ */
42
+ export function getPreviousFileContent(filePath, cwd = process.cwd(), base = resolveDefaultBase()) {
43
+ const relPath = path.isAbsolute(filePath) ? path.relative(cwd, filePath) : filePath;
44
+ const result = spawnSync('git', ['show', `${base}:${relPath}`], {
45
+ cwd,
46
+ encoding: 'utf8',
47
+ timeout: 5000,
48
+ });
49
+ if (result.status !== 0)
50
+ return null;
51
+ return result.stdout;
52
+ }
53
+ //# sourceMappingURL=git-history.js.map
@@ -36,8 +36,8 @@ function buildPalette(brandCfg, cwd) {
36
36
  export const brandTokensRule = {
37
37
  name: 'brand-tokens',
38
38
  severity: 'warning',
39
- async check(touchedFiles, config = {}) {
40
- const brandCfg = config.brand;
39
+ async check(touchedFiles, ctx = {}) {
40
+ const brandCfg = ctx.config?.brand;
41
41
  if (!brandCfg)
42
42
  return [];
43
43
  const cwd = process.cwd();
@@ -1,5 +1,6 @@
1
1
  import { detect } from "../../schema-alignment/detector.js";
2
2
  import { extract } from "../../schema-alignment/extractor/index.js";
3
+ import { getPreviousFileContent } from "../../schema-alignment/git-history.js";
3
4
  import { scanLayers } from "../../schema-alignment/scanner.js";
4
5
  import { runLlmCheck } from "../../schema-alignment/llm-check.js";
5
6
  function isDestructive(entity) {
@@ -50,15 +51,24 @@ function structuralFinding(result, layer, defaultSev, sourceFile) {
50
51
  export const schemaAlignmentRule = {
51
52
  name: 'schema-alignment',
52
53
  severity: 'warning',
53
- async check(touchedFiles, config = {}) {
54
- const saConfig = config['schema-alignment'];
54
+ async check(touchedFiles, ctx = {}) {
55
+ const saConfig = ctx.config?.['schema-alignment'];
55
56
  if (saConfig?.enabled === false)
56
57
  return [];
57
58
  const cwd = process.cwd();
58
59
  const migrationFiles = detect(touchedFiles, saConfig);
59
60
  if (migrationFiles.length === 0)
60
61
  return [];
61
- const allEntities = migrationFiles.flatMap(f => extract(f).map(entity => ({ entity, sourceFile: f })));
62
+ // For Prisma schema files, fetch the previous version from git so we only
63
+ // emit entities for what actually changed in this diff. SQL migrations
64
+ // are inherently a diff already; the SQL extractor ignores
65
+ // `previousContent`, so skipping the `git show` spawn there avoids pure
66
+ // waste (Bugbot LOW on PR #44).
67
+ const allEntities = migrationFiles.flatMap(f => {
68
+ const isPrisma = f.endsWith('.prisma');
69
+ const previousContent = isPrisma ? getPreviousFileContent(f, cwd) : null;
70
+ return extract(f, previousContent).map(entity => ({ entity, sourceFile: f }));
71
+ });
62
72
  if (allEntities.length === 0)
63
73
  return [];
64
74
  const scanResults = scanLayers(allEntities.map(e => e.entity), cwd, saConfig);
@@ -75,7 +85,7 @@ export const schemaAlignmentRule = {
75
85
  return [];
76
86
  const defaultSev = saConfig?.severity ?? 'warning';
77
87
  const llmEnabled = saConfig?.llmCheck !== false;
78
- const engine = config['_engine'];
88
+ const engine = ctx.engine;
79
89
  // Structural mode — always compute these so we can fall back if LLM path yields nothing
80
90
  const structural = [];
81
91
  for (const { result: r, sourceFile } of gapResults) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delegance/claude-autopilot",
3
- "version": "5.5.2",
3
+ "version": "6.2.2",
4
4
  "type": "module",
5
5
  "description": "Autonomous development pipeline for Claude Code: brainstorm → spec → plan → implement → migrate → validate → PR → review → merge. Multi-model, local-first, every phase a skill you can intervene in.",
6
6
  "keywords": [
@@ -52,6 +52,7 @@
52
52
  ],
53
53
  "scripts": {
54
54
  "test": "node scripts/test-runner.mjs",
55
+ "test:adapters:live": "node --test --import=tsx tests/adapters/live/vercel.cert.ts tests/adapters/live/fly.cert.ts tests/adapters/live/render.cert.ts",
55
56
  "typecheck": "tsc --noEmit",
56
57
  "build": "tsc -p tsconfig.build.json && node scripts/post-build-rewrite-imports.mjs",
57
58
  "prepublishOnly": "npm run build && npm test",
@@ -259,7 +259,7 @@ async function cmdGenerate(args: string[]): Promise<number> {
259
259
  let snapContent: string;
260
260
  try {
261
261
  const response = await client.responses.create({
262
- model: process.env.CODEX_MODEL ?? 'gpt-5.3-codex',
262
+ model: process.env.CODEX_MODEL ?? 'gpt-5.5',
263
263
  instructions: 'You write TypeScript snapshot tests. Output ONLY the file contents, no markdown fences.',
264
264
  input: prompt,
265
265
  max_output_tokens: 2000,
@@ -47,7 +47,7 @@ Each phase writes its output to disk. Claude can stop, the user can edit the art
47
47
  - PR review finds criticals → fix on branch, push, re-review (max 2 rounds).
48
48
  - Bugbot finds real bugs → fix, push, re-triage (max 3 rounds).
49
49
  - Unrecoverable failure → stop, report what completed, show what remains.
50
- 4. **Codex review is part of the loop, not optional.** The pipeline explicitly dispatches to `gpt-5.3-codex` for spec review, plan review, and PR review. This is the multi-model moat — don't skip it.
50
+ 4. **Codex review is part of the loop, not optional.** The pipeline explicitly dispatches to `gpt-5.5` for spec review, plan review, and PR review. This is the multi-model moat — don't skip it.
51
51
  5. **Skills are swappable.** `review-2pass` and `council` are alternative review phases — a user can configure which runs. The pipeline doesn't hardcode Claude or Codex.
52
52
 
53
53
  ## Phase outputs
@@ -0,0 +1,104 @@
1
+ ---
2
+ name: make-interfaces-feel-better
3
+ description: Craft-and-feel polish for an interface that already works correctly and is already simple. Use when the user says "feels off", "feels clunky", "not quite right", "doesn't feel polished", "lacks soul", "feels cheap", "add some life to it", "make it feel expensive", "feels like AI slop", or wants motion/typography/microcopy/color work that isn't about fixing bugs or alignment. This is the vibes layer — assumes correctness and subtraction are already handled. If the screen is broken or cluttered, route to /ui-ux-pro-max or /simplify-ui first. Complements frontend-design:frontend-design (creative vision) but is scoped to tuning what exists.
4
+ ---
5
+
6
+ # Make interfaces feel better — the craft layer
7
+
8
+ This skill is for the pass where the interface already *works* and is already *simple*, but still feels mediocre. You are tuning emotion, not structure. If the user hasn't had the basics fixed yet, recommend `/ui-ux-pro-max` and `/simplify-ui` first; great feel on top of a broken layout is lipstick.
9
+
10
+ ## The diagnostic
11
+
12
+ Before touching anything, ask yourself what specific feeling is off. Interfaces usually fail one of five feels:
13
+
14
+ 1. **Cheap** — cramped, low-contrast, unbranded, no texture, inconsistent.
15
+ 2. **Cold / clinical** — correct but soulless. Efficient but no character.
16
+ 3. **Heavy / laggy** — transitions stutter, state changes snap, nothing feels alive.
17
+ 4. **Disorganized** — elements fight for attention; no clear visual hierarchy.
18
+ 5. **Nervous / fussy** — too many animations, too many chips, too many accent colors.
19
+
20
+ The fix for each is different. Name the feeling first, then apply the matching lever below.
21
+
22
+ ## Levers — in order of impact-per-minute
23
+
24
+ ### 1. Typography (highest leverage)
25
+
26
+ - **Pair a display face with a body face.** One distinctive (Playfair, Fraunces, Söhne, Tiempos, Inter Display) + one refined (Inter, Figtree, Söhne, IBM Plex, Geist). Don't use Inter for everything.
27
+ - **Use the display only at top levels** — page title, card titles ≥ 18px. Everything else body.
28
+ - **Tighten line-height on display** (1.1–1.2) and loosen on body (1.5–1.65).
29
+ - **Letter-spacing for uppercase** — eyebrows and section labels get `letter-spacing: 0.05em` or more.
30
+ - **One tabular-nums for numeric data** — `font-variant-numeric: tabular-nums` on any column of amounts makes them snap into alignment.
31
+
32
+ ### 2. Color & contrast
33
+
34
+ - **One dominant color, one accent, one destructive. No fourth.**
35
+ - **Backgrounds are off-white or off-black, never pure.** `#F7F8F6`, `#0B0D0A` — feel warmer than `#FFFFFF` / `#000000`.
36
+ - **Shadows with color** — `box-shadow: 0 2px 12px rgba(brand-color, 0.08)` feels branded; `rgba(0,0,0,0.08)` feels generic.
37
+ - **Gradients only on one element at a time.** Usually the primary CTA or the hero. Gradients everywhere = AI-slop.
38
+
39
+ ### 3. Motion
40
+
41
+ - **Page-load stagger is cheap delight.** 40–80ms stagger on cards/rows hitting the viewport; nothing fancier.
42
+ - **Easing: `cubic-bezier(0.22, 1, 0.36, 1)` for enter/exit.** Not `ease-in-out`.
43
+ - **200–280ms for small transitions, 400–600ms for modals/layouts.** Outside that range feels wrong.
44
+ - **Never animate what the user didn't cause.** Auto-pulsing "new" badges are hostile.
45
+ - **Respect `prefers-reduced-motion`** — drop transitions to 0.01s, keep only opacity/color changes.
46
+
47
+ ### 4. Microcopy
48
+
49
+ - **Button verbs specific to the action.** Not "Submit" — "Send quote for review."
50
+ - **Empty states with personality.** "No quotes yet. Start one — it takes about 3 minutes." Beats "No data."
51
+ - **Error messages that acknowledge** — "That's not quite right — X needs to be Y" rather than "Invalid input."
52
+ - **Success states that celebrate proportionally.** Saved draft = small checkmark. Bound a policy = confetti-adjacent.
53
+ - **Loading copy that sets expectations.** "Matching you with carriers… usually 5 seconds" > spinner alone.
54
+
55
+ ### 5. Texture & depth
56
+
57
+ Not every interface needs these, but they're how screens stop feeling generic:
58
+ - **Noise overlay at 2–4% opacity** on dark backgrounds. Kills the plastic look.
59
+ - **Subtle inner shadow on inputs** — `inset 0 1px 0 rgba(255,255,255,0.4)` on light themes suggests depth.
60
+ - **Asymmetric card padding** — e.g., `24px 24px 20px 24px` sometimes feels better than all-24 because humans scan top-to-bottom.
61
+ - **Left-align eyebrow decoration** — a 2px × 18px accent-color rule before a section label reads as editorial, not chrome.
62
+
63
+ ### 6. The small details
64
+
65
+ - **Focus rings that feel on-brand** — `box-shadow: 0 0 0 3px rgba(brand, 0.2)` beats the default blue browser ring.
66
+ - **Checkmark animation on save** — 300ms stroke-dash reveal, not a static green dot.
67
+ - **Hover states that change border color**, not scale or shadow (which feel toy-like on dense forms).
68
+ - **Caret-color matched to brand.** `caret-color: var(--brand)`.
69
+ - **Chip alignment with inline icons** — baseline-align the icon to the text, don't center — centering looks off for small text.
70
+
71
+ ## What to avoid (AI-slop tells)
72
+
73
+ - Purple-to-pink gradients on white.
74
+ - "Gradient text" for things that aren't hero titles.
75
+ - Emoji in UI chrome (buttons, headers).
76
+ - `font-family: 'Inter', sans-serif` as the only typeface.
77
+ - Drop-shadows the same size on cards, buttons, and modals (varied elevation is the whole point).
78
+ - Buttons with `border-radius: 9999px` that are 32px tall (pill at small scale reads as "claimed to be premium, actually built in 20 min").
79
+ - Glass-morphism backdrops without a real background image behind them.
80
+
81
+ ## Workflow
82
+
83
+ 1. **Name the feel.** In one sentence, write what's wrong. "Feels cheap because inputs have no shadow and everything is pure white on pure white." This grounds the rest.
84
+ 2. **Apply at most 3 levers from the list above.** Do not touch everything — diminishing returns.
85
+ 3. **Reload and look away and back.** Judge fresh, not against your memory of before.
86
+ 4. **Name one thing you resisted adding.** This keeps you honest — feel upgrades are often about resisting maximalism, not piling it on.
87
+ 5. **Show the user which levers you pulled** and invite them to push back on any that felt wrong.
88
+
89
+ ## Red flags during the pass
90
+
91
+ If you catch yourself adding:
92
+ - A new color variable that isn't in the design system
93
+ - A third weight of the display font
94
+ - An animation > 600ms
95
+ - A shadow on a default-state button
96
+ - An emoji inside a form label
97
+
98
+ …stop. You're adding where you should be tuning.
99
+
100
+ ## Interactions
101
+
102
+ - Runs best on a screen that already passed `/ui-ux-pro-max` and `/simplify-ui`.
103
+ - Can safely coexist with `/ui` for a combined sweep.
104
+ - If the user wants a redesign, escalate to `frontend-design:frontend-design`.
@@ -0,0 +1,103 @@
1
+ ---
2
+ name: simplify-ui
3
+ description: Ruthless subtraction pass on an existing UI — visual/UX reduction only. Use when the user says "cut it down", "too much going on", "too cluttered", "remove noise", "pare down", "less is more", "it's too busy", or wants the page trimmed without rebuilding it. This is the "remove before adding" lens — complementary to /ui (full polish pass), /ui-ux-pro-max (correctness audit), and /make-interfaces-feel-better (craft layer). For code-level deduplication, use the plugin /simplify instead.
4
+ ---
5
+
6
+ # Simplify — remove before you add
7
+
8
+ You are looking at a UI and cutting what doesn't earn its place. The default answer is **delete**. Every element has to justify why it survives. If you can't state its purpose in a short sentence, it goes.
9
+
10
+ ## The guiding question
11
+
12
+ For every visible element on the screen, answer:
13
+
14
+ > "What would break for the user if this weren't here?"
15
+
16
+ If the answer is "nothing" or "aesthetics", delete it. If the answer names a concrete user failure, keep it — and then see if it can be smaller.
17
+
18
+ ## What to cut, in priority order
19
+
20
+ ### Tier 1 — cut without thinking
21
+
22
+ 1. **Section headers above single-item sections.** "LIABILITY COVERAGE" over a single field is structural vanity.
23
+ 2. **Helper text that restates the label.** "Enter your email address" under an "Email" field. Pick one.
24
+ 3. **Placeholders that duplicate labels.** Ditto.
25
+ 4. **Status pills identical to adjacent counts.** "5/5" badge next to a "5 of 5 complete" progress bar.
26
+ 5. **Default-zero values displayed as content.** `$0`, `0%`, `null` — render as empty.
27
+ 6. **Decorative icons** that don't carry meaning or affordance. Briefcase next to "Company" is ornament.
28
+ 7. **Explanatory captions** for patterns the user already knows ("Click Submit to submit").
29
+ 8. **"Powered by…" footers on internal tools.**
30
+ 9. **Animated spinners on < 200ms operations.** They flash and look broken.
31
+
32
+ ### Tier 2 — cut after a second look
33
+
34
+ 1. **Duplicate buttons.** "Save" at top and bottom of a form — keep one, usually the bottom if the form is long.
35
+ 2. **Multiple paths to the same action.** A "Create quote" primary button + a "+" FAB + a "New quote" menu item.
36
+ 3. **Breadcrumbs on 2-level-deep pages.** Overkill; use a back button.
37
+ 4. **Card shadows stacked on card borders.** Pick one.
38
+ 5. **Grid lines *and* alternating row backgrounds.** Pick one.
39
+ 6. **Count/progress indicators that update instantly.** If the user answered the field, they know.
40
+ 7. **Summary sentences above tables** that restate what the table shows. ("This table shows quotes. There are 3 quotes.")
41
+ 8. **Emoji or flag icons** next to text that already says the same thing.
42
+ 9. **Confirmation dialogs for non-destructive actions.** "Save draft?" — just save.
43
+
44
+ ### Tier 3 — cut with caution (verify with the user)
45
+
46
+ 1. **Tooltips on self-explanatory controls.** If the icon is standard (× for close), no tooltip needed — unless a11y is the reason.
47
+ 2. **Onboarding hints that persist after first use.**
48
+ 3. **Tutorial steps that could be inferred from labels.**
49
+ 4. **Analytics-only elements** that don't serve the user (tracking pixels belong in code, not chrome).
50
+
51
+ ## What not to cut (hold the line)
52
+
53
+ - Labels, even when obvious — they are your a11y surface.
54
+ - Error messages — always keep; tune the copy under `/make-interfaces-feel-better`.
55
+ - Validation — never cut; maybe defer to blur instead of on-change.
56
+ - Skip links and screen-reader-only text.
57
+ - The single "Undo" or "Back" that lets users recover.
58
+
59
+ ## Density rules after simplification
60
+
61
+ Once you've cut:
62
+ - **3–6 fields per card.** Fewer = sleepy; more = oppressive.
63
+ - **One accent color dominant per card.** Not one per chip.
64
+ - **At most 2 type sizes per card** (label + input/value). Title of the card is the third.
65
+ - **One CTA per screen region.** Multiple = the user has to choose, and they'd rather not.
66
+ - **Zero horizontal scroll.** If the layout forces it on common widths, the layout is wrong.
67
+
68
+ ## Workflow
69
+
70
+ 1. **Screenshot or open the screen.** Read every visible string. Don't cut blind.
71
+ 2. **List every distinct element.** Cards, headers, chips, buttons, helper text, icons, images.
72
+ 3. **Mark each: keep / cut / reduce.** "Reduce" means the element stays but smaller/shorter/less prominent.
73
+ 4. **Cut Tier 1 items immediately.** No discussion.
74
+ 5. **Surface Tier 2/3 cuts as proposals** to the user before applying.
75
+ 6. **After the cut, measure.** Did vertical density improve? Did the primary action get more visible? If neither, you cut the wrong things.
76
+
77
+ ## Micro-patterns
78
+
79
+ - **Collapse single-field sections into the parent card.** Don't delete the field, delete the section wrapper.
80
+ - **Merge two adjacent chips with the same color into one.** "Required + Auto-filled" → "Auto-filled (required)".
81
+ - **Replace "X of Y" with "Y - X remaining"** when remaining is what the user cares about.
82
+ - **Fold secondary actions into an overflow menu (⋯).** Don't show 5 buttons when 1 primary + ⋯ works.
83
+ - **Use whitespace as a divider** before reaching for a `<hr>` or border.
84
+
85
+ ## Red flags that you're over-cutting
86
+
87
+ - Users can't tell which field is required.
88
+ - A keyboard-only user can't move through the form.
89
+ - A screen-reader user can't distinguish regions.
90
+ - The page looks like a wireframe, not a product.
91
+ - You removed something and then had to re-add it in the next session.
92
+
93
+ ## Interactions
94
+
95
+ - Runs best after `/ui-ux-pro-max` (knows what's broken) and before `/make-interfaces-feel-better` (which adds back *quality*, not noise).
96
+ - Combine with `/ui` for a full pass in one shot.
97
+ - Do not run on a screen that's already minimalist — you'll cut into muscle.
98
+
99
+ ## One rule above all
100
+
101
+ > Every element survives by earning its pixel count.
102
+
103
+ If you wouldn't fight to keep it at the next design review, delete it now.
@@ -0,0 +1,117 @@
1
+ ---
2
+ name: ui
3
+ description: Opinionated full-pass UI polish on an existing screen — audit, simplify, align, polish in one shot. Use when the user wants to condense, level, align, clean up, tighten, or "make it feel better." Trigger phrases include "condense the UI", "level these out", "clean up and condense", "waste of space", "align better", "feels cluttered", "tighten this up", "polish", "not a great use of space", "make it look right", "fix the alignment". Self-contained — runs all four lenses internally. For subtraction-only, use /simplify-ui. For correctness-only audit, use /ui-ux-pro-max. For craft/feel-only, use /make-interfaces-feel-better. For greenfield design, escalate to frontend-design:frontend-design.
4
+ ---
5
+
6
+ # UI polish pass
7
+
8
+ You are doing a targeted polish of an **existing** UI, not a greenfield design. The user already has something on screen and wants it to feel better. Match their energy — if they send a screenshot with one complaint, fix that complaint first; don't redesign the whole thing.
9
+
10
+ Run the four steps below **in order**. Skip steps that don't apply — but never skip step 1 (audit).
11
+
12
+ ## Scope contract — what this skill will and won't do
13
+
14
+ **Will:** improve hierarchy, spacing, alignment, copy density, interaction states, typographic balance, and visual finish on the existing screen. Touch the components that produce what's on screen and the styles they inherit.
15
+
16
+ **Won't:** redesign the entire flow, change the data model, restructure information architecture beyond the current screen, introduce a new visual identity, or add net-new features. Preserve the product's existing intent.
17
+
18
+ If the request needs any of the "won't" items, stop and route:
19
+ - New screen / no concept yet → `frontend-design:frontend-design`
20
+ - Subtraction-only ("just cut, don't polish") → `/simplify-ui`
21
+ - Correctness audit only ("what would a senior designer catch?") → `/ui-ux-pro-max`
22
+ - Craft/feel only ("feels off, lacks soul") → `/make-interfaces-feel-better`
23
+
24
+ ## 1. Audit — look at it, don't guess
25
+
26
+ Before touching code:
27
+ - **Look at the actual screen.** If the user sent a screenshot, use Read on it. Don't edit blind.
28
+ - **Measure the complaint.** Read the user's words precisely. "Condense" ≠ "redesign." "Level these out" = fix baseline alignment of specific fields, not every field on the page.
29
+ - **Trace the render path.** Find the component(s) that produced what's on screen. Don't assume — grep for the visible strings (section titles, labels, button text) to locate the exact file/line.
30
+ - **Capture the surrounding system.** Note what styles the component inherits: global input classes, grid wrappers, parent padding, font families. The bug is usually upstream of the visible element.
31
+
32
+ Common blind spots to probe:
33
+ - A "grid alignment issue" is almost always wrapper-margin mismatch, not the grid itself.
34
+ - A "wasted space" complaint is usually `maxWidth` + grid columns + single-field groups compounding.
35
+ - A "doesn't feel right" complaint usually points at typographic hierarchy, not color.
36
+
37
+ ## 2. Simplify — subtract first, add never (almost never)
38
+
39
+ Before adding anything, ask: **what can I remove?**
40
+
41
+ Remove these first, in priority order:
42
+ 1. **Redundant containers and wrappers.** One `<div>` can usually replace three.
43
+ 2. **Subcategory headers for 1-item groups.** "LIABILITY COVERAGE" above a single field burns a row for zero signal. Collapse into the parent.
44
+ 3. **Helper text that restates the label.** "Enter your email here" under an "Email" field is noise.
45
+ 4. **Default-zero values displayed as content.** `$0` and `0` with grey styling look like empty state — just leave empty.
46
+ 5. **Summary/status chips that say what the count already says.** "5 fields required" + a "5/5" badge = one of them goes.
47
+ 6. **Decorative icons that don't map to action or meaning.** A briefcase next to "Company Information" is decoration; a checkmark next to "Complete" is meaning. Keep meaning, cut decoration.
48
+ 7. **Multiple font sizes in the same row.** If a label and its chip are different sizes for no reason, they should match.
49
+
50
+ If something genuinely has to be added, it must carry its weight. A new indicator justifies itself by preventing a user mistake or accelerating a decision; otherwise it's noise.
51
+
52
+ ## 3. Align — everything lives on a grid
53
+
54
+ Misalignment is mostly caused by **inconsistent margins**, not inconsistent grids. Audit these in order:
55
+
56
+ 1. **Wrapper margins across sibling fields.** If `<DateInput>` returns a div with `mb-3` and `<CurrencyInput>` returns a div with `mb-1.5`, an `alignItems: 'end'` grid will put them at different baselines — by exactly the margin delta. Normalize wrappers before touching the grid.
57
+ 2. **Input heights across field types.** Date, select, currency, text, and yes/no all need the same `py` value, same `border-width`, same font-size. One `py-3` among a row of `py-2`s looks like a bug to the eye even if the user can't name it.
58
+ 3. **Label block heights.** Use `min-h-[20px]` on all labels so a 1-line label and a 1-line label-with-chip occupy the same vertical footprint. Labels that wrap to 2 lines *because they have to* are fine; labels that appear to wrap because the column is 20px too narrow are not.
59
+ 4. **Grid column strategies in the same card.** Don't mix `repeat(3, 1fr)` and `repeat(auto-fill, minmax(260px, 1fr))` in sibling rows — column widths will jump between rows for no reason the user understands.
60
+ 5. **`align-items`: prefer `end` for forms.** Anchoring inputs to the row's bottom means they line up regardless of how many lines the labels or helper texts above them take.
61
+
62
+ When a "leveling" complaint comes in, the fix is almost always one of (1) or (2). Check those before rewriting the grid.
63
+
64
+ ## 4. Polish — small things that disproportionately matter
65
+
66
+ These are low-effort, high-payoff tweaks. Apply them in this order:
67
+ - **Sentence-case labels.** "Requested Effective Date" → "Requested effective date" unless the product strongly prefers title case.
68
+ - **Tighten the padding scale.** `py-2 px-3` for inputs, `p-3` / `p-4` for cards, `gap-2` / `gap-3` for flex rows. Don't invent new values.
69
+ - **Right-size interactive affordances.** Yes/No buttons should match adjacent input heights (same `py`). "Submit" buttons should be one step larger, not three.
70
+ - **Consistent green/red semantics.** One accent color for success (`#40C288` / green-100 bg), one for destructive — don't introduce a third.
71
+ - **Chip restraint.** If multiple chips can appear on one label ("Auto-filled", "Suggested", "Required"), reserve one color per meaning and hide conflicting combinations (e.g., a "Suggested" chip disappears the moment "Auto-filled" applies).
72
+ - **Hover states that mean something.** Border color shift > shadow shift > scale transform. Don't use animation where color communicates the change.
73
+ - **Motion only for state changes the user caused.** Page-load staggers are cheap delight; surprise-wiggle on data arrival is usually annoying.
74
+
75
+ ## Opinionated defaults
76
+
77
+ When the user hasn't specified, default to these and move on:
78
+ - **Content width:** 1200px max. Sidebar + main = 220 + 980 with 24–32px gutters. Wider reads as "enterprise app with too many fields"; narrower cramps.
79
+ - **Card padding:** `px-4 py-3`. Cards tighter than this feel underbaked; looser feels sleepy.
80
+ - **Grid gap between fields:** `12px` horizontally, `12px` vertically. Don't exceed 16px unless there's a strong reason.
81
+ - **Typography scale:** label 11–12px semibold, input text 14px regular, body 13px regular, section title 14–15px semibold. Avoid introducing a 4th or 5th size.
82
+ - **Borders:** `1px solid` at all times. `border-2` reads as "please notice me" — reserve it for selected/active states, not defaults.
83
+ - **Corner radius:** `rounded-lg` (8px) for inputs and cards, `rounded-full` only for pills/avatars.
84
+
85
+ ## Anti-patterns — flag these on sight
86
+
87
+ - A single-field "section" with its own uppercase header.
88
+ - `maxWidth` > 1280 on a form-heavy page.
89
+ - `gap: 4` next to `gap: 16` inside the same card.
90
+ - `mb-3` on some wrappers and `mb-1.5` on others, in the same grid.
91
+ - `border-2` on non-selected default states.
92
+ - Helper text that is grammatically a sentence but visually the same size as the label.
93
+ - "Auto-filled" and "Suggested" chips shown simultaneously on one field.
94
+ - Yes/No buttons noticeably taller than neighboring selects.
95
+ - Progress bar counts that include optional fields in the denominator. "X of Y required" is what users actually want.
96
+ - Content that expands to fill whatever width it's given (currency inputs stretched to 600px for a 6-digit number).
97
+
98
+ ## Workflow the user sees
99
+
100
+ 1. **Restate the complaint in one sentence** so the user knows you understood. ("Fields don't line up in Coverage Details" — not "let me analyze the UI.")
101
+ 2. **Diagnose out loud.** Say what's causing it. ("Date wrapper has `mb-3`, currency wrapper has `mb-1.5` — that's the 6px offset.")
102
+ 3. **Make the minimum edit that fixes it.** Don't bundle unrelated cleanup.
103
+ 4. **Say what was left alone and why**, if there are obvious nearby things you chose not to touch.
104
+ 5. **Don't commit** unless the user asked.
105
+
106
+ ## When to escalate
107
+
108
+ Hand off to a different skill when:
109
+ - Request is "design a new X from scratch" → `frontend-design:frontend-design`
110
+ - Request is "write a comprehensive spec for the redesign" → `superpowers:writing-plans`
111
+ - Request is "this feels bad, but I don't know why" and you've already done a polish pass → ask targeted questions before another round.
112
+
113
+ ## Verification
114
+
115
+ After edits, state which complaint was addressed and which were not. If the user sent one screenshot showing one row of fields misaligned, don't report "condensed the whole page" — they'll suspect you did more than asked.
116
+
117
+ If you can run the dev server and re-check visually, do. If you can't (backend-only session, no browser access), say so explicitly: "I can't verify visually — please reload and confirm."