@smartsoft001-mobilems/claude-plugins 2.88.0 → 2.90.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 (44) hide show
  1. package/README.md +27 -2
  2. package/package.json +1 -1
  3. package/plugins/mobilems/.claude-plugin/README.md +21 -2
  4. package/plugins/mobilems/.claude-plugin/plugin.json +1 -1
  5. package/plugins/mobilems/skills/mobilems-articles/SKILL.md +52 -20
  6. package/plugins/mobilems/skills/mobilems-articles/references/module-and-routes.md +24 -0
  7. package/plugins/mobilems/skills/mobilems-articles/scripts/check-translations.js +90 -0
  8. package/plugins/mobilems/skills/mobilems-articles/scripts/verify-module.sh +53 -0
  9. package/plugins/mobilems/skills/mobilems-devops-config/SKILL.md +141 -0
  10. package/plugins/mobilems/skills/mobilems-devops-config/references/docker.md +58 -0
  11. package/plugins/mobilems/skills/mobilems-devops-config/references/env-and-lint.md +59 -0
  12. package/plugins/mobilems/skills/mobilems-devops-config/references/github-hygiene.md +54 -0
  13. package/plugins/mobilems/skills/mobilems-devops-config/references/tooling.md +105 -0
  14. package/plugins/mobilems/skills/mobilems-devops-config/references/workflows.md +410 -0
  15. package/plugins/mobilems/skills/mobilems-devops-config/scripts/detect-foundation.sh +47 -0
  16. package/plugins/mobilems/skills/mobilems-devops-config/scripts/verify-devops.sh +96 -0
  17. package/plugins/mobilems/skills/mobilems-events/SKILL.md +27 -1
  18. package/plugins/mobilems/skills/mobilems-events/references/module-and-routes.md +24 -0
  19. package/plugins/mobilems/skills/mobilems-events/scripts/verify-module.sh +43 -0
  20. package/plugins/mobilems/skills/mobilems-object-collections/SKILL.md +46 -14
  21. package/plugins/mobilems/skills/mobilems-object-collections/references/lib-contents.md +11 -0
  22. package/plugins/mobilems/skills/mobilems-object-collections/references/module-and-routes.md +26 -0
  23. package/plugins/mobilems/skills/mobilems-object-collections/scripts/check-translations.js +90 -0
  24. package/plugins/mobilems/skills/mobilems-object-collections/scripts/verify-module.sh +54 -0
  25. package/plugins/mobilems/skills/mobilems-objects/SKILL.md +42 -10
  26. package/plugins/mobilems/skills/mobilems-objects/references/module-and-routes.md +24 -0
  27. package/plugins/mobilems/skills/mobilems-objects/scripts/check-translations.js +90 -0
  28. package/plugins/mobilems/skills/mobilems-objects/scripts/verify-module.sh +53 -0
  29. package/plugins/mobilems/skills/mobilems-partners/SKILL.md +30 -2
  30. package/plugins/mobilems/skills/mobilems-partners/references/module-and-routes.md +24 -0
  31. package/plugins/mobilems/skills/mobilems-partners/scripts/check-translations.js +90 -0
  32. package/plugins/mobilems/skills/mobilems-partners/scripts/verify-module.sh +53 -0
  33. package/plugins/mobilems/skills/mobilems-project-init/SKILL.md +68 -8
  34. package/plugins/mobilems/skills/mobilems-project-init/references/branding-reset.md +112 -0
  35. package/plugins/mobilems/skills/mobilems-project-init/references/claude-config.md +7 -0
  36. package/plugins/mobilems/skills/mobilems-project-init/references/config-providers.md +1 -1
  37. package/plugins/mobilems/skills/mobilems-project-init/references/qa-hardening.md +30 -30
  38. package/plugins/mobilems/skills/mobilems-project-init/references/shared-lib.md +42 -5
  39. package/plugins/mobilems/skills/mobilems-project-init/references/tailwind-styles.md +33 -23
  40. package/plugins/mobilems/skills/mobilems-project-init/scripts/verify-init.sh +62 -9
  41. package/plugins/mobilems/skills/mobilems-thematic-publications/SKILL.md +25 -1
  42. package/plugins/mobilems/skills/mobilems-thematic-publications/references/lib-contents.md +11 -0
  43. package/plugins/mobilems/skills/mobilems-thematic-publications/references/module-and-routes.md +26 -0
  44. package/plugins/mobilems/skills/mobilems-thematic-publications/scripts/verify-module.sh +43 -0
