@smartsoft001-mobilems/claude-plugins 2.86.0 → 2.88.0

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 (47) hide show
  1. package/package.json +1 -1
  2. package/plugins/mobilems/.claude-plugin/plugin.json +1 -1
  3. package/plugins/mobilems/skills/mobilems-articles/SKILL.md +108 -0
  4. package/plugins/mobilems/skills/mobilems-articles/references/lib-contents.md +164 -0
  5. package/plugins/mobilems/skills/mobilems-articles/references/module-and-routes.md +146 -0
  6. package/plugins/mobilems/skills/mobilems-articles/references/shared-components.md +56 -0
  7. package/plugins/mobilems/skills/mobilems-articles/scripts/detect-init.sh +29 -0
  8. package/plugins/mobilems/skills/mobilems-articles/scripts/verify-module.sh +61 -0
  9. package/plugins/mobilems/skills/mobilems-events/SKILL.md +65 -0
  10. package/plugins/mobilems/skills/mobilems-events/references/lib-contents.md +212 -0
  11. package/plugins/mobilems/skills/mobilems-events/references/module-and-routes.md +113 -0
  12. package/plugins/mobilems/skills/mobilems-events/scripts/detect-init.sh +29 -0
  13. package/plugins/mobilems/skills/mobilems-events/scripts/verify-module.sh +59 -0
  14. package/plugins/mobilems/skills/mobilems-object-collections/SKILL.md +77 -0
  15. package/plugins/mobilems/skills/mobilems-object-collections/references/lib-contents.md +76 -0
  16. package/plugins/mobilems/skills/mobilems-object-collections/references/module-and-routes.md +116 -0
  17. package/plugins/mobilems/skills/mobilems-object-collections/references/shared-components.md +61 -0
  18. package/plugins/mobilems/skills/mobilems-object-collections/scripts/detect-init.sh +29 -0
  19. package/plugins/mobilems/skills/mobilems-object-collections/scripts/verify-module.sh +44 -0
  20. package/plugins/mobilems/skills/mobilems-objects/SKILL.md +80 -0
  21. package/plugins/mobilems/skills/mobilems-objects/references/lib-contents.md +68 -0
  22. package/plugins/mobilems/skills/mobilems-objects/references/module-and-routes.md +108 -0
  23. package/plugins/mobilems/skills/mobilems-objects/references/shared-components.md +69 -0
  24. package/plugins/mobilems/skills/mobilems-objects/scripts/detect-init.sh +29 -0
  25. package/plugins/mobilems/skills/mobilems-objects/scripts/verify-module.sh +51 -0
  26. package/plugins/mobilems/skills/mobilems-partners/SKILL.md +65 -0
  27. package/plugins/mobilems/skills/mobilems-partners/references/lib-contents.md +160 -0
  28. package/plugins/mobilems/skills/mobilems-partners/references/module-and-routes.md +125 -0
  29. package/plugins/mobilems/skills/mobilems-partners/scripts/detect-init.sh +29 -0
  30. package/plugins/mobilems/skills/mobilems-partners/scripts/verify-module.sh +59 -0
  31. package/plugins/mobilems/skills/mobilems-project-init/SKILL.md +151 -0
  32. package/plugins/mobilems/skills/mobilems-project-init/references/app-shell.md +115 -0
  33. package/plugins/mobilems/skills/mobilems-project-init/references/claude-config.md +44 -0
  34. package/plugins/mobilems/skills/mobilems-project-init/references/config-providers.md +203 -0
  35. package/plugins/mobilems/skills/mobilems-project-init/references/npm-deps.md +66 -0
  36. package/plugins/mobilems/skills/mobilems-project-init/references/qa-hardening.md +124 -0
  37. package/plugins/mobilems/skills/mobilems-project-init/references/server-env.md +97 -0
  38. package/plugins/mobilems/skills/mobilems-project-init/references/shared-lib.md +125 -0
  39. package/plugins/mobilems/skills/mobilems-project-init/references/tailwind-styles.md +112 -0
  40. package/plugins/mobilems/skills/mobilems-project-init/scripts/classify-shared-components.py +114 -0
  41. package/plugins/mobilems/skills/mobilems-project-init/scripts/detect-base.sh +49 -0
  42. package/plugins/mobilems/skills/mobilems-project-init/scripts/verify-init.sh +81 -0
  43. package/plugins/mobilems/skills/mobilems-thematic-publications/SKILL.md +60 -0
  44. package/plugins/mobilems/skills/mobilems-thematic-publications/references/lib-contents.md +134 -0
  45. package/plugins/mobilems/skills/mobilems-thematic-publications/references/module-and-routes.md +107 -0
  46. package/plugins/mobilems/skills/mobilems-thematic-publications/scripts/detect-init.sh +29 -0
  47. package/plugins/mobilems/skills/mobilems-thematic-publications/scripts/verify-module.sh +56 -0
