@bastani/atomic 0.6.5 → 0.6.6-1
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/.agents/skills/ado-commit/SKILL.md +2 -0
- package/.agents/skills/ado-create-pr/SKILL.md +2 -0
- package/.agents/skills/advanced-evaluation/SKILL.md +2 -0
- package/.agents/skills/ast-grep/SKILL.md +2 -0
- package/.agents/skills/bdi-mental-states/SKILL.md +2 -0
- package/.agents/skills/bun/SKILL.md +156 -122
- package/.agents/skills/context-compression/SKILL.md +2 -0
- package/.agents/skills/context-degradation/SKILL.md +2 -0
- package/.agents/skills/context-fundamentals/SKILL.md +2 -0
- package/.agents/skills/context-optimization/SKILL.md +2 -0
- package/.agents/skills/create-spec/SKILL.md +2 -0
- package/.agents/skills/docx/SKILL.md +2 -0
- package/.agents/skills/evaluation/SKILL.md +2 -0
- package/.agents/skills/explain-code/SKILL.md +2 -0
- package/.agents/skills/filesystem-context/SKILL.md +2 -0
- package/.agents/skills/find-skills/SKILL.md +2 -0
- package/.agents/skills/gh-commit/SKILL.md +2 -0
- package/.agents/skills/gh-create-pr/SKILL.md +2 -0
- package/.agents/skills/hosted-agents/SKILL.md +2 -0
- package/.agents/skills/impeccable/SKILL.md +117 -304
- package/.agents/skills/impeccable/agents/openai.yaml +4 -0
- package/.agents/skills/{adapt/SKILL.md → impeccable/reference/adapt.md} +2 -11
- package/.agents/skills/{animate/SKILL.md → impeccable/reference/animate.md} +15 -15
- package/.agents/skills/{audit/SKILL.md → impeccable/reference/audit.md} +8 -22
- package/.agents/skills/{bolder/SKILL.md → impeccable/reference/bolder.md} +9 -13
- package/.agents/skills/impeccable/reference/brand.md +114 -0
- package/.agents/skills/{clarify/SKILL.md → impeccable/reference/clarify.md} +2 -11
- package/.agents/skills/{colorize/SKILL.md → impeccable/reference/colorize.md} +23 -12
- package/.agents/skills/impeccable/reference/craft.md +152 -29
- package/.agents/skills/{critique/SKILL.md → impeccable/reference/critique.md} +25 -37
- package/.agents/skills/{delight/SKILL.md → impeccable/reference/delight.md} +9 -11
- package/.agents/skills/{distill/SKILL.md → impeccable/reference/distill.md} +2 -13
- package/.agents/skills/impeccable/reference/document.md +427 -0
- package/.agents/skills/impeccable/reference/extract.md +1 -1
- package/.agents/skills/{harden/SKILL.md → impeccable/reference/harden.md} +1 -43
- package/.agents/skills/{layout/SKILL.md → impeccable/reference/layout.md} +27 -11
- package/.agents/skills/impeccable/reference/live.md +594 -0
- package/.agents/skills/impeccable/reference/motion-design.md +12 -2
- package/.agents/skills/impeccable/reference/onboard.md +234 -0
- package/.agents/skills/{optimize/SKILL.md → impeccable/reference/optimize.md} +4 -12
- package/.agents/skills/{overdrive/SKILL.md → impeccable/reference/overdrive.md} +9 -21
- package/.agents/skills/{critique → impeccable}/reference/personas.md +1 -1
- package/.agents/skills/{polish/SKILL.md → impeccable/reference/polish.md} +31 -23
- package/.agents/skills/impeccable/reference/product.md +62 -0
- package/.agents/skills/{quieter/SKILL.md → impeccable/reference/quieter.md} +7 -11
- package/.agents/skills/impeccable/reference/shape.md +151 -0
- package/.agents/skills/impeccable/reference/teach.md +156 -0
- package/.agents/skills/{typeset/SKILL.md → impeccable/reference/typeset.md} +19 -11
- package/.agents/skills/impeccable/reference/typography.md +31 -14
- package/.agents/skills/impeccable/scripts/cleanup-deprecated.mjs +87 -17
- package/.agents/skills/impeccable/scripts/command-metadata.json +94 -0
- package/.agents/skills/impeccable/scripts/design-parser.mjs +820 -0
- package/.agents/skills/impeccable/scripts/detect-csp.mjs +198 -0
- package/.agents/skills/impeccable/scripts/is-generated.mjs +69 -0
- package/.agents/skills/impeccable/scripts/live-accept.mjs +595 -0
- package/.agents/skills/impeccable/scripts/live-browser.js +4781 -0
- package/.agents/skills/impeccable/scripts/live-inject.mjs +445 -0
- package/.agents/skills/impeccable/scripts/live-poll.mjs +186 -0
- package/.agents/skills/impeccable/scripts/live-server.mjs +694 -0
- package/.agents/skills/impeccable/scripts/live-wrap.mjs +571 -0
- package/.agents/skills/impeccable/scripts/live.mjs +247 -0
- package/.agents/skills/impeccable/scripts/load-context.mjs +141 -0
- package/.agents/skills/impeccable/scripts/modern-screenshot.umd.js +14 -0
- package/.agents/skills/impeccable/scripts/pin.mjs +214 -0
- package/.agents/skills/init/SKILL.md +2 -0
- package/.agents/skills/liteparse/SKILL.md +1 -0
- package/.agents/skills/memory-systems/SKILL.md +2 -0
- package/.agents/skills/multi-agent-patterns/SKILL.md +2 -0
- package/.agents/skills/opentui/SKILL.md +1 -0
- package/.agents/skills/pdf/SKILL.md +2 -0
- package/.agents/skills/playwright-cli/SKILL.md +51 -5
- package/.agents/skills/playwright-cli/references/playwright-tests.md +1 -1
- package/.agents/skills/playwright-cli/references/running-code.md +10 -0
- package/.agents/skills/playwright-cli/references/session-management.md +56 -0
- package/.agents/skills/playwright-cli/references/spec-driven-testing.md +305 -0
- package/.agents/skills/playwright-cli/references/test-generation.md +49 -3
- package/.agents/skills/pptx/SKILL.md +2 -0
- package/.agents/skills/project-development/SKILL.md +2 -0
- package/.agents/skills/prompt-engineer/SKILL.md +2 -0
- package/.agents/skills/research-codebase/SKILL.md +2 -0
- package/.agents/skills/ripgrep/SKILL.md +2 -0
- package/.agents/skills/skill-creator/LICENSE.txt +1 -1
- package/.agents/skills/skill-creator/SKILL.md +2 -0
- package/.agents/skills/sl-commit/SKILL.md +2 -0
- package/.agents/skills/sl-submit-diff/SKILL.md +2 -0
- package/.agents/skills/tdd/SKILL.md +4 -0
- package/.agents/skills/tool-design/SKILL.md +2 -0
- package/.agents/skills/typescript-advanced-types/SKILL.md +2 -1
- package/.agents/skills/typescript-expert/SKILL.md +7 -1
- package/.agents/skills/typescript-react-reviewer/SKILL.md +2 -1
- package/.agents/skills/workflow-creator/SKILL.md +75 -72
- package/.agents/skills/workflow-creator/references/session-config.md +48 -1
- package/.agents/skills/xlsx/SKILL.md +2 -0
- package/.opencode/opencode.json +6 -2
- package/README.md +39 -38
- package/dist/lib/atomic-temp.d.ts +8 -0
- package/dist/lib/atomic-temp.d.ts.map +1 -0
- package/dist/lib/terminal-env.d.ts +9 -0
- package/dist/lib/terminal-env.d.ts.map +1 -0
- package/dist/sdk/providers/claude.d.ts.map +1 -1
- package/dist/sdk/providers/copilot.d.ts +24 -14
- package/dist/sdk/providers/copilot.d.ts.map +1 -1
- package/dist/sdk/runtime/executor.d.ts +8 -0
- package/dist/sdk/runtime/executor.d.ts.map +1 -1
- package/dist/sdk/runtime/port-discovery.d.ts +71 -0
- package/dist/sdk/runtime/port-discovery.d.ts.map +1 -0
- package/dist/sdk/runtime/tmux.d.ts +10 -0
- package/dist/sdk/runtime/tmux.d.ts.map +1 -1
- package/dist/sdk/types.d.ts +1 -0
- package/dist/sdk/types.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/deep-research-codebase/opencode/index.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/open-claude-design/opencode/index.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/ralph/claude/index.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/ralph/copilot/index.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/ralph/helpers/prompts.d.ts +15 -0
- package/dist/sdk/workflows/builtin/ralph/helpers/prompts.d.ts.map +1 -1
- package/dist/sdk/workflows/builtin/ralph/opencode/index.d.ts.map +1 -1
- package/package.json +10 -10
- package/src/commands/cli/chat/index.test.ts +194 -2
- package/src/commands/cli/chat/index.ts +83 -28
- package/src/lib/atomic-temp.test.ts +86 -0
- package/src/lib/atomic-temp.ts +62 -0
- package/src/lib/terminal-env.test.ts +343 -0
- package/src/lib/terminal-env.ts +100 -0
- package/src/scripts/clean-dist.test.ts +53 -0
- package/src/scripts/clean-dist.ts +37 -0
- package/src/sdk/providers/claude.ts +42 -20
- package/src/sdk/providers/copilot.test.ts +365 -0
- package/src/sdk/providers/copilot.ts +117 -15
- package/src/sdk/runtime/cc-debounce.ts +2 -2
- package/src/sdk/runtime/executor.test.ts +322 -1
- package/src/sdk/runtime/executor.ts +159 -96
- package/src/sdk/runtime/port-discovery.test.ts +573 -0
- package/src/sdk/runtime/port-discovery.ts +496 -0
- package/src/sdk/runtime/tmux.ts +22 -2
- package/src/sdk/types.ts +1 -0
- package/src/sdk/workflows/builtin/deep-research-codebase/opencode/index.ts +24 -6
- package/src/sdk/workflows/builtin/open-claude-design/opencode/index.ts +52 -13
- package/src/sdk/workflows/builtin/ralph/claude/index.ts +31 -3
- package/src/sdk/workflows/builtin/ralph/copilot/index.ts +16 -0
- package/src/sdk/workflows/builtin/ralph/helpers/prompts.ts +70 -3
- package/src/sdk/workflows/builtin/ralph/opencode/index.ts +50 -6
- package/src/services/system/auth.test.ts +53 -0
- package/src/services/system/auth.ts +31 -28
- package/src/services/system/detect.ts +1 -1
- package/.agents/skills/shape/SKILL.md +0 -96
- /package/.agents/skills/{critique → impeccable}/reference/cognitive-load.md +0 -0
- /package/.agents/skills/{critique → impeccable}/reference/heuristics-scoring.md +0 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
Shape the UX and UI for a feature before any code is written. This command produces a **design brief**: a structured artifact that guides implementation through discovery, not guesswork.
|
|
2
|
+
|
|
3
|
+
**Scope**: Design planning only. This command does NOT write code. It produces the thinking that makes code good.
|
|
4
|
+
|
|
5
|
+
**Output**: A design brief that can be handed off to $impeccable craft, or directly to $impeccable for freeform implementation. When visual direction probes are used, the images are supporting artifacts, not the primary output.
|
|
6
|
+
|
|
7
|
+
## Philosophy
|
|
8
|
+
|
|
9
|
+
Most AI-generated UIs fail not because of bad code, but because of skipped thinking. They jump to "here's a card grid" without asking "what is the user trying to accomplish?" This command inverts that: understand deeply first, so implementation is precise.
|
|
10
|
+
|
|
11
|
+
## Phase 1: Discovery Interview
|
|
12
|
+
|
|
13
|
+
**Do NOT write any code or make any design decisions during this phase.** Your only job is to understand the feature deeply enough to make excellent design decisions later.
|
|
14
|
+
|
|
15
|
+
This is a required interaction, not optional guidance. Ask these questions in conversation, adapting based on answers. Don't dump them all at once; have a natural dialogue. STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer.
|
|
16
|
+
|
|
17
|
+
### Interview cadence
|
|
18
|
+
|
|
19
|
+
Discovery must include at least one user-answer round unless PRODUCT.md, DESIGN.md, or an already-confirmed brief directly answers the needed design inputs. With a sparse prompt, do **not** synthesize a complete brief for confirmation on the first response.
|
|
20
|
+
|
|
21
|
+
- Use the harness's structured question tool when one exists. Otherwise, ask directly in chat and stop.
|
|
22
|
+
- Ask **2-3 questions per round**, then wait for answers.
|
|
23
|
+
- Treat PRODUCT.md and DESIGN.md as anchors; they reduce repeated questions but do **not** replace shape for craft. Shape is task-specific.
|
|
24
|
+
- Round 1 should clarify purpose, audience/context, and success or emotional outcome.
|
|
25
|
+
- Round 2 should clarify content/data/states and scope/fidelity.
|
|
26
|
+
- Round 3 should clarify visual direction, constraints, and anti-goals when still unresolved.
|
|
27
|
+
|
|
28
|
+
### Purpose & Context
|
|
29
|
+
- What is this feature for? What problem does it solve?
|
|
30
|
+
- Who specifically will use it? (Not "users"; be specific: role, context, frequency)
|
|
31
|
+
- What does success look like? How will you know this feature is working?
|
|
32
|
+
- What's the user's state of mind when they reach this feature? (Rushed? Exploring? Anxious? Focused?)
|
|
33
|
+
|
|
34
|
+
### Content & Data
|
|
35
|
+
- What content or data does this feature display or collect?
|
|
36
|
+
- What are the realistic ranges? (Minimum, typical, maximum, e.g., 0 items, 5 items, 500 items)
|
|
37
|
+
- What are the edge cases? (Empty state, error state, first-time use, power user)
|
|
38
|
+
- Is any content dynamic? What changes and how often?
|
|
39
|
+
|
|
40
|
+
### Design Direction
|
|
41
|
+
|
|
42
|
+
Force a visual decision on three fronts. Skip anything PRODUCT.md or DESIGN.md already answers; ask only what's missing.
|
|
43
|
+
|
|
44
|
+
- **Color strategy for this surface.** Pick one: Restrained / Committed / Full palette / Drenched. Can override the project default if the surface earns it (e.g. a drenched hero inside an otherwise Restrained product).
|
|
45
|
+
- **Theme via scene sentence.** Write one sentence of physical context for this surface — who uses it, where, under what ambient light, in what mood. The sentence forces dark vs light. If it doesn't, add detail until it does.
|
|
46
|
+
- **Two or three named anchor references.** Specific products, brands, objects — not adjectives like "modern" or "clean."
|
|
47
|
+
|
|
48
|
+
### Scope
|
|
49
|
+
|
|
50
|
+
Always ask. Sketch quality and shipped quality are different outputs; don't guess between them.
|
|
51
|
+
|
|
52
|
+
- **Fidelity.** Sketch / mid-fi / high-fi / production-ready?
|
|
53
|
+
- **Breadth.** One screen / a flow / a whole surface?
|
|
54
|
+
- **Interactivity.** Static visual / interactive prototype / shipped-quality component?
|
|
55
|
+
- **Time intent.** Quick exploration, or polish until it ships?
|
|
56
|
+
|
|
57
|
+
Scope answers are task-scoped. Don't write them to PRODUCT.md or DESIGN.md — carry them through the design brief only.
|
|
58
|
+
|
|
59
|
+
### Constraints
|
|
60
|
+
- Are there technical constraints? (Framework, performance budget, browser support)
|
|
61
|
+
- Are there content constraints? (Localization, dynamic text length, user-generated content)
|
|
62
|
+
- Mobile/responsive requirements?
|
|
63
|
+
- Accessibility requirements beyond WCAG AA?
|
|
64
|
+
|
|
65
|
+
### Anti-Goals
|
|
66
|
+
- What should this NOT be? What would be a wrong direction?
|
|
67
|
+
- What's the biggest risk of getting this wrong?
|
|
68
|
+
|
|
69
|
+
## Phase 1.5: Visual Direction Probe (Capability-Gated)
|
|
70
|
+
|
|
71
|
+
After the discovery interview, generate a small set of visual direction probes **before** writing the final brief when all of these are true:
|
|
72
|
+
|
|
73
|
+
- The work is **net-new** or directionally ambiguous enough that visual exploration will clarify the brief.
|
|
74
|
+
- The requested fidelity is **mid-fi, high-fi, or production-ready**. Skip for sketch-only planning.
|
|
75
|
+
- The current harness has **built-in image generation capability** (for example, Codex with a native image tool). Do **not** ask the user to set up external APIs, shell scripts, or one-off tooling just to do this.
|
|
76
|
+
|
|
77
|
+
When those conditions are met, this step is mandatory for Codex and any harness with built-in image generation. Use native image generation; in Codex, use the built-in `image_gen` tool via the imagegen skill. If image generation is unavailable, do not ask the user to install APIs or tooling. State in one line that the image step is skipped because the harness lacks native image generation, then proceed.
|
|
78
|
+
|
|
79
|
+
Use probes to explore visual lanes, not to replace the brief.
|
|
80
|
+
|
|
81
|
+
Do not skip probes because the final UI will be semantic, editable, code-native, responsive, or accessible. Those are implementation requirements, not reasons to avoid visual exploration.
|
|
82
|
+
|
|
83
|
+
### What to generate
|
|
84
|
+
|
|
85
|
+
Generate **2 to 4** distinct direction probes based on the discovery answers, especially:
|
|
86
|
+
|
|
87
|
+
- Color strategy
|
|
88
|
+
- Theme scene sentence
|
|
89
|
+
- Named anchor references
|
|
90
|
+
- Scope and fidelity
|
|
91
|
+
|
|
92
|
+
The probes should differ in primary visual direction (hierarchy, topology, density, typographic voice, or color strategy), not just palette tweaks.
|
|
93
|
+
|
|
94
|
+
### How to use the probes
|
|
95
|
+
|
|
96
|
+
- Treat them as **direction tests**, not final designs.
|
|
97
|
+
- Use them to pressure-test whether the brief is pointing at the right lane.
|
|
98
|
+
- Ask the user which direction feels closest, what feels off, and what should carry forward.
|
|
99
|
+
- If the probes reveal a mismatch, revise the brief inputs before finalizing the brief.
|
|
100
|
+
|
|
101
|
+
### Important limits
|
|
102
|
+
|
|
103
|
+
- Do **not** skip discovery because image generation is available.
|
|
104
|
+
- Do **not** treat generated imagery as final UX specification, final copy, or final accessibility behavior.
|
|
105
|
+
- Do **not** use this step for minor refinements of existing work. It's for shaping a new surface or clarifying a big directional choice.
|
|
106
|
+
|
|
107
|
+
If image generation is unavailable, or the task doesn't benefit from it, skip this phase only with a one-line reason and proceed directly to the design brief.
|
|
108
|
+
|
|
109
|
+
## Phase 2: Design Brief
|
|
110
|
+
|
|
111
|
+
After the interview and any required probes, synthesize everything into a structured design brief. Present it to the user for explicit confirmation before considering this command complete. Stop after asking for confirmation; do not proceed to craft or implementation in the same response unless the user has already approved the brief.
|
|
112
|
+
|
|
113
|
+
### Brief Structure
|
|
114
|
+
|
|
115
|
+
**1. Feature Summary** (2-3 sentences)
|
|
116
|
+
What this is, who it's for, what it needs to accomplish.
|
|
117
|
+
|
|
118
|
+
**2. Primary User Action**
|
|
119
|
+
The single most important thing a user should do or understand here.
|
|
120
|
+
|
|
121
|
+
**3. Design Direction**
|
|
122
|
+
Color strategy (Restrained / Committed / Full palette / Drenched) + the theme scene sentence + 2–3 named anchor references. Reference PRODUCT.md and DESIGN.md where they already answer, and note any per-surface overrides.
|
|
123
|
+
|
|
124
|
+
If you ran the Visual Direction Probe step, name which probe direction won and what changed in the brief because of it.
|
|
125
|
+
|
|
126
|
+
**4. Scope**
|
|
127
|
+
Fidelity, breadth, interactivity, and time intent from the Scope section of the interview. Task-scoped — these don't persist beyond the brief.
|
|
128
|
+
|
|
129
|
+
**5. Layout Strategy**
|
|
130
|
+
High-level spatial approach: what gets emphasis, what's secondary, how information flows. Describe the visual hierarchy and rhythm, not specific CSS.
|
|
131
|
+
|
|
132
|
+
**6. Key States**
|
|
133
|
+
List every state the feature needs: default, empty, loading, error, success, edge cases. For each, note what the user needs to see and feel.
|
|
134
|
+
|
|
135
|
+
**7. Interaction Model**
|
|
136
|
+
How users interact with this feature. What happens on click, hover, scroll? What feedback do they get? What's the flow from entry to completion?
|
|
137
|
+
|
|
138
|
+
**8. Content Requirements**
|
|
139
|
+
What copy, labels, empty state messages, error messages, and microcopy are needed. Note any dynamic content and its realistic ranges.
|
|
140
|
+
|
|
141
|
+
**9. Recommended References**
|
|
142
|
+
Based on the brief, list which impeccable reference files would be most valuable during implementation (e.g., spatial-design.md for complex layouts, motion-design.md for animated features, interaction-design.md for form-heavy features).
|
|
143
|
+
|
|
144
|
+
**10. Open Questions**
|
|
145
|
+
Anything unresolved that the implementer should resolve during build.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer. Ask for explicit confirmation of the brief before finishing. If the user disagrees with any part, revisit the relevant discovery questions. A shape run is incomplete until the brief is confirmed.
|
|
150
|
+
|
|
151
|
+
Once confirmed, the brief is complete. The user can now hand it to $impeccable, or use it to guide any other implementation approach. (If the user wants the full discovery-then-build flow in one step, they should use $impeccable craft instead, which runs this command internally.)
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Teach Flow
|
|
2
|
+
|
|
3
|
+
Gathers design context for a project and writes two complementary files at the project root:
|
|
4
|
+
|
|
5
|
+
- **PRODUCT.md** (strategic): register, target users, product purpose, brand personality, anti-references, strategic design principles. Answers "who/what/why".
|
|
6
|
+
- **DESIGN.md** (visual): visual theme, color palette, typography, components, layout. Follows the [Google Stitch DESIGN.md format](https://stitch.withgoogle.com/docs/design-md/format/). Answers "how it looks".
|
|
7
|
+
|
|
8
|
+
Every other impeccable command reads these files before doing any work.
|
|
9
|
+
|
|
10
|
+
## Step 1: Load current state
|
|
11
|
+
|
|
12
|
+
Run the shared loader first so you know what already exists:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
node .agents/skills/impeccable/scripts/load-context.mjs
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The output tells you whether PRODUCT.md and/or DESIGN.md already exist. If `migrated: true`, legacy `.impeccable.md` was auto-renamed to `PRODUCT.md`. Mention this once to the user.
|
|
19
|
+
|
|
20
|
+
Decision tree:
|
|
21
|
+
- **Neither file exists (empty project or no context yet)**: do Steps 2-4 (write PRODUCT.md), then decide on DESIGN.md based on whether there's code to analyze.
|
|
22
|
+
- **PRODUCT.md exists, DESIGN.md missing**: skip to Step 5 — offer to run `$impeccable document` for DESIGN.md.
|
|
23
|
+
- **PRODUCT.md exists but has no `## Register` section (legacy)**: add it. Infer a hypothesis from the codebase (see Step 2), confirm with the user, write the field.
|
|
24
|
+
- **Both exist**: STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer. Ask which file to refresh. Skip the one the user doesn't want changed.
|
|
25
|
+
- **Just DESIGN.md exists (unusual)**: do Steps 2-4 to produce PRODUCT.md.
|
|
26
|
+
|
|
27
|
+
Never silently overwrite an existing file. Always confirm first.
|
|
28
|
+
|
|
29
|
+
If teach was invoked as a setup blocker by another command, such as `$impeccable craft landing page`, pause that command here. Complete teach, re-run the loader, then resume the original command with the freshly loaded context. For craft, resume into shape next; teach creates project context, but it is not a substitute for the task-specific shape interview and confirmed design brief.
|
|
30
|
+
|
|
31
|
+
## Step 2: Explore the codebase
|
|
32
|
+
|
|
33
|
+
Before asking questions, thoroughly scan the project to discover what you can:
|
|
34
|
+
|
|
35
|
+
- **README and docs**: Project purpose, target audience, any stated goals
|
|
36
|
+
- **Package.json / config files**: Tech stack, dependencies, existing design libraries
|
|
37
|
+
- **Existing components**: Current design patterns, spacing, typography in use
|
|
38
|
+
- **Brand assets**: Logos, favicons, color values already defined
|
|
39
|
+
- **Design tokens / CSS variables**: Existing color palettes, font stacks, spacing scales
|
|
40
|
+
- **Any style guides or brand documentation**
|
|
41
|
+
|
|
42
|
+
Also form a **register hypothesis** from what you find:
|
|
43
|
+
|
|
44
|
+
- Brand signals: `/`, `/about`, `/pricing`, `/blog/*`, `/docs/*`, hero sections, big typography, scroll-driven sections, landing-page-shaped content.
|
|
45
|
+
- Product signals: `/app/*`, `/dashboard`, `/settings`, `/(auth)`, forms, data tables, side/top nav, app-shell components.
|
|
46
|
+
|
|
47
|
+
Register is a hypothesis at this point, not a decision — Step 3 confirms it.
|
|
48
|
+
|
|
49
|
+
Note what you've learned and what remains unclear. This exploration feeds both PRODUCT.md and DESIGN.md.
|
|
50
|
+
|
|
51
|
+
## Step 3: Ask strategic questions (for PRODUCT.md)
|
|
52
|
+
|
|
53
|
+
STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer. Ask only about what you couldn't infer from the codebase.
|
|
54
|
+
|
|
55
|
+
### Interview mode, not confirmation mode
|
|
56
|
+
|
|
57
|
+
If the repo is empty or the user's brief is sparse, run a short interview before proposing PRODUCT.md. Do **not** turn a one-sentence request into a complete inferred PRODUCT.md and ask for blanket confirmation.
|
|
58
|
+
|
|
59
|
+
- Use the harness's structured question tool when one exists. Otherwise, ask directly in chat and stop.
|
|
60
|
+
- Ask **2-3 questions per round**, then wait for answers.
|
|
61
|
+
- Use inferred answers as hypotheses or options, not as finished facts.
|
|
62
|
+
- Complete at least one real user-answer round before drafting PRODUCT.md, unless every required answer is directly discoverable from repo docs.
|
|
63
|
+
- Round 1 should establish register, users/purpose, and desired outcome.
|
|
64
|
+
- Round 2 should establish brand personality or references, anti-references, and accessibility needs.
|
|
65
|
+
|
|
66
|
+
### Minimum viable interview
|
|
67
|
+
|
|
68
|
+
Ask enough to complete PRODUCT.md. At minimum, cover register confirmation, users and purpose, brand personality, anti-references, and accessibility needs unless each answer is directly discoverable from repo context. After at least one interview round, you may propose inferred answers, but the user must confirm them before you write PRODUCT.md. Never synthesize PRODUCT.md from the original task prompt alone.
|
|
69
|
+
|
|
70
|
+
### Register (ask first — it shapes everything below)
|
|
71
|
+
|
|
72
|
+
Every design task is either **brand** (marketing, landing, campaign, long-form content, portfolio — design IS the product) or **product** (app UI, admin, dashboards, tools — design SERVES the product).
|
|
73
|
+
|
|
74
|
+
If Step 2 produced a clear hypothesis, lead with it: *"From the codebase, this looks like a [brand / product] surface — does that match your intent, or should we treat it differently?"*
|
|
75
|
+
|
|
76
|
+
If the signal is genuinely split (e.g. a product with a big marketing landing), STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer. Ask which register describes the **primary** surface. The register can be overridden per task later, but PRODUCT.md carries one default.
|
|
77
|
+
|
|
78
|
+
### Users & Purpose
|
|
79
|
+
- Who uses this? What's their context when using it?
|
|
80
|
+
- What job are they trying to get done?
|
|
81
|
+
- For brand: what emotions should the interface evoke? (confidence, delight, calm, urgency)
|
|
82
|
+
- For product: what workflow are they in? What's the primary task on any given screen?
|
|
83
|
+
|
|
84
|
+
### Brand & Personality
|
|
85
|
+
- How would you describe the brand personality in 3 words?
|
|
86
|
+
- Reference sites or apps that capture the right feel? What specifically about them?
|
|
87
|
+
- For brand, push for real-world references in the right lane (tech-minimal, editorial-magazine, consumer-warm, brutalist-grid, etc.) — not generic "modern" adjectives.
|
|
88
|
+
- For product, push for category best-tool references (Linear, Figma, Notion, Raycast, Stripe).
|
|
89
|
+
- What should this explicitly NOT look like? Any anti-references?
|
|
90
|
+
|
|
91
|
+
### Accessibility & Inclusion
|
|
92
|
+
- Specific accessibility requirements? (WCAG level, known user needs)
|
|
93
|
+
- Considerations for reduced motion, color blindness, or other accommodations?
|
|
94
|
+
|
|
95
|
+
Skip questions where the answer is already clear. **Do NOT ask about colors, fonts, radii, or visual styling here** — those belong in DESIGN.md, not PRODUCT.md.
|
|
96
|
+
|
|
97
|
+
## Step 4: Write PRODUCT.md
|
|
98
|
+
|
|
99
|
+
Write PRODUCT.md only after the user has confirmed the strategic answers from Step 3. If an inferred answer is uncertain or unconfirmed, ask before writing.
|
|
100
|
+
|
|
101
|
+
Synthesize into a strategic document:
|
|
102
|
+
|
|
103
|
+
```markdown
|
|
104
|
+
# Product
|
|
105
|
+
|
|
106
|
+
## Register
|
|
107
|
+
|
|
108
|
+
product
|
|
109
|
+
|
|
110
|
+
## Users
|
|
111
|
+
[Who they are, their context, the job to be done]
|
|
112
|
+
|
|
113
|
+
## Product Purpose
|
|
114
|
+
[What this product does, why it exists, what success looks like]
|
|
115
|
+
|
|
116
|
+
## Brand Personality
|
|
117
|
+
[Voice, tone, 3-word personality, emotional goals]
|
|
118
|
+
|
|
119
|
+
## Anti-references
|
|
120
|
+
[What this should NOT look like. Specific bad-example sites or patterns to avoid.]
|
|
121
|
+
|
|
122
|
+
## Design Principles
|
|
123
|
+
[3-5 strategic principles derived from the conversation. Principles like "practice what you preach", "show, don't tell", "expert confidence" — NOT visual rules like "use OKLCH" or "magenta accent".]
|
|
124
|
+
|
|
125
|
+
## Accessibility & Inclusion
|
|
126
|
+
[WCAG level, known user needs, considerations]
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Register is either `brand` or `product` as a bare value. No prose, no commentary.
|
|
130
|
+
|
|
131
|
+
Write to `PROJECT_ROOT/PRODUCT.md`. If `.impeccable.md` existed, the loader already renamed it — merge into that content rather than starting from scratch.
|
|
132
|
+
|
|
133
|
+
## Step 5: Decide on DESIGN.md
|
|
134
|
+
|
|
135
|
+
Offer `$impeccable document` either way. Two paths:
|
|
136
|
+
|
|
137
|
+
- **Code exists** (CSS tokens, components, a running site): "I can generate a DESIGN.md that captures your visual system (colors, typography, components) so variants stay on-brand. Want to do that now?"
|
|
138
|
+
- **Pre-implementation** (empty project): "I can seed a starter DESIGN.md from five quick questions about color strategy, type direction, motion energy, and references. You can re-run once there's code, to capture the real tokens. Want to do that now?"
|
|
139
|
+
|
|
140
|
+
If the user agrees, delegate to `$impeccable document` (it auto-detects scan vs seed). Load its reference and follow that flow.
|
|
141
|
+
|
|
142
|
+
If the user prefers to skip, mention they can run `$impeccable document` any time later.
|
|
143
|
+
|
|
144
|
+
## Step 6: Confirm and wrap up
|
|
145
|
+
|
|
146
|
+
Summarize:
|
|
147
|
+
- Register captured (brand / product)
|
|
148
|
+
- What was written (PRODUCT.md, DESIGN.md, or both)
|
|
149
|
+
- The 3-5 strategic principles from PRODUCT.md that will guide future work
|
|
150
|
+
- If DESIGN.md is pending, remind the user how to generate it later
|
|
151
|
+
|
|
152
|
+
**Critical: re-run the loader to refresh session context.** After writing PRODUCT.md, run `node .agents/skills/impeccable/scripts/load-context.mjs` one final time and let its full JSON output land in conversation. This ensures subsequent commands in this session use the freshly-written PRODUCT.md, not a stale earlier version.
|
|
153
|
+
|
|
154
|
+
If teach was invoked as a blocker by another impeccable command (e.g. the user ran `$impeccable polish` with no PRODUCT.md), resume that original task now with the fresh context.
|
|
155
|
+
|
|
156
|
+
Optionally STOP and use Codex's structured user-input/question tool when available; if unavailable, ask directly in chat to clarify what you cannot infer. Ask whether they'd like a brief summary of PRODUCT.md appended to AGENTS.md for easier agent reference. If yes, append a short **Design Context** pointer section there.
|
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
description: Improves typography by fixing font choices, hierarchy, sizing, weight, and readability so text feels intentional. Use when the user mentions fonts, type, readability, text hierarchy, sizing looks off, or wants more polished, intentional typography.
|
|
4
|
-
version: 2.1.1
|
|
5
|
-
user-invocable: true
|
|
6
|
-
argument-hint: "[target]"
|
|
1
|
+
Assess and improve typography that feels generic, inconsistent, or poorly structured — turning default-looking text into intentional, well-crafted type.
|
|
2
|
+
|
|
7
3
|
---
|
|
8
4
|
|
|
9
|
-
|
|
5
|
+
## Register
|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
Brand: run the font selection procedure in [brand.md](brand.md). Pairing follows the brand's lane (display serif + sans body for editorial/luxury, one committed sans for tech, etc.). Fluid `clamp()` scale, ≥1.25 ratio between steps.
|
|
12
8
|
|
|
13
|
-
|
|
9
|
+
Product: system fonts and familiar sans stacks are legitimate here. One well-tuned family typically carries the whole UI. Fixed `rem` scale, 1.125–1.2 ratio between more closely-spaced steps.
|
|
14
10
|
|
|
15
11
|
---
|
|
16
12
|
|
|
@@ -47,7 +43,7 @@ Analyze what's weak or generic about the current type:
|
|
|
47
43
|
|
|
48
44
|
## Plan Typography Improvements
|
|
49
45
|
|
|
50
|
-
Consult the [typography reference](
|
|
46
|
+
Consult the [typography reference](typography.md) for detailed guidance on scales, pairing, and loading strategies.
|
|
51
47
|
|
|
52
48
|
Create a systematic plan:
|
|
53
49
|
|
|
@@ -113,4 +109,16 @@ Build a clear type scale:
|
|
|
113
109
|
- **Performance**: Are web fonts loading efficiently without layout shift?
|
|
114
110
|
- **Accessibility**: Does text meet WCAG contrast ratios? Is it zoomable to 200%?
|
|
115
111
|
|
|
116
|
-
Remember: Typography is the foundation of interface design — it carries the majority of information. Getting it right is the highest-leverage improvement you can make.
|
|
112
|
+
Remember: Typography is the foundation of interface design — it carries the majority of information. Getting it right is the highest-leverage improvement you can make.
|
|
113
|
+
|
|
114
|
+
## Live-mode signature params
|
|
115
|
+
|
|
116
|
+
Each variant MUST declare a `scale` param controlling the hierarchy ratio. Express all font sizes in the variant's scoped CSS through `calc(var(--p-scale, 1) * <base>)` or, better, scale the type ramp via `clamp(min, calc(var(--p-scale, 1) * Npx), max)`. Users slide from subdued to commanding.
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{"id":"scale","kind":"range","min":0.85,"max":1.3,"step":0.05,"default":1,"label":"Scale"}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Where the variant riffs on a specific pairing, expose the pairing choice as a `steps` param (e.g. "serif display + sans body" vs. "mono display + sans body" vs. "all-sans"). Each branch routes through `:scope[data-p-pairing="X"]` selectors in scoped CSS.
|
|
123
|
+
|
|
124
|
+
See `reference/live.md` for the full params contract.
|
|
@@ -26,28 +26,20 @@ Popular ratios: 1.25 (major third), 1.333 (perfect fourth), 1.5 (perfect fifth).
|
|
|
26
26
|
|
|
27
27
|
Use `ch` units for character-based measure (`max-width: 65ch`). Line-height scales inversely with line length—narrow columns need tighter leading, wide columns need more.
|
|
28
28
|
|
|
29
|
-
**Non-obvious**:
|
|
29
|
+
**Non-obvious**: Light text on dark backgrounds needs compensation on three axes, not just one. Bump line-height by 0.05–0.1, add a touch of letter-spacing (0.01–0.02em), and optionally step the body weight up one notch (regular → medium). The perceived weight drops across all three; fix all three.
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
### Choosing Distinctive Fonts
|
|
31
|
+
**Paragraph rhythm**: Pick either space between paragraphs OR first-line indentation. Never both. Digital usually wants space; editorial/long-form can justify indent-only.
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
**Pick the font from the brief, not from a category preset.** The most common AI typography failure is reaching for the same "tasteful" font for every editorial brief, the same "modern" font for every tech brief, the same "elegant serif" for every premium brief. Those reflexes produce monoculture across projects. The right font is one whose physical character matches *this specific* brand, audience, and moment.
|
|
33
|
+
## Font Selection & Pairing
|
|
38
34
|
|
|
39
|
-
|
|
35
|
+
The tactical selection procedure and the reflex-reject list live in [reference/brand.md](brand.md) under **Font selection procedure** and **Reflex-reject list** (loaded for brand-register tasks). The rest of this section covers the adjacent knowledge: anti-reflex corrections, system font use, and pairing rules.
|
|
40
36
|
|
|
41
|
-
|
|
42
|
-
2. Now imagine the font as a physical object the brand could ship: a typewriter ribbon, a hand-lettered shop sign, a 1970s mainframe terminal manual, a fabric label on the inside of a coat, a museum exhibit caption, a tax form, a children's book printed on cheap newsprint. Whichever physical object fits the three words is pointing at the right *kind* of typeface.
|
|
43
|
-
3. Browse a font catalog (Google Fonts, Pangram Pangram, Adobe Fonts, Future Fonts, ABC Dinamo) with that physical object in mind. **Reject the first thing that "looks designy."** That's your trained-everywhere reflex. Keep looking.
|
|
44
|
-
4. Avoid your defaults from previous projects. If you find yourself reaching for the same display font you used last time, make yourself pick something else.
|
|
37
|
+
### Anti-reflexes worth defending against
|
|
45
38
|
|
|
46
|
-
**Anti-reflexes worth defending against**:
|
|
47
39
|
- A technical/utilitarian brief does NOT need a serif "for warmth." Most tech tools should look like tech tools.
|
|
48
40
|
- An editorial/premium brief does NOT need the same expressive serif everyone is using right now. Premium can be Swiss-modern, can be neo-grotesque, can be a literal monospace, can be a quiet humanist sans.
|
|
49
41
|
- A children's product does NOT need a rounded display font. Kids' books use real type.
|
|
50
|
-
- A "modern" brief does NOT need a geometric sans. The most modern thing you can do
|
|
42
|
+
- A "modern" brief does NOT need a geometric sans. The most modern thing you can do is not use the font everyone else is using.
|
|
51
43
|
|
|
52
44
|
**System fonts are underrated**: `-apple-system, BlinkMacSystemFont, "Segoe UI", system-ui` looks native, loads instantly, and is highly readable. Consider this for apps where performance > personality.
|
|
53
45
|
|
|
@@ -91,6 +83,12 @@ body {
|
|
|
91
83
|
|
|
92
84
|
Tools like [Fontaine](https://github.com/unjs/fontaine) calculate these overrides automatically.
|
|
93
85
|
|
|
86
|
+
**`swap` vs `optional`**: `swap` shows fallback text immediately and FOUT-swaps when the web font arrives. `optional` uses the fallback if the web font misses a small load budget (~100ms) and avoids the shift entirely. Pick `optional` when zero layout shift matters more than seeing the branded font on slow networks.
|
|
87
|
+
|
|
88
|
+
**Preload the critical weight only**: typically the regular-weight body font used above the fold. Preloading every weight costs more bandwidth than it saves.
|
|
89
|
+
|
|
90
|
+
**Variable fonts for 3+ weights or styles**: a single variable font file is usually smaller than three static weight files, gives fractional weight control, and pairs well with `font-optical-sizing: auto`. For 1–2 weights, static is fine.
|
|
91
|
+
|
|
94
92
|
## Modern Web Typography
|
|
95
93
|
|
|
96
94
|
### Fluid Type
|
|
@@ -101,6 +99,10 @@ Fluid typography via `clamp(min, preferred, max)` scales text smoothly with the
|
|
|
101
99
|
|
|
102
100
|
**Use fixed `rem` scales for**: App UIs, dashboards, and data-dense interfaces. No major app design system (Material, Polaris, Primer, Carbon) uses fluid type in product UI — fixed scales with optional breakpoint adjustments give the spatial predictability that container-based layouts need. Body text should also be fixed even on marketing pages, since the size difference across viewports is too small to warrant it.
|
|
103
101
|
|
|
102
|
+
**Bound your clamp()**: keep `max-size ≤ ~2.5 × min-size`. Wider ratios break the browser's zoom and reflow behaviour and make large viewports feel like the page is shouting.
|
|
103
|
+
|
|
104
|
+
**Scale container width and font-size together** so effective character measure stays in the 45–75ch band at every viewport. A heading that widens faster than its container drifts out of the comfortable measure at the top end.
|
|
105
|
+
|
|
104
106
|
### OpenType Features
|
|
105
107
|
|
|
106
108
|
Most developers don't know these exist. Use them for polish:
|
|
@@ -124,6 +126,21 @@ body { font-kerning: normal; }
|
|
|
124
126
|
|
|
125
127
|
Check what features your font supports at [Wakamai Fondue](https://wakamaifondue.com/).
|
|
126
128
|
|
|
129
|
+
### Rendering polish
|
|
130
|
+
|
|
131
|
+
```css
|
|
132
|
+
/* Even out heading line lengths (browser picks better break points) */
|
|
133
|
+
h1, h2, h3 { text-wrap: balance; }
|
|
134
|
+
|
|
135
|
+
/* Reduce orphans and ragged endings in long prose */
|
|
136
|
+
article p { text-wrap: pretty; }
|
|
137
|
+
|
|
138
|
+
/* Variable fonts: pick the right optical-size master automatically */
|
|
139
|
+
body { font-optical-sizing: auto; }
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
**ALL-CAPS tracking**: capitals sit too close at default spacing. Add 5–12% letter-spacing (`letter-spacing: 0.05em` to `0.12em`) to short all-caps labels, eyebrows, and small headings. Real small caps (via `font-variant-caps`) need the same treatment, slightly gentler.
|
|
143
|
+
|
|
127
144
|
## Typography System Architecture
|
|
128
145
|
|
|
129
146
|
Name tokens semantically (`--text-body`, `--text-heading`), not by value (`--font-size-16`). Include font stacks, size scale, weights, line-heights, and letter-spacing in your token system.
|
|
@@ -21,14 +21,34 @@
|
|
|
21
21
|
import { existsSync, readFileSync, writeFileSync, rmSync, readdirSync, statSync, lstatSync, unlinkSync } from 'node:fs';
|
|
22
22
|
import { join, resolve } from 'node:path';
|
|
23
23
|
|
|
24
|
-
// Skills that were renamed, merged, or folded in v2.0
|
|
24
|
+
// Skills that were renamed, merged, or folded in v2.0, v2.1, and v3.0.
|
|
25
25
|
const DEPRECATED_NAMES = [
|
|
26
|
-
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
|
|
30
|
-
'
|
|
31
|
-
'
|
|
26
|
+
// v2.0 renames
|
|
27
|
+
'frontend-design', // renamed to impeccable
|
|
28
|
+
'teach-impeccable', // folded into /impeccable teach
|
|
29
|
+
// v2.1 merges
|
|
30
|
+
'arrange', // renamed to layout
|
|
31
|
+
'normalize', // merged into polish
|
|
32
|
+
'onboard', // merged into harden
|
|
33
|
+
'extract', // merged into /impeccable extract
|
|
34
|
+
// v3.0 consolidation: all standalone skills -> /impeccable sub-commands
|
|
35
|
+
'adapt',
|
|
36
|
+
'animate',
|
|
37
|
+
'audit',
|
|
38
|
+
'bolder',
|
|
39
|
+
'clarify',
|
|
40
|
+
'colorize',
|
|
41
|
+
'critique',
|
|
42
|
+
'delight',
|
|
43
|
+
'distill',
|
|
44
|
+
'harden',
|
|
45
|
+
'layout',
|
|
46
|
+
'optimize',
|
|
47
|
+
'overdrive',
|
|
48
|
+
'polish',
|
|
49
|
+
'quieter',
|
|
50
|
+
'shape',
|
|
51
|
+
'typeset',
|
|
32
52
|
];
|
|
33
53
|
|
|
34
54
|
// All known harness directories that may contain a skills/ subfolder.
|
|
@@ -37,6 +57,17 @@ const HARNESS_DIRS = [
|
|
|
37
57
|
'.trae', '.trae-cn', '.pi', '.opencode', '.kiro', '.rovodev',
|
|
38
58
|
];
|
|
39
59
|
|
|
60
|
+
// Per-skill fingerprints for SKILL.md bodies that never mentioned
|
|
61
|
+
// "impeccable" in their v2.x source. Used as a last-resort match
|
|
62
|
+
// when no skills-lock.json exists and the word heuristic fails.
|
|
63
|
+
// The strings are lifted verbatim from the v2.x frontmatter
|
|
64
|
+
// descriptions, so collisions with hand-written user skills are
|
|
65
|
+
// vanishingly unlikely.
|
|
66
|
+
const SKILL_FINGERPRINTS = {
|
|
67
|
+
harden: 'Make interfaces production-ready: error handling, empty states',
|
|
68
|
+
optimize: 'Diagnoses and fixes UI performance across loading speed',
|
|
69
|
+
};
|
|
70
|
+
|
|
40
71
|
/**
|
|
41
72
|
* Walk up from startDir until we find a directory that looks like a
|
|
42
73
|
* project root (has package.json, .git, or skills-lock.json).
|
|
@@ -60,19 +91,48 @@ export function findProjectRoot(startDir = process.cwd()) {
|
|
|
60
91
|
}
|
|
61
92
|
|
|
62
93
|
/**
|
|
63
|
-
*
|
|
64
|
-
* SKILL.md and looking for the word "impeccable" (case-insensitive).
|
|
65
|
-
* Returns false for non-existent paths or skills that don't match.
|
|
94
|
+
* Load skills-lock.json from the project root, or null if missing/unreadable.
|
|
66
95
|
*/
|
|
67
|
-
export function
|
|
96
|
+
export function loadLock(projectRoot) {
|
|
97
|
+
const lockPath = join(projectRoot, 'skills-lock.json');
|
|
98
|
+
if (!existsSync(lockPath)) return null;
|
|
99
|
+
try {
|
|
100
|
+
return JSON.parse(readFileSync(lockPath, 'utf-8'));
|
|
101
|
+
} catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Check whether a skill directory belongs to Impeccable. Three layered
|
|
108
|
+
* signals, in order of reliability:
|
|
109
|
+
* 1. Lock source equals "pbakaus/impeccable" (authoritative).
|
|
110
|
+
* 2. SKILL.md body contains the word "impeccable".
|
|
111
|
+
* 3. SKILL.md body contains a per-skill fingerprint (for harden and
|
|
112
|
+
* optimize, whose v2.x SKILL.md never mentioned the pack name).
|
|
113
|
+
*/
|
|
114
|
+
export function isImpeccableSkill(skillDir, { skillName, lock } = {}) {
|
|
115
|
+
// 1. Authoritative: the lock file claims this skill is ours.
|
|
116
|
+
if (skillName && lock?.skills?.[skillName]?.source === 'pbakaus/impeccable') {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
68
119
|
const skillMd = join(skillDir, 'SKILL.md');
|
|
69
120
|
if (!existsSync(skillMd)) return false;
|
|
121
|
+
let content;
|
|
70
122
|
try {
|
|
71
|
-
|
|
72
|
-
return /impeccable/i.test(content);
|
|
123
|
+
content = readFileSync(skillMd, 'utf-8');
|
|
73
124
|
} catch {
|
|
74
125
|
return false;
|
|
75
126
|
}
|
|
127
|
+
// 2. Word-level content heuristic.
|
|
128
|
+
if (/impeccable/i.test(content)) return true;
|
|
129
|
+
// 3. Per-skill fingerprint for old skills that never mentioned the pack.
|
|
130
|
+
// Strip the i- prefix so both `harden` and `i-harden` resolve to the
|
|
131
|
+
// same fingerprint entry.
|
|
132
|
+
const unprefixed = skillName?.startsWith('i-') ? skillName.slice(2) : skillName;
|
|
133
|
+
const fingerprint = unprefixed && SKILL_FINGERPRINTS[unprefixed];
|
|
134
|
+
if (fingerprint && content.includes(fingerprint)) return true;
|
|
135
|
+
return false;
|
|
76
136
|
}
|
|
77
137
|
|
|
78
138
|
/**
|
|
@@ -105,9 +165,12 @@ export function findSkillsDirs(projectRoot) {
|
|
|
105
165
|
|
|
106
166
|
/**
|
|
107
167
|
* Remove deprecated skill directories/symlinks from all harness dirs.
|
|
168
|
+
* Reads skills-lock.json so the authoritative "source" field can
|
|
169
|
+
* drive deletion even when SKILL.md never mentions impeccable.
|
|
108
170
|
* Returns an array of paths that were deleted.
|
|
109
171
|
*/
|
|
110
|
-
export function removeDeprecatedSkills(projectRoot) {
|
|
172
|
+
export function removeDeprecatedSkills(projectRoot, lock) {
|
|
173
|
+
if (lock === undefined) lock = loadLock(projectRoot);
|
|
111
174
|
const targets = buildTargetNames();
|
|
112
175
|
const skillsDirs = findSkillsDirs(projectRoot);
|
|
113
176
|
const deleted = [];
|
|
@@ -129,7 +192,9 @@ export function removeDeprecatedSkills(projectRoot) {
|
|
|
129
192
|
// Symlink: check the target if it's alive, otherwise treat
|
|
130
193
|
// dangling symlinks to deprecated names as safe to remove.
|
|
131
194
|
const targetAlive = existsSync(skillPath);
|
|
132
|
-
const isMatch = targetAlive
|
|
195
|
+
const isMatch = targetAlive
|
|
196
|
+
? isImpeccableSkill(skillPath, { skillName: name, lock })
|
|
197
|
+
: true;
|
|
133
198
|
if (isMatch) {
|
|
134
199
|
unlinkSync(skillPath);
|
|
135
200
|
deleted.push(skillPath);
|
|
@@ -138,7 +203,7 @@ export function removeDeprecatedSkills(projectRoot) {
|
|
|
138
203
|
}
|
|
139
204
|
|
|
140
205
|
// Regular directory -- verify it belongs to impeccable
|
|
141
|
-
if (isImpeccableSkill(skillPath)) {
|
|
206
|
+
if (isImpeccableSkill(skillPath, { skillName: name, lock })) {
|
|
142
207
|
rmSync(skillPath, { recursive: true, force: true });
|
|
143
208
|
deleted.push(skillPath);
|
|
144
209
|
}
|
|
@@ -188,10 +253,15 @@ export function cleanSkillsLock(projectRoot) {
|
|
|
188
253
|
|
|
189
254
|
/**
|
|
190
255
|
* Run the full cleanup. Returns a summary object.
|
|
256
|
+
*
|
|
257
|
+
* Order matters: read the lock and delete directories first, then
|
|
258
|
+
* strip lock entries. Otherwise the authoritative signal is gone by
|
|
259
|
+
* the time directory deletion runs.
|
|
191
260
|
*/
|
|
192
261
|
export function cleanup(projectRoot) {
|
|
193
262
|
const root = projectRoot || findProjectRoot();
|
|
194
|
-
const
|
|
263
|
+
const lock = loadLock(root);
|
|
264
|
+
const deletedPaths = removeDeprecatedSkills(root, lock);
|
|
195
265
|
const removedLockEntries = cleanSkillsLock(root);
|
|
196
266
|
return { deletedPaths, removedLockEntries, projectRoot: root };
|
|
197
267
|
}
|