@techninja/clearstack 0.3.14 → 0.3.16

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/README.md CHANGED
@@ -50,8 +50,9 @@ npm install -D @techninja/clearstack # add to your project
50
50
  npx clearstack init # scaffold (interactive)
51
51
  npx clearstack init -y # scaffold (fullstack defaults)
52
52
  npx clearstack init --static # scaffold (static, no server)
53
+ npx clearstack update # sync docs (skip existing configs)
54
+ npx clearstack update --force # sync docs + overwrite configs
53
55
  npm run spec # check compliance
54
- npm run spec:update # sync docs + configs on upgrade
55
56
  ```
56
57
 
57
58
  Two modes: **fullstack** (Express + WebSocket + JSON DB + SSE) or **static** (localStorage, no server).
@@ -65,7 +66,7 @@ See [QUICKSTART.md](./docs/QUICKSTART.md) for the full walkthrough.
65
66
  - **Light DOM by default.** Shared styles just work.
66
67
  - **JSDoc over TypeScript.** Types without a compile step — validated by `tsc --checkJs`.
67
68
  - **Test at the boundary.** Each phase passes before the next begins.
68
- - **The spec checks itself.** `npm run spec:code` and `npm run spec:docs`.
69
+ - **The spec checks itself.** `npm run spec code` and `npm run spec docs`.
69
70
  - **Lint and format.** ESLint + Prettier, semicolons, 2-space indent.
70
71
 
71
72
  ## Scripts
@@ -78,10 +79,11 @@ npm run lint # ESLint check
78
79
  npm run lint:fix # ESLint auto-fix
79
80
  npm run format # Prettier auto-format
80
81
  npm run typecheck # JSDoc type validation via tsc
81
- npm run spec # Spec compliance check
82
- npm run spec:code # Check code files ≤150 lines
83
- npm run spec:docs # Check doc files ≤500 lines
84
- npm run spec:update # Sync docs + configs from upstream
82
+ npm run spec # Spec compliance (interactive)
83
+ npm run spec all # Full spec check
84
+ npm run spec code # Check code files ≤150 lines
85
+ npm run spec docs # Check doc files ≤500 lines
86
+ npm run spec update # Sync docs from upstream
85
87
  ```
86
88
 
87
89
  ## License
package/bin/cli.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * clearstack CLI — scaffold, update, and check spec-compliant projects.
5
5
  * Usage:
6
6
  * clearstack init [-y] [--static|--fullstack] [--port 3000]
7
- * clearstack update
7
+ * clearstack update [--force]
8
8
  * clearstack check [code|docs|imports|lint|lint es|format|types|audit|all]
9
9
  * clearstack → interactive menu
10
10
  */
