@techninja/clearstack 0.2.16 → 0.2.18

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 (36) hide show
  1. package/docs/BACKEND_API_SPEC.md +85 -48
  2. package/docs/BUILD_LOG.md +42 -19
  3. package/docs/COMPONENT_PATTERNS.md +57 -51
  4. package/docs/CONVENTIONS.md +43 -31
  5. package/docs/FRONTEND_IMPLEMENTATION_RULES.md +57 -58
  6. package/docs/JSDOC_TYPING.md +1 -0
  7. package/docs/QUICKSTART.md +20 -18
  8. package/docs/SERVER_AND_DEPS.md +28 -29
  9. package/docs/STATE_AND_ROUTING.md +53 -52
  10. package/docs/TESTING.md +38 -37
  11. package/docs/app-spec/ENTITIES.md +16 -16
  12. package/docs/app-spec/README.md +4 -4
  13. package/lib/check.js +3 -1
  14. package/lib/package-gen.js +3 -0
  15. package/package.json +5 -2
  16. package/templates/fullstack/data/seed.json +1 -1
  17. package/templates/shared/.configs/.markdownlint.jsonc +9 -0
  18. package/templates/shared/.configs/.stylelintrc.json +16 -0
  19. package/templates/shared/.configs/jsconfig.json +2 -9
  20. package/templates/shared/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
  21. package/templates/shared/.github/ISSUE_TEMPLATE/feature_request.md +1 -1
  22. package/templates/shared/.github/ISSUE_TEMPLATE/spec_correction.md +1 -1
  23. package/templates/shared/.github/pull_request_template.md +3 -0
  24. package/templates/shared/.github/workflows/spec.yml +3 -3
  25. package/templates/shared/docs/app-spec/README.md +8 -8
  26. package/templates/shared/docs/clearstack/BACKEND_API_SPEC.md +85 -48
  27. package/templates/shared/docs/clearstack/BUILD_LOG.md +42 -19
  28. package/templates/shared/docs/clearstack/COMPONENT_PATTERNS.md +57 -51
  29. package/templates/shared/docs/clearstack/CONVENTIONS.md +43 -31
  30. package/templates/shared/docs/clearstack/FRONTEND_IMPLEMENTATION_RULES.md +57 -58
  31. package/templates/shared/docs/clearstack/JSDOC_TYPING.md +1 -0
  32. package/templates/shared/docs/clearstack/QUICKSTART.md +20 -18
  33. package/templates/shared/docs/clearstack/SERVER_AND_DEPS.md +28 -29
  34. package/templates/shared/docs/clearstack/STATE_AND_ROUTING.md +53 -52
  35. package/templates/shared/docs/clearstack/TESTING.md +38 -37
  36. package/templates/shared/src/public/index.html +23 -23
@@ -1,4 +1,5 @@
1
1
  # State & Routing
2
+
2
3
  ## Store, Routing, Unified App State & Realtime Sync
3
4
 
4
5
  > How data flows through the application.
