Repository navigation
Add Release workflow and prepare v0.1.0-alpha.1 #45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,287 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Release | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| on: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Cut a GitHub Release with desktop installers (Linux / macOS / Windows). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| workflow_dispatch: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| inputs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| version: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: "Semver without leading v (e.g. 0.1.0-alpha.1)" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| required: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: string | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default: "0.1.0-alpha.1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| prerelease: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description: "Mark the GitHub Release as a pre-release" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| required: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| type: boolean | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| push: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tags: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - "v*" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| permissions: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| contents: write | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+21
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win Restrict repository write permission to the publish job.
Set the workflow default to Proposed fix permissions:
- contents: write
+ contents: read
...
publish:
name: Publish GitHub Release
needs: [meta, desktop]
runs-on: ubuntu-latest
+ permissions:
+ contents: writeAlso applies to: 225-228 🧰 Tools🪛 zizmor (1.29.0)[error] 22-22: overly broad permissions (excessive-permissions): contents: write is overly broad at the workflow level (excessive-permissions) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| concurrency: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| group: release-${{ github.workflow }}-${{ github.ref }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cancel-in-progress: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| jobs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| meta: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Resolve version | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| outputs: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| version: ${{ steps.out.outputs.version }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tag: ${{ steps.out.outputs.tag }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| prerelease: ${{ steps.out.outputs.prerelease }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - id: out | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shell: bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| VERSION="${{ inputs.version }}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| VERSION="${VERSION#v}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PRERELEASE="${{ inputs.prerelease }}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TAG_NAME="${GITHUB_REF_NAME}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| VERSION="${TAG_NAME#v}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ "$VERSION" == *"-"* ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PRERELEASE=true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PRERELEASE=false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-].+)?$ ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Invalid version: $VERSION" >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "tag=v$VERSION" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "prerelease=$PRERELEASE" >> "$GITHUB_OUTPUT" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+37
to
+60
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- workflow files ---'
git ls-files '.github/workflows/*'
printf '%s\n' '--- release workflow outline/context ---'
wc -l .github/workflows/release.yml
cat -n .github/workflows/release.yml | sed -n '1,180p'
printf '%s\n' '--- relevant references ---'
rg -n -C 3 'inputs\.version|GITHUB_EVENT_NAME|GITHUB_REF_NAME|VERSION=|GITHUB_OUTPUT|package\.json|npm version|tag|release' .github/workflows/release.yml
printf '%s\n' '--- behavioral probe: generated Bash from the current interpolation ---'
python3 - <<'PY'
import subprocess
template = r'''set -euo pipefail
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
VERSION="${{ inputs.version }}"
VERSION="${VERSION#v}"
else
TAG_NAME="${GITHUB_REF_NAME}"
VERSION="${TAG_NAME#v}"
fi
printf 'VERSION=<%s>\n' "$VERSION"
'''
values = {
"benign": "v1.2.3",
"quote": '"; printf "INJECTED"; #',
"command_substitution": '$(printf INJECTED)',
"newline": '1.2.3\nprintf INJECTED\n#',
}
for name, value in values.items():
generated = template.replace("${{ inputs.version }}", value)
result = subprocess.run(
["bash", "-c", generated],
text=True,
capture_output=True,
env={"GITHUB_REF_NAME": "v9.9.9"},
)
print(f"[{name}] exit={result.returncode}")
print("stdout:", repr(result.stdout))
print("stderr:", repr(result.stderr))
PYRepository: Modsofthenation/PerformanceReviewManager Length of output: 13281 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
import subprocess
current = r'''set -euo pipefail
if [[ "workflow_dispatch" == "workflow_dispatch" ]]; then
VERSION="${INPUT_VERSION}"
VERSION="${VERSION#v}"
printf 'VERSION=<%s>\n' "$VERSION"
fi
'''
direct_template = r'''set -euo pipefail
if [[ "workflow_dispatch" == "workflow_dispatch" ]]; then
VERSION="${{ inputs.version }}"
VERSION="${VERSION#v}"
printf 'VERSION=<%s>\n' "$VERSION"
fi
'''
env_template = r'''set -euo pipefail
if [[ "workflow_dispatch" == "workflow_dispatch" ]]; then
VERSION="${RELEASE_VERSION#v}"
printf 'VERSION=<%s>\n' "$VERSION"
fi
'''
values = {
"benign": "v1.2.3",
"command_substitution": '$(printf INJECTED)',
"quote_and_command": '"; printf INJECTED; #',
"newline_command": '1.2.3\nprintf INJECTED\n#',
}
for name, value in values.items():
direct = direct_template.replace("${{ inputs.version }}", value)
direct_result = subprocess.run(
["bash", "-c", direct],
text=True,
capture_output=True,
env={"PATH": "/usr/bin:/bin"},
)
env_result = subprocess.run(
["bash", "-c", env_template],
text=True,
capture_output=True,
env={"PATH": "/usr/bin:/bin", "RELEASE_VERSION": value},
)
print(f"[{name}] direct exit={direct_result.returncode}")
print(f"direct stdout={direct_result.stdout!r}")
print(f"direct stderr={direct_result.stderr!r}")
print(f"[{name}] env exit={env_result.returncode}")
print(f"env stdout={env_result.stdout!r}")
print(f"env stderr={env_result.stderr!r}")
PY
printf '%s\n' '--- current regex versus strict SemVer-shaped cases ---'
python3 - <<'PY'
import re
current = re.compile(r'^[0-9]+\.[0-9]+\.[0-9]+([.-].+)?$')
strict = re.compile(
r'^(0|[1-9][0-9]*)\.'
r'(0|[1-9][0-9]*)\.'
r'(0|[1-9][0-9]*)'
r'(?:-('
r'(?:0|[1-9][0-9]*|'
r'[0-9]*[A-Za-z-][0-9A-Za-z-]*'
r')(?:\.'
r'(?:0|[1-9][0-9]*|'
r'[0-9]*[A-Za-z-][0-9A-Za-z-]*'
r'))*)?'
r'(?:\+'
r'[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$'
)
cases = [
"1.2.3",
"0.1.0-alpha.1",
"1.2.3+build.7",
"1.2.3-alpha+build.7",
"01.2.3",
"1.2.3-01",
"1.2.3.",
"1.2.3.foo",
"1.2.3-alpha..1",
]
for value in cases:
print(f"{value:24} current={bool(current.fullmatch(value))} strict={bool(strict.fullmatch(value))}")
PYRepository: Modsofthenation/PerformanceReviewManager Length of output: 1742 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
import re
workflow_pattern = re.compile(r'^[0-9]+\.[0-9]+\.[0-9]+([.-].+)?$')
cases = [
("1.2.3", True),
("0.1.0-alpha.1", True),
("1.2.3+build.7", False),
("1.2.3-alpha+build.7", True),
("01.2.3", False),
("1.2.3-01", False),
("1.2.3.", False),
("1.2.3.foo", False),
("1.2.3-alpha..1", False),
]
for value, strict_semver_expected in cases:
accepted = bool(workflow_pattern.fullmatch(value))
print(f"{value:24} workflow_regex={accepted} strict_semver_expected={strict_semver_expected}")
PY
printf '%s\n' '--- exact Bash validation behavior ---'
for value in '1.2.3+build.7' '01.2.3' '1.2.3-01' '1.2.3.foo' '1.2.3-alpha..1'; do
if [[ "$value" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-].+)?$ ]]; then
result=accepted
else
result=rejected
fi
printf '%s: %s\n' "$value" "$result"
doneRepository: Modsofthenation/PerformanceReviewManager Length of output: 987 Pass
🧰 Tools🪛 zizmor (1.29.0)[error] 42-42: code injection via template expansion (template-injection): may expand into attacker-controllable code (template-injection) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Resolved tag=v$VERSION prerelease=$PRERELEASE" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Test (Ubuntu) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| needs: meta | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - uses: actions/checkout@v7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - uses: pnpm/action-setup@v6 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| version: 10.33.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - uses: actions/setup-node@v7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+68
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- workflow action references ---'
rg -n '^[[:space:]]*-[[:space:]]+uses:' .github/workflows/release.yml
printf '%s\n' '--- relevant workflow sections ---'
sed -n '1,280p' .github/workflows/release.ymlRepository: Modsofthenation/PerformanceReviewManager Length of output: 10348 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
import json
import re
import urllib.request
from pathlib import Path
workflow = Path(".github/workflows/release.yml").read_text()
refs = re.findall(r'uses:\s*([^@\s]+)@([^\s#]+)', workflow)
for repo, ref in refs:
if "/" not in repo:
continue
if ref.startswith(("v", "stable")):
kind = "heads" if ref == "stable" else "tags"
url = f"https://api.github.com/repos/{repo}/git/ref/{kind}/{ref}"
try:
with urllib.request.urlopen(url) as response:
data = json.load(response)
obj = data.get("object", {})
print(f"{repo}@{ref}: {kind}, type={obj.get('type')}, sha={obj.get('sha')}")
except Exception as exc:
print(f"{repo}@{ref}: lookup failed: {exc}")
else:
print(f"{repo}@{ref}: non-version ref")
PYRepository: Modsofthenation/PerformanceReviewManager Length of output: 2454 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
import json
import re
import subprocess
from pathlib import Path
refs = sorted(set(re.findall(
r'uses:\s*([^@\s]+)@([^\s#]+)',
Path(".github/workflows/release.yml").read_text(),
)))
for repo, ref in refs:
endpoint = "heads" if ref == "stable" else "tags"
url = f"https://api.github.com/repos/{repo}/git/ref/{endpoint}/{ref}"
result = subprocess.run(
["curl", "-kfsSL", "-H", "Accept: application/vnd.github+json", url],
text=True, capture_output=True, check=False,
)
try:
data = json.loads(result.stdout)
obj = data.get("object", {})
print(json.dumps({
"uses": f"{repo}@{ref}",
"ref_type": endpoint,
"object_type": obj.get("type"),
"object_sha": obj.get("sha"),
"error": data.get("message"),
}, sort_keys=True))
except Exception:
print(json.dumps({
"uses": f"{repo}@{ref}",
"error": result.stderr.strip() or result.stdout[:200],
}, sort_keys=True))
PYRepository: Modsofthenation/PerformanceReviewManager Length of output: 1570 Pin all release-pipeline actions to immutable commit SHAs. The workflow uses version tags and the 🧰 Tools🪛 zizmor (1.29.0)[warning] 68-68: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) [error] 72-72: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): this step (cache-poisoning) 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| node-version: 22 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cache: pnpm | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - run: pnpm install --frozen-lockfile | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - run: pnpm rebuild better-sqlite3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - run: pnpm -r typecheck | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - run: pnpm test | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| desktop: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Desktop ${{ matrix.platform }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| needs: [meta, test] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| strategy: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fail-fast: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| matrix: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| include: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - platform: ubuntu-22.04 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| args: --target x86_64-unknown-linux-gnu | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rust_target: x86_64-unknown-linux-gnu | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| artifact: desktop-linux-x86_64 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - platform: macos-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| args: --target aarch64-apple-darwin | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rust_target: aarch64-apple-darwin | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| artifact: desktop-macos-aarch64 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - platform: windows-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| args: --target x86_64-pc-windows-msvc | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rust_target: x86_64-pc-windows-msvc | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| artifact: desktop-windows-x86_64 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| runs-on: ${{ matrix.platform }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - uses: actions/checkout@v7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - uses: pnpm/action-setup@v6 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| version: 10.33.3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - uses: actions/setup-node@v7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| node-version: 22 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cache: pnpm | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Install Linux WebKit deps | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: runner.os == 'Linux' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sudo apt-get update | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - uses: dtolnay/rust-toolchain@stable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| targets: ${{ matrix.rust_target }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - uses: Swatinem/rust-cache@v2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| workspaces: apps/desktop/src-tauri -> target | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - run: pnpm install --frozen-lockfile | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - run: pnpm rebuild better-sqlite3 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Align package versions to release | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shell: bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| VERSION="${{ needs.meta.outputs.version }}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| python3 - <<'PY' "$VERSION" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import json, pathlib, re, sys | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| version = sys.argv[1] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| roots = [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pathlib.Path("package.json"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pathlib.Path("apps/api/package.json"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pathlib.Path("apps/ui/package.json"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pathlib.Path("apps/desktop/package.json"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pathlib.Path("packages/db/package.json"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pathlib.Path("packages/mcp/package.json"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pathlib.Path("packages/shared/package.json"), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for path in roots: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data = json.loads(path.read_text()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| data["version"] = version | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path.write_text(json.dumps(data, indent=2) + "\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| conf = pathlib.Path("apps/desktop/src-tauri/tauri.conf.json") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| conf_data = json.loads(conf.read_text()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| conf_data["version"] = version | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| conf.write_text(json.dumps(conf_data, indent=2) + "\n") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cargo = pathlib.Path("apps/desktop/src-tauri/Cargo.toml") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| text = cargo.read_text() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| text, n = re.subn(r'(?m)^version = "[^"]+"', f'version = "{version}"', text, count=1) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if n != 1: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise SystemExit("failed to patch Cargo.toml version") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cargo.write_text(text) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print(f"set version {version}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PY | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Bundle API sidecar + Node | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: node apps/desktop/scripts/bundle-api-sidecar.mjs --node | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PRM_BUNDLE_NODE: "1" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - uses: tauri-apps/tauri-action@v0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id: tauri | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| projectPath: apps/desktop | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| args: ${{ matrix.args }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| includeUpdaterJson: false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Smoke API sidecar | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shell: bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SIDE="apps/desktop/src-tauri/sidecars" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UI="apps/desktop/src-tauri/ui-dist" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if [[ "${{ runner.os }}" == "Windows" ]]; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NODE="$SIDE/node.exe" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| NODE="$SIDE/node" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| chmod +x "$NODE" || true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test -f "$NODE" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test -f "$SIDE/prm-api.mjs" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test -f "$UI/index.html" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DATA="${RUNNER_TEMP:-/tmp}/prm-sidecar-smoke" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rm -rf "$DATA" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mkdir -p "$DATA" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PRM_DATA_DIR="$DATA" PRM_PORT=8799 PRM_LAUNCH_TOKEN=ci-smoke PRM_UI_DIR="$UI" \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "$NODE" "$SIDE/prm-api.mjs" >"$DATA/out.log" 2>&1 & | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PID=$! | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cleanup() { kill "$PID" 2>/dev/null || true; } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| trap cleanup EXIT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for i in $(seq 1 50); do | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if curl -sf "http://127.0.0.1:8799/api/health" >/dev/null; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "sidecar healthy" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| curl -sf "http://127.0.0.1:8799/api/workspace/status" -H "x-prm-launch-token: ci-smoke" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| sleep 0.2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "sidecar failed to become healthy" >&2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cat "$DATA/out.log" >&2 || true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Stage installer artifacts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| shell: bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SRC="apps/desktop/src-tauri/target/${{ matrix.rust_target }}/release/bundle" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DST="${RUNNER_TEMP}/release-assets" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mkdir -p "$DST" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Prefer distributable installers; skip raw .app directories. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| find "$SRC" -type f \( \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -name '*.deb' -o -name '*.AppImage' -o -name '*.rpm' -o \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -name '*.dmg' -o -name '*.msi' -o -name '*.exe' \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| \) -print -exec cp -v {} "$DST/" \; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ls -la "$DST" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| test -n "$(ls -A "$DST")" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Upload desktop installers | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/upload-artifact@v7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: ${{ matrix.artifact }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path: ${{ runner.temp }}/release-assets/* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if-no-files-found: error | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| retention-days: 30 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| publish: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Publish GitHub Release | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| needs: [meta, desktop] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| runs-on: ubuntu-latest | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| steps: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - uses: actions/checkout@v7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fetch-depth: 0 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Download installer artifacts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: actions/download-artifact@v7 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| path: release-assets | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pattern: desktop-* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| merge-multiple: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: List assets | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: find release-assets -type f | sort | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Ensure release tag exists | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if: github.event_name == 'workflow_dispatch' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| TAG: ${{ needs.meta.outputs.tag }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| run: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| git config user.name "github-actions[bot]" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if git rev-parse "$TAG" >/dev/null 2>&1; then | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| echo "Tag $TAG already exists" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| git tag -a "$TAG" -m "Release $TAG" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| git push origin "$TAG" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+241
to
+254
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win Verify the existing tag points to the built commit. Line 249 only checks whether the tag exists. A manual run from another ref can upload new installers to a release whose tag identifies an older commit. If the tag exists, compare its dereferenced commit with Proposed fix- if git rev-parse "$TAG" >/dev/null 2>&1; then
- echo "Tag $TAG already exists"
+ if git rev-parse -q --verify "refs/tags/$TAG^{commit}" >/dev/null; then
+ TAG_COMMIT="$(git rev-list -n 1 "$TAG")"
+ HEAD_COMMIT="$(git rev-parse HEAD)"
+ if [[ "$TAG_COMMIT" != "$HEAD_COMMIT" ]]; then
+ echo "Tag $TAG points to $TAG_COMMIT, but this build uses $HEAD_COMMIT" >&2
+ exit 1
+ fi
+ echo "Tag $TAG already exists at the built commit"
else
git tag -a "$TAG" -m "Release $TAG"
git push origin "$TAG"📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - name: Create GitHub Release | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uses: softprops/action-gh-release@v2 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tag_name: ${{ needs.meta.outputs.tag }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: Performance Review Manager ${{ needs.meta.outputs.tag }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| prerelease: ${{ needs.meta.outputs.prerelease == 'true' }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| generate_release_notes: true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| body: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Alpha release | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Local workbench for evidence-backed performance reviews and promotion cases. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Desktop installers | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | Platform | Artifact | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |----------|----------| | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | Linux x86_64 | `.deb` / `.AppImage` | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | macOS Apple Silicon | `.dmg` | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| | Windows x86_64 | `.msi` / NSIS `.exe` | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Notes | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - First-run: create an empty workspace or demo team; lock/encrypt between sessions. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Demo password is for exploration only — do not store real employee data behind it. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - Signed auto-update is not enabled yet; use **Settings → Check for desktop updates** or download from this release. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### Verify | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Compare checksums after download if your browser provides them, then install and unlock a fresh workspace. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| files: | | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| release-assets/* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| env: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,7 @@ Performance Review Manager — a local, single-user ("solo EM") pnpm monorepo. S | |
| - `@prm/api` (`apps/api`) — Hono + better-sqlite3 backend on `http://127.0.0.1:8787`. Run with `pnpm dev:api` (uses `tsx watch`, no strict typecheck). | ||
| - `@prm/ui` (`apps/ui`) — React + Vite frontend on `http://localhost:5173`, proxies `/api` → the API. Run with `pnpm dev:ui`. | ||
| - `pnpm dev` runs both in parallel — this is the primary dev entrypoint. | ||
| - `@prm/desktop` (`apps/desktop`) — Tauri shell. `desktop:dev`/`desktop:build` need Rust + system WebView libraries and are not validated in the headless cloud VM. Packaged desktop installers run only via Actions → **Desktop Installers** → **Run workflow** (not on every merge; defaults to Windows + Linux). | ||
| - `@prm/desktop` (`apps/desktop`) — Tauri shell. `desktop:dev`/`desktop:build` need Rust + system WebView libraries and are not validated in the headless cloud VM. Packaged desktop installers run via Actions → **Desktop Installers** → **Run workflow** (not on every merge; defaults to Windows + Linux). Formal GitHub Releases (with installers attached) use Actions → **Release** → **Run workflow**. | ||
|
|
||
| ### Package manager (important, non-obvious) | ||
| - This repo requires **pnpm 10.33.3**. The VM's default corepack resolves pnpm 11, which (a) rejects this committed lockfile via a `minimumReleaseAge` supply-chain policy and (b) ignores the `pnpm.onlyBuiltDependencies` field in `package.json` that is needed to build the `better-sqlite3` native module. The update script pins 10.33.3 via `corepack prepare [email protected] --activate`; keep using pnpm 10.x. If native `better-sqlite3` is missing, run `pnpm rebuild better-sqlite3`. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Derive prerelease status from the release version.
A manual run can publish
0.1.0-alpha.1withprerelease: false. That release can then become/releases/latest, despite the desktop updater excluding prereleases.Derive
PRERELEASEfrom the validated SemVer prerelease component for both triggers. Alternatively, fail when the manual input conflicts with the version.Also applies to: 41-52
🤖 Prompt for AI Agents