@techninja/clearstack 0.3.36 → 0.3.38

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.
@@ -8,73 +8,120 @@ only read static HTML — they don't execute JavaScript. Since Clearstack apps a
8
8
  SPAs with a single `index.html`, every shared link shows the same generic
9
9
  metadata regardless of the actual page content.
10
10
 
11
- This is a baseline expectation for any web project in 2025. If your link preview
12
- looks sketchy, people don't click.
13
-
14
- ## Proposal
11
+ ## Solution
12
+
13
+ Clearstack generates two things from the route config:
14
+
15
+ 1. **Static HTML shells** with OG meta tags (for crawlers)
16
+ 2. **Dynamic OG images** (1200×630 PNGs rendered via Playwright)
17
+
18
+ Both are driven by the same `clearstack.routes.json` config and data sources.
19
+
20
+ ## Route Config
21
+
22
+ ```json
23
+ {
24
+ "/trait/:slug": {
25
+ "title": "{slug.name}",
26
+ "description": "{slug.description}",
27
+ "image": "{slug.cover_image.url}",
28
+ "data": "src/data/trait_manifest.json:traits",
29
+ "ogTemplate": "trait"
30
+ },
31
+ "/shop/product/:sku": {
32
+ "title": "{sku.name} | {store.name}",
33
+ "description": "{sku.description}",
34
+ "image": "{store.url}{sku.images.0}",
35
+ "data": "src/data/products.json",
36
+ "ogTemplate": "product"
37
+ }
38
+ }
39
+ ```
15
40
 
16
- Clearstack already requires routes to be defined in the app spec with metadata
17
- (title, description). The build system should use this to generate static HTML
18
- shells for each route — just enough for crawlers to read OG tags, while the SPA
19
- still handles rendering for real users.
41
+ ### Fields
20
42
 
21
- ## How it should work
43
+ | Field | Required | Description |
44
+ | -------------- | -------- | ------------------------------------------------------- |
45
+ | `title` | yes | Template string with `{path.to.data}` interpolation |
46
+ | `description` | yes | Template string for meta description |
47
+ | `image` | no | Template string for og:image URL |
48
+ | `data` | no | Data source — `filepath:jsonPath` (supports arrays/objects) |
49
+ | `ogTemplate` | no | Template name → resolves to `src/og-templates/{name}.html` |
22
50
 
23
- 1. **Spec defines routes with metadata:**
51
+ ### Data Sources
24
52
 
25
- ```yaml
26
- routes:
27
- /traits/:id:
28
- title: '{trait.emoji} {trait.name} | {app.name}'
29
- description: '{trait.description}'
30
- image: '{trait.cover_image.url}'
31
- data: trait_manifest.traits
32
- ```
53
+ - **Arrays** — each item becomes a page
54
+ - **Objects** — entries become arrays with the key set as `slug`
55
+ - **JSON path** — dot notation into nested structures (e.g. `manifest.json:traits`)
33
56
 
34
- 2. **Build reads the spec + data sources:**
35
- - For static routes (`/about`, `/pricing`): generate one HTML file
36
- - For dynamic routes (`/traits/:id`): iterate over the data source, generate
37
- one HTML file per entry
57
+ ## OG Image Templates
38
58
 
39
- 3. **Generated HTML contains:**
40
- - Correct `<title>` and `<meta name="description">`
41
- - `og:title`, `og:description`, `og:image`, `og:url`
42
- - `twitter:card`, `twitter:title`, `twitter:description`, `twitter:image`
43
- - The same `<body>` as index.html (SPA takes over client-side)
59
+ Templates are HTML files at `src/og-templates/` rendered by Playwright at
60
+ 1200×630 and screenshotted to PNG.
44
61
 
45
- 4. **Deploy serves these files:**
46
- - Cloudflare Pages / Netlify / Vercel serve the static file if it exists
47
- - Falls back to `404.html` (SPA) for routes without generated pages
62
+ ### Resolution Order
48
63
 
49
- ## Requirements
64
+ 1. `src/og-templates/{ogTemplate}.html` (route-specific)
65
+ 2. `src/og-templates/default.html` (project default)
66
+ 3. Built-in default (gradient card with title/description)
50
67
 