@@ -54,7 +54,7 @@ async function run(action) {
54
54
  await init(PKG_ROOT, { yes, ...flags });
55
55
  } else if (action === 'update') {
56
56
  const { update } = await import('../lib/update.js');
57
- await update(PKG_ROOT);
57
+ await update(PKG_ROOT, { force: !!flags.force });
58
58
  } else if (action === 'check') {
59
59
  const subs = args.filter((a) => a !== cmd && !a.startsWith('-'));
60
60
  const { check } = await import('../lib/check.js');
@@ -298,7 +298,7 @@ multiple keys.
298
298
 
299
299
  - **One script per domain.** `test`, `spec`, `lint` — not `test:node`,
300
300
  `test:browser`, `lint:fix`, `spec:code`, `spec:docs`.
301
- - **Arguments over aliases.** `pnpm spec check code` instead of
301
+ - **Arguments over aliases.** `pnpm spec code` instead of
302
302
  `pnpm spec:code`. The CLI handles routing.
303
303
  - **Interactive by default.** Running `pnpm spec` with no arguments shows
304
304
  a menu of available actions. Users discover commands by using the tool.
@@ -43,7 +43,7 @@ If a `package.json` already exists, Clearstack merges into it — your existing
43
43
 
44
44
  ```
45
45
  your-project/
46
- ├── .configs/ # Managedsynced on update
46
+ ├── .configs/ # ✏️ Scaffolded once yours to customize
47
47
  ├── .github/ # CI workflow, PR + issue templates
48
48
  ├── docs/
49
49
  │ ├── clearstack/ # ⟳ Managed — spec docs, synced on update
@@ -108,14 +108,16 @@ When Clearstack releases a new version:
108
108
 
109
109
  ```bash
110
110
  npm update @techninja/clearstack # bump the package
111
- npm run spec:update # sync docs + configs
111
+ npm run spec update # sync docs, skip existing configs
112
+ npm run spec update --force # sync docs + overwrite configs
112
113
  git diff docs/ .configs/ # review what changed
113
114
  ```
114
115
 
115
116
  This updates:
116
117
 
117
- - `docs/clearstack/*.md` — spec documentation
118
- - `.configs/*` — linter, formatter, type checker, test runner configs
118
+ - `docs/clearstack/*.md` — spec documentation (always overwritten)
119
+ - `.configs/*` — skipped if already exists (your customizations are safe)
120
+ - `.configs/*` with `--force` — overwritten with latest defaults
119
121
 
120
122
  This never touches:
121
123
 
@@ -127,12 +129,16 @@ This never touches:
127
129
  ## 8. Spec Compliance
128
130
 
129
131
  ```bash
130
- npm run spec # full check via clearstack binary
131
- npm run spec:code # code files ≤150 lines
132
- npm run spec:docs # doc files ≤500 lines
133
- npm run lint:fix # ESLint auto-fix
134
- npm run format # Prettier auto-format
135
- npm run typecheck # JSDoc type validation
132
+ npm run spec # interactive menu
133
+ npm run spec all # full check
134
+ npm run spec code # code files ≤150 lines
135
+ npm run spec docs # doc files ≤500 lines
136
+ npm run spec lint # ESLint + Stylelint + Markdown
137
+ npm run spec lint es # ESLint only
138
+ npm run spec format # Prettier
139
+ npm run spec imports # import map aliases
140
+ npm run spec types # JSDoc type validation
141
+ npm run spec audit # security audit
136
142
  npm test # Node + browser tests
137
143
  ```
138
144
 
@@ -153,21 +159,21 @@ SPEC_IGNORE_DIRS=node_modules,src/vendor,.git,.configs
153
159
  The scaffolded `.github/workflows/spec.yml` runs all checks on every PR:
154
160
 
155
161
  ```
156
- spec:code spec:docs → lint format typecheck test
162
+ spec all → lint + format + code + docs + imports + types + audit
157
163
  ```
158
164
 
159
165
  ## Summary
160
166
 
161
- | Task | Command |
162
- | --------------------- | -------------------------------------- |
163
- | Install Clearstack | `npm install -D @techninja/clearstack` |
164
- | Scaffold (fullstack) | `npx clearstack init` |
165
- | Scaffold (static) | `npx clearstack init --static` |
166
- | Install dependencies | `npm install` |
167
- | Start dev server | `npm run dev` |
168
- | Lint + format | `npm run lint:fix && npm run format` |
169
- | Type check | `npm run typecheck` |
170
- | Run tests | `npm test` |
171
- | Full spec check | `npm run spec` |
172
- | Update spec + configs | `npm run spec:update` |
173
- | Review spec changes | `git diff docs/ .configs/` |
167
+ | Task | Command |
168
+ | --------------------- | ------------------------------------------ |
169
+ | Install Clearstack | `npm install -D @techninja/clearstack` |
170
+ | Scaffold (fullstack) | `npx clearstack init` |
171
+ | Scaffold (static) | `npx clearstack init --static` |
172
+ | Install dependencies | `npm install` |
173
+ | Start dev server | `npm run dev` |
174
+ | Lint + format | `npm run spec lint && npm run spec format` |
175
+ | Type check | `npm run typecheck` |
176
+ | Run tests | `npm test` |
177
+ | Full spec check | `npm run spec` |
178
+ | Update spec + configs | `npm run spec update` |
179
+ | Review spec changes | `git diff docs/ .configs/` |
package/lib/check.js CHANGED
@@ -42,11 +42,9 @@ export function loadConfig(projectDir) {
42
42
  };
43
43
  }
44
44
 
45
- /**
46
- * Build check commands for the detected package manager.
47
- * @param {string} runner
48
- */
49
- function buildCmds(runner) {
45
+ /** Build check commands for the detected package manager. */
46
+ export function buildCmds(projectDir) {
47
+ const runner = detectRunner(projectDir);
50
48
  const audit = runner === 'pnpm exec' ? 'pnpm audit --prod' : 'npm audit --omit=dev';
51
49
  return {
52
50
  lint: `${runner} eslint --config .configs/eslint.config.js . --fix`,
@@ -58,8 +56,6 @@ function buildCmds(runner) {
58
56
  };
59
57
  }
60
58
 
61
- /** @deprecated Use buildCmds() instead — kept for backward compat. */
62
- export const CMDS = buildCmds('npx');
63
59
 
64
60
  /** @typedef {{ key: string, name: string, parent?: string, run: () => boolean }} Check */
65
61
 
@@ -108,10 +104,10 @@ export function parentKeys(checks) {
108
104
  return [...new Set(checks.filter((c) => c.parent).map((c) => c.parent))];
109
105
  }
110
106
 
111
- /** Run the full spec compliance check (used by clearstack CLI). */
107
+ /** Run the full spec compliance check (used by clearstack CLI and scripts/spec.js). */
112
108
  export async function check(projectDir, scope) {
113
109
  const cfg = loadConfig(projectDir);
114
- const cmds = buildCmds(detectRunner(projectDir));
110
+ const cmds = buildCmds(projectDir);
115
111
  const checks = buildChecks(projectDir, cfg, cmds);
116
112
 
117
113
  if (scope && scope !== 'all') {
@@ -127,7 +123,7 @@ export async function check(projectDir, scope) {
127
123
  return;
128
124
  }
129
125
 
130
- console.log('Running spec compliance check...\n');
126
+ console.log('🔍 Clearstack compliance checking now... 💙\n');
131
127
  const results = checks.map((c) => c.run());
132
128
  const passed = results.filter(Boolean).length;
133
129
  console.log(`\n${'='.repeat(40)}`);
@@ -21,7 +21,7 @@ export async function writePackageJson(dest, vars, existing) {
21
21
  dev: 'node --watch --env-file=.env --env-file=.env.local src/server.js',
22
22
  postinstall: 'node scripts/setup.js',
23
23
  test: 'node scripts/test.js',
24
- spec: 'clearstack',
24
+ spec: 'node scripts/spec.js',
25
25
  };
26
26
 
27
27
  const specDeps = {
package/lib/update.js CHANGED
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Spec updater — syncs docs and configs from the clearstack package.
3
- * Copies new versions so the user can review the git diff.
3
+ * Docs are overwritten (clearstack-owned). Configs skip existing files
4
+ * to preserve project customizations — use --force to overwrite.
4
5
  * @module lib/update
5
6
  */
6
7
 
@@ -8,24 +9,27 @@ import { readdirSync, readFileSync, writeFileSync, existsSync, mkdirSync } from
8
9
  import { resolve, join } from 'node:path';
9
10
 
10
11
  /**
11
- * Sync a source directory to a destination, comparing file contents.
12
+ * Sync a source directory to a destination.
12
13
  * @param {string} src
13
14
  * @param {string} dest
14
15
  * @param {string} label
16
+ * @param {{ skipExisting?: boolean }} [opts]
15
17
  * @returns {number} count of updated files
16
18
  */
17
- function syncDir(src, dest, label) {
19
+ function syncDir(src, dest, label, opts = {}) {
18
20
  if (!existsSync(src)) return 0;
19
21
  mkdirSync(dest, { recursive: true });
20
-
21
22
  const files = readdirSync(src).filter((f) => !f.startsWith('.spec'));
22
23
  let updated = 0;
23
24
 
24
25
  for (const file of files) {
25
- const srcContent = readFileSync(join(src, file), 'utf-8');
26
26
  const destPath = join(dest, file);
27
+ if (opts.skipExisting && existsSync(destPath)) {
28
+ console.log(` ⏭ Skipped: ${label}/${file} (exists, use --force to overwrite)`);
29
+ continue;
30
+ }
31
+ const srcContent = readFileSync(join(src, file), 'utf-8');
27
32
  const destContent = existsSync(destPath) ? readFileSync(destPath, 'utf-8') : '';
28
-
29
33
  if (srcContent !== destContent) {
30
34
  writeFileSync(destPath, srcContent);
31
35
  console.log(` ✓ Updated: ${label}/${file}`);
@@ -36,25 +40,29 @@ function syncDir(src, dest, label) {
36
40
  }
37
41
 
38
42
  /**
39
- * Update spec docs and configs from the clearstack package to the local project.
43
+ * Update spec docs and configs from the clearstack package.
40
44
  * @param {string} pkgRoot - Root of the clearstack package
45
+ * @param {{ force?: boolean }} [opts]
41
46
  */
42
- export async function update(pkgRoot) {
47
+ export async function update(pkgRoot, opts = {}) {
43
48
  const templateShared = resolve(pkgRoot, 'templates/shared');
44
49
  let total = 0;
45
50
 
46
51
  console.log('');
47
52
 
53
+ // Docs: always overwrite (clearstack-owned content)
48
54
  total += syncDir(
49
55
  resolve(templateShared, 'docs/clearstack'),
50
56
  resolve(process.cwd(), 'docs/clearstack'),
51
57
  'docs/clearstack',
52
58
  );
53
59
 
60
+ // Configs: skip existing unless --force (project may have customized)
54
61
  total += syncDir(
55
62
  resolve(templateShared, '.configs'),
56
63
  resolve(process.cwd(), '.configs'),
57
64
  '.configs',
65
+ { skipExisting: !opts.force },
58
66
  );
59
67
 
60
68
  // Merge .gitignore (append missing lines, never remove user entries)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@techninja/clearstack",
3
- "version": "0.3.14",
3
+ "version": "0.3.16",
4
4
  "type": "module",
5
5
  "description": "A no-build web component framework specification — scaffold, validate, and evolve spec-compliant projects",
6
6
  "bin": {
@@ -24,20 +24,8 @@ jobs:
24
24
  - name: Install Playwright Chromium
25
25
  run: npx playwright install chromium --with-deps
26
26
 
27
- - name: Code line counts (≤150)
28
- run: node scripts/spec.js code
29
-
30
- - name: Doc line counts (≤500)
31
- run: node scripts/spec.js docs
32
-
33
- - name: ESLint
34
- run: npx eslint --config .configs/eslint.config.js .
35
-
36
- - name: Prettier
37
- run: npx prettier --config .configs/.prettierrc --check src scripts server.js tests
38
-
39
- - name: JSDoc types (tsc --checkJs)
40
- run: npx tsc --project .configs/jsconfig.json
27
+ - name: Spec compliance
28
+ run: node scripts/spec.js all
41
29
 
42
30
  - name: Node tests
43
31
  run: node --test tests/*.test.js src/utils/*.test.js src/store/*.test.js
@@ -298,7 +298,7 @@ multiple keys.
298
298
 
299
299
  - **One script per domain.** `test`, `spec`, `lint` — not `test:node`,
300
300
  `test:browser`, `lint:fix`, `spec:code`, `spec:docs`.
301
- - **Arguments over aliases.** `pnpm spec check code` instead of
301
+ - **Arguments over aliases.** `pnpm spec code` instead of
302
302
  `pnpm spec:code`. The CLI handles routing.
303
303
  - **Interactive by default.** Running `pnpm spec` with no arguments shows
304
304
  a menu of available actions. Users discover commands by using the tool.
@@ -43,7 +43,7 @@ If a `package.json` already exists, Clearstack merges into it — your existing
43
43
 
44
44
  ```
45
45
  your-project/
46
- ├── .configs/ # Managedsynced on update
46
+ ├── .configs/ # ✏️ Scaffolded once yours to customize
47
47
  ├── .github/ # CI workflow, PR + issue templates
48
48
  ├── docs/
49
49
  │ ├── clearstack/ # ⟳ Managed — spec docs, synced on update
@@ -108,14 +108,16 @@ When Clearstack releases a new version:
108
108
 
109
109
  ```bash
110
110
  npm update @techninja/clearstack # bump the package
111
- npm run spec:update # sync docs + configs
111
+ npm run spec update # sync docs, skip existing configs
112
+ npm run spec update --force # sync docs + overwrite configs
112
113
  git diff docs/ .configs/ # review what changed
113
114
  ```
114
115
 
115
116
  This updates:
116
117
 
117
- - `docs/clearstack/*.md` — spec documentation
118
- - `.configs/*` — linter, formatter, type checker, test runner configs
118
+ - `docs/clearstack/*.md` — spec documentation (always overwritten)
119
+ - `.configs/*` — skipped if already exists (your customizations are safe)
120
+ - `.configs/*` with `--force` — overwritten with latest defaults
119
121
 
120
122
  This never touches:
121
123
 
@@ -127,12 +129,16 @@ This never touches:
127
129
  ## 8. Spec Compliance
128
130
 
129
131
  ```bash
130
- npm run spec # full check via clearstack binary
131
- npm run spec:code # code files ≤150 lines
132
- npm run spec:docs # doc files ≤500 lines
133
- npm run lint:fix # ESLint auto-fix
134
- npm run format # Prettier auto-format
135
- npm run typecheck # JSDoc type validation
132
+ npm run spec # interactive menu
133
+ npm run spec all # full check
134
+ npm run spec code # code files ≤150 lines
135
+ npm run spec docs # doc files ≤500 lines
136
+ npm run spec lint # ESLint + Stylelint + Markdown
137
+ npm run spec lint es # ESLint only
138
+ npm run spec format # Prettier
139
+ npm run spec imports # import map aliases
140
+ npm run spec types # JSDoc type validation
141
+ npm run spec audit # security audit
136
142
  npm test # Node + browser tests
137
143
  ```
138
144
 
@@ -153,21 +159,21 @@ SPEC_IGNORE_DIRS=node_modules,src/vendor,.git,.configs
153
159
  The scaffolded `.github/workflows/spec.yml` runs all checks on every PR:
154
160
 
155
161
  ```
156
- spec:code spec:docs → lint format typecheck test
162
+ spec all → lint + format + code + docs + imports + types + audit
157
163
  ```
158
164
 
159
165
  ## Summary
160
166
 
161
- | Task | Command |
162
- | --------------------- | -------------------------------------- |
163
- | Install Clearstack | `npm install -D @techninja/clearstack` |
164
- | Scaffold (fullstack) | `npx clearstack init` |
165
- | Scaffold (static) | `npx clearstack init --static` |
166
- | Install dependencies | `npm install` |
167
- | Start dev server | `npm run dev` |
168
- | Lint + format | `npm run lint:fix && npm run format` |
169
- | Type check | `npm run typecheck` |
170
- | Run tests | `npm test` |
171
- | Full spec check | `npm run spec` |
172
- | Update spec + configs | `npm run spec:update` |
173
- | Review spec changes | `git diff docs/ .configs/` |
167
+ | Task | Command |
168
+ | --------------------- | ------------------------------------------ |
169
+ | Install Clearstack | `npm install -D @techninja/clearstack` |
170
+ | Scaffold (fullstack) | `npx clearstack init` |
171
+ | Scaffold (static) | `npx clearstack init --static` |
172
+ | Install dependencies | `npm install` |
173
+ | Start dev server | `npm run dev` |
174
+ | Lint + format | `npm run spec lint && npm run spec format` |
175
+ | Type check | `npm run typecheck` |
176
+ | Run tests | `npm test` |
177
+ | Full spec check | `npm run spec` |
178
+ | Update spec + configs | `npm run spec update` |
179
+ | Review spec changes | `git diff docs/ .configs/` |
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Spec enforcement — interactive menu + CLI shortcuts.
5
+ * Delegates all check logic to @techninja/clearstack.
6
+ * @module scripts/spec
7
+ */
8
+
9
+ import {
10
+ loadConfig,
11
+ buildChecks,
12
+ buildCmds,
13
+ resolveChecks,
14
+ parentKeys,
15
+ check,
16
+ } from '@techninja/clearstack/lib/check.js';
17
+
18
+ const ROOT = new URL('..', import.meta.url).pathname.replace(/\/$/, '');
19
+ const [sub, subsub] = process.argv.slice(2);
20
+ const scope = subsub ? `${sub} ${subsub}` : sub;
21
+
22
+ if (scope) {
23
+ await check(ROOT, scope);
24
+ } else {
25
+ await interactive(ROOT);
26
+ }
27
+
28
+ /** Show interactive menu, then run the selected check. */
29
+ async function interactive(dir) {
30
+ const cfg = loadConfig(dir);
31
+ const checks = buildChecks(dir, cfg, buildCmds(dir));
32
+ try {
33
+ const { select } = await import('@inquirer/prompts');
34
+ const action = await select({
35
+ message: 'Spec checker — what do you want to validate?',
36
+ choices: menuChoices(checks),
37
+ });
38
+ await check(dir, action);
39
+ } catch (e) {
40
+ if (e?.name === 'ExitPromptError') process.exit(0);
41
+ throw e;
42
+ }
43
+ }
44
+
45
+ /** Build interactive menu choices with hierarchy. */
46
+ function menuChoices(checks) {
47
+ const choices = [];
48
+ const seen = new Set();
49
+ for (const c of checks) {
50
+ if (c.parent && !seen.has(c.parent)) {
51
+ seen.add(c.parent);
52
+ const kids = checks.filter((k) => k.parent === c.parent);
53
+ const label = kids.map((k) => k.name).join(' + ');
54
+ choices.push({ name: `${label} [${c.parent}]`, value: c.parent });
55
+ for (const k of kids)
56
+ choices.push({ name: ` ${k.name} [${c.parent} ${k.key}]`, value: `${c.parent} ${k.key}` });
57
+ } else if (!c.parent) {
58
+ choices.push({ name: `${c.name} [${c.key}]`, value: c.key });
59
+ }
60
+ }
61
+ choices.push({ name: 'All (full spec check)', value: 'all' });
62
+ return choices;
63
+ }