@@ -19,7 +20,11 @@ export default define({
19
20
  tag: 'app-toggle',
20
21
  open: false,
21
22
  render: ({ open }) => html`
22
- <button onclick="${host => { host.open = !host.open; }}">
23
+ <button
24
+ onclick="${(host) => {
25
+ host.open = !host.open;
26
+ }}"
27
+ >
23
28
  ${open ? 'Close' : 'Open'}
24
29
  </button>
25
30
  `,
@@ -85,9 +90,11 @@ export default define({
85
90
  tag: 'theme-toggle',
86
91
  state: store(AppState),
87
92
  render: ({ state }) => html`
88
- <button onclick="${host => {
89
- store.set(host.state, { theme: host.state.theme === 'light' ? 'dark' : 'light' });
90
- }}">
93
+ <button
94
+ onclick="${(host) => {
95
+ store.set(host.state, { theme: host.state.theme === 'light' ? 'dark' : 'light' });
96
+ }}"
97
+ >
91
98
  Theme: ${state.theme}
92
99
  </button>
93
100
  `,
@@ -114,13 +121,14 @@ const UserModel = {
114
121
  lastName: '',
115
122
  email: '',
116
123
  [store.connect]: {
117
- get: (id) => fetch(`/api/users/${id}`).then(r => r.json()),
118
- set: (id, values) => fetch(`/api/users/${id}`, {
119
- method: 'PUT',
120
- headers: { 'Content-Type': 'application/json' },
121
- body: JSON.stringify(values),
122
- }).then(r => r.json()),
123
- list: (id) => fetch(`/api/users?${new URLSearchParams(id)}`).then(r => r.json()),
124
+ get: (id) => fetch(`/api/users/${id}`).then((r) => r.json()),
125
+ set: (id, values) =>
126
+ fetch(`/api/users/${id}`, {
127
+ method: 'PUT',
128
+ headers: { 'Content-Type': 'application/json' },
129
+ body: JSON.stringify(values),
130
+ }).then((r) => r.json()),
131
+ list: (id) => fetch(`/api/users?${new URLSearchParams(id)}`).then((r) => r.json()),
124
132
  },
125
133
  };
126
134
 
@@ -129,19 +137,19 @@ export default UserModel;
129
137
 
130
138
  #### Store API Quick Reference
131
139
 
132
- | Method | Purpose |
133
- |---|---|
134
- | `store(Model)` | Descriptor — binds model to a component property |
135
- | `store.get(Model, id)` | Get a cached instance (triggers fetch if needed) |
136
- | `store.set(model, values)` | Update (async, returns Promise) |
137
- | `store.sync(model, values)` | Update (sync, immediate) |
138
- | `store.pending(model)` | `false` or `Promise` while loading |
139
- | `store.ready(model)` | `true` when loaded and valid |
140
- | `store.error(model)` | `false` or `Error` |
141
- | `store.clear(Model)` | Invalidate singular model cache |
142
- | `store.clear([Model])` | Invalidate list cache — **required for list stores** |
143
- | `store.submit(draft)` | Submit draft mode changes |
144
- | `store.resolve(Model, id)` | Returns Promise that resolves when ready |
140
+ | Method | Purpose |
141
+ | --------------------------- | ---------------------------------------------------- |
142
+ | `store(Model)` | Descriptor — binds model to a component property |
143
+ | `store.get(Model, id)` | Get a cached instance (triggers fetch if needed) |
144
+ | `store.set(model, values)` | Update (async, returns Promise) |
145
+ | `store.sync(model, values)` | Update (sync, immediate) |
146
+ | `store.pending(model)` | `false` or `Promise` while loading |
147
+ | `store.ready(model)` | `true` when loaded and valid |
148
+ | `store.error(model)` | `false` or `Error` |
149
+ | `store.clear(Model)` | Invalidate singular model cache |
150
+ | `store.clear([Model])` | Invalidate list cache — **required for list stores** |
151
+ | `store.submit(draft)` | Submit draft mode changes |
152
+ | `store.resolve(Model, id)` | Returns Promise that resolves when ready |
145
153
 
146
154
  #### Decision Tree: Local vs Shared State
147
155
 
@@ -161,13 +169,12 @@ clear triggers re-fetch). Always guard property access on list items:
161
169
 
162
170
  ```javascript
163
171
  // ❌ BAD — task may be pending, accessing .title throws
164
- tasks.map((task) => html`<span>${task.title}</span>`)
172
+ tasks.map((task) => html`<span>${task.title}</span>`);
165
173
 
166
174
  // ✅ GOOD — guard each item, show fallback for pending items
167
- tasks.map((task) => store.ready(task)
168
- ? html`<span>${task.title}</span>`
169
- : html`<span class="spinner"></span>`
170
- )
175
+ tasks.map((task) =>
176
+ store.ready(task) ? html`<span>${task.title}</span>` : html`<span class="spinner"></span>`,
177
+ );
171
178
  ```
172
179
 
173
180
  This is especially important after batch operations (e.g. drag reorder)
@@ -189,11 +196,7 @@ import HomeView from '../pages/home/index.js';
189
196
  export default define({
190
197
  tag: 'app-router',
191
198
  stack: router(HomeView, { url: '/' }),
192
- render: ({ stack }) => html`
193
- <template layout="column height::100vh">
194
- ${stack}
195
- </template>
196
- `,
199
+ render: ({ stack }) => html` <template layout="column height::100vh"> ${stack} </template> `,
197
200
  });
198
201
  ```
199
202
 
@@ -222,14 +225,14 @@ export default define({
222
225
 
223
226
  ### Routing Patterns
224
227
 
225
- | Pattern | Code |
226
- |---|---|
227
- | Navigate to view | `<a href="${router.url(View)}">` |
228
- | Navigate with params | `router.url(View, { id: '42' })` |
229
- | Back button | `<a href="${router.backUrl()}">Back</a>` |
230
- | Check active view | `router.active(View)` |
231
- | Guarded route | `guard: () => isAuthenticated()` |
232
- | Dialog overlay | `dialog: true` on the view config |
228
+ | Pattern | Code |
229
+ | -------------------- | ---------------------------------------- |
230
+ | Navigate to view | `<a href="${router.url(View)}">` |
231
+ | Navigate with params | `router.url(View, { id: '42' })` |
232
+ | Back button | `<a href="${router.backUrl()}">Back</a>` |
233
+ | Check active view | `router.active(View)` |
234
+ | Guarded route | `guard: () => isAuthenticated()` |
235
+ | Dialog overlay | `dialog: true` on the view config |
233
236
 
234
237
  ---
235
238
 
@@ -253,12 +256,12 @@ DOM
253
256
 
254
257
  ### AppState vs Entity Models
255
258
 
256
- | Concern | Where |
257
- |---|---|
258
- | Theme, sidebar, UI flags | `AppState` (singleton) |
259
+ | Concern | Where |
260
+ | ------------------------- | ------------------------------------- |
261
+ | Theme, sidebar, UI flags | `AppState` (singleton) |
259
262
  | User records, posts, etc. | `UserModel`, `PostModel` (enumerable) |
260
- | Form draft state | `store(Model, { draft: true })` |
261
- | Route state | `router()` — managed by hybrids |
263
+ | Form draft state | `store(Model, { draft: true })` |
264
+ | Route state | `router()` — managed by hybrids |
262
265
 
263
266
  ---
264
267
 
@@ -280,7 +283,7 @@ export function connectRealtime(url, modelMap) {
280
283
  source.addEventListener('update', (event) => {
281
284
  const { type } = JSON.parse(event.data);
282
285
  const Model = modelMap[type];
283
- if (Model) store.clear(Model); // full clear triggers re-fetch
286
+ if (Model) store.clear(Model); // full clear triggers re-fetch
284
287
  });
285
288
 
286
289
  source.addEventListener('error', () => {
@@ -326,9 +329,7 @@ export default define({
326
329
  return disconnect;
327
330
  },
328
331
  },
329
- render: ({ stack }) => html`
330
- <template layout="column height::100vh">${stack}</template>
331
- `,
332
+ render: ({ stack }) => html` <template layout="column height::100vh">${stack}</template> `,
332
333
  });
333
334
  ```
334
335
 
@@ -354,7 +355,7 @@ source.addEventListener('update', (event) => {
354
355
  const { type } = JSON.parse(event.data);
355
356
  clearTimeout(timers[type]);
356
357
  timers[type] = setTimeout(() => {
357
- store.clear([Model]); // one clear after the batch settles
358
+ store.clear([Model]); // one clear after the batch settles
358
359
  }, 300);
359
360
  });
360
361
  ```
package/docs/TESTING.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # Testing
2
+
2
3
  ## Philosophy, Tools & Patterns
3
4
 
4
5
  > How we test in a no-build web component project.
@@ -17,15 +18,15 @@ bugs at the boundary where they're introduced, not 5 layers up.
17
18
 
18
19
  ### Core Principles
19
20
 
20
- | Principle | Rule |
21
- |---|---|
22
- | Test at the right level | Pure logic → unit. Components → browser. API → integration. |
23
- | No mocking the framework | Don't mock `html`, `store`, or `define`. Test through them. |
24
- | Real browser for components | Web components need a real DOM. No jsdom, no happy-dom. |
25
- | Zero build for tests | Test files are ES modules, same as app code. |
26
- | Small test files | Same 150-line rule applies to test files. |
27
- | Test behavior, not implementation | Assert what the user sees, not internal state shape. |
28
- | Co-locate tests | Tests live next to the code they test. |
21
+ | Principle | Rule |
22
+ | --------------------------------- | ----------------------------------------------------------- |
23
+ | Test at the right level | Pure logic → unit. Components → browser. API → integration. |
24
+ | No mocking the framework | Don't mock `html`, `store`, or `define`. Test through them. |
25
+ | Real browser for components | Web components need a real DOM. No jsdom, no happy-dom. |
26
+ | Zero build for tests | Test files are ES modules, same as app code. |
27
+ | Small test files | Same 150-line rule applies to test files. |
28
+ | Test behavior, not implementation | Assert what the user sees, not internal state shape. |
29
+ | Co-locate tests | Tests live next to the code they test. |
29
30
 
30
31
  ---
31
32
 
@@ -33,10 +34,10 @@ bugs at the boundary where they're introduced, not 5 layers up.
33
34
 
34
35
  ### Two Test Runners, Clear Boundaries
35
36
 
36
- | Tool | Tests | Runs in |
37
- |---|---|---|
38
- | `node:test` (built-in) | Server, utils, store model shapes | Node.js |
39
- | `@web/test-runner` | Components, pages, browser integration | Real Chromium |
37
+ | Tool | Tests | Runs in |
38
+ | ---------------------- | -------------------------------------- | ------------- |
39
+ | `node:test` (built-in) | Server, utils, store model shapes | Node.js |
40
+ | `@web/test-runner` | Components, pages, browser integration | Real Chromium |
40
41
 
41
42
  No other test frameworks. No Jest, no Mocha, no Jasmine.
42
43
 
@@ -77,24 +78,24 @@ server.test.js ← node:test
77
78
 
78
79
  ### Test File Naming
79
80
 
80
- | Code file | Test file |
81
- |---|---|
81
+ | Code file | Test file |
82
+ | --------------- | -------------------- |
82
83
  | `app-button.js` | `app-button.test.js` |
83
84
  | `formatDate.js` | `formatDate.test.js` |
84
- | `UserModel.js` | `UserModel.test.js` |
85
- | `src/server.js` | `server.test.js` |
85
+ | `UserModel.js` | `UserModel.test.js` |
86
+ | `src/server.js` | `server.test.js` |
86
87
 
87
88
  ### What Gets Tested
88
89
 
89
- | Layer | What to assert |
90
- |---|---|
91
- | **Utils** | Input → output. Edge cases. |
90
+ | Layer | What to assert |
91
+ | ---------------- | ------------------------------------------------------------------------- |
92
+ | **Utils** | Input → output. Edge cases. |
92
93
  | **Store models** | Shape is correct. Computed fields work. Storage connector URLs are right. |
93
- | **Atoms** | Renders correct HTML. Props reflect to attributes. Events fire. |
94
- | **Molecules** | Child atoms are present. Composed behavior works. |
95
- | **Organisms** | Store integration. Data flows to children. |
96
- | **Server API** | CRUD responses. Schema endpoint. Status codes. |
97
- | **Pages** | Don't unit-test pages. Test via manual or E2E if needed. |
94
+ | **Atoms** | Renders correct HTML. Props reflect to attributes. Events fire. |
95
+ | **Molecules** | Child atoms are present. Composed behavior works. |
96
+ | **Organisms** | Store integration. Data flows to children. |
97
+ | **Server API** | CRUD responses. Schema endpoint. Status codes. |
98
+ | **Pages** | Don't unit-test pages. Test via manual or E2E if needed. |
98
99
 
99
100
  ---
100
101
 
@@ -191,7 +192,9 @@ describe('app-button', () => {
191
192
  it('dispatches click event', async () => {
192
193
  const el = await fixture(html`<app-button label="Go"></app-button>`);
193
194
  let clicked = false;
194
- el.addEventListener('click', () => { clicked = true; });
195
+ el.addEventListener('click', () => {
196
+ clicked = true;
197
+ });
195
198
  el.shadowRoot.querySelector('button').click();
196
199
  expect(clicked).to.be.true;
197
200
  });
@@ -230,9 +233,7 @@ import { playwrightLauncher } from '@web/test-runner-playwright';
230
233
  export default {
231
234
  files: 'src/components/**/*.test.js',
232
235
  nodeResolve: true,
233
- browsers: [
234
- playwrightLauncher({ product: 'chromium' }),
235
- ],
236
+ browsers: [playwrightLauncher({ product: 'chromium' })],
236
237
  };
237
238
  ```
238
239
 
@@ -255,14 +256,14 @@ export default {
255
256
 
256
257
  Each implementation phase must pass its tests before proceeding:
257
258
 
258
- | Phase | Implement | Then test |
259
- |---|---|---|
260
- | 1. Infrastructure | server, vendor script, index.html | Server starts, routes respond, vendor files exist |
261
- | 2. Store + Utils | models, formatDate, realtimeSync | Model shapes, util outputs, localStorage round-trip |
262
- | 3. Atoms | app-button, app-badge, app-icon | Render, props, events |
263
- | 4. Molecules | task-card, project-card | Composition, slot content |
264
- | 5. Organisms | task-list, project-header | Store binding, data rendering |
265
- | 6. Pages + Router | views, app-router | Navigation, full page render |
259
+ | Phase | Implement | Then test |
260
+ | ----------------- | --------------------------------- | --------------------------------------------------- |
261
+ | 1. Infrastructure | server, vendor script, index.html | Server starts, routes respond, vendor files exist |
262
+ | 2. Store + Utils | models, formatDate, realtimeSync | Model shapes, util outputs, localStorage round-trip |
263
+ | 3. Atoms | app-button, app-badge, app-icon | Render, props, events |
264
+ | 4. Molecules | task-card, project-card | Composition, slot content |
265
+ | 5. Organisms | task-list, project-header | Store binding, data rendering |
266
+ | 6. Pages + Router | views, app-router | Navigation, full page render |
266
267
 
267
268
  **Rule: never skip a checkpoint.** If phase 3 tests fail, fix before
268
269
  starting phase 4. Bugs compound; catch them at the boundary.
@@ -4,27 +4,27 @@
4
4
 
5
5
  The top-level organizational unit.
6
6
 
7
- | Field | Type | Required | Notes |
8
- |---|---|---|---|
9
- | id | string (uuid) | auto | Read-only, generated on create |
10
- | name | string | yes | 1–200 chars |
11
- | description | string | no | Max 1000 chars |
12
- | status | enum | no | `active` (default), `archived` |
13
- | createdAt | date-time | auto | Read-only |
7
+ | Field | Type | Required | Notes |
8
+ | ----------- | ------------- | -------- | ------------------------------ |
9
+ | id | string (uuid) | auto | Read-only, generated on create |
10
+ | name | string | yes | 1–200 chars |
11
+ | description | string | no | Max 1000 chars |
12
+ | status | enum | no | `active` (default), `archived` |
13
+ | createdAt | date-time | auto | Read-only |
14
14
 
15
15
  ## Task
16
16
 
17
17
  A work item belonging to a Project.
18
18
 
19
- | Field | Type | Required | Notes |
20
- |---|---|---|---|
21
- | id | string (uuid) | auto | Read-only, generated on create |
22
- | projectId | string (uuid) | yes | Foreign key → Project.id |
23
- | title | string | yes | 1–200 chars |
24
- | status | enum | no | `todo` (default), `doing`, `done` |
25
- | priority | enum | no | `low`, `med` (default), `high` |
26
- | sortOrder | number | no | Manual ordering within a project |
27
- | createdAt | date-time | auto | Read-only |
19
+ | Field | Type | Required | Notes |
20
+ | --------- | ------------- | -------- | --------------------------------- |
21
+ | id | string (uuid) | auto | Read-only, generated on create |
22
+ | projectId | string (uuid) | yes | Foreign key → Project.id |
23
+ | title | string | yes | 1–200 chars |
24
+ | status | enum | no | `todo` (default), `doing`, `done` |
25
+ | priority | enum | no | `low`, `med` (default), `high` |
26
+ | sortOrder | number | no | Manual ordering within a project |
27
+ | createdAt | date-time | auto | Read-only |
28
28
 
29
29
  ## Relationships
30
30
 
@@ -11,9 +11,9 @@ all served as raw ES modules with zero build tools.
11
11
 
12
12
  ## Features
13
13
 
14
- | Feature | Entities | Patterns Exercised |
15
- |---|---|---|
16
- | Project management | Project | CRUD, schema discovery, validation, SSE sync |
17
- | Task tracking | Task | Filtered lists, drag reorder, status enums |
14
+ | Feature | Entities | Patterns Exercised |
15
+ | ------------------ | -------- | -------------------------------------------- |
16
+ | Project management | Project | CRUD, schema discovery, validation, SSE sync |
17
+ | Task tracking | Task | Filtered lists, drag reorder, status enums |
18
18
 
19
19
  See [ENTITIES.md](./ENTITIES.md) for field definitions and relationships.
package/lib/check.js CHANGED
@@ -47,8 +47,10 @@ export async function check(projectDir, scope) {
47
47
  const results = [
48
48
  checkFiles(projectDir, cfg.codeExt, cfg.codeMax, cfg.ignore, `Code (max ${cfg.codeMax} lines)`),
49
49
  checkFiles(projectDir, cfg.docsExt, cfg.docsMax, cfg.ignore, `Docs (max ${cfg.docsMax} lines)`),
50
- runCmd('ESLint', 'npx eslint --config .configs/eslint.config.js .', projectDir),
50
+ runCmd('ESLint', 'npx eslint --config .configs/eslint.config.js . --fix', projectDir),
51
+ runCmd('Stylelint', 'npx stylelint --config .configs/.stylelintrc.json "src/**/*.css" --fix', projectDir),
51
52
  runCmd('Prettier', 'npx prettier --config .configs/.prettierrc --check src', projectDir),
53
+ runCmd('Markdown', 'npx markdownlint-cli2 --config .configs/.markdownlint.jsonc --fix "docs/**/*.md" "*.md"', projectDir),
52
54
  runCmd('JSDoc types', 'npx tsc --project .configs/jsconfig.json', projectDir),
53
55
  ];
54
56
 
@@ -43,8 +43,11 @@ export async function writePackageJson(dest, vars, existing) {
43
43
  eslint: '^10.1.0',
44
44
  'eslint-config-prettier': '^10.1.8',
45
45
  'eslint-plugin-jsdoc': '^62.8.1',
46
+ 'markdownlint-cli2': '^0.22.0',
46
47
  playwright: '^1.50.0',
47
48
  prettier: '^3.8.1',
49
+ stylelint: '^17.6.0',
50
+ 'stylelint-config-standard': '^40.0.0',
48
51
  typescript: '^6.0.2',
49
52
  };
50
53
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@techninja/clearstack",
3
- "version": "0.2.16",
3
+ "version": "0.2.18",
4
4
  "type": "module",
5
5
  "description": "A no-build web component framework specification — scaffold, validate, and evolve spec-compliant projects",
6
6
  "bin": {
@@ -23,7 +23,7 @@
23
23
  "test": "node --test tests/*.test.js src/utils/*.test.js src/store/*.test.js",
24
24
  "spec": "node --env-file=.env scripts/spec.js",
25
25
  "lint": "eslint --config .configs/eslint.config.js . --fix",
26
- "format": "prettier --config .configs/.prettierrc --write src scripts tests",
26
+ "format": "prettier --config .configs/.prettierrc --write src scripts tests templates/**/*.md templates/**/*.html templates/**/*.css templates/**/*.json",
27
27
  "typecheck": "tsc --project .configs/jsconfig.json",
28
28
  "release": "node scripts/release.js",
29
29
  "prepublishOnly": "node scripts/sync-docs.js"
@@ -54,8 +54,11 @@
54
54
  "express": "^5.2.1",
55
55
  "hybrids": "^9.1.22",
56
56
  "lucide-static": "^1.7.0",
57
+ "markdownlint-cli2": "^0.21.0",
57
58
  "playwright": "^1.50.0",
58
59
  "prettier": "^3.8.1",
60
+ "stylelint": "^17.6.0",
61
+ "stylelint-config-standard": "^40.0.0",
59
62
  "typescript": "^6.0.2",
60
63
  "ws": "^8.20.0"
61
64
  }
@@ -1 +1 @@
1
- {"example": {}}
1
+ { "example": {} }
@@ -0,0 +1,9 @@
1
+ {
2
+ "default": true,
3
+ "MD013": false,
4
+ "MD024": { "siblings_only": true },
5
+ "MD033": false,
6
+ "MD040": false,
7
+ "MD041": false,
8
+ "MD060": false,
9
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "stylelint-config-standard",
3
+ "rules": {
4
+ "import-notation": "string",
5
+ "selector-class-pattern": null,
6
+ "custom-property-pattern": null,
7
+ "no-descending-specificity": null,
8
+ "rule-empty-line-before": [
9
+ "always",
10
+ {
11
+ "except": ["first-nested"],
12
+ "ignore": ["after-comment"]
13
+ }
14
+ ]
15
+ }
16
+ }
@@ -13,13 +13,6 @@
13
13
  "hybrids": ["../node_modules/hybrids/types/index.d.ts"]
14
14
  }
15
15
  },
16
- "include": [
17
- "../src/**/*.js",
18
- "../scripts/**/*.js"
19
- ],
20
- "exclude": [
21
- "../node_modules",
22
- "../src/public/vendor",
23
- "../**/*.test.js"
24
- ]
16
+ "include": ["../src/**/*.js", "../scripts/**/*.js"],
17
+ "exclude": ["../node_modules", "../src/public/vendor", "../**/*.test.js"]
25
18
  }
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: Bug Report
3
3
  about: Something isn't working as expected
4
- title: "[Bug] "
4
+ title: '[Bug] '
5
5
  labels: bug
6
6
  ---
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: Feature Request
3
3
  about: Suggest a new feature or improvement
4
- title: "[Feature] "
4
+ title: '[Feature] '
5
5
  labels: enhancement
6
6
  ---
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: Spec Correction
3
3
  about: The spec says one thing but implementation reveals another
4
- title: "[Spec] "
4
+ title: '[Spec] '
5
5
  labels: spec
6
6
  ---
7
7
 
@@ -11,12 +11,15 @@
11
11
  <!-- List the key changes. Group by category if helpful. -->
12
12
 
13
13
  ### Added
14
+
14
15
  -
15
16
 
16
17
  ### Changed
18
+
17
19
  -
18
20
 
19
21
  ### Fixed
22
+
20
23
  -
21
24
 
22
25
  ## Spec Compliance
@@ -12,11 +12,11 @@ jobs:
12
12
  runs-on: ubuntu-latest
13
13
 
14
14
  steps:
15
- - uses: actions/checkout@v5
15
+ - uses: actions/checkout@v6
16
16
 
17
- - uses: actions/setup-node@v5
17
+ - uses: actions/setup-node@v6
18
18
  with:
19
- node-version: 20
19
+ node-version: 24
20
20
  cache: npm
21
21
 
22
22
  - run: npm ci
@@ -12,14 +12,14 @@ and architectural decisions live.
12
12
 
13
13
  ## What to Document
14
14
 
15
- | Document | Example content |
16
- |---|---|
17
- | `ENTITIES.md` | Your domain entities, their relationships, field descriptions |
18
- | `PATTERNS.md` | Project-specific component patterns, naming overrides |
19
- | `API.md` | Custom API endpoints beyond the generic CRUD |
20
- | `DEPLOYMENT.md` | How this project is built, deployed, and monitored |
21
- | `DECISIONS.md` | Architecture Decision Records — why you chose X over Y |
22
- | `OVERRIDES.md` | Where your project intentionally deviates from the base spec and why |
15
+ | Document | Example content |
16
+ | --------------- | -------------------------------------------------------------------- |
17
+ | `ENTITIES.md` | Your domain entities, their relationships, field descriptions |
18
+ | `PATTERNS.md` | Project-specific component patterns, naming overrides |
19
+ | `API.md` | Custom API endpoints beyond the generic CRUD |
20
+ | `DEPLOYMENT.md` | How this project is built, deployed, and monitored |
21
+ | `DECISIONS.md` | Architecture Decision Records — why you chose X over Y |
22
+ | `OVERRIDES.md` | Where your project intentionally deviates from the base spec and why |
23
23
 
24
24
  ## Rules
25
25