@@ -12,6 +12,7 @@ Use this skill to create or repair GitLab CI for projects that need conservative
1. Inspect the repository before writing CI.
Read the existing `.gitlab-ci.yml` if present.
Search for build entrypoints such as `package.json`, `pnpm` scripts, root `.sh` files, Docker-based build scripts, OSS upload helpers, and any project `AGENTS.md` rules.
Explicitly verify whether `package.json`, `pnpm-lock.yaml`, `package-lock.json`, `yarn.lock`, and `pnpm-workspace.yaml` really exist before choosing an install strategy.
Treat project-level comment blocks and copied examples as hints until they are confirmed by the repository or by the user. Do not copy a sample “第二部分:项目级说明” into the final CI as if it were automatically true for the current project.
2. Identify the deployment model.
...
...
@@ -20,9 +21,12 @@ Use this skill to create or repair GitLab CI for projects that need conservative
Determine whether artifacts are passed through a shared transfer directory instead of GitLab artifacts.
Determine whether build output directories must be isolated by module or environment.
Determine whether the user wants tag-prefix routing so only one environment or module job set runs for a given tag.
Identify the release contract with this evidence priority: user-provided CI snippets or variable names first, then the current repository `.gitlab-ci.yml` and release scripts, then organization clues in the current repository such as `springjk/ci-helper:latest`, `springjk/webdev:*`, `oss-deploy`, `OSS_DEPLOY_NAME`, and `tags: [web]`, then neighboring repositories in the same workspace that clearly belong to the same Bingo or SGKT family, and finally align the generated result to the fixed OSS release pattern used by this skill.
Determine whether the repository or the user has already established a release contract, such as a fixed `.release_template`, a required release image like `springjk/ci-helper:latest`, a required script signature like `sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"`, or a required uploader like `oss-deploy`.
For Bingo, SGKT, `nceduc`, `dhq`, `xinyu`, and `sr` style frontend repositories, or repositories that use `springjk/webdev`, multiple `.env.*`, multiple `build:*` scripts, or have same-family neighbors in the workspace, assume the organization-standard frontend release model first: `build_x + release_x` pairing, `release` on `springjk/ci-helper:latest`, explicit `tags: ["web"]`, `sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"`, and OSS upload through `oss-deploy`.
Unless the user explicitly asks to collapse stages, preserve strict `build_x + release_x` pairing and keep release focused on zip packaging plus OSS upload.
If an existing repository or user-provided snippet establishes the release contract, treat that contract as mandatory and preserve it unless the user explicitly asks to replace it.
This skill does not downgrade release to artifacts-only. If repository evidence is incomplete, continue collecting evidence from neighboring same-family repositories and still generate the fixed OSS release structure.
3. Confirm the GitLab compatibility target.
If the user mentions an old GitLab version such as 11.x, assume conservative compatibility.
...
...
@@ -47,7 +51,8 @@ Default to this structure unless the repo clearly needs something else:
- Helper scripts live under `ci/` when they are reused by multiple jobs.
- Usage documentation lives in `CI_USAGE.md` when the pipeline has multiple environments or non-obvious constraints.
- If the user wants selective execution, add explicit tag-prefix conditions per job pair so one tag only triggers the intended `build_x + release_x`.
- Prefer OSS-oriented release behavior by default: generate `dist-x-<date>.zip` and `dist-x-latest.zip`, stage them into upload directories when needed, and upload from release jobs. Do not silently replace this with “copy to server directory + switch current symlink” unless the repository already uses that deployment model and the user wants to preserve it.
- For Bingo or SGKT family frontend repositories, default the generated release contract to `image: springjk/ci-helper:latest`, `tags: ["web"]`, and `sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"` unless stronger evidence from the repository or user overrides it with another organization-standard contract.
- Use fixed OSS-oriented release behavior: generate `dist-x-<date>.zip` and `dist-x-latest.zip`, stage them into upload directories when needed, and upload from release jobs. Do not replace this skill's release stage with GitLab artifacts-only output.
- If the repository or the user already defines a concrete OSS release skeleton, preserve the release image, script entry, argument order, uploader contract, and variable names unless the user explicitly requests a migration. Do not downgrade that release stage to GitLab artifacts-only output, ad hoc server-directory copying, or a different uploader contract.
## Legacy GitLab Rules
...
...
@@ -84,9 +89,13 @@ For each environment or module X:
- Put build output in `$TRANSFER_BASE_DIR/x/dist`.
- Package release output as `dist-x-<date>.zip` and `dist-x-latest.zip` when the project wants versioned zips.
- If the uploader only accepts directories, stage zip files inside dedicated upload directories before calling the uploader.
- If any evidence shows the organization contract `image: springjk/ci-helper:latest` plus `tags: ["web"]` plus `sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"`, keep all three elements together. Do not preserve only one or two of them.
- If the project already uses a release template such as `image: springjk/ci-helper:latest` plus `sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"`, keep that structure and wire every `release_x` job through `OSS_DEPLOY_NAME`. Do not rename the variable or replace the image unless the user explicitly approves the change.
- If using tag-prefix routing, give each pair a unique non-overlapping prefix and apply the same prefix condition to both `build_x` and `release_x`.
- Do not keep only `build_x` when the skill is supposed to follow the default OSS release pattern; if a release job is intentionally omitted, document why and confirm that this is a user choice rather than an accidental drift from the standard pattern.
- Never output an artifacts-only `release` stage from this skill. The fixed mode is `build_x + release_x` plus OSS upload.
- Map `OSS_DEPLOY_NAME` from real `package.json``build:*` targets first, then infer naming style from same-family repositories when needed. Do not mechanically reuse the build target as the OSS name if the family convention points to names like `bingo-prod`, `bingo-dev`, `shangrao-dev`, or `xinyu-prod`.
- When any `OSS_DEPLOY_NAME` value is inferred rather than confirmed, say so explicitly in the final explanation and tell the user that only the variable value should change, not the script structure.
## Shell Script Rules
...
...
@@ -97,6 +106,8 @@ When the repository already uses `.sh` build scripts:
- Make scripts POSIX `sh` unless the repository clearly needs `bash`.
- Validate shell syntax after editing.
- Match the install command to the actual repository package manager. Do not force `pnpm` only because a copied comment block says so if the repository actually uses `npm` or `yarn`.
- If CI uses `pnpm`, only use `pnpm install --frozen-lockfile` when the repository really contains `pnpm-lock.yaml`. If `pnpm-lock.yaml` is missing, fall back to `pnpm install --no-frozen-lockfile`, log the mismatch clearly, and recommend adding the lockfile later.
- If docs, README, comments, or copied examples claim a lockfile exists but the repository does not contain it, treat the repository state as source of truth and update the docs to remove the mismatch.
- For npm-based repositories in this skill, use `npm install`. Do not use `npm ci`.
## Validation
...
...
@@ -106,14 +117,19 @@ After edits, validate at least these points:
- YAML parses successfully.
- Unsupported keys for the target GitLab version are absent.
- Every active `build_*` job has a matching `release_*` job.
- The final pipeline still preserves `build_x + release_x` pairs and does not drift to build-only or artifacts-only release.
-`springjk/ci-helper:latest` is still present whenever the established organization release contract requires it.
- Every concrete job has `tags: ["web"]` if the project requires that runner tag.
- The release command still calls `sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"` when that contract was established.
- Tag-prefix expressions do not overlap unless the user explicitly wants multiple pairs to run.
- Shell scripts pass `sh -n`.
- Documentation matches the actual active jobs.
- Lockfile assumptions in CI, scripts, and docs all match the repository state that was actually checked.
- The selected Node image is an official `node:X-alpine` image whose version matches the project evidence.
- Project-level notes copied into comments have been verified against real build scripts before being treated as facts.
- If the repository or user provided a release snippet, the final `.release_template` still uses the required release image, script command, argument order, and uploader variable names.
- The release path still stages zip files into directories before calling the uploader when that uploader contract requires directories.
- Every `release_*` job has `OSS_DEPLOY_NAME`, and the final explanation distinguishes confirmed mappings from inferred mappings.
When the project fits the common pattern of tag-triggered frontend publishing with shell-based build helpers, reuse the bundled template at [`assets/gitlab-tag-release-template`](assets/gitlab-tag-release-template).
Copy only the files that fit the target repository, then replace placeholders such as `__MODULE_NAME__`, `__BUILD_TARGET__`, `__PNPM_BUILD_SCRIPT__`, `__RUNNER_TAG__`, `__PACKAGE_DIR__`, and `__TAG_PREFIX__`.
Copy only the files that fit the target repository, then replace placeholders such as `__BUILD_TARGET__`, `__BUILD_COMMAND__`, `__PACKAGE_MANAGER__`, `__PACKAGE_DIR__`, `__TAG_PREFIX__`, and `__OSS_DEPLOY_NAME__`.
When the project has multiple frontend modules such as `web` and `admin`, prefer [`assets/gitlab-multi-frontend-template`](assets/gitlab-multi-frontend-template).
Use it when each module needs its own isolated build output directory, its own `build_x + release_x` pair, and optionally its own tag prefix such as `web-*` or `admin-*`.
@@ -4,17 +4,14 @@ Use this template when the repository has multiple frontend modules such as `web
## Replace these placeholders
-`__RUNNER_TAG__`
-`__BUILD_IMAGE__`
-`__RELEASE_IMAGE__`
-`__WEB_PACKAGE_DIR__`
-`__WEB_INSTALL_COMMAND__`
-`__WEB_PACKAGE_MANAGER__`
-`__WEB_BUILD_COMMAND__`
-`__WEB_DIST_SUBDIR__`
-`__WEB_OSS_NAME__`
-`__WEB_TAG_PREFIX__`
-`__ADMIN_PACKAGE_DIR__`
-`__ADMIN_INSTALL_COMMAND__`
-`__ADMIN_PACKAGE_MANAGER__`
-`__ADMIN_BUILD_COMMAND__`
-`__ADMIN_DIST_SUBDIR__`
-`__ADMIN_OSS_NAME__`
...
...
@@ -28,18 +25,42 @@ Use this template when the repository has multiple frontend modules such as `web
4. Dist directories are normalized to `/cache/transfer/${CI_PIPELINE_ID}/web/dist` and `/cache/transfer/${CI_PIPELINE_ID}/admin/dist`.
5. Only tags matching the configured module prefix trigger that module pair.
6. Prefer an official Node image such as `node:16-alpine` or `node:24-alpine`, selected from project evidence.
7. Each build script checks the real lockfile state first, so pnpm repositories without `pnpm-lock.yaml` automatically fall back to `pnpm install --no-frozen-lockfile`.
8. For Bingo / SGKT family repositories, `release_*` defaults to `springjk/ci-helper:latest` and all concrete jobs default to `tags: ["web"]`.
9. Each `release_*` keeps the contract `sh ci/release-dist.sh "$MODULE_NAME" "$OSS_DEPLOY_NAME"` and this skill does not downgrade release to artifacts-only.
## Package manager rule
Choose each module's install and build commands from the checked-in repository:
- npm module: `__WEB_INSTALL_COMMAND__` could be `npm install`, `__WEB_BUILD_COMMAND__` could be `npm run build`
- pnpm module: `__ADMIN_INSTALL_COMMAND__` could be `pnpm install --frozen-lockfile`, `__ADMIN_BUILD_COMMAND__` could be `pnpm run build --filter=@vben/web-antdv-next`
- yarn module: use `yarn install --frozen-lockfile` plus the module's real build command
- First verify whether these files really exist in the repository: `package.json`, `pnpm-lock.yaml`, `package-lock.json`, `yarn.lock`, `pnpm-workspace.yaml`
- Also verify each module's real build entrypoints from `package.json` scripts, existing `build*.sh`, and existing `ci/*.sh`
- npm module: set `__WEB_PACKAGE_MANAGER__` or `__ADMIN_PACKAGE_MANAGER__` to `npm`, then use the module's real `__WEB_BUILD_COMMAND__` or `__ADMIN_BUILD_COMMAND__`
- pnpm module with `pnpm-lock.yaml`: set the module package manager to `pnpm`, then use the real build command
- pnpm module without `pnpm-lock.yaml`: still use `pnpm`, but let the script fall back to `pnpm install --no-frozen-lockfile` and keep the warning in logs
- yarn module with `yarn.lock`: use `yarn` plus the module's real build command
- yarn module without `yarn.lock`: let the script fall back to `yarn install`
Do not assume all modules use `pnpm` just because one copied project note mentions it.
Do not hardcode `pnpm install --frozen-lockfile` unless the repository actually contains `pnpm-lock.yaml`.
If documentation or copied samples claim a lockfile exists but the repository does not contain it, follow the repository state and update the docs to match.
Do not use `npm ci` as the default npm install command in this template.
## Release contract rule
When the target repository is part of the Bingo / SGKT family and no stronger repository-specific contract overrides it, keep these elements together:
For `__WEB_OSS_NAME__`, `__ADMIN_OSS_NAME__`, and similar values, distinguish between:
- confirmed mappings from the current repository or explicit user input
- inferred mappings from same-family repository naming patterns
If a mapping is inferred, call it out in the final explanation and tell the user they only need to adjust the variable value if the real OSS name differs.
## Prefix design rule
On older GitLab versions, use simple non-overlapping prefixes.
@@ -11,15 +11,12 @@ Use this template when the project needs:
## Replace these placeholders
-`__PACKAGE_DIR__`
-`__RUNNER_TAG__`
-`__BUILD_IMAGE__`
-`__RELEASE_IMAGE__`
-`__BUILD_TARGET__`
-`__INSTALL_COMMAND__`
-`__PACKAGE_MANAGER__`
-`__BUILD_COMMAND__`
-`__MODULE_NAME__`
-`__JOB_SUFFIX__`
-`__TAG_PREFIX__`
-`__OSS_DEPLOY_NAME__`
## Required files
...
...
@@ -29,24 +26,55 @@ Use this template when the project needs:
## Default behavior
1. Build job installs dependencies and runs one target build command.
1. Build job first checks the real repository files, then installs dependencies and runs one target build command.
2. Dist is copied to `$TRANSFER_BASE_DIR/<target>/dist`.
3. Release job creates dated and latest zip files.
4. Each zip is staged inside an upload directory before calling `oss-deploy`.
5. Only tags matching `__TAG_PREFIX__*` trigger this job pair.
6. Prefer an official Node image such as `node:16-alpine` or `node:24-alpine`, selected from project evidence.
7. If the repo uses pnpm but has no `pnpm-lock.yaml`, the build script logs the mismatch and falls back to `pnpm install --no-frozen-lockfile`.
8. For Bingo / SGKT family repositories, `release` defaults to `springjk/ci-helper:latest` and all concrete jobs default to `tags: ["web"]`.
9. The release command shape stays `sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"` and this skill does not downgrade release to artifacts-only.
## Package manager rule
Choose install and build commands from the checked-in repository, not from copied comments:
Choose package manager and build command from the checked-in repository, not from copied comments.
Before finalizing CI, verify whether these files really exist in the repository:
- npm repo: `__INSTALL_COMMAND__` might be `npm install`, `__BUILD_COMMAND__` might be `npm run build:demo`
- pnpm repo: `__INSTALL_COMMAND__` might be `pnpm install --frozen-lockfile`, `__BUILD_COMMAND__` might be `pnpm run build:demo`
- yarn repo: `__INSTALL_COMMAND__` might be `yarn install --frozen-lockfile`, `__BUILD_COMMAND__` might be `yarn build:demo`
-`package.json`
-`pnpm-lock.yaml`
-`package-lock.json`
-`yarn.lock`
-`pnpm-workspace.yaml`
Do not hardcode `pnpm` in the template output unless the repository actually uses `pnpm`.
Also verify the real build entrypoints:
-`package.json` scripts
- existing `build*.sh`
- existing `ci/*.sh`
The template shell script branches on the real files that exist at runtime:
- npm repo: set `__PACKAGE_MANAGER__` to `npm`, `__BUILD_COMMAND__` might be `npm run build:demo`
- pnpm repo with `pnpm-lock.yaml`: set `__PACKAGE_MANAGER__` to `pnpm`, `__BUILD_COMMAND__` might be `pnpm run build:demo`
- pnpm repo without `pnpm-lock.yaml`: still set `__PACKAGE_MANAGER__` to `pnpm`, and let the script fall back to `pnpm install --no-frozen-lockfile`
- yarn repo with `yarn.lock`: set `__PACKAGE_MANAGER__` to `yarn`, `__BUILD_COMMAND__` might be `yarn build:demo`
- yarn repo without `yarn.lock`: let the script fall back to `yarn install`
Do not hardcode `pnpm install --frozen-lockfile` unless the repository actually contains `pnpm-lock.yaml`.
If documentation or copied examples claim `pnpm-lock.yaml` exists but the repository does not contain it, follow the repository state, log the mismatch, and update the docs.
Do not use `npm ci` as the default npm install command in this template.
## Release contract rule
When the target repository is part of the Bingo / SGKT family and no stronger repository-specific contract overrides it, keep these elements together:
If `OSS_DEPLOY_NAME` cannot be confirmed from the current repository, infer it from same-family repositories and mark it in the final explanation as an inferred value that can be adjusted without changing the script structure.
## Prefix design rule
On older GitLab versions, use simple non-overlapping prefixes.
3. Verify whether any copied “项目级说明” block is factual for this repo or only a reusable example; do not assume it is true without checking.
4. Map each environment to a concrete build command.
5. Detect the Node major version from primary evidence and prefer an official `node:X-alpine` image with the matching major version.
6. Decide whether helper scripts under `ci/` reduce repetition.
7. Generate `build_x + release_x` pairs only for active environments.
8. If the user wants one tag to run only one pair, assign unique tag prefixes per pair.
9. Remove paused environments completely, including matching release jobs and documentation references.
10. If the repository or user provides a release snippet, preserve its release image, script signature, uploader contract, and variable names unless explicitly asked to migrate.
11. Validate YAML and shell syntax.
12. Update usage docs if you changed active jobs, file names, or release behavior.
3. Collect release-contract evidence in this order: user-provided CI snippets and variable names, current repository CI and release scripts, organization clues inside the current repository, neighboring same-family repositories in the same workspace, then align the generated result to this skill's fixed OSS release pattern.
4. Explicitly verify whether `package.json`, `pnpm-lock.yaml`, `package-lock.json`, `yarn.lock`, and `pnpm-workspace.yaml` really exist before deciding how CI installs dependencies.
5. Verify whether any copied “项目级说明” block is factual for this repo or only a reusable example; do not assume it is true without checking.
6. If the repository name, environments, or neighboring projects indicate Bingo, SGKT, `nceduc`, `dhq`, `xinyu`, or `sr`, start from the organization-standard frontend release model instead of a generic template.
7. Map each environment to a concrete build command.
8. Detect the Node major version from primary evidence and prefer an official `node:X-alpine` image with the matching major version.
9. Decide whether helper scripts under `ci/` reduce repetition.
10. Generate `build_x + release_x` pairs only for active environments.
11. If the user wants one tag to run only one pair, assign unique tag prefixes per pair.
12. Remove paused environments completely, including matching release jobs and documentation references.
13. If the repository or user provides a release snippet, preserve its release image, script signature, uploader contract, and variable names unless explicitly asked to migrate.
14. Validate YAML and shell syntax.
15. Update usage docs if you changed active jobs, file names, release behavior, or lockfile assumptions.
## Organization-standard frontend release model
When any of these signals are present, assume the repository belongs to the organization-standard frontend family first:
- Repository or environment names include `sgkt`, `bingo`, `nceduc`, `dhq`, `xinyu`, or `sr`
- The repository uses `springjk/webdev`
- The repository contains multiple `.env.*` files and multiple `build:*` scripts
- The same workspace contains clearly related frontend repositories
If you need per-environment selective triggering on GitLab 11.x, prefer `only: refs + variables` with disjoint prefixes.
...
...
@@ -108,11 +132,14 @@ If the repository has two or more frontend modules, start from `assets/gitlab-mu
Pick the install command from real repository evidence:
-`pnpm install --frozen-lockfile` when the repo actually uses `pnpm`
-`pnpm install --frozen-lockfile` only when the repo actually uses `pnpm` and really contains `pnpm-lock.yaml`
-`pnpm install --no-frozen-lockfile` when the repo uses `pnpm` but `pnpm-lock.yaml` is currently missing
-`npm install` when the repo actually uses `npm`
-`yarn install --frozen-lockfile` when the repo actually uses `yarn`
-`yarn install --frozen-lockfile` when the repo actually uses `yarn` and really contains `yarn.lock`
-`yarn install` when the repo uses `yarn` but `yarn.lock` is currently missing
Do not force `pnpm` because a copied comment block says so if the checked-in repository does not support it.
If copied docs or examples mention `pnpm-lock.yaml` but the repository does not contain it, treat that as a documentation mismatch, follow the repository state, and fix the docs.
Do not use `npm ci` in this skill. For npm-based repositories, use `npm install`.
## Default release script behavior
...
...
@@ -125,8 +152,9 @@ Do not use `npm ci` in this skill. For npm-based repositories, use `npm install`
4. If uploader only accepts directories, copy each zip into a dedicated upload directory.
5. Call the uploader for the dated package and latest package.
Default to OSS-oriented release logic. Only switch to server-directory deployment when the repository already uses that model and the user wants to preserve it.
Default to OSS-oriented release logic in this skill. Do not switch to artifacts-only release.
If the repository or the user already established a release contract such as `springjk/ci-helper:latest` and `OSS_DEPLOY_NAME`, preserve that contract exactly unless the user explicitly requests a migration.
If any evidence establishes the triple `springjk/ci-helper:latest` plus `tags: ["web"]` plus `sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"`, keep all three together. Do not downgrade to generic Alpine, omit the `web` runner tag, or replace the script with artifacts-only behavior.
## Common failure patterns
...
...
@@ -166,6 +194,11 @@ Prefer official images such as `node:16-alpine` or `node:24-alpine`, selected fr
Some repositories or runner environments fail on `npm ci` even though `npm install` works normally.
For npm-based repositories in this skill, always use `npm install`.
### `ERR_PNPM_NO_LOCKFILE`
CI used `pnpm install --frozen-lockfile`, but the repository does not actually contain `pnpm-lock.yaml`.
Treat the missing lockfile as the root cause, fall back to `pnpm install --no-frozen-lockfile`, and update the docs so they stop claiming the lockfile exists.
### Uploader says source path not found
The uploader may expect a directory instead of a file.
...
...
@@ -177,6 +210,13 @@ The skill may have simplified release into `artifacts`, a generic Alpine image,
Re-check whether the repository or the user already specified a release image, `oss-deploy`, `OSS_DEPLOY_NAME`, or a fixed `ci/release-dist.sh` call shape.
When those exist, they are not optional hints. Restore them and align every `release_x` job to the same contract.
### Current repo looks blank but same-family repos already use OSS release
Some Bingo or SGKT repositories have incomplete local CI history even though the organization contract is stable in neighboring repositories.
Do not conclude “no OSS contract” from the current repo alone.
Search same-family repositories in the workspace for `springjk/ci-helper:latest`, `tags: [web]`, `OSS_DEPLOY_NAME`, `oss-deploy`, and `ci/release-dist.sh`.
If those neighbors consistently use the organization contract, inherit that contract and mark `OSS_DEPLOY_NAME` mappings as confirmed or inferred in the final explanation.
### UI shows jobs the user no longer wants
Remove the matching `build_x` and `release_x` jobs together.
...
...
@@ -188,7 +228,10 @@ Do not do these unless the user explicitly wants them:
- Do not replace the standard `build_x + release_x` OSS flow with server-directory deployment.
- Do not replace an existing or user-specified OSS release template such as `springjk/ci-helper:latest` plus `sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"` with a generic image, `artifacts`, or another release contract.
- Do not preserve only one or two parts of the organization-standard release triple. If `springjk/ci-helper:latest`, `tags: ["web"]`, and `sh ci/release-dist.sh "$BUILD_TARGET" "$OSS_DEPLOY_NAME"` are established, keep all three.
- Do not use custom repository-specific Node images when an official `node:X-alpine` image can be selected from project evidence.
- Do not treat copied “项目级说明” sections as proven facts without checking the repository.
- Do not hardcode `pnpm install --frozen-lockfile` unless `pnpm-lock.yaml` really exists in the repository.
- Do not use `npm ci` as the default npm install command.
- Do not leave only `build_x` without `release_x` when the default OSS release pattern is expected.
- Do not output artifacts-only release from this skill. The fixed mode is `build_x + release_x` plus OSS upload.