@smartsoft001-mobilems/claude-plugins 2.85.0 → 2.87.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 (176) hide show
  1. package/.claude-plugin/marketplace.json +2 -6
  2. package/package.json +2 -2
  3. package/plugins/mobilems/.claude-plugin/README.md +30 -0
  4. package/plugins/mobilems/.claude-plugin/plugin.json +5 -0
  5. package/plugins/mobilems/scripts/refresh-mobilems-api-spec.sh +372 -0
  6. package/plugins/mobilems/skills/mobilems-articles/SKILL.md +84 -0
  7. package/plugins/mobilems/skills/mobilems-articles/references/lib-contents.md +164 -0
  8. package/plugins/mobilems/skills/mobilems-articles/references/module-and-routes.md +146 -0
  9. package/plugins/mobilems/skills/mobilems-articles/references/shared-components.md +56 -0
  10. package/plugins/mobilems/skills/mobilems-articles/scripts/detect-init.sh +29 -0
  11. package/plugins/mobilems/skills/mobilems-articles/scripts/verify-module.sh +61 -0
  12. package/plugins/mobilems/skills/mobilems-docs-reader/SKILL.md +116 -0
  13. package/plugins/mobilems/skills/mobilems-events/SKILL.md +65 -0
  14. package/plugins/mobilems/skills/mobilems-events/references/lib-contents.md +212 -0
  15. package/plugins/mobilems/skills/mobilems-events/references/module-and-routes.md +113 -0
  16. package/plugins/mobilems/skills/mobilems-events/scripts/detect-init.sh +29 -0
  17. package/plugins/mobilems/skills/mobilems-events/scripts/verify-module.sh +59 -0
  18. package/plugins/mobilems/skills/mobilems-object-collections/SKILL.md +52 -0
  19. package/plugins/mobilems/skills/mobilems-object-collections/references/lib-contents.md +76 -0
  20. package/plugins/mobilems/skills/mobilems-object-collections/references/module-and-routes.md +116 -0
  21. package/plugins/mobilems/skills/mobilems-object-collections/references/shared-components.md +61 -0
  22. package/plugins/mobilems/skills/mobilems-object-collections/scripts/detect-init.sh +29 -0
  23. package/plugins/mobilems/skills/mobilems-object-collections/scripts/verify-module.sh +44 -0
  24. package/plugins/mobilems/skills/mobilems-objects/SKILL.md +52 -0
  25. package/plugins/mobilems/skills/mobilems-objects/references/lib-contents.md +68 -0
  26. package/plugins/mobilems/skills/mobilems-objects/references/module-and-routes.md +108 -0
  27. package/plugins/mobilems/skills/mobilems-objects/references/shared-components.md +69 -0
  28. package/plugins/mobilems/skills/mobilems-objects/scripts/detect-init.sh +29 -0
  29. package/plugins/mobilems/skills/mobilems-objects/scripts/verify-module.sh +51 -0
  30. package/plugins/mobilems/skills/mobilems-partners/SKILL.md +65 -0
  31. package/plugins/mobilems/skills/mobilems-partners/references/lib-contents.md +160 -0
  32. package/plugins/mobilems/skills/mobilems-partners/references/module-and-routes.md +125 -0
  33. package/plugins/mobilems/skills/mobilems-partners/scripts/detect-init.sh +29 -0
  34. package/plugins/mobilems/skills/mobilems-partners/scripts/verify-module.sh +59 -0
  35. package/plugins/mobilems/skills/mobilems-project-init/SKILL.md +134 -0
  36. package/plugins/mobilems/skills/mobilems-project-init/references/app-shell.md +107 -0
  37. package/plugins/mobilems/skills/mobilems-project-init/references/claude-config.md +44 -0
  38. package/plugins/mobilems/skills/mobilems-project-init/references/config-providers.md +203 -0
  39. package/plugins/mobilems/skills/mobilems-project-init/references/npm-deps.md +66 -0
  40. package/plugins/mobilems/skills/mobilems-project-init/references/server-env.md +89 -0
  41. package/plugins/mobilems/skills/mobilems-project-init/references/shared-lib.md +125 -0
  42. package/plugins/mobilems/skills/mobilems-project-init/references/tailwind-styles.md +106 -0
  43. package/plugins/mobilems/skills/mobilems-project-init/scripts/classify-shared-components.py +114 -0
  44. package/plugins/mobilems/skills/mobilems-project-init/scripts/detect-base.sh +49 -0
  45. package/plugins/mobilems/skills/mobilems-project-init/scripts/verify-init.sh +73 -0
  46. package/plugins/mobilems/skills/mobilems-thematic-publications/SKILL.md +60 -0
  47. package/plugins/mobilems/skills/mobilems-thematic-publications/references/lib-contents.md +134 -0
  48. package/plugins/mobilems/skills/mobilems-thematic-publications/references/module-and-routes.md +107 -0
  49. package/plugins/mobilems/skills/mobilems-thematic-publications/scripts/detect-init.sh +29 -0
  50. package/plugins/mobilems/skills/mobilems-thematic-publications/scripts/verify-module.sh +56 -0
  51. package/plugins/flow/.claude-plugin/README.md +0 -91
  52. package/plugins/flow/.claude-plugin/merge-permissions.js +0 -97
  53. package/plugins/flow/.claude-plugin/plugin.json +0 -5
  54. package/plugins/flow/.claude-plugin/settings.template.json +0 -86
  55. package/plugins/flow/agents/angular-component-scaffolder.md +0 -175
  56. package/plugins/flow/agents/angular-directive-builder.md +0 -153
  57. package/plugins/flow/agents/angular-guard-builder.md +0 -243
  58. package/plugins/flow/agents/angular-jest-test-writer.md +0 -474
  59. package/plugins/flow/agents/angular-pipe-builder.md +0 -169
  60. package/plugins/flow/agents/angular-resolver-builder.md +0 -286
  61. package/plugins/flow/agents/angular-service-builder.md +0 -161
  62. package/plugins/flow/agents/angular-signal-state-builder.md +0 -339
  63. package/plugins/flow/agents/angular-test-diagnostician.md +0 -279
  64. package/plugins/flow/agents/angular-testbed-configurator.md +0 -315
  65. package/plugins/flow/agents/arch-scaffolder.md +0 -278
  66. package/plugins/flow/agents/e2e-data-testid-injector.md +0 -197
  67. package/plugins/flow/agents/e2e-project-scaffolder.md +0 -194
  68. package/plugins/flow/agents/e2e-test-writer.md +0 -350
  69. package/plugins/flow/agents/shared-agent-evolver.md +0 -294
  70. package/plugins/flow/agents/shared-build-verifier.md +0 -160
  71. package/plugins/flow/agents/shared-config-updater.md +0 -310
  72. package/plugins/flow/agents/shared-coverage-enforcer.md +0 -184
  73. package/plugins/flow/agents/shared-error-handler.md +0 -217
  74. package/plugins/flow/agents/shared-file-creator.md +0 -344
  75. package/plugins/flow/agents/shared-impl-orchestrator.md +0 -312
  76. package/plugins/flow/agents/shared-impl-reporter.md +0 -368
  77. package/plugins/flow/agents/shared-impl-teammate.md +0 -201
  78. package/plugins/flow/agents/shared-linear-subtask-iterator.md +0 -337
  79. package/plugins/flow/agents/shared-logic-implementer.md +0 -243
  80. package/plugins/flow/agents/shared-maia-api.md +0 -26
  81. package/plugins/flow/agents/shared-parallelization-analyzer.md +0 -343
  82. package/plugins/flow/agents/shared-performance-validator.md +0 -168
  83. package/plugins/flow/agents/shared-plan-perspective.md +0 -269
  84. package/plugins/flow/agents/shared-project-standardizer.md +0 -205
  85. package/plugins/flow/agents/shared-report-synthesizer.md +0 -188
  86. package/plugins/flow/agents/shared-review-teammate.md +0 -189
  87. package/plugins/flow/agents/shared-security-scanner.md +0 -186
  88. package/plugins/flow/agents/shared-style-enforcer.md +0 -230
  89. package/plugins/flow/agents/shared-subtask-dependency-analyzer.md +0 -188
  90. package/plugins/flow/agents/shared-tdd-developer.md +0 -350
  91. package/plugins/flow/agents/shared-team-coordinator.md +0 -189
  92. package/plugins/flow/agents/shared-test-fixer.md +0 -186
  93. package/plugins/flow/agents/shared-test-runner.md +0 -191
  94. package/plugins/flow/agents/shared-ui-classifier.md +0 -263
  95. package/plugins/flow/agents/shared-verification-orchestrator.md +0 -194
  96. package/plugins/flow/agents/shared-verification-runner.md +0 -140
  97. package/plugins/flow/agents/ui-a11y-validator.md +0 -305
  98. package/plugins/flow/agents/ui-screenshot-reporter.md +0 -329
  99. package/plugins/flow/agents/ui-web-designer.md +0 -214
  100. package/plugins/flow/scripts/compute-session-tokens.sh +0 -39
  101. package/plugins/flow/skills/a11y-audit/SKILL.md +0 -214
  102. package/plugins/flow/skills/angular-patterns/SKILL.md +0 -191
  103. package/plugins/flow/skills/browser-capture/SKILL.md +0 -238
  104. package/plugins/flow/skills/commit/SKILL.md +0 -259
  105. package/plugins/flow/skills/debug-helper/SKILL.md +0 -375
  106. package/plugins/flow/skills/impl/SKILL.md +0 -992
  107. package/plugins/flow/skills/linear-suggestion/SKILL.md +0 -132
  108. package/plugins/flow/skills/maia-files-delete/SKILL.md +0 -59
  109. package/plugins/flow/skills/maia-files-upload/SKILL.md +0 -57
  110. package/plugins/flow/skills/nx-conventions/SKILL.md +0 -326
  111. package/plugins/flow/skills/plan/SKILL.md +0 -1033
  112. package/plugins/flow/skills/push/SKILL.md +0 -759
  113. package/plugins/flow/skills/review/SKILL.md +0 -443
  114. package/plugins/flow/skills/test-e2e/SKILL.md +0 -161
  115. package/plugins/flow/skills/test-unit/SKILL.md +0 -456
  116. package/plugins/flow-external/.claude-plugin/README.md +0 -152
  117. package/plugins/flow-external/.claude-plugin/merge-permissions.js +0 -80
  118. package/plugins/flow-external/.claude-plugin/plugin.json +0 -5
  119. package/plugins/flow-external/.claude-plugin/settings.template.json +0 -78
  120. package/plugins/flow-external/agents/angular-component-scaffolder.md +0 -269
  121. package/plugins/flow-external/agents/angular-directive-builder.md +0 -130
  122. package/plugins/flow-external/agents/angular-guard-builder.md +0 -70
  123. package/plugins/flow-external/agents/angular-pipe-builder.md +0 -82
  124. package/plugins/flow-external/agents/angular-resolver-builder.md +0 -74
  125. package/plugins/flow-external/agents/angular-service-builder.md +0 -160
  126. package/plugins/flow-external/agents/angular-state-builder.md +0 -254
  127. package/plugins/flow-external/agents/shared-build-verifier.md +0 -67
  128. package/plugins/flow-external/agents/shared-impl-orchestrator.md +0 -88
  129. package/plugins/flow-external/agents/shared-impl-reporter.md +0 -135
  130. package/plugins/flow-external/agents/shared-linear-subtask-iterator.md +0 -70
  131. package/plugins/flow-external/agents/shared-ui-classifier.md +0 -38
  132. package/plugins/flow-external/agents/ui-web-designer.md +0 -179
  133. package/plugins/flow-external/scripts/compute-session-tokens.sh +0 -39
  134. package/plugins/flow-external/skills/a11y-audit/SKILL.md +0 -96
  135. package/plugins/flow-external/skills/angular-cli-conventions/SKILL.md +0 -267
  136. package/plugins/flow-external/skills/angular-patterns/SKILL.md +0 -170
  137. package/plugins/flow-external/skills/browser-capture/SKILL.md +0 -68
  138. package/plugins/flow-external/skills/commit/SKILL.md +0 -114
  139. package/plugins/flow-external/skills/debug-helper/SKILL.md +0 -131
  140. package/plugins/flow-external/skills/impl/SKILL.md +0 -217
  141. package/plugins/flow-external/skills/linear-suggestion/SKILL.md +0 -62
  142. package/plugins/flow-external/skills/maia-files-delete/SKILL.md +0 -34
  143. package/plugins/flow-external/skills/maia-files-upload/SKILL.md +0 -41
  144. package/plugins/flow-external/skills/plan/SKILL.md +0 -334
  145. package/plugins/flow-external/skills/push/SKILL.md +0 -232
  146. package/plugins/flow-legacy/.claude-plugin/README.md +0 -143
  147. package/plugins/flow-legacy/.claude-plugin/merge-permissions.js +0 -94
  148. package/plugins/flow-legacy/.claude-plugin/plugin.json +0 -5
  149. package/plugins/flow-legacy/.claude-plugin/settings.template.json +0 -79
  150. package/plugins/flow-legacy/agents/angular-component-scaffolder.md +0 -323
  151. package/plugins/flow-legacy/agents/angular-directive-builder.md +0 -258
  152. package/plugins/flow-legacy/agents/angular-guard-builder.md +0 -322
  153. package/plugins/flow-legacy/agents/angular-pipe-builder.md +0 -227
  154. package/plugins/flow-legacy/agents/angular-resolver-builder.md +0 -332
  155. package/plugins/flow-legacy/agents/angular-service-builder.md +0 -271
  156. package/plugins/flow-legacy/agents/angular-state-builder.md +0 -479
  157. package/plugins/flow-legacy/agents/shared-impl-orchestrator.md +0 -174
  158. package/plugins/flow-legacy/agents/shared-impl-reporter.md +0 -232
  159. package/plugins/flow-legacy/agents/shared-linear-subtask-iterator.md +0 -187
  160. package/plugins/flow-legacy/agents/shared-tdd-developer.md +0 -306
  161. package/plugins/flow-legacy/agents/shared-test-runner.md +0 -131
  162. package/plugins/flow-legacy/agents/shared-ui-classifier.md +0 -145
  163. package/plugins/flow-legacy/scripts/compute-session-tokens.sh +0 -39
  164. package/plugins/flow-legacy/skills/a11y-audit/SKILL.md +0 -214
  165. package/plugins/flow-legacy/skills/angular-patterns/SKILL.md +0 -346
  166. package/plugins/flow-legacy/skills/browser-capture/SKILL.md +0 -238
  167. package/plugins/flow-legacy/skills/commit/SKILL.md +0 -215
  168. package/plugins/flow-legacy/skills/debug-helper/SKILL.md +0 -395
  169. package/plugins/flow-legacy/skills/impl/SKILL.md +0 -710
  170. package/plugins/flow-legacy/skills/linear-suggestion/SKILL.md +0 -132
  171. package/plugins/flow-legacy/skills/maia-files-delete/SKILL.md +0 -59
  172. package/plugins/flow-legacy/skills/maia-files-upload/SKILL.md +0 -57
  173. package/plugins/flow-legacy/skills/nx-conventions/SKILL.md +0 -368
  174. package/plugins/flow-legacy/skills/plan/SKILL.md +0 -742
  175. package/plugins/flow-legacy/skills/push/SKILL.md +0 -645
  176. package/plugins/flow-legacy/skills/test-unit/SKILL.md +0 -500