51
- - Zero config for basic cases (route title + description → OG tags)
52
- - Opt-in image support (from data source or static asset)
53
- - Works with any deploy target that supports static files + SPA fallback
54
- - Doesn't require a server or edge function
55
- - Build is fast (64 pages in <1s, 648 pages in <5s)
68
+ ### Template Conventions
56
69
 
57
- ## Prior art
70
+ - Use `{tokenName}` interpolation for data (word chars + dots only)
71
+ - Local assets (`src="/logo.svg"`) are inlined as data URIs automatically
72
+ - Remote images (`https://...`) load via Playwright's network
73
+ - CSS custom properties from project tokens are injected into context
74
+ - Available computed fields: `{variantsFormatted}`, `{uniqueFormatted}`
58
75
 
59
- - Asili's `scripts/build-og.js` — generates 64 trait pages from manifest data
60
- - Next.js `generateMetadata` — server-side, requires Node runtime
61
- - Astro content collections — static generation from markdown frontmatter
76
+ ### Available Context Variables
62
77
 
63
- ## Implementation notes
78
+ | Variable | Source |
79
+ | -------------------- | ----------------------------------- |
80
+ | `{title}` | Resolved + truncated route title |
81
+ | `{description}` | Resolved + truncated description |
82
+ | `{image}` | Resolved image URL |
83
+ | `{emoji}` | From item data |
84
+ | `{bg}`, `{primary}` | From project CSS tokens |
85
+ | `{variantsFormatted}`| Formatted number (K/M suffix) |
86
+ | All item fields | Spread directly (e.g. `{name}`, `{pgs_count}`) |
64
87
 
65
- This could be a `clearstack build` subcommand or a plugin:
88
+ ## CLI Commands
66
89
 
67
90
  ```bash
68
- clearstack build og # Generate OG pages from spec
69
- clearstack build # Full build including OG
91
+ # Generate OG HTML pages (for crawlers)
92
+ clearstack build og --url=https://mysite.com --out=dist
93
+
94
+ # Generate OG images (all routes)
95
+ clearstack build og-images --site=MySite --out=dist
96
+
97
+ # Generate a single image (fast iteration)
98
+ clearstack build og-images --slug=EFO_0004279 --site=MySite --out=dist/og
99
+
100
+ # Generate both HTML + images
101
+ clearstack build all --url=https://mysite.com --site=MySite --out=dist
70
102
  ```
71
103
 
