@techninja/clearstack 0.3.10 → 0.3.12
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/docs/CONVENTIONS.md
CHANGED
|
@@ -267,6 +267,25 @@ This prevents premature extraction while keeping the eventual split obvious.
|
|
|
267
267
|
function moveObj(o, dx, dy) { ... }
|
|
268
268
|
```
|
|
269
269
|
|
|
270
|
+
### When a File Exceeds 150 Lines
|
|
271
|
+
|
|
272
|
+
The **only correct response** is to split the file into two or more files.
|
|
273
|
+
Never do any of the following to reduce line count:
|
|
274
|
+
|
|
275
|
+
- Remove or shorten JSDoc comments
|
|
276
|
+
- Collapse multi-line expressions onto one line
|
|
277
|
+
- Remove blank lines between logical sections
|
|
278
|
+
- Combine unrelated functions into one
|
|
279
|
+
- Delete code that is still needed
|
|
280
|
+
|
|
281
|
+
These make the code harder to read, which defeats the purpose of the limit.
|
|
282
|
+
The limit exists to force decomposition, not compression.
|
|
283
|
+
|
|
284
|
+
The spec checker runs formatters (Prettier, ESLint `--fix`) **before**
|
|
285
|
+
counting lines, so the line count always reflects the formatted result.
|
|
286
|
+
Write code in its natural readable form, run `npm run spec all`, and if
|
|
287
|
+
a file is over the limit, split it.
|
|
288
|
+
|
|
270
289
|
---
|
|
271
290
|
|
|
272
291
|
## npm Scripts: One Entry Point Per Domain
|
|
@@ -328,6 +347,53 @@ multiple keys.
|
|
|
328
347
|
Spec is the inner dev loop — run it constantly. Tests are the commit gate —
|
|
329
348
|
run them before pushing. CI runs both, in parallel.
|
|
330
349
|
|
|
350
|
+
### Spec Output Contract
|
|
351
|
+
|
|
352
|
+
The spec checker is designed for **minimal, complete output**. Every check
|
|
353
|
+
prints exactly one line: ✅ on pass, ❌ on fail with the violating file and
|
|
354
|
+
reason. The final summary is 2 lines (`N/N checks passed`).
|
|
355
|
+
|
|
356
|
+
Total output for a passing run is ~12 lines. A failing run adds one line
|
|
357
|
+
per violation with the exact file path and what to fix.
|
|
358
|
+
|
|
359
|
+
**Do not pipe, grep, tail, or filter spec output.** It is already the
|
|
360
|
+
minimal actionable result. Filtering it discards the violation details
|
|
361
|
+
that tell you which file to fix, forcing redundant re-runs.
|
|
362
|
+
|
|
363
|
+
To narrow scope, run a targeted check instead of filtering `all`:
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
# Run everything
|
|
367
|
+
npm run spec all
|
|
368
|
+
|
|
369
|
+
# Run one check by key
|
|
370
|
+
npm run spec code # line counts (code files ≤150)
|
|
371
|
+
npm run spec docs # line counts (doc files ≤500)
|
|
372
|
+
npm run spec imports # import map aliases (no ../)
|
|
373
|
+
npm run spec types # JSDoc types (tsc --checkJs)
|
|
374
|
+
npm run spec audit # security audit
|
|
375
|
+
|
|
376
|
+
# Parent keys run all children
|
|
377
|
+
npm run spec lint # ESLint + Stylelint + Markdown lint
|
|
378
|
+
npm run spec format # Prettier (all formatters)
|
|
379
|
+
|
|
380
|
+
# Child keys run one
|
|
381
|
+
npm run spec lint es # ESLint only
|
|
382
|
+
npm run spec lint css # Stylelint only
|
|
383
|
+
npm run spec lint md # Markdown lint only
|
|
384
|
+
npm run spec format prettier
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
# ❌ Wrong — discards violation file paths
|
|
389
|
+
npm run spec all 2>&1 | tail -3
|
|
390
|
+
npm run spec all 2>&1 | grep -E "pass|fail"
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
This matters especially for LLM-assisted development: the spec output is
|
|
394
|
+
structured so an LLM can read it in one pass, identify the failing file,
|
|
395
|
+
and fix it without re-running the check. Filtering breaks that loop.
|
|
396
|
+
|
|
331
397
|
---
|
|
332
398
|
|
|
333
399
|
## Session Retrospective
|
|
@@ -478,25 +478,11 @@ re-fetches automatically.
|
|
|
478
478
|
### Debouncing Batch Operations
|
|
479
479
|
|
|
480
480
|
Operations like drag-to-reorder send multiple PUTs, each triggering an SSE
|
|
481
|
-
event. Without debouncing, each event clears the store
|
|
482
|
-
re-render while the previous render is still pending — causing cascading
|
|
483
|
-
errors.
|
|
481
|
+
event. Without debouncing, each event clears the store mid-render.
|
|
484
482
|
|
|
485
483
|
The `connectRealtime()` utility debounces by entity type: multiple SSE
|
|
486
|
-
events within 300ms trigger only one `store.clear()`.
|
|
487
|
-
|
|
484
|
+
events within 300ms trigger only one `store.clear()`. A reorder of 5 tasks
|
|
485
|
+
sends 5 PUTs → 5 SSE events → 1 store clear after the batch settles.
|
|
488
486
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
const timers = {};
|
|
492
|
-
source.addEventListener('update', (event) => {
|
|
493
|
-
const { type } = JSON.parse(event.data);
|
|
494
|
-
clearTimeout(timers[type]);
|
|
495
|
-
timers[type] = setTimeout(() => {
|
|
496
|
-
store.clear([Model]); // one clear after the batch settles
|
|
497
|
-
}, 300);
|
|
498
|
-
});
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
For the local user, the UI should not call `store.clear()` explicitly
|
|
502
|
-
after batch operations — let the debounced SSE handler do it once.
|
|
487
|
+
For the local user, don't call `store.clear()` explicitly after batch
|
|
488
|
+
operations — let the debounced SSE handler do it once.
|
package/lib/check.js
CHANGED
|
@@ -69,12 +69,6 @@ export function buildChecks(dir, cfg, cmds) {
|
|
|
69
69
|
const css = () => countFiles(dir, ['.css'], cfg.ignore);
|
|
70
70
|
const md = () => countFiles(dir, ['.md'], cfg.ignore);
|
|
71
71
|
return [
|
|
72
|
-
{ key: 'code', name: `Code (max ${cfg.codeMax} lines)`,
|
|
73
|
-
run: () => checkFileLines(dir, cfg.codeExt, cfg.codeMax, cfg.ignore, `Code (max ${cfg.codeMax} lines)`) },
|
|
74
|
-
{ key: 'docs', name: `Docs (max ${cfg.docsMax} lines)`,
|
|
75
|
-
run: () => checkFileLines(dir, cfg.docsExt, cfg.docsMax, cfg.ignore, `Docs (max ${cfg.docsMax} lines)`) },
|
|
76
|
-
{ key: 'imports', name: 'Import map aliases (no ../ imports)',
|
|
77
|
-
run: () => checkImports(dir, cfg.ignore, 'Import map aliases (no ../ imports)') },
|
|
78
72
|
{ key: 'es', name: 'ESLint', parent: 'lint',
|
|
79
73
|
run: () => runCmd('ESLint', cmds.lint, dir, `${js()} files`) },
|
|
80
74
|
{ key: 'css', name: 'Stylelint', parent: 'lint',
|
|
@@ -83,6 +77,12 @@ export function buildChecks(dir, cfg, cmds) {
|
|
|
83
77
|
run: () => runCmd('Markdown', cmds.mdlint, dir, `${md()} files`) },
|
|
84
78
|
{ key: 'prettier', name: 'Prettier', parent: 'format',
|
|
85
79
|
run: () => runCmd('Prettier', cmds.prettier, dir, `${js()} files`) },
|
|
80
|
+
{ key: 'code', name: `Code (max ${cfg.codeMax} lines)`,
|
|
81
|
+
run: () => checkFileLines(dir, cfg.codeExt, cfg.codeMax, cfg.ignore, `Code (max ${cfg.codeMax} lines)`) },
|
|
82
|
+
{ key: 'docs', name: `Docs (max ${cfg.docsMax} lines)`,
|
|
83
|
+
run: () => checkFileLines(dir, cfg.docsExt, cfg.docsMax, cfg.ignore, `Docs (max ${cfg.docsMax} lines)`) },
|
|
84
|
+
{ key: 'imports', name: 'Import map aliases (no ../ imports)',
|
|
85
|
+
run: () => checkImports(dir, cfg.ignore, 'Import map aliases (no ../ imports)') },
|
|
86
86
|
{ key: 'types', name: 'JSDoc types (tsc --checkJs)',
|
|
87
87
|
run: () => runCmd('JSDoc types', cmds.types, dir, `${js()} files`) },
|
|
88
88
|
{ key: 'audit', name: 'Security audit',
|
package/package.json
CHANGED
|
@@ -267,6 +267,25 @@ This prevents premature extraction while keeping the eventual split obvious.
|
|
|
267
267
|
function moveObj(o, dx, dy) { ... }
|
|
268
268
|
```
|
|
269
269
|
|
|
270
|
+
### When a File Exceeds 150 Lines
|
|
271
|
+
|
|
272
|
+
The **only correct response** is to split the file into two or more files.
|
|
273
|
+
Never do any of the following to reduce line count:
|
|
274
|
+
|
|
275
|
+
- Remove or shorten JSDoc comments
|
|
276
|
+
- Collapse multi-line expressions onto one line
|
|
277
|
+
- Remove blank lines between logical sections
|
|
278
|
+
- Combine unrelated functions into one
|
|
279
|
+
- Delete code that is still needed
|
|
280
|
+
|
|
281
|
+
These make the code harder to read, which defeats the purpose of the limit.
|
|
282
|
+
The limit exists to force decomposition, not compression.
|
|
283
|
+
|
|
284
|
+
The spec checker runs formatters (Prettier, ESLint `--fix`) **before**
|
|
285
|
+
counting lines, so the line count always reflects the formatted result.
|
|
286
|
+
Write code in its natural readable form, run `npm run spec all`, and if
|
|
287
|
+
a file is over the limit, split it.
|
|
288
|
+
|
|
270
289
|
---
|
|
271
290
|
|
|
272
291
|
## npm Scripts: One Entry Point Per Domain
|
|
@@ -328,6 +347,53 @@ multiple keys.
|
|
|
328
347
|
Spec is the inner dev loop — run it constantly. Tests are the commit gate —
|
|
329
348
|
run them before pushing. CI runs both, in parallel.
|
|
330
349
|
|
|
350
|
+
### Spec Output Contract
|
|
351
|
+
|
|
352
|
+
The spec checker is designed for **minimal, complete output**. Every check
|
|
353
|
+
prints exactly one line: ✅ on pass, ❌ on fail with the violating file and
|
|
354
|
+
reason. The final summary is 2 lines (`N/N checks passed`).
|
|
355
|
+
|
|
356
|
+
Total output for a passing run is ~12 lines. A failing run adds one line
|
|
357
|
+
per violation with the exact file path and what to fix.
|
|
358
|
+
|
|
359
|
+
**Do not pipe, grep, tail, or filter spec output.** It is already the
|
|
360
|
+
minimal actionable result. Filtering it discards the violation details
|
|
361
|
+
that tell you which file to fix, forcing redundant re-runs.
|
|
362
|
+
|
|
363
|
+
To narrow scope, run a targeted check instead of filtering `all`:
|
|
364
|
+
|
|
365
|
+
```bash
|
|
366
|
+
# Run everything
|
|
367
|
+
npm run spec all
|
|
368
|
+
|
|
369
|
+
# Run one check by key
|
|
370
|
+
npm run spec code # line counts (code files ≤150)
|
|
371
|
+
npm run spec docs # line counts (doc files ≤500)
|
|
372
|
+
npm run spec imports # import map aliases (no ../)
|
|
373
|
+
npm run spec types # JSDoc types (tsc --checkJs)
|
|
374
|
+
npm run spec audit # security audit
|
|
375
|
+
|
|
376
|
+
# Parent keys run all children
|
|
377
|
+
npm run spec lint # ESLint + Stylelint + Markdown lint
|
|
378
|
+
npm run spec format # Prettier (all formatters)
|
|
379
|
+
|
|
380
|
+
# Child keys run one
|
|
381
|
+
npm run spec lint es # ESLint only
|
|
382
|
+
npm run spec lint css # Stylelint only
|
|
383
|
+
npm run spec lint md # Markdown lint only
|
|
384
|
+
npm run spec format prettier
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
# ❌ Wrong — discards violation file paths
|
|
389
|
+
npm run spec all 2>&1 | tail -3
|
|
390
|
+
npm run spec all 2>&1 | grep -E "pass|fail"
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
This matters especially for LLM-assisted development: the spec output is
|
|
394
|
+
structured so an LLM can read it in one pass, identify the failing file,
|
|
395
|
+
and fix it without re-running the check. Filtering breaks that loop.
|
|
396
|
+
|
|
331
397
|
---
|
|
332
398
|
|
|
333
399
|
## Session Retrospective
|
|
@@ -478,25 +478,11 @@ re-fetches automatically.
|
|
|
478
478
|
### Debouncing Batch Operations
|
|
479
479
|
|
|
480
480
|
Operations like drag-to-reorder send multiple PUTs, each triggering an SSE
|
|
481
|
-
event. Without debouncing, each event clears the store
|
|
482
|
-
re-render while the previous render is still pending — causing cascading
|
|
483
|
-
errors.
|
|
481
|
+
event. Without debouncing, each event clears the store mid-render.
|
|
484
482
|
|
|
485
483
|
The `connectRealtime()` utility debounces by entity type: multiple SSE
|
|
486
|
-
events within 300ms trigger only one `store.clear()`.
|
|
487
|
-
|
|
484
|
+
events within 300ms trigger only one `store.clear()`. A reorder of 5 tasks
|
|
485
|
+
sends 5 PUTs → 5 SSE events → 1 store clear after the batch settles.
|
|
488
486
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
const timers = {};
|
|
492
|
-
source.addEventListener('update', (event) => {
|
|
493
|
-
const { type } = JSON.parse(event.data);
|
|
494
|
-
clearTimeout(timers[type]);
|
|
495
|
-
timers[type] = setTimeout(() => {
|
|
496
|
-
store.clear([Model]); // one clear after the batch settles
|
|
497
|
-
}, 300);
|
|
498
|
-
});
|
|
499
|
-
```
|
|
500
|
-
|
|
501
|
-
For the local user, the UI should not call `store.clear()` explicitly
|
|
502
|
-
after batch operations — let the debounced SSE handler do it once.
|
|
487
|
+
For the local user, don't call `store.clear()` explicitly after batch
|
|
488
|
+
operations — let the debounced SSE handler do it once.
|