mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-11 21:57:14 +03:00
* Add a platform axis (web / ios / android / adaptive) to the skill Orthogonal to register: register decides whether design IS or SERVES the product; platform decides the delivery target and which native conventions apply. Set `## Platform` in PRODUCT.md; a missing field defaults to `web`, so legacy projects are unaffected. - extractPlatform() in skill/scripts/context.mjs (mirrors extractRegister); the CLI appends a NEXT STEP directive to read the native reference(s). `adaptive` (Flutter / RN / KMP shipping both iOS and Android) loads both ios.md and android.md. - New reference/ios.md (Apple HIG distilled) and reference/android.md (Material 3 distilled); reference/web.md is a thin pointer. The native refs frame register's role as narrow: platform conformance is the bar, brand lives in the expressive layer the platform gives you, never by breaking the rails. - Setup step 5 loads the native reference(s) when platform is native. Live mode and the detect CLI stay web-only, gated off ios/android/adaptive. - init asks platform right after register; adapt/audit/animate/layout carry short platform divergence notes; all secondary spots thread `adaptive`. - a11y stays in audit.md (loading it at design time makes output timid), so the native refs carry no Accessibility section; audit.md's Platform section owns native a11y. - Tests: extractPlatform unit coverage + skill-behavior scenario 10 (PRODUCT.md platform ios -> agent loads ios.md). Source-first: only skill/, scripts/, tests/, CLAUDE.md, NOTICE.md, the changelog and version are committed; the sync workflow regenerates the provider trees and ./plugin on merge. ios.md / android.md are distilled from the MIT-licensed ehmo/platform-design-skills; attribution in NOTICE.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Address review: gate web tools on native platforms, drop version churn Maintainer-review fixes applied with AI assistance (Claude Code), on top of the rebased platform-axis commit: - Design hook (post-edit and Cursor pre-edit) now resolves the project platform via loadContext + extractPlatform and skips its web rule scan for ios / android / adaptive projects, so React Native / Flutter code never draws web-shaped findings (new hook-lib resolveProjectPlatform / isNativePlatform helpers, covered by unit and subprocess tests). - context.mjs CLI warns on an unrecognized ## Platform value (e.g. a toolchain name like `flutter`) instead of silently defaulting to web; extractRegister / extractPlatform now share extractSectionValue. - Removed reference/web.md: nothing loaded it; CLAUDE.md carries the "web has no extra rulebook" explanation. - init.md: skip live-mode config (Step 6) for native platforms; note the per-app PRODUCT.md pattern for repos shipping web + native. - android.md: Material-everywhere apps that also ship on iPhone still owe iOS OS guarantees (safe areas, Reduce Motion, edge-swipe back). - ios.md: reworded a design-time line that framed Dynamic Type as an accessibility check (a11y stays owned by audit.md). - Renumbered the new skill-behavior scenario to 14 after main's 10-13; updated CLAUDE.md scenario list; added android + unrecognized-value CLI test cases. - No version or changelog changes: versioning happens at release time. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Tighten platform reference prose Editorial pass on the platform-axis text, applied with AI assistance (Claude Code) under maintainer direction: - ios.md / android.md rewritten to house style: single-line paragraphs (no hard wraps), one-sentence scope intro, deduplicated intro/slop-test, register-compression down to two sentences. In-file attribution paragraphs removed (NOTICE.md owns attribution); "read on top of the register reference" cruft removed (SKILL step 5 and the context.mjs directive already say it). Bans sections dropped: they restated the rules above them; the two additive items (tab-bar overload, hover-dependent affordances) folded into rules. ~40% smaller each. - Sub-command Platform sections (adapt, audit, animate, layout), SKILL step 5, init.md platform prose, and the context.mjs directive trimmed the same way. Build (prose validators, counts) and both test runners green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Treat an empty PRODUCT.md section as absent, not the next heading Copilot review catch: extractSectionValue read the next `## ...` heading as the section value when a field was left empty, which made the CLI warn "value `## Product Purpose` is not recognized". Stop at the next heading and return null instead. Regression tests for extractPlatform, extractRegister, and the CLI warning path. Applied with AI assistance (Claude Code) under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Only read a token list of both native targets as adaptive Bugbot catch: after the exact platform tokens failed, any Platform line containing the words ios and android was classified adaptive, so negated or explanatory prose ("web only, not ios or android") silently loaded both native refs and skipped the hook, with no warning. The combo parse now accepts only list separators and the two platform words; anything else falls through to the CLI's unrecognized-value WARNING. Regression tests added. Applied with AI assistance (Claude Code) under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com>
246 lines
7.9 KiB
JavaScript
246 lines
7.9 KiB
JavaScript
/**
|
|
* Realistic-looking PRODUCT.md / DESIGN.md fixtures.
|
|
*
|
|
* Long enough to clear the "<200 chars / placeholder" heuristic the loader
|
|
* uses to decide whether to gate on `init`. Plausible enough that the agent
|
|
* treats them as real context rather than test scaffolding.
|
|
*/
|
|
export const PRODUCT_MD_SAMPLE = `# Acme Notes
|
|
|
|
## Register
|
|
brand
|
|
|
|
## Product Purpose
|
|
Acme Notes is a marketing-driven landing page for a research-grade note-taking
|
|
tool aimed at independent scientists and graduate students. The site needs to
|
|
communicate that the product respects the reader's intelligence — no SaaS
|
|
buzzwords, no metric-theater, no "trusted by leading teams" wallpaper.
|
|
|
|
## Users
|
|
Working researchers (PhD students, postdocs, principal investigators) who
|
|
already maintain disciplined note-taking systems and are choosing between
|
|
ours and rolling their own in a Zettelkasten plugin.
|
|
|
|
## Brand
|
|
Editorial, considered, technical. The product is for people who quote
|
|
Knuth. The voice is closer to a long-read magazine than to a startup
|
|
landing page.
|
|
|
|
## Anti-references
|
|
- Notion (too consumer / too rounded)
|
|
- Obsidian (too community-cottagecore)
|
|
- Any SaaS landing page with a hero-metric grid
|
|
|
|
## Strategic Principles
|
|
- Type does most of the work. The hero is words, not chrome.
|
|
- One named accent color, used sparingly.
|
|
- Never lead with screenshots. Lead with the idea.
|
|
`;
|
|
|
|
/**
|
|
* Same project shape as PRODUCT_MD_SAMPLE but with no `## Register` field.
|
|
* Exercises the cascade fallback (task cue then surface in focus) in
|
|
* scenarios where context.mjs cannot detect the register and the agent
|
|
* must follow the SKILL.md priority list to pick brand.md.
|
|
*/
|
|
export const PRODUCT_MD_SAMPLE_NO_REGISTER = `# Acme Notes
|
|
|
|
## Product Purpose
|
|
Acme Notes is a marketing-driven landing page for a research-grade note-taking
|
|
tool aimed at independent scientists and graduate students. The site needs to
|
|
communicate that the product respects the reader's intelligence: no SaaS
|
|
buzzwords, no metric-theater, no "trusted by leading teams" wallpaper.
|
|
|
|
## Users
|
|
Working researchers (PhD students, postdocs, principal investigators) who
|
|
already maintain disciplined note-taking systems and are choosing between
|
|
ours and rolling their own in a Zettelkasten plugin.
|
|
|
|
## Brand
|
|
Editorial, considered, technical. The product is for people who quote
|
|
Knuth. The voice is closer to a long-read magazine than to a startup
|
|
landing page.
|
|
|
|
## Anti-references
|
|
- Notion (too consumer / too rounded)
|
|
- Obsidian (too community-cottagecore)
|
|
- Any SaaS landing page with a hero-metric grid
|
|
|
|
## Strategic Principles
|
|
- Type does most of the work. The hero is words, not chrome.
|
|
- One named accent color, used sparingly.
|
|
- Never lead with screenshots. Lead with the idea.
|
|
`;
|
|
|
|
/**
|
|
* Native iOS app fixture: product register, `## Platform` set to `ios`.
|
|
* Exercises Setup step 5 — when context.mjs reports the platform is native,
|
|
* the agent must also load `reference/ios.md` (Apple HIG) on top of the
|
|
* register reference. Product register because this is app UI, not marketing.
|
|
*/
|
|
export const PRODUCT_MD_SAMPLE_IOS = `# Tideline
|
|
|
|
## Register
|
|
product
|
|
|
|
## Platform
|
|
ios
|
|
|
|
## Product Purpose
|
|
Tideline is a native iOS app for coastal anglers: tide tables, solunar
|
|
windows, and a logbook. It SERVES the task — get in, read the conditions,
|
|
log a catch — so fluent iPhone users should trust it instantly rather than
|
|
relearn navigation. Earned familiarity over novelty.
|
|
|
|
## Users
|
|
Saltwater anglers checking conditions dockside on an iPhone, often one-handed
|
|
in bright sun and sometimes offline. They live in Apple Weather, Notes, and
|
|
Maps and expect the same gestures and controls here.
|
|
|
|
## Brand
|
|
Calm, legible, marine. Identity shows through color, type accent, and the
|
|
logbook's character — never by reinventing the navigation bar or the back
|
|
gesture.
|
|
|
|
## Anti-references
|
|
- Web dashboards ported into a WebView
|
|
- Custom toggles and bespoke tab bars that fight the platform
|
|
- Cluttered, metric-theater home screens
|
|
|
|
## Strategic Principles
|
|
- Platform conformance is the structural bar; brand lives in the expressive layer.
|
|
- Standard navigation, SF Symbols, Dynamic Type, Dark Mode first-class.
|
|
- One accent tint drives interactive elements.
|
|
`;
|
|
|
|
/**
|
|
* Tiny static landing page fixture for scenarios that invoke sub-commands
|
|
* (polish, audit) without standing up a full framework project. Gives the
|
|
* agent something concrete to inspect so it doesn't bail with "what
|
|
* should I work on?" before completing Setup.
|
|
*/
|
|
export const MINIMAL_LANDING_HTML = `<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Acme Notes</title>
|
|
<style>
|
|
:root { --ink: #1a1a1a; --paper: #fafafa; --accent: #b7410e; }
|
|
body { background: var(--paper); color: var(--ink); font-family: serif; max-width: 65ch; margin: 4rem auto; padding: 0 1.5rem; }
|
|
h1 { font-size: 3rem; letter-spacing: -0.02em; line-height: 1.05; }
|
|
a.cta { display: inline-block; background: var(--accent); color: var(--paper); padding: 0.5rem 1rem; text-decoration: none; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h1>For those who build their own index.</h1>
|
|
<p>Acme Notes is not a productivity tool. It is an archive, designed for the researcher who treats their notes as an external brain.</p>
|
|
<a class="cta" href="#start">Begin Archive</a>
|
|
</body>
|
|
</html>
|
|
`;
|
|
|
|
/**
|
|
* Minimal SvelteKit project. Exercises Setup step 2 ("familiarize
|
|
* yourself with any existing design system, conventions, and components"):
|
|
* the agent should explore at least one of these code files before
|
|
* producing a polish or craft pass.
|
|
*/
|
|
export const SVELTE_PROJECT_FILES = {
|
|
'package.json': `${JSON.stringify(
|
|
{
|
|
name: 'acme-notes',
|
|
type: 'module',
|
|
dependencies: { svelte: '^4.0.0', '@sveltejs/kit': '^2.0.0' },
|
|
scripts: { dev: 'vite dev', build: 'vite build' },
|
|
},
|
|
null,
|
|
2,
|
|
)}\n`,
|
|
'svelte.config.js': `import adapter from '@sveltejs/adapter-auto';
|
|
|
|
export default {
|
|
kit: { adapter: adapter() },
|
|
};
|
|
`,
|
|
'src/app.css': `:root {
|
|
--ink: oklch(0.16 0.02 250);
|
|
--paper: oklch(0.98 0.01 90);
|
|
--accent: oklch(0.55 0.18 28);
|
|
--hairline: oklch(0.16 0.02 250 / 0.08);
|
|
}
|
|
|
|
body {
|
|
background: var(--paper);
|
|
color: var(--ink);
|
|
font-family: 'Inter', sans-serif;
|
|
line-height: 1.55;
|
|
}
|
|
`,
|
|
'src/lib/components/Button.svelte': `<script>
|
|
export let variant = 'primary';
|
|
</script>
|
|
|
|
<button class="btn btn-{variant}">
|
|
<slot />
|
|
</button>
|
|
|
|
<style>
|
|
.btn { font: inherit; border: 0; cursor: pointer; padding: 0.5rem 1rem; }
|
|
.btn-primary { background: var(--accent); color: var(--paper); }
|
|
.btn-ghost { background: transparent; color: var(--ink); border-bottom: 1px solid currentColor; }
|
|
</style>
|
|
`,
|
|
'src/lib/components/Card.svelte': `<div class="card">
|
|
<slot />
|
|
</div>
|
|
|
|
<style>
|
|
.card {
|
|
border-top: 1px solid var(--hairline);
|
|
padding: 2rem 0;
|
|
}
|
|
</style>
|
|
`,
|
|
'src/routes/+page.svelte': `<script>
|
|
import Button from '$lib/components/Button.svelte';
|
|
import Card from '$lib/components/Card.svelte';
|
|
</script>
|
|
|
|
<svelte:head>
|
|
<title>Acme Notes</title>
|
|
</svelte:head>
|
|
|
|
<main>
|
|
<h1>For those who build their own index.</h1>
|
|
<p>Acme Notes is not a productivity tool. It is an archive.</p>
|
|
<Button>Begin Archive</Button>
|
|
<Card>Some featured content.</Card>
|
|
</main>
|
|
`,
|
|
};
|
|
|
|
export const DESIGN_MD_SAMPLE = `# Acme Notes — Design System
|
|
|
|
## Colors
|
|
- \`--ink\`: oklch(0.16 0.02 250) — body copy
|
|
- \`--paper\`: oklch(0.98 0.01 90) — body background
|
|
- \`--accent\`: oklch(0.55 0.18 28) — terracotta, used at <8% surface
|
|
|
|
## Typography
|
|
- Display: GT Sectra (commercial), 700, tracking -0.02em
|
|
- Body: Inter, 400, 1.55 line-height, 65ch max
|
|
- Mono: JetBrains Mono, 400 (rare, only for callouts)
|
|
|
|
## Spacing
|
|
Multi-modular scale: 4 / 8 / 12 / 24 / 48 / 96 px.
|
|
|
|
## Elevation
|
|
Mostly flat. A single 1px hairline border at oklch(0.16 0.02 250 / 0.08)
|
|
separates major regions. No drop shadows under 16px blur.
|
|
|
|
## Components
|
|
- Buttons: text-only by default; a single solid primary in accent for CTAs.
|
|
- Cards: avoid; prefer hairlined regions and inline lists.
|
|
- Forms: floating labels, no border on the input — underline only.
|
|
`;
|