@@ -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,73 @@
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
+ grep -q "./lib/components" libs/shared/angular/src/index.ts && pass "shared-lib components barrel populated" || bad "components barrel in shared-lib index.ts"
28
+ [ -f .claude/settings.json ] && grep -q "flow@mobilems" .claude/settings.json && pass "flow@mobilems enabled" || bad "flow@mobilems in .claude/settings.json"
29
+
30
+ echo "== Foundation scope (no feature modules yet) =="
31
+ 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
32
+ # feature routes reference a museum-* lib; loadChildren + the import often span lines, so match museum- anywhere
33
+ 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
34
+
35
+ echo "== Foundation shared library is self-contained =="
36
+ COMP=libs/shared/angular/src/lib/components
37
+ # the widget container registers only foundation widgets (feature gallery widgets are added by module skills)
38
+ WID="$COMP/widget/widget.component.ts"
39
+ if [ -f "$WID" ]; then
40
+ if grep -qE "WidgetGalleryObjectComponent|WidgetGalleryArticleComponent" "$WID"; then
41
+ bad "widget container references a feature gallery widget — build it with foundation widgets only"
42
+ else
43
+ pass "widget container has foundation widgets only"
44
+ fi
45
+ else
46
+ bad "widget container missing"
47
+ fi
48
+ # objects.model holds only the foundation model types (the object-specific ISpecificObject is feature code)
49
+ OBJMODEL=libs/shared/angular/src/lib/models/objects.model.ts
50
+ if [ -f "$OBJMODEL" ]; then
51
+ grep -qE "from '[^']*objects-domain'" "$OBJMODEL" && bad "objects.model imports MsObject — foundation holds only the generic types" || pass "objects.model holds foundation types only"
52
+ grep -qE "AdvancedFilterType|KeyValue" "$OBJMODEL" && pass "foundation model types present" || bad "foundation model types missing from objects.model.ts"
53
+ fi
54
+
55
+ echo "== Build-safety invariant: shared lib imports no feature package =="
56
+ LEAK="$(grep -rlnE "from '@[^']*/(objects|articles|public-collections)-(domain|shell-angular|shell-dtos)'" libs/shared/angular/src 2>/dev/null || true)"
57
+ if [ -n "$LEAK" ]; then
58
+ bad "shared lib still imports a feature package — foundation will not build without it:"
59
+ printf ' %s\n' $LEAK >&2
60
+ else
61
+ pass "shared lib imports no feature package"
62
+ fi
63
+
64
+ echo "== Prefix threaded =="
65
+ if grep -rq "@msr/" libs/shared/angular/src apps/web/src 2>/dev/null && [ "$PREFIX" != "msr" ]; then
66
+ bad "stray @msr/ imports (prefix not fully threaded to @$PREFIX/)"
67
+ else
68
+ pass "no stray reference-prefix imports"
69
+ fi
70
+
71
+ echo
72
+ if [ "$fail" = 0 ]; then echo "VERIFY: all checks passed."; else echo "VERIFY: FAILED — fix the items above and re-run." >&2; fi
73
+ 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`.
@@ -0,0 +1,134 @@
1
+ # libs/museum-thematic-paths — structure to create
2
+
3
+ Copy from the reference repo's `libs/museum-thematic-paths` and thread `<PREFIX>`. The lib has two
4
+ projects: a `domain` (entity/interfaces/enums) and a `shell/angular` (the Angular module + NgRx
5
+ `+state` + UI).
6
+
7
+ ```
8
+ libs/museum-thematic-paths/
9
+ ├── domain/ # project: museum-thematic-paths-domain
10
+ │ ├── package.json # "name": "museum-thematic-paths-domain"
11
+ │ └── src/
12
+ │ ├── index.ts # export * from './lib/entities'; './lib/enums'; './lib/interfaces';
13
+ │ ├── features.ts # export const DOMAIN_SERVICES = [];
14
+ │ └── lib/
15
+ │ ├── entities/ # MuseumThematicPath (+ index)
16
+ │ ├── enums/ # WidgetType enum (+ index)
17
+ │ └── interfaces.ts # IThematicPath, IPage, IMenu, IImageFile, ICopyright, IDictionaryEntity, …
18
+ └── shell/angular/ # project: museum-thematic-paths-shell-angular
19
+ └── src/
20
+ ├── index.ts # export * from './lib/pages'; export * from './lib/thematic-paths.module';
21
+ └── lib/
22
+ ├── thematic-paths.module.ts # MuseumThematicPathsModule (references/module-and-routes.md)
23
+ ├── thematic-paths.routes.ts
24
+ ├── +state/ # thematic-paths.facade.ts (ThematicPathsFacade), thematic-paths.reducer.ts (getReducer), thematic-paths.selectors.ts
25
+ ├── components/ # intro, main, menu, page, show-widgets, list-item, filters,
26
+ │ # widgets/{page-header,text,image,video,audio,image-gallery/*} (+ index)
27
+ ├── directives/ # scroll-intersection.directive.ts (+ .spec)
28
+ ├── pages/ # list (ListComponent), item (ItemComponent) + index
29
+ └── services/ # thematic-paths.service.ts + index (SERVICES)
30
+ ```
31
+
32
+ > There is **no `src/__mocks__/` dir** in this lib (objects had one; thematic-paths does not). Copy
33
+ > only what the reference has.
34
+
35
+ ## Domain entity (verbatim — thread nothing; pure types)
36
+
37
+ Unlike objects' `MuseumObject extends MsObject`, this entity `implements` the local interfaces — it
38
+ does NOT extend a feature base class:
39
+
40
+ ```ts
41
+ import { IEntity } from '@smartsoft001/domain-core';
42
+ import { Field, Model } from '@smartsoft001/models';
43
+
44
+ import {
45
+ ICopyright,
46
+ IDictionaryEntity,
47
+ IImageFile,
48
+ IMenu,
49
+ IThematicPath,
50
+ } from '../interfaces';
51
+
52
+ @Model({})
53
+ export class MuseumThematicPath implements IEntity<any>, IThematicPath {
54
+ id!: any;
55
+
56
+ @Field() title!: string;
57
+ @Field() textColor!: string;
58
+ @Field() subTitle!: string;
59
+ @Field() shortDescription!: string;
60
+ @Field() author!: string;
61
+ @Field() backgroundColor!: string;
62
+ @Field() backgroundColorEnabled!: boolean;
63
+ @Field() backgroundImage!: IImageFile | null;
64
+ @Field() copyright!: ICopyright;
65
+ @Field() cycles!: IDictionaryEntity[];
66
+ @Field() image?: IImageFile;
67
+ @Field() keywords!: IDictionaryEntity[];
68
+ @Field() landingPageEnabled!: boolean;
69
+ @Field() menuBackgroundColor!: string;
70
+ @Field() menuBackgroundImage!: string;
71
+ @Field() menuType!: 'vertical' | 'horizontal';
72
+ @Field() publicationDate!: string;
73
+ @Field() sections!: IMenu[];
74
+ }
75
+ ```
76
+
77
+ Copy `domain/src/lib/interfaces.ts` verbatim (defines `IThematicPath`, `IPage`, `IMenu`, `IImageFile`,
78
+ `ICopyright`, `IDictionaryEntity`, and the page/widget shapes the reducer + components consume) and
79
+ `domain/src/lib/enums/index.ts` (`WidgetType`).
80
+
81
+ ## Shell `+state` (NgRx — copy verbatim, thread `<PREFIX>`)
82
+
83
+ - `thematic-paths.reducer.ts` exports `getReducer()` — wraps `@smartsoft001/crud-shell-angular`'s
84
+ `getReducer('thematicPaths')` and adds thematic-specific cases (page loading, page desc, menu
85
+ display, widget id, etc.). This is the function passed as `reducerFactory` in the module config.
86
+ - `thematic-paths.facade.ts` exports `ThematicPathsFacade extends CrudFacade<MuseumThematicPath>`
87
+ with the paged-reader actions (`loadPage`, `loadPageDesc`, `setPage`, `setWidget`,
88
+ `setMenuDisplay`, `openPageDesc`) and signal accessors.
89
+ - `thematic-paths.selectors.ts` — the `getThematic*` selectors the facade reads.
90
+
91
+ ## Services — `services/index.ts` exports a `SERVICES` array (copy verbatim)
92
+
93
+ The service extends `CrudBaseService` and is bound to BOTH `CrudService` and `ArticlesService` (the
94
+ reused Articles shared module resolves `ArticlesService`):
95
+
96
+ ```ts
97
+ import { CrudService } from '@smartsoft001/crud-shell-angular';
98
+ import { ArticlesService } from '@smartsoft001-mobilems/articles-shell-angular';
99
+
100
+ import { ThematicPathsService } from './thematic-paths.service';
101
+
102
+ export * from './thematic-paths.service';
103
+
104
+ export const SERVICES = [
105
+ ThematicPathsService,
106
+ { provide: CrudService, useClass: ThematicPathsService },
107
+ { provide: ArticlesService, useClass: ThematicPathsService },
108
+ ];
109
+ ```
110
+
111
+ `ThematicPathsService extends CrudBaseService<MuseumThematicPath>` (from
112
+ `@smartsoft001-mobilems/angular`) and adds `getPage`/`getPageDesc` for the paged reader.
113
+
114
+ ## Wiring
115
+
116
+ - **tsconfig.base.json paths** (add both):
117
+ ```json
118
+ "@<PREFIX>/museum-thematic-paths/domain": ["libs/museum-thematic-paths/domain/src/index.ts"],
119
+ "@<PREFIX>/museum-thematic-paths/shell/angular": ["libs/museum-thematic-paths/shell/angular/src/index.ts"]
120
+ ```
121
+ - **project.json / build config** — copy each project's config (names `museum-thematic-paths-domain`,
122
+ `museum-thematic-paths-shell-angular`) and normalize every path field the reference baked to its
123
+ origin location — `sourceRoot`, `dest`, `outputPath`, `coverageDirectory`, `jestConfig`,
124
+ `lintFilePatterns`, and the jest `displayName` — to `libs/museum-thematic-paths/...`. Some reference modules carry stale
125
+ values (e.g. a `sourceRoot` missing the `shell/angular` segment, or a `coverageDirectory` under
126
+ `packages/...`) while others are already correct — verify each against a known-good sibling and fix
127
+ only the stale ones. A `domain` with no `project.json` (Nx-inferred) is fine — just set its
128
+ `package.json` `name`.
129
+ - **commit scope** — `commitlint.config.js` reads `libs/` dir names, so `museum-thematic-paths`
130
+ becomes a valid scope automatically; no edit needed.
131
+
132
+ This module reuses the Articles shared module, so it needs the three `@smartsoft001-mobilems/articles-*`
133
+ npm packages (see SKILL.md step 1). It does NOT need `online-3d-viewer`; `leaflet`/`openseadragon`/
134
+ `swiper` are foundation deps used by the gallery widgets if present.
@@ -0,0 +1,107 @@
1
+ # MuseumThematicPathsModule + route registration
2
+
3
+ ## `libs/museum-thematic-paths/shell/angular/src/lib/thematic-paths.module.ts`
4
+
5
+ Thread `<PREFIX>` (the `environment` + domain imports). This module REUSES `ArticlesSharedModule`
6
+ (the same shared module the news/articles modules use) but configures it over its OWN
7
+ `MuseumThematicPath` entity with its OWN `getReducer` and **no `baseQuery`**. The `Masonry` factory
8
+ returns the real library in the browser and a no-op mock during SSR (identical to objects).
9
+
10
+ ```ts
11
+ import { NgModule } from '@angular/core';
12
+ import { FormsModule } from '@angular/forms';
13
+ import { RouterModule } from '@angular/router';
14
+ import { SharedModule as SmartSharedModule } from '@smartsoft001/angular';
15
+ import { ArticlesSharedModule } from '@smartsoft001-mobilems/articles-shell-angular';
16
+ import { Masonry } from '@thisissoon/angular-masonry';
17
+
18
+ import { environment } from '@<PREFIX>/angular';
19
+ import { MuseumThematicPath } from '@<PREFIX>/museum-thematic-paths/domain';
20
+
21
+ import { ThematicPathsFacade } from './+state/thematic-paths.facade';
22
+ import { getReducer } from './+state/thematic-paths.reducer';
23
+ import { SERVICES } from './services';
24
+ import { routes } from './thematic-paths.routes';
25
+
26
+ @NgModule({
27
+ providers: [
28
+ ThematicPathsFacade,
29
+ ...SERVICES,
30
+ {
31
+ provide: Masonry,
32
+ useFactory: () => {
33
+ if (typeof window !== 'undefined' && (window as any)['Masonry']) {
34
+ return (window as any)['Masonry'];
35
+ }
36
+ // Return a mock for SSR
37
+ return class {
38
+ constructor() {
39
+ // no-op
40
+ }
41
+ layout() {
42
+ return;
43
+ }
44
+ reloadItems() {
45
+ return;
46
+ }
47
+ destroy() {
48
+ return;
49
+ }
50
+ };
51
+ },
52
+ },
53
+ ],
54
+ imports: [
55
+ FormsModule,
56
+ SmartSharedModule,
57
+ ArticlesSharedModule.forFeature({
58
+ routing: false,
59
+ config: {
60
+ reducerFactory: getReducer,
61
+ type: MuseumThematicPath,
62
+ apiUrl: environment.apiUrl,
63
+ entity: 'thematicPaths',
64
+ },
65
+ }),
66
+ RouterModule.forChild(routes),
67
+ ],
68
+ })
69
+ export class MuseumThematicPathsModule {}
70
+ ```
71
+
72
+ > Contrast with `mobilems-objects` (`ObjectsSharedModule.forFeature` over `MsObject`, no
73
+ > `reducerFactory`): here the module reuses `ArticlesSharedModule`, supplies `reducerFactory: getReducer`,
74
+ > and there is deliberately **no `baseQuery`** in the config.
75
+
76
+ ## `thematic-paths.routes.ts`
77
+
78
+ ```ts
79
+ import { Route } from '@angular/router';
80
+
81
+ import { ItemComponent, ListComponent } from './pages';
82
+
83
+ export const routes: Route[] = [
84
+ { path: ':id/:slug', component: ItemComponent },
85
+ { path: ':id', component: ItemComponent },
86
+ { path: '', component: ListComponent },
87
+ ];
88
+ ```
89
+
90
+ ## Register in `apps/web/src/app/app.routes.ts`
91
+
92
+ This module registers a single **top-level** route. Add the `sciezki-tematyczne` route to the
93
+ `appRoutes` array (idempotently — if a `sciezki-tematyczne` route already exists, skip). It is a
94
+ content publication browsed from the top level, so it is NOT added under the `wyszukaj/:text` search
95
+ route — thematic-paths does not appear in the search results.
96
+
97
+ Top-level — add to `appRoutes`:
98
+
99
+ ```ts
100
+ {
101
+ path: 'sciezki-tematyczne',
102
+ loadChildren: () =>
103
+ import('@<PREFIX>/museum-thematic-paths/shell/angular').then(
104
+ (m) => m.MuseumThematicPathsModule,
105
+ ),
106
+ },
107
+ ```
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # detect-init.sh <workspace-root>
4
+ #
5
+ # Precondition gate for mobilems-objects (and the other module skills follow the same shape):
6
+ # confirm the MobilEMS foundation from mobilems-project-init is present. Portable to macOS bash 3.2.
7
+ #
8
+ # Exit 0 → foundation present, OK to add the module.
9
+ # Exit 3 → foundation missing (tell the user to run /mobilems:project-init first).
10
+ set -eu
11
+
12
+ ROOT="${1:?usage: detect-init.sh <workspace-root>}"
13
+ cd "$ROOT" 2>/dev/null || { echo "ERROR: no such dir: $ROOT" >&2; exit 2; }
14
+
15
+ miss() {
16
+ echo "FOUNDATION MISSING: $1" >&2
17
+ echo "Run /mobilems:project-init first to lay down the MobilEMS foundation." >&2
18
+ exit 3
19
+ }
20
+
21
+ [ -f apps/web/src/app/app.config.ts ] || miss "app.config.ts missing"
22
+ grep -q "SharedModule.forRoot" apps/web/src/app/app.config.ts || miss "SharedModule.forRoot not in app.config.ts (foundation not applied)"
23
+ grep -q "./lib/components" libs/shared/angular/src/index.ts 2>/dev/null || miss "shared-lib components barrel not populated"
24
+ [ -f apps/web/src/app/app.routes.ts ] || miss "app.routes.ts missing"
25
+
26
+ PREFIX="$(grep -oE '@[a-z0-9-]+/angular' tsconfig.base.json | head -1 | sed -E 's#@([a-z0-9-]+)/angular#\1#')"
27
+ echo "FOUNDATION OK. Detected prefix: ${PREFIX:-<unknown>}"
28
+ [ -d libs/museum-objects ] && echo "NOTE: libs/museum-objects already exists — build steps must be idempotent." >&2
29
+ exit 0
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # verify-module.sh <workspace-root> <PREFIX>
4
+ #
5
+ # Post-condition check for mobilems-thematic-publications: library created, ArticlesSharedModule
6
+ # wired over MuseumThematicPath with its own reducer, facade + +state present, the
7
+ # sciezki-tematyczne route registered as a single top-level route, and the Articles deps installed.
8
+ # macOS bash 3.2 safe.
9
+ set -eu
10
+
11
+ ROOT="${1:?usage: verify-module.sh <workspace-root> <PREFIX>}"
12
+ PREFIX="${2:?usage: verify-module.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
+ MOD=libs/museum-thematic-paths/shell/angular/src/lib/thematic-paths.module.ts
20
+
21
+ echo "== Library =="
22
+ [ -f "$MOD" ] && pass "MuseumThematicPathsModule present" || bad "thematic-paths.module.ts missing"
23
+ [ -f libs/museum-thematic-paths/domain/src/lib/entities/museum-thematic-path.entity.ts ] && pass "MuseumThematicPath entity present" || bad "domain entity missing"
24
+ grep -q "class MuseumThematicPath" libs/museum-thematic-paths/domain/src/lib/entities/museum-thematic-path.entity.ts 2>/dev/null && pass "MuseumThematicPath class declared" || bad "MuseumThematicPath class not declared"
25
+ grep -q "museum-thematic-paths/shell/angular" tsconfig.base.json && pass "tsconfig shell path added" || bad "tsconfig shell path missing"
26
+ grep -q "museum-thematic-paths/domain" tsconfig.base.json && pass "tsconfig domain path added" || bad "tsconfig domain path missing"
27
+
28
+ echo "== Module wiring =="
29
+ grep -q "ArticlesSharedModule.forFeature" "$MOD" 2>/dev/null && pass "ArticlesSharedModule.forFeature wired" || bad "ArticlesSharedModule.forFeature missing"
30
+ grep -q "entity: 'thematicPaths'" "$MOD" 2>/dev/null && pass "entity 'thematicPaths' configured" || bad "entity 'thematicPaths' missing"
31
+ grep -q "type: MuseumThematicPath" "$MOD" 2>/dev/null && pass "type MuseumThematicPath configured" || bad "type MuseumThematicPath missing"
32
+ grep -q "reducerFactory: getReducer" "$MOD" 2>/dev/null && pass "reducerFactory: getReducer configured" || bad "reducerFactory: getReducer missing"
33
+ grep -q "ThematicPathsFacade" "$MOD" 2>/dev/null && pass "ThematicPathsFacade provided" || bad "ThematicPathsFacade not provided"
34
+
35
+ echo "== +state =="
36
+ STATE=libs/museum-thematic-paths/shell/angular/src/lib/+state
37
+ [ -f "$STATE/thematic-paths.facade.ts" ] && pass "facade present" || bad "thematic-paths.facade.ts missing"
38
+ [ -f "$STATE/thematic-paths.reducer.ts" ] && pass "reducer present" || bad "thematic-paths.reducer.ts missing"
39
+ grep -q "export function getReducer" "$STATE/thematic-paths.reducer.ts" 2>/dev/null && pass "getReducer exported" || bad "getReducer not exported in reducer"
40
+
41
+ echo "== Route registration =="
42
+ ROUTES=apps/web/src/app/app.routes.ts
43
+ grep -q "museum-thematic-paths/shell/angular" "$ROUTES" && pass "thematic-paths route registered" || bad "thematic-paths route not in app.routes.ts"
44
+ # single top-level route — expect exactly 1 occurrence
45
+ n=$(grep -c "museum-thematic-paths/shell/angular" "$ROUTES" || true)
46
+ [ "${n:-0}" -eq 1 ] && pass "registered as a single top-level route ($n)" || bad "expected exactly 1 route registration, found $n"
47
+ grep -q "sciezki-tematyczne" "$ROUTES" && pass "sciezki-tematyczne path present" || bad "sciezki-tematyczne path missing"
48
+
49
+ echo "== Deps =="
50
+ grep -q "@smartsoft001-mobilems/articles-domain" package.json && pass "articles-domain dep" || bad "articles-domain dep missing"
51
+ grep -q "@smartsoft001-mobilems/articles-shell-angular" package.json && pass "articles-shell-angular dep" || bad "articles-shell-angular dep missing"
52
+ grep -q "@smartsoft001-mobilems/articles-shell-dtos" package.json && pass "articles-shell-dtos dep" || bad "articles-shell-dtos dep missing"
53
+
54
+ echo
55
+ if [ "$fail" = 0 ]; then echo "VERIFY: all checks passed."; else echo "VERIFY: FAILED — fix the items above and re-run." >&2; fi
56
+ exit "$fail"