72
- The spec parser already knows all routes. The data source connection is the new
73
- piece — reading from JSON manifests, markdown frontmatter, or API responses at
74
- build time.
104
+ ### Flags
105
+
106
+ | Flag | Description |
107
+ | ---------- | ------------------------------------ |
108
+ | `--out` | Output directory (default: `dist`) |
109
+ | `--url` | Base URL for og:url tags |
110
+ | `--site` | Site name for badge/branding |
111
+ | `--logo` | Logo path or URL |
112
+ | `--slug` | Single item slug (fast iteration) |
113
+
114
+ ## Requirements
115
+
116
+ - Zero config for basic cases (route title + description → OG tags)
117
+ - Custom templates per page type via `ogTemplate` field
118
+ - Design tokens (CSS variables) automatically available in templates
119
+ - Local assets inlined as data URIs (no file:// security issues)
120
+ - Fast iteration: `--slug` flag renders one image in ~2s
121
+ - Full batch: 64 pages in <60s
122
+ - Works with any static deploy target (Cloudflare Pages, Netlify, Vercel)
75
123
 
76
- ## Open questions
124
+ ## Dependencies
77
125
 
78
- - Should this live in core clearstack or as an optional plugin?
79
- - How to handle routes that need auth/user data (skip them? generic fallback?)
80
- - Image generation (dynamic OG images with text overlay) — future scope?
126
+ - **Playwright** (devDependency) for OG image rendering
127
+ - No runtime dependencies generated files are static PNGs + HTML
@@ -0,0 +1,116 @@
1
+ # Spec Workflow: LLM Sessions & Compliance
2
+
3
+ ## The Problem
4
+
5
+ LLM coding sessions move fast. Features emerge through rapid iteration,
6
+ and stopping to run `npm run spec` after every file edit creates friction
7
+ that kills creative velocity. But ignoring the spec entirely leads to
8
+ a costly batch refactor at the end — splitting files, fixing lint, and
9
+ chasing type errors across dozens of changes.
10
+
11
+ ## The Balance: Feature Checkpoints
12
+
13
+ Don't run spec after every change. Don't ignore it until deploy. Instead,
14
+ run spec at **natural feature boundaries**:
15
+
16
+ ```
17
+ Feature unit complete → npm run spec code
18
+ Section complete → npm run spec all
19
+ Pre-deploy → npm run spec all + types
20
+ ```
21
+
22
+ A "feature unit" is a logical chunk: "media grid view works," "portfolio
23
+ section complete," "name correction system done." Not every file save.
24
+
25
+ ## Project Rules for LLM Context
26
+
27
+ The biggest spec compliance gap is **the LLM not knowing the rules exist.**
28
+ Spec docs live in `docs/` but aren't automatically loaded into session
29
+ context. Fix this with a project-level rules file:
30
+
31
+ ```
32
+ .amazonq/rules/clearstack.md # Loaded every session automatically
33
+ ```
34
+
35
+ This file should state:
36
+
37
+ - The 150-line limit and what to do at 120 lines
38
+ - Decomposition patterns (what to extract when)
39
+ - Code style enforcement (so the LLM writes compliant code from the start)
40
+ - The assumption that spec watch may be running
41
+
42
+ When an LLM knows the constraint exists, it naturally writes smaller
43
+ files, adds `SPLIT CANDIDATE` comments, and avoids patterns that will
44
+ need refactoring later.
45
+
46
+ ## The SPLIT CANDIDATE Pattern
47
+
48
+ When a file passes ~120 lines during development:
49
+
50
+ ```javascript
51
+ // SPLIT CANDIDATE: keyboard handler → utils/mediaKeys.js
52
+ // SPLIT CANDIDATE: carousel template → utils/mediaCarousel.js
53
+ ```
54
+
55
+ These comments serve two purposes:
56
+
57
+ 1. Signal to the current session where to split if the file goes over
58
+ 2. Signal to a future session exactly how to decompose without re-reading
59
+
60
+ ## Spec Watch Mode (Proposed)
61
+
62
+ A dashboard that runs continuously during development:
63
+
64
+ ```bash
65
+ npm run spec --watch
66
+ ```
67
+
68
+ Displays a compact status board:
69
+
70
+ ```
71
+ ✅ code (67 files)
72
+ ✅ lint (44 files)
73
+ ⚠️ types (1 warning)
74
+ ✅ docs (12 files)
75
+ ```
76
+
77
+ When a violation occurs, it shows the error inline and provides a
78
+ copy-pasteable block the developer can drop into their LLM session:
79
+
80
+ ```
81
+ ❌ code: src/pages/media/media-detail-view.js (167 lines, max 150)
82
+ Split candidates: L45 data loading, L89 carousel template, L140 related grid
83
+ ```
84
+
85
+ This gives the LLM everything it needs to fix the issue without running
86
+ the check itself, re-reading the file, or guessing at the structure.
87
+
88
+ ## Automated Ignore Configuration
89
+
90
+ The spec checker should manage ignore paths centrally rather than
91
+ requiring manual duplication across eslint, prettier, stylelint, and
92
+ jsconfig. A single `SPEC_IGNORE_DIRS` in `.env` should propagate to
93
+ all tools automatically, or the spec checker should inject ignores
94
+ when running each tool.
95
+
96
+ Current pain: adding `src/space/` required editing 5 different config
97
+ files. It should require editing one.
98
+
99
+ ## Decomposition Patterns for Views
100
+
101
+ View components (page-level) are the most common files to exceed 150
102
+ lines because they combine: imports, data loading, state management,
103
+ keyboard handlers, and large template literals.
104
+
105
+ Extraction priority (most reusable → most specific):
106
+
107
+ | What to extract | Where to put it | When |
108
+ |----------------|-----------------|------|
109
+ | Data loading/caching | `src/utils/{feature}Loader.js` | >20 lines of fetch/transform |
110
+ | Keyboard/event handlers | `src/utils/{feature}Keys.js` | >10 lines of handler logic |
111
+ | Repeated template fragments | `src/utils/{feature}Template.js` | Used in 2+ views |
112
+ | Render sub-sections | `src/utils/{feature}Render.js` | Single view, but >30 lines |
113
+ | Shared UI (header, breadcrumb) | `src/components/` | Used site-wide |
114
+
115
+ The goal isn't to have zero logic in view files — it's to keep each
116
+ file answerable with "what does this do?" in one pass.