@@ -0,0 +1,59 @@
1
+ # Env / lint / node
2
+
3
+ ## `.env.dev`
4
+
5
+ The CI build copies this to `.env` (`cp .env.dev .env`) before `nx build web --prod`. The values
6
+ are **project-specific** — collect them in step 1 (from an existing `.env*`, from
7
+ `apps/web/src/environments/environment.prod.ts`, or by prompting). Do not commit a real `.env`
8
+ (only `.env.dev`); `.env` should already be git-ignored by the base.
9
+
10
+ Template (replace the `{{...}}` placeholders):
11
+
12
+ ```dotenv
13
+ APP_VERSION={{APP_VERSION}}
14
+
15
+ API_URL={{API_URL}}
16
+ SITE_URL={{SITE_URL}}
17
+ MULTIMEDIA_URL={{MULTIMEDIA_URL}}
18
+ ```
19
+
20
+ Shape of the values, using `<museum>` for the client's own slug — these are patterns to follow, not
21
+ values to paste:
22
+
23
+ ```dotenv
24
+ APP_VERSION=0.0.2
25
+
26
+ API_URL=https://muza-api.<museum-domain>/
27
+ SITE_URL=https://mobilems-muzeum-<museum>-qa.smartsoft.biz.pl/
28
+ MULTIMEDIA_URL=https://muza-serwer-cdn.<museum-domain>/
29
+ ```
30
+
31
+ `SITE_URL` is the one to get right: it drives `og:url`, `sitemap.xml` and `robots.txt`, so a value
32
+ carried over from another project ships that project's domain in this app's SEO. Pass this project's
33
+ expected host as the third argument to `verify-devops.sh` to have it checked.
34
+
35
+ These keys map to the `/env.js` runtime-env template that `mobilems-project-init` sets up in
36
+ `server.ts` (`API_URL`/`SITE_URL`/`APP_VERSION` are the base set; `MULTIMEDIA_URL` is the MobilEMS
37
+ addition). If a project is missing `MULTIMEDIA_URL` handling in `server.ts`, that's a project-init
38
+ gap — flag it, don't fix it here.
39
+
40
+ ## `.eslintignore`
41
+
42
+ ```gitignore
43
+ node_modules
44
+ **/tailwind.config.js
45
+ ```
46
+
47
+ ## `.nvmrc`
48
+
49
+ A single line with the node version from step 1 — keep it identical to the Dockerfile base image
50
+ and every workflow `node-version`:
51
+
52
+ ```
53
+ {{NODE_VERSION}}
54
+ ```
55
+
56
+ If a project already has a `.nvmrc` with a different version (e.g. `24.16.0` vs the team's
57
+ `24.5.0`), treat the existing value as the source of truth for `{{NODE_VERSION}}` unless the user
58
+ asks to bump it — then thread that one version everywhere and re-run `verify-devops.sh` to confirm
59
+ consistency.
@@ -0,0 +1,54 @@
1
+ # `.github` hygiene — agent config does not live in `.github`
2
+
3
+ `.github/` is for GitHub itself: **workflows, composite actions, and GitHub's own metadata**
4
+ (`CODEOWNERS`, issue/PR templates, `dependabot.yml`, `git-commit-instructions.md`).
5
+
6
+ Agent configuration targets the **Claude Code architecture** and belongs under `.claude/`:
7
+
8
+ | Artifact | Location |
9
+ | ------------------ | -------------------------------------------------------------- |
10
+ | Skills | `.claude/skills/<name>/SKILL.md` (+ its references/scripts) |
11
+ | Subagents | `.claude/agents/<name>.md` |
12
+ | Prompts / commands | `.claude/commands/<name>.md` |
13
+ | Settings, plugins | `.claude/settings.json` (`enabledPlugins`, permissions, hooks) |
14
+
15
+ Scaffolding tools drop agent config into `.github/` in the GitHub-Copilot layout instead — Nx's AI
16
+ setup writes `.github/skills/`, `.github/agents/`, `.github/prompts/`; other tools add
17
+ `.github/instructions/`, `.github/chatmodes/`, `.github/copilot-instructions.md`. Those files are not
18
+ read by Claude Code, so they are inert at best. At worst they are a second, stale copy of something a
19
+ plugin already provides: the `nx-*` skill family and `monitor-ci` (with its `ci-monitor-subagent`
20
+ agent and `monitor-ci.prompt.md`) ship with `nx@nx-claude-plugins`, so a project that enables that
21
+ plugin and keeps the `.github` copies maintains two versions that drift apart, with the unused one
22
+ invisible in review.
23
+
24
+ ## Rule
25
+
26
+ For every entry under `.github/{skills,agents,prompts,instructions,chatmodes}` and
27
+ `.github/copilot-instructions.md`:
28
+
29
+ | Case | Action |
30
+ | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
31
+ | **Duplicate** of a plugin enabled in `.claude/settings.json` (`nx@nx-claude-plugins`, `smart@smartsoft`, `flow@*`, `mobilems@mobilems`) | **Delete** — the plugin is the single source |
32
+ | **Bespoke** to this project (no plugin ships it) | **Move** into `.claude/` per the table above, converting to the Claude Code layout (`.agent.md` / `.prompt.md` suffixes become plain `<name>.md`) |
33
+ | GitHub's own metadata (`workflows`, `actions`, `CODEOWNERS`, templates, `dependabot.yml`, `git-commit-instructions.md`) | **Keep** |
34
+
35
+ Deciding "duplicate": compare the skill/agent name against the plugins enabled in
36
+ `.claude/settings.json`. When a name is ambiguous, diff it against the plugin's copy under
37
+ `node_modules` / the plugin cache; if it is materially customized, treat it as bespoke and move it.
38
+
39
+ ## How to apply
40
+
41
+ 1. List what is there — do not assume:
42
+ ```bash
43
+ ls -d .github/skills .github/agents .github/prompts .github/instructions \
44
+ .github/chatmodes .github/copilot-instructions.md 2>/dev/null
45
+ ```
46
+ 2. Classify each entry with the table above and **show the user the plan** (delete list + move list)
47
+ before touching anything. Deleting files is not reversible from the skill's side — ask.
48
+ 3. Apply with `git mv` / `git rm` so the history follows the move.
49
+ 4. If anything moved into `.claude/`, name it in the final summary — a project-local skill or agent
50
+ is a candidate for upstreaming into a plugin.
51
+ 5. Leave `.github` containing only `workflows/`, `actions/`, and GitHub metadata.
52
+
53
+ > If the plugin that duplicates a deleted skill is **not** enabled in `.claude/settings.json`, enable
54
+ > it there (`nx@nx-claude-plugins` for the Nx skills) instead of keeping the `.github` copy.
@@ -0,0 +1,105 @@
1
+ # Update tooling
2
+
3
+ `npm run update` refreshes the `@smartsoft001*` packages to `@latest`, syncs the smartsoft Claude
4
+ plugins, and re-merges their permissions. This is generic across all museum projects — write it
5
+ verbatim.
6
+
7
+ ## `tools/scripts/update.js`
8
+
9
+ ```js
10
+ const { execSync } = require('child_process');
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+
14
+ // Clear npm cache with force
15
+ console.log('Clearing npm cache...');
16
+ try {
17
+ execSync('npm cache clean --force', { stdio: 'inherit' });
18
+ console.log('npm cache cleared successfully');
19
+ } catch (error) {
20
+ console.error('Failed to clear npm cache:', error.message);
21
+ }
22
+
23
+ // Read package.json
24
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
25
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
26
+
27
+ // Get all @smartsoft001 packages
28
+ const dependencies = packageJson.dependencies || {};
29
+ const devDependencies = packageJson.devDependencies || {};
30
+ const allDeps = { ...dependencies, ...devDependencies };
31
+
32
+ const smartsoftPackages = Object.keys(allDeps).filter((pkg) =>
33
+ pkg.startsWith('@smartsoft001'),
34
+ );
35
+
36
+ if (smartsoftPackages.length === 0) {
37
+ console.log('No @smartsoft001 packages found');
38
+ process.exit(0);
39
+ }
40
+
41
+ console.log('Found @smartsoft001 packages:', smartsoftPackages);
42
+
43
+ // Update all packages with single npm install command
44
+ const packagesWithLatest = smartsoftPackages
45
+ .map((pkg) => `${pkg}@latest`)
46
+ .join(' ');
47
+ console.log(`Updating all @smartsoft001 packages to latest...`);
48
+
49
+ try {
50
+ execSync(`npm install ${packagesWithLatest}`, { stdio: 'inherit' });
51
+ console.log('All @smartsoft001 packages updated successfully!');
52
+ } catch (error) {
53
+ console.error('Failed to update packages:', error.message);
54
+ }
55
+
56
+ try {
57
+ execSync(`claude plugin update smart@smartsoft --scope project || true`, {
58
+ stdio: 'inherit',
59
+ });
60
+ execSync(`claude plugin update flow@smart-pro --scope project || true`, {
61
+ stdio: 'inherit',
62
+ });
63
+ console.log('Claude plugins updated successfully!');
64
+ } catch (error) {
65
+ console.error('Failed to update Claude plugins:', error.message);
66
+ }
67
+
68
+ try {
69
+ execSync(
70
+ `node node_modules/@smartsoft001/claude-plugins/plugins/smart/.claude-plugin/merge-permissions.js `,
71
+ {
72
+ stdio: 'inherit',
73
+ },
74
+ );
75
+ execSync(
76
+ `node node_modules/@smartsoft001/pro-claude-plugins/plugins/flow/.claude-plugin/merge-permissions.js `,
77
+ {
78
+ stdio: 'inherit',
79
+ },
80
+ );
81
+ console.log('Claude plugin permissions merged successfully!');
82
+ } catch (error) {
83
+ console.error('Failed to merge Claude plugin permissions:', error.message);
84
+ }
85
+
86
+ console.log('Update complete!');
87
+ ```
88
+
89
+ ## `package.json` scripts
90
+
91
+ Merge these into the existing `scripts` block (keep any scripts already there):
92
+
93
+ ```json
94
+ {
95
+ "scripts": {
96
+ "update": "node ./tools/scripts/update.js",
97
+ "postinstall": "husky install"
98
+ }
99
+ }
100
+ ```
101
+
102
+ - `update` — the script above.
103
+ - `postinstall: husky install` — installs the Husky git hooks (`.husky/commit-msg`, `pre-push`,
104
+ `post-merge`). Some projects use `"prepare": "husky install"` instead; if `prepare` already runs
105
+ `husky install`, leave it and do **not** add a duplicate `postinstall`.
@@ -0,0 +1,410 @@
1
+ # GitHub Actions
2
+
3
+ Write each file under `.github/`. `{{NODE_VERSION}}` = the node version from step 1 (keep it
4
+ identical to `.nvmrc` and the Dockerfile). All client-specific values are GitHub Actions
5
+ **secrets** — the files contain only `${{ secrets.* }}` references, never literals.
6
+
7
+ The branch model: `development` → CI build + Docker push + dispatch QA deploy; `main` →
8
+ push-to-client (GitLab mirror + SSH production deploy).
9
+
10
+ ---
11
+
12
+ ## `.github/actions/cached-deps/action.yml`
13
+
14
+ ```yaml
15
+ name: 'Get & Cache Dependencies'
16
+ description: 'Get the dependencies (via npm) and cache them.'
17
+ inputs:
18
+ caching:
19
+ description: 'Whether to cache dependencies or not.'
20
+ required: false
21
+ default: 'true'
22
+ node-version:
23
+ description: 'Node version.'
24
+ required: false
25
+ default: '18'
26
+ outputs:
27
+ used-cache:
28
+ description: 'Whether the cache was used.'
29
+ value: ${{ steps.install.outputs.cache }}
30
+ runs:
31
+ using: 'composite'
32
+ steps:
33
+ - name: Install NodeJS
34
+ uses: actions/setup-node@v3
35
+ with:
36
+ node-version: ${{ inputs.node-version }}
37
+ - name: Cache dependencies
38
+ if: inputs.caching == 'true'
39
+ id: cache
40
+ uses: actions/cache@v3
41
+ with:
42
+ path: node_modules
43
+ key: deps-node-modules-${{ hashFiles('**/package-lock.json') }}
44
+ - name: Install dependencies
45
+ id: install
46
+ if: steps.cache.outputs.cache-hit != 'true' || inputs.caching != 'true'
47
+ run: |
48
+ npm ci
49
+ echo "cache='${{ inputs.caching }}'" >> $GITHUB_OUTPUT
50
+ shell: bash
51
+ ```
52
+
53
+ ---
54
+
55
+ ## `.github/workflows/development.yml`
56
+
57
+ ```yaml
58
+ name: Development
59
+ on:
60
+ workflow_dispatch:
61
+ push:
62
+ branches:
63
+ - development
64
+
65
+ jobs:
66
+ main:
67
+ runs-on: ubuntu-latest
68
+ permissions:
69
+ contents: 'write'
70
+ actions: 'read'
71
+ steps:
72
+ - name: Checkout git
73
+ uses: actions/checkout@v6
74
+ with:
75
+ fetch-depth: 0
76
+ - name: Setup node
77
+ uses: actions/setup-node@v6
78
+ with:
79
+ node-version: { { NODE_VERSION } }
80
+ cache: 'npm'
81
+ - name: Load & cache dependencies
82
+ id: cache-deps
83
+ uses: ./.github/actions/cached-deps
84
+ with:
85
+ node-version: '{{NODE_VERSION}}'
86
+ - name: Set version
87
+ run: npm version minor --no-git-tag-version
88
+ - id: package
89
+ run: |
90
+ echo "::set-output name=version::$(node -p "require('./package.json').version")"
91
+ - name: Copy .env.dev to .env
92
+ run: cp .env.dev .env
93
+ - name: Build NX
94
+ run: |
95
+ npx nx build web --prod --verbose
96
+ - name: Set up Docker Buildx
97
+ uses: docker/setup-buildx-action@v3
98
+ - name: Login to DockerHub
99
+ uses: docker/login-action@v3
100
+ with:
101
+ username: ${{ secrets.GITLAB_USERNAME }}
102
+ password: ${{ secrets.GITLAB_TOKEN }}
103
+ registry: dockerregistry.mobilems.pl
104
+ - name: Build and push docker
105
+ run: |
106
+ docker buildx build -f apps/web/Dockerfile --build-arg VERSION=${{ steps.package.outputs.version }} -t dockerregistry.mobilems.pl/${{ secrets.GITLAB_REPO_PATH }}:${{ steps.package.outputs.version }} --push .
107
+ - name: Commit git
108
+ uses: stefanzweifel/git-auto-commit-action@v4
109
+ with:
110
+ commit_message: 'build(github): publish ${{ steps.package.outputs.version }} [skip ci]'
111
+ tagging_message: 'v${{ steps.package.outputs.version }}'
112
+
113
+ - uses: lasith-kg/dispatch-workflow@v1
114
+ id: workflow-dispatch
115
+ name: 'Deploy to qa'
116
+ with:
117
+ dispatch-method: workflow_dispatch
118
+ repo: ${{ secrets.DEPLOY_REPO }}
119
+ owner: smartsoft001
120
+ ref: main
121
+ workflow: deploy.yml
122
+ token: ${{ secrets.DEPLOY_TOKEN }}
123
+ workflow-inputs: |
124
+ {
125
+ "version": "${{ steps.package.outputs.version }}",
126
+ "env": "qa"
127
+ }
128
+ ```
129
+
130
+ ---
131
+
132
+ ## `.github/workflows/e2e.yml`
133
+
134
+ ```yaml
135
+ name: E2E Tests
136
+ on:
137
+ workflow_dispatch:
138
+
139
+ jobs:
140
+ e2e:
141
+ runs-on: ubuntu-latest
142
+ permissions:
143
+ contents: 'read'
144
+ steps:
145
+ - name: Checkout git
146
+ uses: actions/checkout@v6
147
+ with:
148
+ fetch-depth: 0
149
+ - name: Setup node
150
+ uses: actions/setup-node@v6
151
+ with:
152
+ node-version: { { NODE_VERSION } }
153
+ cache: 'npm'
154
+ - name: Load & cache dependencies
155
+ id: cache-deps
156
+ uses: ./.github/actions/cached-deps
157
+ with:
158
+ node-version: '{{NODE_VERSION}}'
159
+ - name: Copy .env.dev to .env
160
+ run: cp .env.dev .env
161
+ - name: Build NX
162
+ run: npx nx build web --prod --verbose
163
+ - name: Install Playwright browsers
164
+ run: npx playwright install --with-deps chromium webkit
165
+ - name: Run E2E tests
166
+ run: npx nx e2e web-e2e
167
+ - name: Upload Playwright report
168
+ if: always()
169
+ uses: actions/upload-artifact@v4
170
+ with:
171
+ name: playwright-report
172
+ path: |
173
+ dist/.playwright/apps/web-e2e/
174
+ apps/web-e2e/test-results/
175
+ lighthouse-results/
176
+ audit-results/
177
+ retention-days: 30
178
+ ```
179
+
180
+ ---
181
+
182
+ ## `.github/workflows/push-to-client.yml`
183
+
184
+ ```yaml
185
+ name: Push to client
186
+
187
+ on:
188
+ workflow_dispatch:
189
+ push:
190
+ branches:
191
+ - main
192
+
193
+ jobs:
194
+ push:
195
+ runs-on: ubuntu-latest
196
+ steps:
197
+ - name: Checkout code
198
+ uses: actions/checkout@v5.0.0
199
+ with:
200
+ fetch-depth: 0
201
+
202
+ - name: Set up user
203
+ run: |
204
+ git config --global user.name "${{ secrets.GITLAB_USERNAME }}"
205
+ git config --global user.email "${{ secrets.GITLAB_USERNAME }}"
206
+
207
+ - name: Add remote and push
208
+ run: |
209
+ git remote add client https://${{ secrets.GITLAB_USERNAME }}:${{ secrets.GITLAB_TOKEN }}@git.mobilems.pl/${{ secrets.GITLAB_REPO_PATH }}
210
+ git push client --force
211
+
212
+ - name: Get package version
213
+ id: package
214
+ run: |
215
+ echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"
216
+
217
+ - name: Install OpenVPN
218
+ run: sudo apt-get update && sudo apt-get install -y openvpn
219
+
220
+ - name: Create OpenVPN config file
221
+ run: echo "${{ secrets.OPENVPN_CONFIG }}" > /tmp/openvpn.ovpn
222
+
223
+ - name: Connect to OpenVPN
224
+ uses: kota65535/github-openvpn-connect-action@v3
225
+ with:
226
+ config_file: /tmp/openvpn.ovpn
227
+
228
+ - name: Deploy to production server
229
+ uses: appleboy/ssh-action@v1
230
+ with:
231
+ host: ${{ secrets.PROD_SSH_HOST }}
232
+ username: ${{ secrets.PROD_SSH_USERNAME }}
233
+ key: ${{ secrets.PROD_SSH_KEY }}
234
+ passphrase: ${{ secrets.PROD_SSH_PASSPHRASE }}
235
+ port: ${{ secrets.PROD_SSH_PORT }}
236
+ envs: VERSION,DOCKER_USER,DOCKER_PASS
237
+ script: |
238
+ cd ~/front
239
+ cp docker-front-stack.yml.template docker-front-stack.yml
240
+ sed -i "s/\$VERSION/$VERSION/g" docker-front-stack.yml
241
+ docker logout dockerregistry.mobilems.pl || true
242
+ docker login -u "$DOCKER_USER" -p "$DOCKER_PASS" dockerregistry.mobilems.pl
243
+ docker stack deploy -c docker-front-stack.yml front --with-registry-auth
244
+ docker logout dockerregistry.mobilems.pl
245
+ env:
246
+ VERSION: ${{ steps.package.outputs.version }}
247
+ DOCKER_USER: ${{ secrets.GITLAB_USERNAME }}
248
+ DOCKER_PASS: ${{ secrets.GITLAB_TOKEN }}
249
+ ```
250
+
251
+ ---
252
+
253
+ ## `.github/workflows/ai-plan.yml`
254
+
255
+ ```yaml
256
+ name: AI Plan
257
+
258
+ on:
259
+ repository_dispatch:
260
+ types: [linear-ai-plan]
261
+ workflow_dispatch:
262
+ inputs:
263
+ issue_id:
264
+ description: 'Linear issue identifier (e.g. GAL-123)'
265
+ required: true
266
+ type: string
267
+
268
+ concurrency:
269
+ group: ai-plan-${{ github.event.client_payload.issue_id || github.event.inputs.issue_id }}
270
+ cancel-in-progress: false
271
+
272
+ jobs:
273
+ plan:
274
+ uses: smartsoft001/github-actions-shared/.github/workflows/ai-plan.yml@v1
275
+ with:
276
+ issue_id: ${{ github.event.client_payload.issue_id || github.event.inputs.issue_id }}
277
+ secrets:
278
+ CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
279
+ LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
280
+ ```
281
+
282
+ ---
283
+
284
+ ## `.github/workflows/ai-impl.yml`
285
+
286
+ ```yaml
287
+ name: AI Impl
288
+
289
+ on:
290
+ repository_dispatch:
291
+ types: [linear-ai-impl]
292
+ workflow_dispatch:
293
+ inputs:
294
+ issue_id:
295
+ description: 'Linear issue identifier (e.g. GAL-123). The branch will be created with this exact name.'
296
+ required: true
297
+ type: string
298
+ base_branch:
299
+ description: 'Override PR target (default: development)'
300
+ required: false
301
+ type: string
302
+ ai_size:
303
+ description: 'Manual override for AI gate classification (S/M/L). Leave empty for default M.'
304
+ required: false
305
+ type: choice
306
+ default: ''
307
+ options: ['', 'S', 'M', 'L']
308
+ ai_complexity:
309
+ description: 'Manual override for AI gate classification (S/M/L). Leave empty for default M.'
310
+ required: false
311
+ type: choice
312
+ default: ''
313
+ options: ['', 'S', 'M', 'L']
314
+
315
+ concurrency:
316
+ group: ai-impl-${{ github.event.client_payload.issue_id || github.event.inputs.issue_id }}
317
+ cancel-in-progress: false
318
+
319
+ jobs:
320
+ impl:
321
+ uses: smartsoft001/github-actions-shared/.github/workflows/ai-impl.yml@v1
322
+ with:
323
+ issue_id: ${{ github.event.client_payload.issue_id || github.event.inputs.issue_id }}
324
+ base_branch: ${{ github.event.client_payload.base_branch || github.event.inputs.base_branch || 'development' }}
325
+ ai_size: ${{ github.event.client_payload.ai_size || github.event.inputs.ai_size || '' }}
326
+ ai_complexity: ${{ github.event.client_payload.ai_complexity || github.event.inputs.ai_complexity || '' }}
327
+ secrets:
328
+ CLAUDE_CODE_OAUTH_TOKEN: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
329
+ LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
330
+ ```
331
+
332
+ ---
333
+
334
+ ## `.github/workflows/ci.yml.disabled`
335
+
336
+ Kept **disabled** (the `.disabled` suffix means GitHub never runs it). It's the Nx-Cloud template;
337
+ the team enables it by renaming to `ci.yml` and uncommenting the distribution line.
338
+
339
+ ```yaml
340
+ name: CI
341
+
342
+ on:
343
+ push:
344
+ branches:
345
+ - main
346
+ pull_request:
347
+
348
+ permissions:
349
+ actions: read
350
+ contents: read
351
+
352
+ jobs:
353
+ main:
354
+ runs-on: ubuntu-latest
355
+ steps:
356
+ - uses: actions/checkout@v4
357
+ with:
358
+ filter: tree:0
359
+ fetch-depth: 0
360
+
361
+ # This enables task distribution via Nx Cloud
362
+ # Run this command as early as possible, before dependencies are installed
363
+ # Learn more at https://nx.dev/ci/reference/nx-cloud-cli#npx-nxcloud-startcirun
364
+ # Uncomment this line to enable task distribution
365
+ # - run: npx nx start-ci-run --distribute-on="3 linux-medium-js" --stop-agents-after="e2e-ci"
366
+
367
+ # Cache node_modules
368
+ - uses: actions/setup-node@v4
369
+ with:
370
+ node-version: { { NODE_VERSION } }
371
+ cache: 'npm'
372
+
373
+ - run: npm ci
374
+ - name: Install Playwright browsers
375
+ run: npx playwright install --with-deps chromium
376
+
377
+ # Prepend any command with "nx-cloud record --" to record its logs to Nx Cloud
378
+ # - run: npx nx-cloud record -- echo Hello World
379
+ - run: npx nx run-many -t lint test build e2e
380
+ # Nx Cloud recommends fixes for failures to help you get CI green faster. Learn more: https://nx.dev/ci/features/self-healing-ci
381
+ - run: npx nx fix-ci
382
+ if: always()
383
+ ```
384
+
385
+ > Note: the reference's `ci.yml.disabled` pins Node 20. We thread `{{NODE_VERSION}}` here so the
386
+ > disabled template matches the rest of the project. If a project has a live `ci.yml` on a stale
387
+ > node version, report the drift and ask before changing it.
388
+
389
+ ---
390
+
391
+ ## Required GitHub Actions secrets
392
+
393
+ Configured in the repo's **Settings → Secrets and variables → Actions** — never committed. Print
394
+ this table for the user after writing the workflows:
395
+
396
+ | Secret | Used by | Purpose |
397
+ | ------------------------- | --------------------------- | ------------------------------------------------- |
398
+ | `GITLAB_USERNAME` | development, push-to-client | Docker registry + GitLab mirror user |
399
+ | `GITLAB_TOKEN` | development, push-to-client | Docker registry + GitLab mirror token |
400
+ | `GITLAB_REPO_PATH` | development, push-to-client | Image path / GitLab repo path |
401
+ | `DEPLOY_REPO` | development | Companion `<project>-deploy` repo name |
402
+ | `DEPLOY_TOKEN` | development | Token to dispatch `deploy.yml` in the deploy repo |
403
+ | `OPENVPN_CONFIG` | push-to-client | OpenVPN `.ovpn` config content |
404
+ | `PROD_SSH_HOST` | push-to-client | Production server host |
405
+ | `PROD_SSH_USERNAME` | push-to-client | Production SSH user |
406
+ | `PROD_SSH_KEY` | push-to-client | Production SSH private key |
407
+ | `PROD_SSH_PASSPHRASE` | push-to-client | SSH key passphrase |
408
+ | `PROD_SSH_PORT` | push-to-client | SSH port |
409
+ | `CLAUDE_CODE_OAUTH_TOKEN` | ai-plan, ai-impl | Claude Code OAuth token |
410
+ | `LINEAR_API_KEY` | ai-plan, ai-impl | Linear API key |
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # detect-foundation.sh <workspace-root>
4
+ #
5
+ # Precondition gate for mobilems-devops-config. Confirms the target is a MobilEMS museum app whose
6
+ # app-runtime foundation (built by mobilems-project-init) is already in place — this skill only adds
7
+ # the ops/deployment layer on top, it does NOT set up SSR / translations / app.config.
8
+ # Portable to the macOS system bash (3.2) — no bash-4 features.
9
+ #
10
+ # Exit 0 → MobilEMS foundation detected, OK to add the ops layer.
11
+ # Exit 2 → bad workspace path.
12
+ # Exit 3 → not a MobilEMS foundation (tell the user to run /mobilems:mobilems-project-init first).
13
+ set -eu
14
+
15
+ ROOT="${1:?usage: detect-foundation.sh <workspace-root>}"
16
+ cd "$ROOT" 2>/dev/null || { echo "ERROR: no such dir: $ROOT" >&2; exit 2; }
17
+
18
+ fail_no_foundation() {
19
+ echo "NOT A MOBILEMS FOUNDATION: $1" >&2
20
+ echo "Run /mobilems:mobilems-project-init first (this skill only adds the ops/deployment layer)." >&2
21
+ exit 3
22
+ }
23
+
24
+ # --- museum app + SSR foundation signals ---
25
+ [ -f apps/web/src/server.ts ] || fail_no_foundation "apps/web/src/server.ts missing (no SSR)"
26
+ [ -f package.json ] || fail_no_foundation "package.json missing"
27
+ grep -q "@smartsoft001-mobilems" package.json || fail_no_foundation "@smartsoft001-mobilems/* not in package.json"
28
+ grep -q "/api/translations" apps/web/src/server.ts || fail_no_foundation "/api/translations endpoint missing in server.ts"
29
+ [ -f apps/web/public/translations.json ] || fail_no_foundation "apps/web/public/translations.json missing"
30
+
31
+ echo "MOBILEMS FOUNDATION OK."
32
+
33
+ # --- report which ops artifacts are already present (informational; this skill fills the gaps) ---
34
+ have() { if [ -e "$1" ]; then echo " have: $1"; else echo " MISSING: $1"; fi; }
35
+ echo "Existing ops artifacts:"
36
+ have apps/web/Dockerfile
37
+ have .github/actions/cached-deps/action.yml
38
+ have .github/workflows/development.yml
39
+ have .github/workflows/e2e.yml
40
+ have .github/workflows/push-to-client.yml
41
+ have .github/workflows/ai-plan.yml
42
+ have .github/workflows/ai-impl.yml
43
+ have tools/scripts/update.js
44
+ have .env.dev
45
+ have .eslintignore
46
+ have .nvmrc
47
+ exit 0