@@ -0,0 +1,125 @@
1
+ # Build the foundation shared library
2
+
3
+ The shared library `libs/shared/angular` (alias `@<PREFIX>/angular`) holds the museum's shared
4
+ Angular building blocks: the `App` shell, header, footer, the generic page renderer, filters,
5
+ gallery, map, slider, carousels, content widgets, WCAG + SEO services, interceptors, pipes,
6
+ directives, tools, models, and `configs.module.ts`. Build it by copying from the reference repo's
7
+ `libs/shared/angular/src/lib` and threading `<PREFIX>` (the reference uses `@msr`).
8
+
9
+ The library starts as the base shell that exports only `environment` + `EnvironmentService` with
10
+ empty `lib/` placeholder dirs — fill those dirs with the **foundation shared components**.
11
+
12
+ ## Foundation shared components vs feature shared components
13
+
14
+ The shared library contains two kinds of shared component, separated by a simple structural rule:
15
+
16
+ - A **foundation shared component** depends only on Angular, the smartsoft framework packages, and
17
+ other foundation shared components. **Build these here.**
18
+ - A **feature shared component** imports a feature domain package
19
+ (`@smartsoft001-mobilems/objects-domain`, `…/articles-domain`, `…/public-collections-domain`) to
20
+ render that entity, e.g. the per-entity grid/list cards and the object/article gallery widgets.
21
+ Each of these belongs to its feature's module skill (`mobilems-objects`,
22
+ `mobilems-object-collections`, `mobilems-articles`), which builds it alongside the feature's npm
23
+ package. The foundation does not build them, because the foundation does not install those
24
+ packages.
25
+
26
+ This rule keeps the layering clean and lets the foundation library build on its own. The home-page
27
+ carousels (`new-objects-carousel`, `news-carousel`, `partners-carousel`) and the home page are
28
+ **foundation** shared components — they take `IObject` / `IArticle` / `IPartner` from the shared
29
+ `models/data.interface.ts` and never import a feature package, so build them here.
30
+
31
+ ## Identify the foundation set
32
+
33
+ Run `python3 scripts/classify-shared-components.py <reference-repo>/libs/shared/angular/src/lib/components`.
34
+ It prints two lists — **FOUNDATION** (build here) and **FEATURE-OWNED** (built by a module skill) —
35
+ by following imports: any component that imports a feature package, or a component that does, is
36
+ FEATURE-OWNED. A typical FEATURE-OWNED set (confirm with the classifier on your reference app) is:
37
+
38
+ | Feature shared component | Built by |
39
+ | ------------------------------------------ | ------------------------------ |
40
+ | `objects-grid-item`, `objects-list-item` | `mobilems-objects` |
41
+ | `widget/gallery-object` | `mobilems-objects` |
42
+ | `collections-grid-item` | `mobilems-object-collections` |
43
+ | `articles-grid-item`, `articles-list-item` | `mobilems-articles` (articles) |
44
+ | `news-grid-item`, `news-list-item` | `mobilems-articles` (news) |
45
+ | `widget/gallery-article` | `mobilems-articles` |
46
+
47
+ Build everything else — `app`, `header`, `footer`, `page`, the `filter*` family, `breadcrumbs`,
48
+ `pagination`, `searchbar`, `loader`, `error-retry`, `scroll-top`, `skip-links`, `wcag`, `gallery`,
49
+ `map`, `slider`, `carousel`, the three carousels above, `category-dropdown`, `dropdown`, `menu-item`,
50
+ `next-page`, `calendar`, `confirmation-modal`, `newsletter-*`, `image-info-panel`, `icons`, `tabs`,
51
+ and the `widget` container with its foundation widgets.
52
+
53
+ > Trust the script over this table for the **leaf** components (the grid/list cards and the
54
+ > `widget/gallery-*` sub-widgets) — if the reference diverges, the script is authoritative there.
55
+ > **One expected exception:** the script also lists the `widget` **container** (`components/widget`)
56
+ > as FEATURE-OWNED, because the reference container imports the feature gallery sub-widgets. That is
57
+ > not a signal to skip it — the container is foundation infrastructure. Build it (see "The widget
58
+ > container" below) registering only the foundation widgets.
59
+
60
+ ## The widget container
61
+
62
+ `components/widget/widget.component.ts` renders content blocks by mapping an `ArticleWidgetType` to a
63
+ component. The classifier flags this container FEATURE-OWNED (the reference one imports the feature
64
+ gallery sub-widgets), but build it here — it is foundation infrastructure the page renderer needs.
65
+ Build it registering only the **foundation widgets** — `text`, `image`, `video`, `audio`,
66
+ `gallery-image`, `media` — and their type-map entries; do not import or register the
67
+ `gallery-object` / `gallery-article` sub-widgets (those don't exist in the foundation). The
68
+ `mobilems-objects` / `mobilems-articles` skills add their `GALLERY_OBJECT` / `GALLERY_ARTICLE` imports
69
+ and type-map entries when they build those widgets. Build the widget barrel
70
+ (`components/widget/index.ts`) exporting the foundation widgets only.
71
+
72
+ ## models/objects.model.ts
73
+
74
+ This file holds foundation model types the shared components use (`SortType`, `KeyValue` → `dropdown`,
75
+ `AdvancedFilterType` → `filter-dictionary-input`, `FileType`, `MULTIMEDIA_DICTIONARY`,
76
+ `IModel3DObject`, `IAnimationObject`, …). Build it with those types. The one object-specific type,
77
+ `ISpecificObject extends MsObject`, is a feature type — the `mobilems-objects` skill adds it (with
78
+ the `MsObject` import) when it builds the objects module. Keep `models/index.ts` exporting
79
+ `./objects.model`.
80
+
81
+ ## The rest of the lib
82
+
83
+ Build `services/`, `pipes/`, `directives/`, `tools/`, `models/` (incl. `data.interface.ts` with
84
+ `IObject`/`IArticle`/`IPartner`), `interceptors/`, `environments/` (with the `multimediaUrl` field —
85
+ see `server-env.md`), and `configs.module.ts`. These are foundation code. Confirm with the
86
+ build-safety grep below; if any of these files imports a feature package on your reference, it is
87
+ feature code and belongs to a module skill — leave it out.
88
+
89
+ ## Barrels
90
+
91
+ - `src/index.ts` — the full barrel: re-export `./lib/components`, `./lib/services`,
92
+ `./lib/configs.module`, `./lib/models`, `./lib/pipes`, `./lib/tools`, `./lib/interceptors`,
93
+ `./lib/directives`, `./lib/environments`.
94
+ - `components/index.ts` — export the foundation shared components (and keep the `COMPONENTS` array,
95
+ which holds `AppComponent`/`FooterComponent`/`HeaderComponent`). Module skills add their feature
96
+ shared components' exports when they build them.
97
+
98
+ ## Build-safety invariant
99
+
100
+ The foundation library must build with no feature package installed. The check is positive and
101
+ authoritative — this grep over the workspace's shared lib returns nothing:
102
+
103
+ ```bash
104
+ grep -rlnE "from '@[^']*/(objects|articles|public-collections)-(domain|shell-angular|shell-dtos)'" \
105
+ libs/shared/angular/src
106
+ ```
107
+
108
+ `verify-init.sh` runs it, plus checks the `widget` container imports no gallery-object/article and
109
+ `objects.model.ts` carries no `MsObject` import.
110
+
111
+ ## project.json / build config
112
+
113
+ Keep the base's normalized `libs/shared/angular/project.json`, `ng-package.json`, `jest.config.ts`,
114
+ and tsconfigs (a full base already fixed the generator's `packages/shared/angular` leftover). Verify
115
+ `tsconfig.lib.json` keeps `"types": ["node"]` (the env code uses `process.env`). If the base's shared
116
+ lib is minimal and ships only `src/` (no `project.json`/`ng-package.json`/`jest.config.ts`/tsconfigs),
117
+ copy those from the reference and normalize their `dest`/`coverageDirectory`/paths to
118
+ `libs/shared/angular/...`.
119
+
120
+ ## Thread the prefix everywhere — including the lib's own package.json
121
+
122
+ After copying, the only reference-prefix string left should be gone. Beyond the import statements,
123
+ remember to thread `<PREFIX>` in `libs/shared/angular/package.json` `"name"` (it reads
124
+ `@<reference-prefix>/angular` in the reference → set it to `@<PREFIX>/angular`). A workspace-wide grep
125
+ for the reference prefix (`@msr/`) should return nothing.
@@ -0,0 +1,112 @@
1
+ # Tailwind (smart- prefix) layered onto scss
2
+
3
+ The base is scss-only. MobilEMS adds Tailwind with the **`smart-`** class prefix (so utilities read
4
+ `smart-flex`, `smart-container`, …) and a museum global stylesheet. Tailwind processes the scss via
5
+ postcss, so scss and Tailwind coexist — no migration.
6
+
7
+ ## 1. `tailwind.config.js` (workspace root — create verbatim, no placeholders)
8
+
9
+ ```js
10
+ /** @type {import('tailwindcss').Config} */
11
+ module.exports = {
12
+ content: ['./apps/web/src/**/*.{html,ts}', './libs/**/*.{html,ts}'],
13
+ prefix: 'smart-',
14
+ darkMode: ['class', '[class~="contrast-high"]'],
15
+ theme: {
16
+ extend: {
17
+ colors: {
18
+ primary: {
19
+ DEFAULT: '#414141',
20
+ active: 'rgb(223 223 223)',
21
+ red: 'rgb(193 18 31)',
22
+ },
23
+ dark: {
24
+ DEFAULT: '#100f0d',
25
+ yellow: '#ffff00',
26
+ },
27
+ },
28
+ gridTemplateColumns: {
29
+ 'auto-fit': 'repeat(auto-fit, minmax(min(350px, 100%), 1fr))',
30
+ },
31
+ boxShadow: {
32
+ custom:
33
+ '0px 5px 5px rgba(0, 0, 0, 0.2), 0 10px 10px rgba(0, 0, 0, 0.1), 0 20px 20px rgba(0, 0, 0, 0.15)',
34
+ },
35
+ fontFamily: {
36
+ satoshi: [
37
+ 'Satoshi',
38
+ 'Satoshi Fallback',
39
+ 'Satoshi Fallback Android',
40
+ 'sans-serif',
41
+ ],
42
+ oswald: [
43
+ 'Oswald',
44
+ 'Oswald Fallback',
45
+ 'Oswald Fallback Android',
46
+ 'sans-serif',
47
+ ],
48
+ 'fira-sans': [
49
+ 'Fira Sans',
50
+ 'Fira Sans Fallback',
51
+ 'Fira Sans Fallback Android',
52
+ 'sans-serif',
53
+ ],
54
+ },
55
+ fontWeight: { extralight: '200' },
56
+ },
57
+ },
58
+ plugins: [],
59
+ };
60
+ ```
61
+
62
+ > The `content` globs already cover `libs/**`, so feature libs added later are picked up — no edit
63
+ > needed when modules arrive. `darkMode` keys off `contrast-high` for the WCAG high-contrast toggle.
64
+
65
+ > **QA gotcha (fonts):** when the project's design swaps in its own heading font, verify it covers
66
+ > Polish diacritics (`ą ć ę ł ń ś ź ż` + uppercase). Bacasime Antique, Prata and Italiana lack them
67
+ > — titles silently render in a fallback font and QA rejects it (verified replacements: Gilda
68
+ > Display, Playfair Display). Never leave a `fontFamily` entry as an empty array — it falls back to
69
+ > system sans. See `references/qa-hardening.md` §5.
70
+
71
+ ## 2. postcss
72
+
73
+ Add Tailwind + autoprefixer to postcss. If the base has a `postcss.config.js`/`.json`, add the
74
+ plugins; otherwise create `postcss.config.js`:
75
+
76
+ ```js
77
+ module.exports = {
78
+ plugins: {
79
+ tailwindcss: {},
80
+ autoprefixer: {},
81
+ },
82
+ };
83
+ ```
84
+
85
+ Add `tailwindcss` + `autoprefixer` to `devDependencies` (resolve current lines via `npm view`). The
86
+ base `.eslintignore` already ignores `**/tailwind.config.js`.
87
+
88
+ ## 3. `apps/web/src/styles.scss` (overwrite)
89
+
90
+ **Reference mode:** copy `apps/web/src/styles.scss` from the reference repo verbatim. It is ~500
91
+ lines of pure CSS/scss — font-face metric-override fallbacks (CLS mitigation), the Tailwind
92
+ directives (`@tailwind base/components/utilities`), the swiper + leaflet css imports, `.smart-container*`
93
+ layout utilities, WCAG body classes (`text-small`/`text-large`/letter+word spacing/grayscale),
94
+ masonry column widths, fullscreen-`dialog` rules, and the Windows `forced-colors` block. It targets
95
+ some feature selectors (e.g. `app-thematic-paths-menu`) but that is harmless — CSS for absent
96
+ elements is a no-op, so copy it whole.
97
+
98
+ **Foundation-only mode:** write a minimal `styles.scss` with just the Tailwind directives + the
99
+ `@import` lines for swiper/leaflet and the `.smart-container` utility; note the rest in the TODO doc.
100
+
101
+ The structure is:
102
+
103
+ ```scss
104
+ @import 'swiper/swiper-bundle.css';
105
+ @import 'leaflet/dist/leaflet.css';
106
+
107
+ @tailwind base;
108
+ @tailwind components;
109
+ @tailwind utilities;
110
+
111
+ /* font-face fallbacks, @layer utilities { .smart-container … }, WCAG, masonry, dialogs, forced-colors */
112
+ ```
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env python3
2
+ """classify-shared-components.py <shared-lib components dir>
3
+
4
+ Split a MobilEMS shared-lib `components` tree into FOUNDATION shared components (mobilems-project-init
5
+ builds these) and FEATURE-OWNED shared components (built by the owning mobilems-<module> skill,
6
+ because they depend on a feature package).
7
+
8
+ A "component" is a directory holding a non-spec *.component.ts. It is FEATURE-OWNED when it:
9
+ 1. imports a feature package (objects/articles/public-collections/news/partners domain|shell,
10
+ or a @.../museum-<x> subpath), OR
11
+ 2. imports another FEATURE-OWNED component — by relative path or by that component's exported
12
+ symbol (transitive, to a fixpoint).
13
+
14
+ Trust this over any hand-maintained table: if the reference repo diverges, this is authoritative.
15
+ Exit 0 on success; prints two sections (FEATURE-OWNED, FOUNDATION), one path per line, relative to <dir>.
16
+ """
17
+ import os
18
+ import re
19
+ import sys
20
+
21
+ FEATURE_RE = re.compile(
22
+ r"(objects|articles|public-collections|news|partners)-(domain|shell-angular|shell-dtos)"
23
+ r"|/museum-[a-z-]+"
24
+ )
25
+ EXPORT_RE = re.compile(r"export\s+(?:class|const|interface|type)\s+([A-Za-z0-9_]+)")
26
+ IMPORT_LINE_RE = re.compile(r"^\s*import\b|from\s+['\"]")
27
+ REL_IMPORT_RE = re.compile(r"from\s+['\"](\.\.?/[^'\"]+)['\"]")
28
+
29
+
30
+ def unit_ts_files(unit):
31
+ return [
32
+ os.path.join(unit, f)
33
+ for f in os.listdir(unit)
34
+ if f.endswith(".ts") and not f.endswith(".spec.ts")
35
+ ]
36
+
37
+
38
+ def read(files):
39
+ out = []
40
+ for f in files:
41
+ try:
42
+ with open(f, encoding="utf-8") as fh:
43
+ out.append(fh.read())
44
+ except OSError:
45
+ pass
46
+ return "\n".join(out)
47
+
48
+
49
+ def main():
50
+ if len(sys.argv) != 2:
51
+ sys.exit("usage: classify-shared-components.py <shared-lib/src/lib/components>")
52
+ root = os.path.abspath(sys.argv[1])
53
+ if not os.path.isdir(root):
54
+ sys.exit(f"ERROR: not a directory: {root}")
55
+
56
+ # discover units (dirs with a non-spec *.component.ts)
57
+ units = sorted(
58
+ {
59
+ dirpath
60
+ for dirpath, _, files in os.walk(root)
61
+ if any(f.endswith(".component.ts") and not f.endswith(".spec.ts") for f in files)
62
+ }
63
+ )
64
+
65
+ text = {u: read(unit_ts_files(u)) for u in units}
66
+ imports = {u: "\n".join(l for l in text[u].splitlines() if IMPORT_LINE_RE.search(l)) for u in units}
67
+ exports = {
68
+ u: set(EXPORT_RE.findall(text[u])) for u in units
69
+ }
70
+
71
+ feature_owned = {u for u in units if FEATURE_RE.search(imports[u])}
72
+
73
+ changed = True
74
+ while changed:
75
+ changed = False
76
+ feature_owned_symbols = {}
77
+ for d in feature_owned:
78
+ for s in exports[d]:
79
+ feature_owned_symbols.setdefault(s, d)
80
+ for u in units:
81
+ if u in feature_owned:
82
+ continue
83
+ hit = False
84
+ # (a) relative import into a feature_owned unit's directory
85
+ for rel in REL_IMPORT_RE.findall(imports[u]):
86
+ target = os.path.normpath(os.path.join(u, rel))
87
+ if any(target == d or target.startswith(d + os.sep) for d in feature_owned):
88
+ hit = True
89
+ break
90
+ # (b) imports a symbol exported by a feature_owned unit
91
+ if not hit:
92
+ for s in feature_owned_symbols:
93
+ if re.search(r"\b" + re.escape(s) + r"\b", imports[u]):
94
+ hit = True
95
+ break
96
+ if hit:
97
+ feature_owned.add(u)
98
+ changed = True
99
+
100
+ def rel(u):
101
+ return os.path.relpath(u, root)
102
+
103
+ print("FEATURE-OWNED:")
104
+ for u in units:
105
+ if u in feature_owned:
106
+ print(" " + rel(u))
107
+ print("FOUNDATION:")
108
+ for u in units:
109
+ if u not in feature_owned:
110
+ print(" " + rel(u))
111
+
112
+
113
+ if __name__ == "__main__":
114
+ main()
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # detect-base.sh <workspace-root>
4
+ #
5
+ # Precondition gate for mobilems-project-init. Confirms the target is a scaffold-nx-workspace BASE
6
+ # (generic Nx + Angular-SSR shell) that has NOT yet had the MobilEMS delta applied. Portable to the
7
+ # macOS system bash (3.2) — no bash-4 features.
8
+ #
9
+ # Exit 0 → base detected, OK to apply the delta.
10
+ # Exit 3 → no base shell found (tell the user to run /smart:scaffold-nx-workspace first).
11
+ # Exit 4 → MobilEMS delta already present (init looks already applied).
12
+ set -eu
13
+
14
+ ROOT="${1:?usage: detect-base.sh <workspace-root>}"
15
+ cd "$ROOT" 2>/dev/null || { echo "ERROR: no such dir: $ROOT" >&2; exit 2; }
16
+
17
+ fail_no_base() {
18
+ echo "NOT A BASE: $1" >&2
19
+ echo "Run /smart:scaffold-nx-workspace first to create the generic Nx + Angular-SSR shell." >&2
20
+ exit 3
21
+ }
22
+
23
+ # --- base shell signals ---
24
+ [ -f apps/web/src/server.ts ] || fail_no_base "apps/web/src/server.ts missing"
25
+ [ -f apps/web/src/app/app.config.ts ] || fail_no_base "apps/web/src/app/app.config.ts missing"
26
+ [ -f apps/web/src/app/app.routes.ts ] || fail_no_base "apps/web/src/app/app.routes.ts missing"
27
+ [ -f libs/shared/angular/src/index.ts ] || fail_no_base "libs/shared/angular/src/index.ts missing"
28
+ [ -f tsconfig.base.json ] || fail_no_base "tsconfig.base.json missing"
29
+
30
+ # base app.routes.ts has no feature loadChildren yet
31
+ if grep -qE "loadChildren" apps/web/src/app/app.routes.ts; then
32
+ echo "WARNING: app.routes.ts already has loadChildren — base may already be extended." >&2
33
+ fi
34
+
35
+ # --- already-applied signals (any one → likely already MobilEMS) ---
36
+ applied=0
37
+ [ -f tailwind.config.js ] && grep -q "smart-" tailwind.config.js 2>/dev/null && applied=1
38
+ grep -q "@smartsoft001-mobilems/angular" package.json 2>/dev/null && applied=1
39
+ [ -d libs/museum-objects ] && applied=1
40
+ if [ "$applied" = 1 ]; then
41
+ echo "ALREADY APPLIED: MobilEMS signals found (tailwind smart- prefix / mobilems dep / libs/museum-*)." >&2
42
+ echo "If you meant to re-run, revert the delta first." >&2
43
+ exit 4
44
+ fi
45
+
46
+ # --- report the detected prefix (from the single tsconfig path) ---
47
+ PREFIX="$(grep -oE '@[a-z0-9-]+/angular' tsconfig.base.json | head -1 | sed -E 's#@([a-z0-9-]+)/angular#\1#')"
48
+ echo "BASE OK. Detected prefix: ${PREFIX:-<unknown — inspect tsconfig.base.json paths>}"
49
+ exit 0
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # verify-init.sh <workspace-root> <PREFIX>
4
+ #
5
+ # Post-condition check for mobilems-project-init. Asserts the MobilEMS delta landed AND the hard
6
+ # foundation is self-contained (no feature modules / no feature routes / shared lib imports no
7
+ # feature package).
8
+ # Portable to macOS system bash (3.2). Exit 0 = all pass; exit 1 = one or more checks failed.
9
+ set -eu
10
+
11
+ ROOT="${1:?usage: verify-init.sh <workspace-root> <PREFIX>}"
12
+ PREFIX="${2:?usage: verify-init.sh <workspace-root> <PREFIX>}"
13
+ cd "$ROOT" 2>/dev/null || { echo "ERROR: no such dir: $ROOT" >&2; exit 2; }
14
+
15
+ fail=0
16
+ pass() { echo " PASS: $1"; }
17
+ bad() { echo " FAIL: $1" >&2; fail=1; }
18
+
19
+ echo "== Delta applied =="
20
+ [ -f tailwind.config.js ] && grep -q "prefix: 'smart-'" tailwind.config.js && pass "tailwind smart- prefix" || bad "tailwind.config.js with smart- prefix"
21
+ grep -q "@smartsoft001-mobilems/angular" package.json && pass "mobilems framework dep" || bad "@smartsoft001-mobilems/angular in package.json"
22
+ grep -q "@ngrx/store" package.json && pass "ngrx dep" || bad "@ngrx/store in package.json"
23
+ grep -q "SharedModule.forRoot" apps/web/src/app/app.config.ts && pass "SharedModule.forRoot in app.config" || bad "SharedModule.forRoot in app.config.ts"
24
+ grep -q "SEARCH_CONFIG_TOKEN" apps/web/src/app/app.config.ts && pass "SEARCH_CONFIG_TOKEN" || bad "SEARCH_CONFIG_TOKEN in app.config.ts"
25
+ grep -q "multimediaUrl" apps/web/src/server.ts && pass "multimediaUrl in server.ts" || bad "multimediaUrl in server.ts"
26
+ grep -q "/api/translations" apps/web/src/server.ts && pass "/api/translations endpoint" || bad "/api/translations in server.ts"
27
+
28
+ echo "== QA hardening (references/qa-hardening.md) =="
29
+ # dynamic sitemap/robots endpoints (static copies shipped another museum's domain in past projects)
30
+ grep -q "sitemap.xml" apps/web/src/server.ts && pass "dynamic /sitemap.xml endpoint" || bad "/sitemap.xml endpoint in server.ts (SITE_URL-driven, never a static copy)"
31
+ grep -q "robots.txt" apps/web/src/server.ts && pass "dynamic /robots.txt endpoint" || bad "/robots.txt endpoint in server.ts (SITE_URL-driven, never a static copy)"
32
+ if ls apps/web/public/favicon.ico apps/web/src/favicon.ico >/dev/null 2>&1; then pass "favicon present"; else bad "favicon.ico missing (QA bug 'Brak ikony' in two projects)"; fi
33
+ # an empty fontFamily array silently falls back to system sans (QA-rejected typography)
34
+ if grep -qE ":\s*\[\s*\]" tailwind.config.js 2>/dev/null; then bad "empty fontFamily array in tailwind.config.js (heading font falls back to system sans)"; else pass "no empty fontFamily entries"; fi
35
+ grep -q "./lib/components" libs/shared/angular/src/index.ts && pass "shared-lib components barrel populated" || bad "components barrel in shared-lib index.ts"
36
+ [ -f .claude/settings.json ] && grep -q "flow@mobilems" .claude/settings.json && pass "flow@mobilems enabled" || bad "flow@mobilems in .claude/settings.json"
37
+
38
+ echo "== Foundation scope (no feature modules yet) =="
39
+ if ls -d libs/museum-* >/dev/null 2>&1; then bad "libs/museum-* present (feature modules are built by the module skills)"; else pass "no libs/museum-*"; fi
40
+ # feature routes reference a museum-* lib; loadChildren + the import often span lines, so match museum- anywhere
41
+ if grep -qE "museum-" apps/web/src/app/app.routes.ts; then bad "feature route (museum-*) in app.routes.ts"; else pass "no feature routes"; fi
42
+
43
+ echo "== Foundation shared library is self-contained =="
44
+ COMP=libs/shared/angular/src/lib/components
45
+ # the widget container registers only foundation widgets (feature gallery widgets are added by module skills)
46
+ WID="$COMP/widget/widget.component.ts"
47
+ if [ -f "$WID" ]; then
48
+ if grep -qE "WidgetGalleryObjectComponent|WidgetGalleryArticleComponent" "$WID"; then
49
+ bad "widget container references a feature gallery widget — build it with foundation widgets only"
50
+ else
51
+ pass "widget container has foundation widgets only"
52
+ fi
53
+ else
54
+ bad "widget container missing"
55
+ fi
56
+ # objects.model holds only the foundation model types (the object-specific ISpecificObject is feature code)
57
+ OBJMODEL=libs/shared/angular/src/lib/models/objects.model.ts
58
+ if [ -f "$OBJMODEL" ]; then
59
+ grep -qE "from '[^']*objects-domain'" "$OBJMODEL" && bad "objects.model imports MsObject — foundation holds only the generic types" || pass "objects.model holds foundation types only"
60
+ grep -qE "AdvancedFilterType|KeyValue" "$OBJMODEL" && pass "foundation model types present" || bad "foundation model types missing from objects.model.ts"
61
+ fi
62
+
63
+ echo "== Build-safety invariant: shared lib imports no feature package =="
64
+ LEAK="$(grep -rlnE "from '@[^']*/(objects|articles|public-collections)-(domain|shell-angular|shell-dtos)'" libs/shared/angular/src 2>/dev/null || true)"
65
+ if [ -n "$LEAK" ]; then
66
+ bad "shared lib still imports a feature package — foundation will not build without it:"
67
+ printf ' %s\n' $LEAK >&2
68
+ else
69
+ pass "shared lib imports no feature package"
70
+ fi
71
+
72
+ echo "== Prefix threaded =="
73
+ if grep -rq "@msr/" libs/shared/angular/src apps/web/src 2>/dev/null && [ "$PREFIX" != "msr" ]; then
74
+ bad "stray @msr/ imports (prefix not fully threaded to @$PREFIX/)"
75
+ else
76
+ pass "no stray reference-prefix imports"
77
+ fi
78
+
79
+ echo
80
+ if [ "$fail" = 0 ]; then echo "VERIFY: all checks passed."; else echo "VERIFY: FAILED — fix the items above and re-run." >&2; fi
81
+ exit "$fail"
@@ -0,0 +1,60 @@
1
+ ---
2
+ name: mobilems-thematic-publications
3
+ description: Add the museum THEMATIC PATHS / PUBLICATIONS feature module (ścieżki tematyczne) to a MobilEMS app initialized with mobilems-project-init. Use whenever the user wants to add / scaffold / wire the thematic paths / thematic publications module, the "ścieżki tematyczne" pages (list + paged publication reader with widgets), or asks to "dodaj moduł ścieżek tematycznych / publikacji tematycznych". Creates libs/museum-thematic-paths (domain + shell/angular), registers the /sciezki-tematyczne route, and adds the Articles npm packages it reuses. Requires the MobilEMS foundation to exist first.
4
+ user-invocable: true
5
+ allowed-tools: Bash, Read, Write, Edit, Glob, Grep, AskUserQuestion
6
+ ---
7
+
8
+ # MobilEMS thematic paths / publications module
9
+
10
+ Add the **thematic paths / publications** (ścieżki tematyczne) feature module on top of a MobilEMS
11
+ foundation produced by `mobilems-project-init`. This module's entire UI lives inside its own
12
+ `libs/museum-thematic-paths` library, so this skill builds that library and registers a single
13
+ top-level route.
14
+
15
+ > **Naming heads-up.** This skill is named _thematic-publications_ (the museum-domain term users say),
16
+ > but the artifact it generates is **thematic-paths**: folder `libs/museum-thematic-paths`, class
17
+ > `MuseumThematicPathsModule`, route `sciezki-tematyczne`, entity `'thematicPaths'`. Always emit the
18
+ > _thematic-paths_ names — "publications" is only the spoken alias.
19
+
20
+ The module is a list/detail feature where each entry is a multi-page publication: a `ListComponent`
21
+ of thematic paths plus an `ItemComponent` that renders a paged reader (intro, menu, page, widgets —
22
+ page-header, text, image, video, audio, image-gallery) backed by `ArticlesSharedModule.forFeature`
23
+ over the `MuseumThematicPath` entity. It REUSES the Articles shared module (like news) but with its
24
+ OWN domain entity, its OWN reducer (`getReducer`), and **no `baseQuery`**.
25
+
26
+ ## Precondition
27
+
28
+ Run `scripts/detect-init.sh <workspace-root>`. It confirms the MobilEMS foundation is present
29
+ (`SharedModule.forRoot` in `app.config.ts`, a populated shared-lib barrel). If not, tell the user to
30
+ run `/mobilems:project-init` first. Hold `<PREFIX>` (from `tsconfig.base.json`; reference uses
31
+ `@msr`) and the reference repo path (same one init used).
32
+
33
+ ## Steps
34
+
35
+ 1. **npm deps** — add `@smartsoft001-mobilems/articles-domain`,
36
+ `@smartsoft001-mobilems/articles-shell-angular`, `@smartsoft001-mobilems/articles-shell-dtos`
37
+ (this module reuses the Articles shared module — `ArticlesSharedModule` + `ArticlesService`).
38
+ Match the installed mobilems line; resolve versions at run time; do not `npm install` unless
39
+ asked. Adding is idempotent — if `mobilems-articles` already installed these, nothing changes.
40
+ 2. **Library** — create `libs/museum-thematic-paths/{domain,shell/angular}` per
41
+ `references/lib-contents.md`: copy the domain entity/interfaces/enums and the shell
42
+ (`MuseumThematicPathsModule`, routes, `+state/*`, `components/*`, `pages/{list,item}`, `services`,
43
+ `directives`), thread `<PREFIX>`. Add the two `tsconfig.base.json` paths and the
44
+ `museum-thematic-paths` commit scope.
45
+ 3. **Module + routes** — see `references/module-and-routes.md`: `MuseumThematicPathsModule` wraps
46
+ `ArticlesSharedModule.forFeature({ routing: false, config: { reducerFactory: getReducer, type: MuseumThematicPath, apiUrl, entity: 'thematicPaths' } })`
47
+ (note: **no baseQuery**) with the `Masonry` SSR factory and provides `ThematicPathsFacade` +
48
+ `SERVICES`. Add the lazy `sciezki-tematyczne` route to the `appRoutes` array in
49
+ `apps/web/src/app/app.routes.ts` as a single top-level route.
50
+ 4. **Verify** — run `scripts/verify-module.sh <workspace-root> <PREFIX>`: asserts the lib + entity
51
+ exist, the tsconfig path is added, `ArticlesSharedModule.forFeature` is wired with
52
+ `entity: 'thematicPaths'` + `MuseumThematicPath` + `reducerFactory`, `ThematicPathsFacade` is
53
+ provided, the `+state` files are present, the `sciezki-tematyczne` route is registered as a single
54
+ top-level route, and the three Articles deps are in `package.json`. Fix and re-run.
55
+
56
+ ## Notes
57
+
58
+ - This skill ONLY touches the thematic-paths module + its route. It never adds other feature modules,
59
+ never re-runs the foundation, and never edits `libs/shared/angular`.
60
+ - Bundled `references/` + `scripts/` ship automatically. Do not hand-edit `plugin.json`.