diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 85c548c0..3dba235b 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,5 +1,5 @@ name: "🐛 Bug report" -description: "Something in CopyPaste does not work the way it should" +description: "Something in CoPanda does not work the way it should" labels: ["bug"] body: - type: markdown @@ -15,7 +15,7 @@ body: - type: input id: version attributes: - label: "CopyPaste version" + label: "CoPanda version" description: "Shown under **Settings → About**." placeholder: "3.0.0" validations: @@ -79,7 +79,7 @@ body: attributes: label: "Logs (optional)" description: | - CopyPaste keeps two plain-text logs, `cp-gui.log` for the settings window and + CoPanda keeps two plain-text logs, `cp-gui.log` for the settings window and `cp-panel.log` for the panel. **Settings → History → Data folder → Open folder** takes you there, or look in `%LocalAppData%\CopyPaste\logs` on Windows and `~/Library/Application Support/CopyPaste/logs` on a Mac. They record events and errors, diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index a894ded2..b7ee277a 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,11 +1,11 @@ name: "💡 Feature request" -description: "Something CopyPaste could do, or do better" +description: "Something CoPanda could do, or do better" labels: ["enhancement"] body: - type: markdown attributes: value: | - Ideas are welcome. CopyPaste tries to stay small, fast and private: everything stays on + Ideas are welcome. CoPanda tries to stay small, fast and private: everything stays on your machine, nothing needs an account, and the panel should feel native on Windows and on a Mac. A request that keeps to that has the best chance. @@ -15,7 +15,7 @@ body: id: problem attributes: label: "What are you trying to do?" - description: "The situation, not the solution: what you were doing when CopyPaste fell short." + description: "The situation, not the solution: what you were doing when CoPanda fell short." placeholder: "I copy the same three addresses every day and have to search for them each time." validations: required: true diff --git a/.github/workflows/bundle.yml b/.github/workflows/bundle.yml index 3c3047b4..76e561cd 100644 --- a/.github/workflows/bundle.yml +++ b/.github/workflows/bundle.yml @@ -124,23 +124,27 @@ jobs: "lay down the panel; the sidecar was not bundled" want 'StrCpy $INSTDIR "$LOCALAPPDATA\Programs' \ "keep the binaries out of the data folder" + want '!define MAINBINARYNAME "cp-gui"' \ + "keep cp-gui.exe, the program the startup entry and the shortcuts already point at" + want '!define HOMENAME "CopyPaste"' \ + "keep the folders, keys and startup entry it has always had under CopyPaste" want '_is1" "UninstallString"' \ "look for CopyPaste 2 before copying anything" for one in history.db history.db-wal history.db-shm config.toml update.json; do - want "Delete \"\$LOCALAPPDATA\\\${PRODUCTNAME}\\$one\"" \ + want "Delete \"\$LOCALAPPDATA\\\${HOMENAME}\\$one\"" \ "take the $one it owns when asked to delete its data" done for one in cp-gui.log cp-panel.log; do - want "Delete \"\$LOCALAPPDATA\\\${PRODUCTNAME}\\logs\\$one\"" \ + want "Delete \"\$LOCALAPPDATA\\\${HOMENAME}\\logs\\$one\"" \ "take its own $one" done for one in blobs thumbs; do - want "RmDir /r \"\$LOCALAPPDATA\\\${PRODUCTNAME}\\$one\"" \ + want "RmDir /r \"\$LOCALAPPDATA\\\${HOMENAME}\\$one\"" \ "take the $one it owns" done - want 'RmDir "$LOCALAPPDATA\${PRODUCTNAME}\logs"' \ + want 'RmDir "$LOCALAPPDATA\${HOMENAME}\logs"' \ "leave the log folder only once its own logs are gone" - want 'RmDir "$LOCALAPPDATA\${PRODUCTNAME}"' \ + want 'RmDir "$LOCALAPPDATA\${HOMENAME}"' \ "leave the shared folder standing unless it is already empty" stray=$(grep -oiE 'RmDir( /[A-Za-z]+)* /r "[^"]*"' "$flat" \ | grep -viE '(\\blobs|\\thumbs|\$\{BUNDLEID\}|\$INSTDIR)"$' || true) diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml index 7ef1286a..bc6c9907 100644 --- a/.github/workflows/cla.yml +++ b/.github/workflows/cla.yml @@ -20,7 +20,7 @@ jobs: project: copypaste document-url: https://github.com/rgdevment/CopyPaste/blob/main/CLA.md not-signed-message: >- - Thanks for the pull request. CopyPaste is released under the GPL-3.0 and offered under + Thanks for the pull request. CoPanda is released under the GPL-3.0 and offered under separate commercial terms, which requires a signature from whoever opened it and every author and co-author of its commits before it can be merged. You keep the copyright on your work. To sign, post a comment on this pull request with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 767738cc..825dc983 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -431,7 +431,7 @@ jobs: echo "::error::the bundler produced no installer" exit 1 fi - cp "$setup" "dist/copypaste-installer-$v-windows-x86_64.exe" + cp "$setup" "dist/copanda-installer-$v-windows-x86_64.exe" ls -l dist - name: Sign it for the updater @@ -443,7 +443,7 @@ jobs: TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} run: | v="${{ needs.version.outputs.version }}" - exe="../dist/copypaste-installer-$v-windows-x86_64.exe" + exe="../dist/copanda-installer-$v-windows-x86_64.exe" rm -f "$exe.sig" npm run tauri -- signer sign --app-version "$v" "$exe" test -s "$exe.sig" || { echo "::error::no updater signature was written"; exit 1; } @@ -560,7 +560,7 @@ jobs: - name: It carries the panel, on one chip run: | - app="target/$TARGET/release/bundle/macos/CopyPaste.app" + app="target/$TARGET/release/bundle/macos/CoPanda.app" plist="$app/Contents/Info.plist" test -d "$app" || { echo "::error::the bundler produced no app"; exit 1; } status=0 @@ -590,7 +590,7 @@ jobs: - name: The app is really signed if: env.HAS_P12 == 'true' run: | - app="target/$TARGET/release/bundle/macos/CopyPaste.app" + app="target/$TARGET/release/bundle/macos/CoPanda.app" codesign --verify --deep --strict --verbose=2 "$app" if codesign -dv "$app" 2>&1 | grep -q "Signature=adhoc"; then echo "::error::$app came out ad-hoc signed; notarisation would refuse it" @@ -619,7 +619,7 @@ jobs: APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} run: | out="target/$TARGET/release/bundle/macos" - app="$out/CopyPaste.app" + app="$out/CoPanda.app" ditto -c -k --keepParent "$app" "$RUNNER_TEMP/app.zip" xcrun notarytool submit "$RUNNER_TEMP/app.zip" \ @@ -629,12 +629,12 @@ jobs: xcrun stapler validate "$app" rm -f "$out"/*.app.tar.gz "$out"/*.app.tar.gz.sig - COPYFILE_DISABLE=1 tar --no-xattrs -czf "$out/CopyPaste.app.tar.gz" -C "$out" CopyPaste.app + COPYFILE_DISABLE=1 tar --no-xattrs -czf "$out/CoPanda.app.tar.gz" -C "$out" CoPanda.app rm -rf "$RUNNER_TEMP/rt" && mkdir -p "$RUNNER_TEMP/rt" - tar -xzf "$out/CopyPaste.app.tar.gz" -C "$RUNNER_TEMP/rt" - codesign --verify --deep --strict "$RUNNER_TEMP/rt/CopyPaste.app" - xcrun stapler validate "$RUNNER_TEMP/rt/CopyPaste.app" + tar -xzf "$out/CoPanda.app.tar.gz" -C "$RUNNER_TEMP/rt" + codesign --verify --deep --strict "$RUNNER_TEMP/rt/CoPanda.app" + xcrun stapler validate "$RUNNER_TEMP/rt/CoPanda.app" - name: Sign it for the updater if: env.HAS_UPDATER_KEY == 'true' && env.HAS_APPLE_ID == 'true' @@ -645,9 +645,9 @@ jobs: run: | v="${{ needs.version.outputs.version }}" out="../target/$TARGET/release/bundle/macos" - npm run tauri -- signer sign --app-version "$v" "$out/CopyPaste.app.tar.gz" - test -s "$out/CopyPaste.app.tar.gz.sig" - base64 -d < "$out/CopyPaste.app.tar.gz.sig" > "$RUNNER_TEMP/one.minisig" + npm run tauri -- signer sign --app-version "$v" "$out/CoPanda.app.tar.gz" + test -s "$out/CoPanda.app.tar.gz.sig" + base64 -d < "$out/CoPanda.app.tar.gz.sig" > "$RUNNER_TEMP/one.minisig" if ! bash ../scripts/signed_for.sh "$RUNNER_TEMP/one.minisig" "$v"; then echo "::error::the updater signature is not bound to $v" exit 1 @@ -658,21 +658,21 @@ jobs: v="${{ needs.version.outputs.version }}" mkdir -p dist out="target/$TARGET/release/bundle/macos" - app="$out/CopyPaste.app" + app="$out/CoPanda.app" if xcrun stapler validate "$app" >/dev/null 2>&1 \ - && [ -s "$out/CopyPaste.app.tar.gz.sig" ]; then - cp "$out/CopyPaste.app.tar.gz" "dist/copypaste-$v-macos-$ARCH.app.tar.gz" - cp "$out/CopyPaste.app.tar.gz.sig" "dist/copypaste-$v-macos-$ARCH.app.tar.gz.sig" + && [ -s "$out/CoPanda.app.tar.gz.sig" ]; then + cp "$out/CoPanda.app.tar.gz" "dist/copanda-$v-macos-$ARCH.app.tar.gz" + cp "$out/CoPanda.app.tar.gz.sig" "dist/copanda-$v-macos-$ARCH.app.tar.gz.sig" else echo "::warning::no stapled, signed tarball; macOS $ARCH gets no self-update this release" - rm -f "$out/CopyPaste.app.tar.gz" "$out/CopyPaste.app.tar.gz.sig" + rm -f "$out/CoPanda.app.tar.gz" "$out/CoPanda.app.tar.gz.sig" fi dmg=$(ls target/$TARGET/release/bundle/dmg/*.dmg 2>/dev/null | head -1) || true if [ -z "$dmg" ]; then echo "::error::the bundler produced no disk image" exit 1 fi - cp "$dmg" "dist/copypaste-installer-$v-macos-$ARCH.dmg" + cp "$dmg" "dist/copanda-installer-$v-macos-$ARCH.dmg" ls -l dist - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 @@ -764,7 +764,7 @@ jobs: & "$($sdk.FullName)\x64\makepri.exe" new /pr msix /cf priconfig.xml /of msix/resources.pri /o if ($LASTEXITCODE -ne 0) { Write-Host "::error::makepri would not index the package"; exit 1 } - & "$($sdk.FullName)\x64\makeappx.exe" pack /d msix /p "dist/copypaste-$v-windows-x64.msix" /o + & "$($sdk.FullName)\x64\makeappx.exe" pack /d msix /p "dist/copanda-$v-windows-x64.msix" /o if ($LASTEXITCODE -ne 0) { Write-Host "::error::makeappx refused the package"; exit 1 } Get-ChildItem dist @@ -777,7 +777,7 @@ jobs: Sort-Object Name -Descending | Select-Object -First 1 $v = "${{ needs.version.outputs.version }}" $out = "$env:RUNNER_TEMP\unpacked" - & "$($sdk.FullName)\x64\makeappx.exe" unpack /p "dist/copypaste-$v-windows-x64.msix" /d $out /o | Out-Null + & "$($sdk.FullName)\x64\makeappx.exe" unpack /p "dist/copanda-$v-windows-x64.msix" /d $out /o | Out-Null [xml]$m = Get-Content "$out\AppxManifest.xml" $said = $m.Package.Identity.Name @@ -854,11 +854,11 @@ jobs: run: | v="${{ needs.version.outputs.version }}" status=0 - want="dist/copypaste-installer-$v-windows-x86_64.exe" + want="dist/copanda-installer-$v-windows-x86_64.exe" if [ "${BUILD_MACOS}" = "true" ]; then for arch in aarch64 x86_64; do - want="$want dist/copypaste-$v-macos-$arch.app.tar.gz" - if [ ! -s "dist/copypaste-installer-$v-macos-$arch.dmg" ]; then + want="$want dist/copanda-$v-macos-$arch.app.tar.gz" + if [ ! -s "dist/copanda-installer-$v-macos-$arch.dmg" ]; then echo "::error::the macOS $arch disk image is missing" status=1 fi @@ -887,9 +887,9 @@ jobs: v="${{ needs.version.outputs.version }}" jq -r '.plugins.updater.pubkey' app/src-tauri/tauri.conf.json | base64 -d > feed.pub - for one in "dist/copypaste-installer-$v-windows-x86_64.exe" \ - "dist/copypaste-$v-macos-aarch64.app.tar.gz" \ - "dist/copypaste-$v-macos-x86_64.app.tar.gz"; do + for one in "dist/copanda-installer-$v-windows-x86_64.exe" \ + "dist/copanda-$v-macos-aarch64.app.tar.gz" \ + "dist/copanda-$v-macos-x86_64.app.tar.gz"; do [ -s "$one" ] || continue base64 -d < "$one.sig" > one.minisig if ! minisign -Vm "$one" -p feed.pub -x one.minisig; then @@ -1005,7 +1005,7 @@ jobs: - uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4 with: - subject-path: dist/copypaste-*,dist/SHA256SUMS + subject-path: dist/copanda-*,dist/SHA256SUMS - name: Notes from the tag id: notes @@ -1122,9 +1122,9 @@ jobs: run: | v="${{ needs.version.outputs.version }}" base="https://github.com/${{ github.repository }}/releases/download/${GITHUB_REF_NAME}" - win="copypaste-installer-$v-windows-x86_64.exe" - arm="copypaste-$v-macos-aarch64.app.tar.gz" - intel="copypaste-$v-macos-x86_64.app.tar.gz" + win="copanda-installer-$v-windows-x86_64.exe" + arm="copanda-$v-macos-aarch64.app.tar.gz" + intel="copanda-$v-macos-x86_64.app.tar.gz" if [ -s "dist/$win.sig" ]; then ws=$(cat "dist/$win.sig") @@ -1460,13 +1460,13 @@ jobs: TAG="${GITHUB_REF_NAME}" VERSION="${{ needs.version.outputs.version }}" BASE="https://github.com/${{ github.repository }}/releases/download/${TAG}" - DMG_ARM="copypaste-installer-${VERSION}-macos-aarch64.dmg" - DMG_INTEL="copypaste-installer-${VERSION}-macos-x86_64.dmg" + DMG_ARM="copanda-installer-${VERSION}-macos-aarch64.dmg" + DMG_INTEL="copanda-installer-${VERSION}-macos-x86_64.dmg" if [[ "$VERSION" == *-* ]]; then - CASK="copypaste-beta"; CASK_OTHER="copypaste"; SUFFIX=" (beta)" + CASK="copanda-beta"; CASK_OTHER="copanda"; FORMER="copypaste-beta"; FORMER_OTHER="copypaste"; SUFFIX=" (beta)" else - CASK="copypaste"; CASK_OTHER="copypaste-beta"; SUFFIX="" + CASK="copanda"; CASK_OTHER="copanda-beta"; FORMER="copypaste"; FORMER_OTHER="copypaste-beta"; SUFFIX="" fi fetch() { @@ -1495,14 +1495,15 @@ jobs: git config user.email "github-actions[bot]@users.noreply.github.com" mkdir -p Casks - if [ -f "Casks/${CASK}.rb" ]; then - had=$(sed -n 's/^[[:space:]]*version "\(.*\)"/\1/p' "Casks/${CASK}.rb" | head -1) + for one in "Casks/${CASK}.rb" "Casks/${FORMER}.rb"; do + [ -f "$one" ] || continue + had=$(sed -n 's/^[[:space:]]*version "\(.*\)"/\1/p' "$one" | head -1) if [ -n "$had" ] && [ "$had" != "$VERSION" ] \ && [ "$(printf '%s\n%s\n' "$had" "$VERSION" | sort -V | tail -1)" != "$VERSION" ]; then echo "::warning::the tap already offers ${had}; writing ${VERSION} would downgrade every Mac that runs brew upgrade" exit 0 fi - fi + done cat > "Casks/${CASK}.rb" <<-CASK cask "${CASK}" do @@ -1512,17 +1513,18 @@ jobs: sha256 arm: "${ARM_SHA}", intel: "${INTEL_SHA}" - url "${BASE}/copypaste-installer-${VERSION}-macos-#{arch}.dmg" + url "${BASE}/copanda-installer-${VERSION}-macos-#{arch}.dmg" + name "CoPanda" name "CopyPaste" desc "Clipboard history that stays on your machine${SUFFIX}" - homepage "https://rgdevment.com/copypaste/" + homepage "https://www.copanda.app/" auto_updates true - conflicts_with cask: "${CASK_OTHER}" + conflicts_with cask: ["${CASK_OTHER}", "${FORMER_OTHER}"] depends_on macos: :ventura - app "CopyPaste.app" + app "CoPanda.app" uninstall quit: "com.rgdevment.copypaste" @@ -1534,23 +1536,38 @@ jobs: end CASK - if [ "${{ needs.version.outputs.prerelease }}" = "false" ] \ - && [ -f "Casks/${CASK_OTHER}.rb" ]; then - beta=$(sed -n 's/^[[:space:]]*version "\(.*\)"/\1/p' "Casks/${CASK_OTHER}.rb" | head -1) - if [ -n "$beta" ] \ - && [ "$(printf '%s\n%s\n' "${beta%%-*}" "$VERSION" | sort -V | tail -1)" \ - = "$VERSION" ]; then - git rm -q "Casks/${CASK_OTHER}.rb" - echo "retired Casks/${CASK_OTHER}.rb: it still offered $beta, and $VERSION passes it" - fi + if [ "${{ needs.version.outputs.prerelease }}" = "false" ]; then + for one in "${CASK_OTHER}" copypaste-beta; do + [ -f "Casks/${one}.rb" ] || continue + beta=$(sed -n 's/^[[:space:]]*version "\(.*\)"/\1/p' "Casks/${one}.rb" | head -1) + if [ -n "$beta" ] \ + && [ "$(printf '%s\n%s\n' "${beta%%-*}" "$VERSION" | sort -V | tail -1)" \ + = "$VERSION" ]; then + git rm -q "Casks/${one}.rb" + echo "retired Casks/${one}.rb: it still offered $beta, and $VERSION passes it" + fi + done + fi + + if [ -f "Casks/${FORMER}.rb" ]; then + git rm -q "Casks/${FORMER}.rb" fi + [ -s cask_renames.json ] || echo '{}' > cask_renames.json + jq --arg was "$FORMER" --arg now "$CASK" '.[$was] = $now' cask_renames.json > /tmp/renames.json + for gone in $(jq -r '.[]' /tmp/renames.json | sort -u); do + [ -f "Casks/${gone}.rb" ] && continue + jq --arg gone "$gone" --arg now "$CASK" 'map_values(if . == $gone then $now else . end)' \ + /tmp/renames.json > /tmp/next.json + mv /tmp/next.json /tmp/renames.json + done + mv /tmp/renames.json cask_renames.json - git add Casks + git add Casks cask_renames.json if git diff --cached --quiet; then echo "tap already at ${VERSION}" exit 0 fi - git commit -m "copypaste ${VERSION}" + git commit -m "copanda ${VERSION}" for attempt in 1 2 3 4 5; do if git push origin HEAD:main; then @@ -1620,10 +1637,10 @@ jobs: GH_TOKEN: ${{ github.token }} KOMAC_FORK_OWNER: rgdevment-bot FORCE_HYPERLINK: "0" - PACKAGE: rgdevment.CopyPaste + PACKAGE: rgdevment.CoPanda VERSION: ${{ needs.version.outputs.version }} TAG: ${{ github.ref_name }} - INSTALLERS: '^copypaste-installer-.*-windows-x86_64\.exe$' + INSTALLERS: '^copanda-installer-.*-windows-x86_64\.exe$' KEEP: "5" run: | set -euo pipefail diff --git a/CLA.md b/CLA.md index bdfc8ef2..2a46a710 100644 --- a/CLA.md +++ b/CLA.md @@ -1,9 +1,9 @@ # Contributor License Agreement -CopyPaste Individual Contributor License Agreement, version 1.2. +CoPanda Individual Contributor License Agreement, version 1.3. -Thank you for contributing to CopyPaste. This agreement exists for one reason: -CopyPaste is released under the GPL-3.0 **and** offered under separate +Thank you for contributing to CoPanda. This agreement exists for one reason: +CoPanda is released under the GPL-3.0 **and** offered under separate [commercial terms](COMMERCIAL.md) to organisations that cannot comply with the GPL. Offering those commercial terms requires the right to license the whole codebase that way — including your contribution. Without this @@ -35,8 +35,15 @@ one You submitted before**. Code reaches a project by more routes than a Pull Request, and a signature that only looked forward would leave those earlier routes unaccounted for. +**"Project"** means the software kept in the repository at +, whatever name it is published under. +It was released as CopyPaste up to version 3.1 and is released as CoPanda from +version 3.2. A change of name, of repository address or of any other identifier +is not a new project: this agreement, and every signature already given under +it, carries over unchanged. + **"Project Owner"** means Mario Hidalgo G. (rgdevment), the copyright holder -and maintainer of CopyPaste, and whoever holds those rights after him — a +and maintainer of CoPanda, and whoever holds those rights after him — a successor, or anyone the project is assigned or transferred to, in whole or in part. The licences You grant below run to them on the same terms, and to no wider ones. @@ -108,7 +115,7 @@ provide support for your Contribution, though you may do so if you choose. These are the counterweights to the rights you grant, and they bind the Project Owner: -- The community edition of CopyPaste stays available under the GPL-3.0. +- The community edition of CoPanda stays available under the GPL-3.0. - Your Contribution is never removed from the open source project in order to make it exclusive to a commercial edition. - Your authorship is preserved. Git history is not rewritten to erase it. @@ -156,13 +163,13 @@ I have read the CLA Document and I hereby sign the CLA You sign once. Every later Pull Request from the same GitHub account is covered automatically. -This signature covers CopyPaste only. Other projects by the same owner have their +This signature covers CoPanda only. Other projects by the same owner have their own agreement and their own signature record. ## If you would rather not sign That is a legitimate choice, and it costs you nothing else in this project. -You can still use CopyPaste, report bugs, request features, discuss design, +You can still use CoPanda, report bugs, request features, discuss design, package it for your distribution, help with translations, and fork the project under the GPL-3.0. Only merging code into this repository requires the agreement. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index aed1f368..a482d9dc 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,15 +2,15 @@ ## Our Pledge -We as contributors and maintainers of **CopyPaste** pledge to make participation in our community a welcoming, respectful, and harassment-free experience for everyone—regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. +We as contributors and maintainers of **CoPanda** pledge to make participation in our community a welcoming, respectful, and harassment-free experience for everyone—regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. -**CopyPaste** is a community project—built by people, for people. This code of conduct reflects our core values: transparency, collaboration, and respect. +**CoPanda** is a community project—built by people, for people. This code of conduct reflects our core values: transparency, collaboration, and respect. --- ## Our Philosophy -**CopyPaste** is a community effort, not a corporate product. We believe: +**CoPanda** is a community effort, not a corporate product. We believe: - **Collaboration over competition** — We're building _with_ you, not _for_ you. - **Respect over ego** — Good ideas can come from anywhere, regardless of experience level. @@ -128,7 +128,7 @@ We follow these principles when enforcing the Code of Conduct: ## A Personal Project, Shared with the Community -**CopyPaste** started as my personal project and grew into something bigger—a community effort. That means: +**CoPanda** started as my personal project and grew into something bigger—a community effort. That means: - **We're all equals here** — Maintainer, contributors, and users build together. - **I respect your time** — If you report an issue, I'll respond. If you contribute code, I'll review it fairly. @@ -141,7 +141,7 @@ This Code of Conduct isn't about creating a legal shield—it's about creating a ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1, with modifications to reflect the values and spirit of the **CopyPaste** project. +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1, with modifications to reflect the values and spirit of the **CoPanda** project. For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). @@ -154,7 +154,7 @@ If you have questions about this Code of Conduct: - [Open a Discussion](https://github.com/rgdevment/CopyPaste/discussions) — Ask publicly, I'm happy to clarify. - [Email me](mailto:github@apirest.cl) — If it's sensitive, reach out privately. -### Thank you for helping make CopyPaste a welcoming and inclusive project +### Thank you for helping make CoPanda a welcoming and inclusive project --- diff --git a/COMMERCIAL.md b/COMMERCIAL.md index 46bb69b6..43fc4d58 100644 --- a/COMMERCIAL.md +++ b/COMMERCIAL.md @@ -1,6 +1,6 @@ # Commercial licensing -CopyPaste is dual licensed. +CoPanda is dual licensed. - **GPL-3.0** — free for everyone, forever. See [LICENSE](LICENSE). - **Commercial licence** — for organisations that cannot accept the GPL's @@ -17,7 +17,7 @@ matter how many people use it or for how long. **You do not need a commercial licence to:** -- Install and use CopyPaste at home or at work, on any number of machines. +- Install and use CoPanda at home or at work, on any number of machines. - Deploy it across an entire organisation, including internal IT rollouts. - Read, audit, or fork the source. - Modify it for your own internal use, without publishing those changes. @@ -30,7 +30,7 @@ licence: it does not. Internal use is not distribution. ### Packaging it for a distribution or package manager **You do not need a commercial licence, and you never will.** Building -CopyPaste for any distribution channel — a package manager, a software +CoPanda for any distribution channel — a package manager, a software repository, or your own build pipeline — is exactly the redistribution the GPL is designed to permit. Ship the package, keep the licence notices and make the source available as the GPL requires, and you are done. @@ -40,7 +40,7 @@ harder, open an issue — that is a bug worth fixing. **You likely do need one to:** -- Ship CopyPaste, or code derived from it, inside a **product you distribute +- Ship CoPanda, or code derived from it, inside a **product you distribute to others**, without licensing that product under the GPL. - Redistribute it under **your own brand** without the GPL's source disclosure requirement. The notices of the third-party work inside it still go with it; @@ -57,13 +57,13 @@ fine, carry on". ## What a commercial licence gives you -- The right to use, modify, and redistribute CopyPaste **without the GPL's +- The right to use, modify, and redistribute CoPanda **without the GPL's copyleft obligations** — no requirement to publish your modifications or to license your own product under the GPL. - Written permission you can hand to your legal or procurement team. -It covers the code the project owns, which is all of CopyPaste's own source. -It cannot cover the work of others that CopyPaste is built on. +It covers the code the project owns, which is all of CoPanda's own source. +It cannot cover the work of others that CoPanda is built on. Terms, scope, and price are agreed per case rather than published, because a single-seat integration and an OEM redistribution are not the same deal. @@ -71,22 +71,22 @@ Contact with what you want to do and the scale of it. ## Third-party components -CopyPaste is built on other people's open source work, listed with its licence +CoPanda is built on other people's open source work, listed with its licence in [THIRD-PARTY-BUNDLED.md](THIRD-PARTY-BUNDLED.md). Those licences come with it -whichever licence you hold for CopyPaste itself. +whichever licence you hold for CoPanda itself. - **Permissive licences** — MIT, MIT-0, Apache-2.0 (with or without the LLVM exception), BSD-2-Clause, BSD-3-Clause, 0BSD, ISC, Zlib, BSL-1.0, Unicode-3.0, PSF-2.0, CC0-1.0 and the Unlicense, which is nearly all of it. They allow a closed product, and they ask for their notices to ship with it. - CopyPaste already shows them, with their full texts, under **About**; keep + CoPanda already shows them, with their full texts, under **About**; keep that, or carry both files another way. - **MPL-2.0** — thirteen crates in the binaries: `symphonia` and its codec and format crates, which decode audio for the waveform in the panel, and `option-ext`, through the updater. Their copyleft stops at their own files: change any of them and you publish those files under the MPL, and either way you tell recipients where their source is. -- **Slint** — the toolkit the panel is drawn with. CopyPaste uses it under +- **Slint** — the toolkit the panel is drawn with. CoPanda uses it under GPL-3.0 and cannot pass it on under other terms. A closed desktop product can use it at no cost under the [Slint Royalty-free Desktop, Mobile, and Web Applications License 2.0](https://github.com/slint-ui/slint/blob/master/LICENSES/LicenseRef-Slint-Royalty-free-2.0.md), @@ -96,7 +96,7 @@ whichever licence you hold for CopyPaste itself. Slint's APIs, or Slint on its own; those need a licence from SixtyFPS GmbH, who make Slint. -Every commercial agreement for CopyPaste says this in writing: the licensee +Every commercial agreement for CoPanda says this in writing: the licensee distributes Slint under the Slint Royalty-free License 2.0 and meets its attribution, or holds a Slint licence of their own; keeps the MPL-2.0 files available in source form, with any changes made to them; and ships the @@ -107,10 +107,10 @@ third-party notices with the product. The GPL's section 10 forbids imposing further restrictions on recipients, which conflicts with the terms of some application stores — Apple's App Store being the well-known case. For the code the project owns, that conflict binds -**licensees**, not the copyright holder: a third party cannot publish CopyPaste +**licensees**, not the copyright holder: a third party cannot publish CoPanda there, and the project itself can, under separate terms it grants to itself. -That reaches only the project's own code. Slint comes to CopyPaste under the +That reaches only the project's own code. Slint comes to CoPanda under the GPL as well, so a build for such a store takes Slint under its royalty-free licence instead, whose attribution the README already carries. @@ -119,7 +119,7 @@ defer to the software's own licence. ## Why the project is set up this way -The dual model exists so CopyPaste can stay genuinely free for the people who +The dual model exists so CoPanda can stay genuinely free for the people who use it, while commercial redistribution that would otherwise contribute nothing back has a way to support it. Whichever side you are on, the GPL edition is not a crippled version — it is the same application, and it stays diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6e6d8965..0d6e9ec3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ -# Contributing to CopyPaste +# Contributing to CoPanda -Thank you for considering contributing to **CopyPaste**! 🎉 +Thank you for considering contributing to **CoPanda**! 🎉 This project exists thanks to people like you. Whether it's your first open source contribution or you're an experienced developer—**everyone is welcome here**. @@ -8,7 +8,7 @@ This project exists thanks to people like you. Whether it's your first open sour ## Our Philosophy -**CopyPaste** is a personal project that grew into something bigger—a community effort. It was created by an individual developer ([@rgdevment](https://github.com/rgdevment)) with a simple idea: build the clipboard tool he always wanted to use. +**CoPanda** is a personal project that grew into something bigger—a community effort. It was created by an individual developer ([@rgdevment](https://github.com/rgdevment)) with a simple idea: build the clipboard tool he always wanted to use. We believe in: @@ -18,7 +18,7 @@ We believe in: - **Collaborative community** — We build together, not in silos - **Valuable feedback** — Your opinion matters as much as code -**There is no premium version and no feature is ever held back** — what you install is the whole application. CopyPaste is free software, created by and for the community. +**There is no premium version and no feature is ever held back** — what you install is the whole application. CoPanda is free software, created by and for the community. It is also dual licensed: anyone who wants to redistribute it inside a product of their own needs [separate terms](COMMERCIAL.md). Using it, deploying it across a company, or packaging it for a distribution never does. @@ -43,7 +43,7 @@ In many ways! Code is just one of them: 2. If it doesn't exist, open a new one with: - Clear description of the problem - Steps to reproduce - - CopyPaste version and OS (with version) + - CoPanda version and OS (with version) - Screenshots if applicable ### Contribute Code @@ -91,7 +91,7 @@ In many ways! Code is just one of them: ### Translate -Do you speak another language? Help us bring CopyPaste to more people. Check the [localization guide](README.md#localization-help-translate-copypaste) in the README. +Do you speak another language? Help us bring CoPanda to more people. Check the [localization guide](README.md#localization-help-translate-copanda) in the README. ### Improve Documentation @@ -176,7 +176,7 @@ the subject on `main`. ## License and Rights -CopyPaste is released under the **GNU General Public License v3.0 (GPL-3.0)** +CoPanda is released under the **GNU General Public License v3.0 (GPL-3.0)** and offered under separate [commercial terms](COMMERCIAL.md) to organisations that cannot comply with it. Your contributions are licensed the same way. @@ -214,12 +214,12 @@ on you, whatever helped you write it. Read [CLA.md](CLA.md) for the full text — it is short, and worth the two minutes before you sign it. -If you would rather not sign, you can still use CopyPaste, report bugs, +If you would rather not sign, you can still use CoPanda, report bugs, request features, discuss design, package it for your distribution, and fork the project under the GPL-3.0. Only merging code into this repository requires the agreement. -**Packaging CopyPaste for a distribution or package manager needs no agreement +**Packaging CoPanda for a distribution or package manager needs no agreement and no commercial licence** — that is ordinary GPL redistribution, and packagers are welcome. See [COMMERCIAL.md](COMMERCIAL.md). @@ -244,6 +244,6 @@ We want this to be a safe and welcoming space for everyone. Please read our [Cod ---
-

Thank you for being part of CopyPaste. 💙

+

Thank you for being part of CoPanda. 💙

— Mario (rgdevment)

diff --git a/Cargo.toml b/Cargo.toml index 1f5267d1..fd07be03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ version = "3.0.0-dev" edition = "2024" rust-version = "1.98" license = "GPL-3.0-only" -homepage = "https://rgdevment.com/copypaste/" +homepage = "https://www.copanda.app/" repository = "https://github.com/rgdevment/CopyPaste" publish = false diff --git a/PRIVACY.md b/PRIVACY.md index a1afbae6..8c141a9b 100644 --- a/PRIVACY.md +++ b/PRIVACY.md @@ -6,7 +6,7 @@ ## The Short Version -**Everything stays on your computer.** CopyPaste does not collect, transmit, or share any of your data. There's no cloud, no accounts, no telemetry, no analytics, no tracking — nothing leaves your machine, ever. +**Everything stays on your computer.** CoPanda does not collect, transmit, or share any of your data. There's no cloud, no accounts, no telemetry, no analytics, no tracking — nothing leaves your machine, ever. **"Everything local" is not a feature — it's the foundation.** It's a technical fact you can verify yourself: the entire source code is [open and public](https://github.com/rgdevment/CopyPaste). Read the code, run a network monitor, check for yourself. @@ -14,7 +14,7 @@ ## Our Privacy Philosophy: Everything Local -CopyPaste was built with a **privacy-first** mindset from day one. This isn't an afterthought or a feature — it's a core design principle. **Everything stays on your machine.** +CoPanda was built with a **privacy-first** mindset from day one. This isn't an afterthought or a feature — it's a core design principle. **Everything stays on your machine.** - 🔒 **Local-only by design** — Your data never leaves your computer - 🚫 **No telemetry** — We don't measure, track, or analyze your usage @@ -24,13 +24,13 @@ CopyPaste was built with a **privacy-first** mindset from day one. This isn't an - 🚫 **No automatic reporting** — Errors are logged locally only; nothing is sent anywhere without your action - 🔍 **Fully auditable** — Every line of code is open source under [GPLv3](LICENSE) -**The data on your computer is yours.** I built CopyPaste to respect that boundary completely — not just in policy, but in code. +**The data on your computer is yours.** I built CoPanda to respect that boundary completely — not just in policy, but in code. --- -## What Data Does CopyPaste Store? +## What Data Does CoPanda Store? -CopyPaste monitors your system clipboard to maintain a local history. The following data is stored **exclusively on your computer**: +CoPanda monitors your system clipboard to maintain a local history. The following data is stored **exclusively on your computer**: ### Clipboard Content @@ -55,7 +55,7 @@ These folders are protected by your operating system's user account permissions. --- -## What CopyPaste Does NOT Do +## What CoPanda Does NOT Do To be absolutely clear: @@ -73,13 +73,13 @@ To be absolutely clear: ## Network Requests -CopyPaste makes **one type of network request** for update checking: +CoPanda makes **one type of network request** for update checking: ### Update Checker | Detail | Value | | :--- | :--- | -| **Purpose** | Check whether a newer version of CopyPaste is available | +| **Purpose** | Check whether a newer version of CoPanda is available | | **URL** | `https://raw.githubusercontent.com/rgdevment/CopyPaste/manifest/release-manifest.json` | | **Method** | `GET` (read-only) | | **Data sent** | Standard HTTP headers only — **no user data** | @@ -95,38 +95,38 @@ CopyPaste makes **one type of network request** for update checking: - Only when you press «Update» does the app also read `latest.json` (or `candidate.json` for test versions) from the same branch, which says where the installer lives and carries its signature - The installer is **cryptographically signed**, and the signature is verified against a public key built into the app before anything is installed. The download address is also checked against our own release hosts before a single byte is fetched - **Microsoft Store version:** nothing is checked and nothing is offered. The Store delivers its own updates -- **Homebrew** (`copypaste`, or `copypaste-beta` for test versions): the same as a standalone build, «Update» downloads and installs it. The cask tells Homebrew that CopyPaste updates itself, so `brew upgrade --cask` keeps working too -- **Standalone builds (Windows / macOS):** if you press «Update», and only then, the installer is downloaded and run, and CopyPaste restarts itself. Nothing is downloaded or installed without you asking for it +- **Homebrew** (`copanda`, or `copanda-beta` for test versions): the same as a standalone build, «Update» downloads and installs it. The cask tells Homebrew that CoPanda updates itself, so `brew upgrade --cask` keeps working too +- **Standalone builds (Windows / macOS):** if you press «Update», and only then, the installer is downloaded and run, and CoPanda restarts itself. Nothing is downloaded or installed without you asking for it ### User-Initiated Browser Navigation -When you explicitly click one of the links in **Settings → About**, CopyPaste opens it in your default browser: +When you explicitly click one of the links in **Settings → About**, CoPanda opens it in your default browser: - **Repository** and **Give it a star** → `https://github.com/rgdevment/CopyPaste` - **AlternativeTo** → `https://alternativeto.net/software/copypaste/about/` - **Privacy** → `https://github.com/rgdevment/CopyPaste/blob/main/PRIVACY.md` - **Sponsor the project** → `https://github.com/sponsors/rgdevment` - **Buy me a coffee** → `https://buymeacoffee.com/rgdevment` -- **Rate it on the Store** (Windows only) → opens the Microsoft Store app on CopyPaste's review page +- **Rate it on the Store** (Windows only) → opens the Microsoft Store app on CoPanda's review page - **Other tools** → `https://rgdevment.com/tisty/` and `https://rgdevment.com/linkunbound/` The same goes for a link you open from a card in the panel. If [LinkUnbound](https://github.com/rgdevment/LinkUnbound) is installed, these web links go through it so it can pick the browser; otherwise they go straight to your default browser. -These are standard browser navigations initiated by your action — CopyPaste does not make these requests itself. +These are standard browser navigations initiated by your action — CoPanda does not make these requests itself. --- ## Sensitive Data Protection -CopyPaste includes built-in protections for sensitive content: +CoPanda includes built-in protections for sensitive content: ### Concealed Content Exclusion -When an application marks what it copies as secret, CopyPaste **skips it entirely** — the content is never hashed, never turned into an entry, never written to the database or to disk. This is how password managers keep their output out of clipboard history. +When an application marks what it copies as secret, CoPanda **skips it entirely** — the content is never hashed, never turned into an entry, never written to the database or to disk. This is how password managers keep their output out of clipboard history. ### How It Works -Each platform has a standard marker that the copying application sets, and CopyPaste checks for it before reading anything: +Each platform has a standard marker that the copying application sets, and CoPanda checks for it before reading anything: | Platform | Marker it honours | | :--- | :--- | @@ -139,13 +139,13 @@ The check asks only whether the marker is present, never for the secret's conten The limits matter more than the promise, so plainly: -- **The marker is set by the other application, not by CopyPaste.** Whether a given password manager sets it depends on that application, its version and its own settings. Most major ones do. We do not publish a list of "supported" managers, because that would be a compatibility claim we cannot keep honest across every release of every one of them. +- **The marker is set by the other application, not by CoPanda.** Whether a given password manager sets it depends on that application, its version and its own settings. Most major ones do. We do not publish a list of "supported" managers, because that would be a compatibility claim we cannot keep honest across every release of every one of them. - **Content that merely looks sensitive is not detected.** A password you type into a text file and copy carries no marker, so it is stored like any other text. -- If you rely on this, verify it once with your own password manager: copy a credential and check that no entry appears in CopyPaste. Ten seconds, and it tells you more than any list we could publish. +- If you rely on this, verify it once with your own password manager: copy a credential and check that no entry appears in CoPanda. Ten seconds, and it tells you more than any list we could publish. ### Windows Clipboard History -CopyPaste operates independently from Windows' built-in clipboard history (`Win+V`). Your CopyPaste settings do not affect Windows clipboard behavior, and vice versa. +CoPanda operates independently from Windows' built-in clipboard history (`Win+V`). Your CoPanda settings do not affect Windows clipboard behavior, and vice versa. --- @@ -155,13 +155,13 @@ A few features read something else on your computer. All of it stays local: - **Importing CopyPaste 2's history** (Settings → Backup, or the welcome tour) reads the 2.x database and pictures from disk, only when you ask. Nothing of the 2.x is changed or uploaded. - **Pasting a picture into a terminal** works by checking which application is in front when you paste, so the picture can arrive as its file path. That check is a local look at the foreground process; nothing about it is stored or sent. -- **Opening a web link** goes through [LinkUnbound](https://github.com/rgdevment/LinkUnbound) if it is installed. CopyPaste only checks whether it is there. +- **Opening a web link** goes through [LinkUnbound](https://github.com/rgdevment/LinkUnbound) if it is installed. CoPanda only checks whether it is there. --- ## Backup and Restore -CopyPaste can export a backup and restore from one. Both are **manual actions you start yourself** — nothing is backed up automatically, and no backup ever leaves your machine on its own. +CoPanda can export a backup and restore from one. Both are **manual actions you start yourself** — nothing is backed up automatically, and no backup ever leaves your machine on its own. ### What the Backup Contains @@ -181,7 +181,7 @@ Importing **adds** what the file holds to the history you already have. It never ### Leftovers from CopyPaste 2 -CopyPaste 2 could leave `.pre-restore-` folders in its data directory after an interrupted restore. CopyPaste 3 never creates them. If you find one, it is a copy of your old history, and **Delete CopyPaste 2's data** in Settings → Backup removes it along with the rest of the 2.x data. +CopyPaste 2 could leave `.pre-restore-` folders in its data directory after an interrupted restore. CoPanda 3 never creates them. If you find one, it is a copy of your old history, and **Delete CopyPaste 2's data** in Settings → Backup removes it along with the rest of the 2.x data. --- @@ -189,7 +189,7 @@ CopyPaste 2 could leave `.pre-restore-` folders in its data directory ### Automatic Cleanup -- CopyPaste automatically deletes unpinned items older than your configured retention period: 7, 30 or 90 days, or Forever (default: **30 days**) +- CoPanda automatically deletes unpinned items older than your configured retention period: 7, 30 or 90 days, or Forever (default: **30 days**) - If you set a history size (256 MB, 512 MB or 1 GB), the oldest unpinned items go first once it is exceeded - Cleanup runs periodically in the background - **Pinned items are preserved** regardless of the retention setting @@ -207,36 +207,36 @@ either way. ### Complete Data Removal (Uninstall) -To completely remove all CopyPaste data when uninstalling: +To completely remove all CoPanda data when uninstalling: **Windows:** -1. Uninstall CopyPaste (via Settings → Apps or the standalone uninstaller) +1. Uninstall CoPanda (via Settings → Apps or the standalone uninstaller) 2. Delete the data folder: `%LOCALAPPDATA%\CopyPaste\` **macOS:** -1. Move CopyPaste to Trash from Applications +1. Move CoPanda to Trash from Applications 2. Delete the data folder: `~/Library/Application Support/CopyPaste/` -After these steps, no CopyPaste data remains on your system. +After these steps, no CoPanda data remains on your system. --- ## Children's Privacy -CopyPaste does not knowingly collect any personal information from anyone, including children under 13. The application does not collect personal information from any user — it has no accounts, no registration, and no data transmission. +CoPanda does not knowingly collect any personal information from anyone, including children under 13. The application does not collect personal information from any user — it has no accounts, no registration, and no data transmission. --- ## Microsoft Store Distribution -CopyPaste is available through the [Microsoft Store](https://apps.microsoft.com/detail/9NBJRZF3K856). The Store version: +CoPanda is available through the [Microsoft Store](https://apps.microsoft.com/detail/9NBJRZF3K856). The Store version: - **Follows the same privacy principles** as the standalone version - **Makes no update check at all** — updates are delivered through the Microsoft Store - **Uses MSIX packaging** — installs/uninstalls cleanly with Windows standard mechanisms -- **Microsoft Store policies** apply to distribution, but CopyPaste itself does not share any data with Microsoft beyond what the Store platform requires for installation and updates +- **Microsoft Store policies** apply to distribution, but CoPanda itself does not share any data with Microsoft beyond what the Store platform requires for installation and updates For Microsoft's own privacy practices regarding the Store, refer to [Microsoft's Privacy Statement](https://privacy.microsoft.com/privacystatement). @@ -244,7 +244,7 @@ For Microsoft's own privacy practices regarding the Store, refer to [Microsoft's ## Open Source Transparency -The best privacy policy is one you can verify. CopyPaste is **100% open source** under the [GNU General Public License v3.0](LICENSE): +The best privacy policy is one you can verify. CoPanda is **100% open source** under the [GNU General Public License v3.0](LICENSE): - 📂 **Full source code:** [github.com/rgdevment/CopyPaste](https://github.com/rgdevment/CopyPaste) - 🔍 **Audit the code yourself** — every network request, every database write, every file operation @@ -262,7 +262,7 @@ If we ever change this privacy policy, the changes will be: - Reflected in the "Last updated" date at the top - Documented in the release notes -Since CopyPaste is open source, any change to privacy behavior would also be visible as a code change in the public repository before it reaches you. +Since CoPanda is open source, any change to privacy behavior would also be visible as a code change in the public repository before it reaches you. --- @@ -277,5 +277,5 @@ If you have questions or concerns about this privacy policy: ---
-

Everything local. Your clipboard is yours — I built CopyPaste to keep it that way.

+

Everything local. Your clipboard is yours — I built CoPanda to keep it that way.

diff --git a/README.md b/README.md index ff29ef79..8f302f07 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@
- CopyPaste — Free Open Source Clipboard Manager for Windows and macOS + CoPanda — Free Open Source Clipboard Manager for Windows and macOS -

CopyPaste — Free Open Source Clipboard Manager

+

CoPanda (formerly CopyPaste) — Free Open Source Clipboard Manager

+

An extra thumb for your clipboard.

A local-first clipboard history and copy paste tool for Windows and macOS.
No ads. No telemetry. No accounts. Just a fast, private clipboard utility built for productivity.

@@ -13,30 +14,30 @@ License GPL-3.0 - Sponsor CopyPaste on GitHub + Sponsor CoPanda on GitHub Buy me a coffee

-

CopyPaste 3.0 is here — rewritten in Rust, for Windows and macOS.
+

CopyPaste is now CoPanda — the same app, the same history, a name of its own.
Get it from Releases.

-

Download CopyPaste

+

Download CoPanda

- Get CopyPaste clipboard manager from Microsoft Store + Get CoPanda clipboard manager from Microsoft Store   - Install CopyPaste clipboard manager via Homebrew on macOS + Install CoPanda clipboard manager via Homebrew on macOS

- rgdevment.com/copypaste + www.copanda.app

@@ -46,11 +47,11 @@ --- -**CopyPaste** is a free, open source **clipboard manager** and **clipboard history** tool I built because the alternatives frustrated me. Most copy paste utilities are either bloated, ugly, or treat you as a product. I wanted a **copy tool** that felt native, respected my privacy, and just worked — so I built one and shared it. +**CoPanda** is a free, open source **clipboard manager** and **clipboard history** tool I built because the alternatives frustrated me. Most copy paste utilities are either bloated, ugly, or treat you as a product. I wanted a **copy tool** that felt native, respected my privacy, and just worked — so I built one and shared it. This isn't a company product. I'm a developer who needed a better **copy paste** tool for my desktop, built it for myself, and decided to open source it for anyone who feels the same. No ads, no telemetry, no subscriptions, no data collection — just a lightweight **clipboard utility** that lives on your machine and nowhere else. -**Why people choose CopyPaste over other clipboard managers:** +**Why people choose CoPanda over other clipboard managers:** - **100% local** — your clipboard history never leaves your computer. No cloud, no servers, no accounts. - **Truly free** — no premium tiers, no feature gates, no "free trial" tricks. GPL v3, forever. @@ -59,13 +60,13 @@ This isn't a company product. I'm a developer who needed a better **copy paste** - **Fast and light** — starts in milliseconds, uses minimal resources. You'll forget it's running. - **Easy to read** — a clean, opaque panel that follows your system theme, light or dark, so what you copied is the first thing you see. -> I use CopyPaste every day on Windows 11 and macOS. If something feels off, [let me know](#found-a-bug-have-feedback) — this project keeps improving because of real-world use. +> I use CoPanda every day on Windows 11 and macOS. If something feels off, [let me know](#found-a-bug-have-feedback) — this project keeps improving because of real-world use. --- ## Table of Contents -- [See It in Action](#see-copypaste-in-action) +- [See It in Action](#see-copanda-in-action) - [Why I Built This](#why-i-built-this) - [What It Is / What It Isn't](#what-it-is--what-it-isnt) - [Who Is This For?](#who-is-this-for) @@ -78,7 +79,7 @@ This isn't a company product. I'm a developer who needed a better **copy paste** - [Coming from CopyPaste 2](#coming-from-copypaste-2) - [Found a Bug? Have Feedback?](#found-a-bug-have-feedback) - [What's Coming and What's Changed](#whats-coming-and-whats-changed) -- [Localization](#localization-help-translate-copypaste) +- [Localization](#localization-help-translate-copanda) - [Want to Help?](#want-to-help) - [Tech Stack](#tech-stack-for-developers) - [Themes](#themes) @@ -88,24 +89,26 @@ This isn't a company product. I'm a developer who needed a better **copy paste** - [License and Spirit](#license-and-spirit) - [Acknowledgements](#acknowledgements) -## See CopyPaste in Action +## See CoPanda in Action

- CopyPaste clipboard manager demo — search clipboard history, paste with keyboard shortcuts, cross-platform on Windows and macOS + CoPanda clipboard manager demo — search clipboard history, paste with keyboard shortcuts, cross-platform on Windows and macOS
Fast search, clean cards, and a native feel across Windows and macOS.

- CopyPaste clipboard history — the panel with everything you copied, opened with Ctrl+Alt+V on Windows and macOS - CopyPaste copy tool — type #image, #link or #token to filter the clipboard history by kind + CoPanda, an extra thumb for your clipboard: searchable, private and always on your machine

- CopyPaste paste as — paste a token as a header or curl, a colour in rgb(), JSON minified or a link in Markdown - CopyPaste privacy — 100% local, no account, no telemetry, passwords from 1Password or Bitwarden are ignored + CoPanda clipboard history — the panel with everything you copied, opened with Ctrl+Alt+V on Windows and macOS + CoPanda copy tool — type #image, #link or #token to filter the clipboard history by kind

- CopyPaste settings — light, dark or system theme, six accent colours and your own shortcut - CopyPaste is a free and open source clipboard manager for Windows and macOS under GPL-3.0 + CoPanda paste as — paste a token as a header or curl, a colour in rgb(), JSON minified or a link in Markdown + CoPanda privacy — 100% local, no account, no telemetry, passwords from 1Password or Bitwarden are ignored +

+ CoPanda settings — light, dark or system theme, six accent colours and your own shortcut + CoPanda is a free and open source clipboard manager for Windows and macOS under GPL-3.0
--- @@ -116,7 +119,7 @@ I'm not a company. I'm a developer who copies and pastes things hundreds of time Most **clipboard managers** out there are either bloated, ugly, Windows-only, or silently collecting your data. In 2026, a **copy paste tool** should feel native, responsive, and beautiful on every platform. I couldn't find one that did, so I built my own. -**CopyPaste started as a personal productivity tool.** I needed a lightweight **copy history** utility that: +**CoPanda started as a personal productivity tool.** I needed a lightweight **copy history** utility that: - Didn't hog system resources - Looked and felt like part of my OS, not a widget dropped on top @@ -132,13 +135,13 @@ Every line of code is public. You can read it, fork it, or learn from it. This i ## What It Is / What It Isn't -**CopyPaste is:** +**CoPanda is:** - A **local-first clipboard manager** and **clipboard history** app for Windows and macOS - A fast, keyboard-driven **copy-paste utility** for daily productivity and workflow efficiency - A **copy tool** you can trust — **open source** (GPL v3), inspect every line, fork it, contribute to it -**CopyPaste is not:** +**CoPanda is not:** - A cloud clipboard or sync service - A telemetry or analytics tool @@ -161,7 +164,7 @@ If you copy and paste throughout your day, this **clipboard manager** is for you ## Privacy and Security -**Everything stays local.** CopyPaste is built on a single, non-negotiable principle: your clipboard data never leaves your computer. This copy-paste tool was designed with privacy as the foundation, not an afterthought. +**Everything stays local.** CoPanda is built on a single, non-negotiable principle: your clipboard data never leaves your computer. This copy-paste tool was designed with privacy as the foundation, not an afterthought. - **Local-only storage** — no cloud, no servers, no data syncing - **No tracking** — no telemetry, no analytics, no hidden collection of any kind @@ -169,14 +172,14 @@ If you copy and paste throughout your day, this **clipboard manager** is for you - **Secrets marked as secret are never read** — what an app marks as secret or concealed when it copies, as most password managers (1Password, Bitwarden, etc.) do, never reaches the history - **Log export is voluntary** — you choose when and what to share; logs never contain clipboard content -**By design, CopyPaste will never have:** accounts, subscriptions, ads, cloud sync, or "AI analysis" of your clipboard. +**By design, CoPanda will never have:** accounts, subscriptions, ads, cloud sync, or "AI analysis" of your clipboard. For responsible disclosure and security contact info, see [SECURITY.md](SECURITY.md).
Where is my clipboard data stored? -CopyPaste stores everything locally under your user profile. The 3.0 keeps one +CoPanda stores everything locally under your user profile. The 3.0 keeps one folder with the history, the files behind it and its settings: **Windows** — `%LOCALAPPDATA%\CopyPaste\` @@ -243,14 +246,14 @@ If you care about privacy and control, this clipboard manager is made for you. R ## Keyboard Shortcuts -CopyPaste keeps `Ctrl+V` under the active application's control and uses one +CoPanda keeps `Ctrl+V` under the active application's control and uses one global shortcut of its own to open the history panel. On a Mac the panel answers the keys of the system it runs on: ⌘ where Windows uses Ctrl, and the keys a Mac keyboard does not have are replaced by the ones it does. | Where | Windows | macOS | Action | | :---- | :------ | :---- | :----- | -| App you're in | Ctrl+V | ⌘V | Normal paste. CopyPaste does not intercept it. | +| App you're in | Ctrl+V | ⌘V | Normal paste. CoPanda does not intercept it. | | Anywhere | Ctrl+Alt+V | ⌃⌥V | Open the panel. Change it in Settings → Keyboard shortcuts; if another program already uses it, free alternatives are offered. | | Panel | Enter | ⏎ | Paste the selected item. | | Panel | Shift + Enter | ⇧⏎ | Paste as plain text. | @@ -352,9 +355,9 @@ walks you through it. > [Install from the Microsoft Store](https://apps.microsoft.com/detail/9NBJRZF3K856) -**winget** — coming soon. CopyPaste is not in the winget catalogue yet. +**winget** — coming soon. CoPanda is not in the winget catalogue yet. -> The [Scoop bucket](https://github.com/rgdevment/scoop-bucket) carries CopyPaste +> The [Scoop bucket](https://github.com/rgdevment/scoop-bucket) carries CoPanda > 2 and is not fed by the 3.0 release. **Standalone `.exe`** — direct download from [GitHub Releases](https://github.com/rgdevment/CopyPaste/releases/latest). The installer is self-signed; see the [security note](#standalone-downloads) below. @@ -363,17 +366,17 @@ walks you through it. ### macOS -**Homebrew** (recommended) — picks the build for your chip, Apple Silicon or Intel; afterwards CopyPaste updates itself from Settings → About: +**Homebrew** (recommended) — picks the build for your chip, Apple Silicon or Intel; afterwards CoPanda updates itself from Settings → About: ```sh -brew tap rgdevment/tap && brew install --cask copypaste +brew tap rgdevment/tap && brew install --cask copanda ``` Test versions, which arrive before anyone else's and can break, have a cask of their own: ```sh -brew tap rgdevment/tap && brew install --cask copypaste-beta +brew tap rgdevment/tap && brew install --cask copanda-beta ``` **Standalone `.dmg`** — direct download from [GitHub Releases](https://github.com/rgdevment/CopyPaste/releases/latest), one per chip, with manual updates. @@ -393,8 +396,8 @@ Direct packages live on [GitHub Releases](https://github.com/rgdevment/CopyPaste | Platform | File | Notes | | :---------- | :------------------------- | :-------------------------------------------------------------------------- | -| **Windows** | `copypaste-installer--windows-x86_64.exe` | Self-signed installer — see security note below | -| **macOS** | `copypaste-installer--macos-aarch64.dmg` · `copypaste-installer--macos-x86_64.dmg` | One per chip: Apple Silicon (`aarch64`) or Intel (`x86_64`) | +| **Windows** | `copanda-installer--windows-x86_64.exe` | Self-signed installer — see security note below | +| **macOS** | `copanda-installer--macos-aarch64.dmg` · `copanda-installer--macos-x86_64.dmg` | One per chip: Apple Silicon (`aarch64`) or Intel (`x86_64`) | Each release also carries a `SHA256SUMS` file with the checksum of every download, and a build attestation from GitHub that ties each file to the @@ -403,7 +406,7 @@ workflow run in this repository that built it.
Windows standalone: security warnings -Since CopyPaste is an independent open source project, the installer uses a self-signed certificate. Windows and your browser may show security warnings — **this is normal and expected.** +Since CoPanda is an independent open source project, the installer uses a self-signed certificate. Windows and your browser may show security warnings — **this is normal and expected.** - **Browser:** Chrome/Edge may block the download — click Keep or Keep anyway. - **SmartScreen:** Click More info → Run anyway (only happens once). @@ -415,17 +418,17 @@ Since CopyPaste is an independent open source project, the installer uses a self ## FAQ -**Is CopyPaste free?** +**Is CoPanda free?** Yes. Completely free and open source. No premium tiers, no subscriptions, no paywalls — ever. That covers using it anywhere, including across a company, and packaging it for a distribution or package manager. Only redistributing it inside a product of your own needs [separate terms](COMMERCIAL.md). **Does it upload my clipboard data?** -No. Everything stays on your machine. There is no cloud, no server, no sync. CopyPaste is a local-first clipboard manager by design — your copy paste data never leaves your computer. +No. Everything stays on your machine. There is no cloud, no server, no sync. CoPanda is a local-first clipboard manager by design — your copy paste data never leaves your computer. **Does it store passwords?** -Not what an app marks as secret. Most password managers mark what they copy as secret or concealed, and CopyPaste never reads it. A password copied from an ordinary place, such as a text file, carries no mark and is kept like any other text. The [Privacy Policy](PRIVACY.md#sensitive-data-protection) explains the limits. +Not what an app marks as secret. Most password managers mark what they copy as secret or concealed, and CoPanda never reads it. A password copied from an ordinary place, such as a text file, carries no mark and is kept like any other text. The [Privacy Policy](PRIVACY.md#sensitive-data-protection) explains the limits. **Do I need internet to use it?** -No. CopyPaste works fully offline. Outside the Microsoft Store it makes a lightweight check for updates when you open Settings → About, at most once a day (no user data sent), but works perfectly without a connection. +No. CoPanda works fully offline. Outside the Microsoft Store it makes a lightweight check for updates when you open Settings → About, at most once a day (no user data sent), but works perfectly without a connection. **Does it sync clipboard history between devices?** No. There's intentionally no cloud sync. Your copy history stays on the device where you copied it. This is a local-first copy tool, not a cloud service. @@ -443,7 +446,7 @@ Optionally, yes, on both systems. Enable it in Settings → General. On Windows Yes. There is a build for each chip, Apple Silicon and Intel. Homebrew picks the right one for you, and the Releases page carries both. **Can it replace the Windows clipboard history (Win+V)?** -Yes. Win+V keeps your last 25 items and forgets the unpinned ones when Windows restarts. CopyPaste keeps what you copy for as long as you choose, searchable in milliseconds, with images, files, links and colours as cards you can pin, name and paste in another form. It opens with its own shortcut, so Win+V stays where it is. +Yes. Win+V keeps your last 25 items and forgets the unpinned ones when Windows restarts. CoPanda keeps what you copy for as long as you choose, searchable in milliseconds, with images, files, links and colours as cards you can pin, name and paste in another form. It opens with its own shortcut, so Win+V stays where it is. **How do I paste as plain text?** Open the panel and press **Shift+Enter** (⇧⏎ on a Mac). **Alt+Enter** (⌥⏎) offers the other forms a card carries, such as Markdown, formatted JSON or a colour in another notation. @@ -454,8 +457,8 @@ Yes, on Windows and macOS. Drag a card into a browser upload, a chat or a folder **Is it an alternative to Ditto, Maccy or CopyQ?** Yes. The [Alternatives](#alternatives) section compares them honestly, including where each of them is the better choice. -**How is CopyPaste different from other clipboard managers?** -CopyPaste is a personal project, not a company product. There are no ads, no telemetry, no accounts, and no data collection. Unlike most copy paste tools, it's built to feel native on each platform, it's fully keyboard-driven, and it respects your privacy completely. It's an open source clipboard utility focused on productivity — you can verify every line of code yourself. +**How is CoPanda different from other clipboard managers?** +CoPanda is a personal project, not a company product. There are no ads, no telemetry, no accounts, and no data collection. Unlike most copy paste tools, it's built to feel native on each platform, it's fully keyboard-driven, and it respects your privacy completely. It's an open source clipboard utility focused on productivity — you can verify every line of code yourself. --- @@ -476,7 +479,7 @@ doing, what you expected, and the version shown in **Settings → About**. ### The logs, if they help -CopyPaste writes two plain-text log files beside your history — +CoPanda writes two plain-text log files beside your history — `logs/cp-gui.log` for the settings window and `logs/cp-panel.log` for the panel. **Settings → History → Data folder → Open folder** takes you there. @@ -504,7 +507,7 @@ restored twice without making a mess. ### A completely clean slate -Quit CopyPaste from the tray (Windows) or the menu bar (macOS) and delete the +Quit CoPanda from the tray (Windows) or the menu bar (macOS) and delete the data folder listed above. **Settings → History → Data folder → Open folder** takes you to it. Starting it again is a fresh installation, welcome tour included. @@ -538,9 +541,9 @@ I keep a clear record of what's been added, fixed, and planned: --- -## Localization: Help Translate CopyPaste +## Localization: Help Translate CoPanda -CopyPaste should speak your language. Currently it supports English and Spanish, but the goal is to reach people everywhere. +CoPanda should speak your language. Currently it supports English and Spanish, but the goal is to reach people everywhere. ### Currently Supported Languages @@ -557,7 +560,7 @@ CopyPaste should speak your language. Currently it supports English and Spanish, ### Help Add a New Language -CopyPaste is written in two languages at once, and every string sits next to its +CoPanda is written in two languages at once, and every string sits next to its twin. There is no translation file format to learn: the pairs live in the code. #### Where the words are @@ -591,7 +594,7 @@ installer template picks its messages with `$LANGUAGE`. - Keep translations concise — UI space is limited - Use a neutral tone, and address the reader informally - Preserve placeholders like `{one}` -- Don't translate brand names (CopyPaste, Windows, etc.) +- Don't translate brand names (CoPanda, Windows, etc.) - Don't change the keys, only what they say --- @@ -601,7 +604,7 @@ installer template picks its messages with `$LANGUAGE`. Contributions are always appreciated — whether that's a bug report, a translation, or a pull request: - **Write Code** — Fix bugs or add features. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup. -- **Translate** — Add your language. [See guide](#localization-help-translate-copypaste). +- **Translate** — Add your language. [See guide](#localization-help-translate-copanda). - **Report Bugs** — If something breaks, [open an issue](https://github.com/rgdevment/CopyPaste/issues/new). - **Share Ideas** — Tell me what you wish this clipboard manager could do. @@ -628,7 +631,7 @@ If you're curious about what's under the hood of this open source clipboard mana ## Themes -CopyPaste follows your system theme automatically — no configuration needed. +CoPanda follows your system theme automatically — no configuration needed. - **Light** — Clean and bright, matching a light OS theme. - **Dark** — Easy on the eyes, matching a dark OS theme. @@ -644,7 +647,7 @@ everything else changes, so go and look. | Project | Platform | Where your data lives | Licence | | :-- | :-- | :-- | :-- | -| **CopyPaste** | Windows, macOS | Your disk, no account | GPL-3.0 | +| **CoPanda** | Windows, macOS | Your disk, no account | GPL-3.0 | | [Ditto](https://github.com/sabrogden/Ditto) | Windows | Your disk; can sync between your own machines | GPL-3.0 | | [CopyQ](https://github.com/hluk/CopyQ) | Windows, macOS, Linux | Your disk | GPL-3.0 | | [Maccy](https://github.com/p0deje/Maccy) | macOS | Your disk | MIT | @@ -654,13 +657,13 @@ everything else changes, so go and look. | [Raycast](https://www.raycast.com) | macOS | Your disk, with their service behind other features | Freemium, closed source | | Clipboard history | Windows, built in | Your disk; Microsoft's cloud if you turn syncing on | Part of Windows | -What CopyPaste does that most of these do not: **one application on Windows and +What CoPanda does that most of these do not: **one application on Windows and macOS** rather than one per system, **text read out of your screenshots** so a picture is searchable by what it says, **fifteen kinds recognised on their own** with a view that suits each, and **pasting the same card in another form** without touching what is stored. -Each of them is better than CopyPaste at something. CopyQ is scriptable to a +Each of them is better than CoPanda at something. CopyQ is scriptable to a degree nothing here matches and runs on Linux too. Maccy is smaller and faster to reach for. Ditto has years of Windows polish and syncing between machines. Raycast is a whole launcher that happens to keep a clipboard. Pick what fits the @@ -670,7 +673,7 @@ way you work. ## Other Tools by the Same Author -I build free, open source tools focused on privacy and productivity. If you like CopyPaste, you might also find these useful: +I build free, open source tools focused on privacy and productivity. If you like CoPanda, you might also find these useful:

@@ -713,14 +716,14 @@ whether those tests would notice a change rather than merely cover the line. ## License and Spirit -**CopyPaste** — A modern, open source clipboard manager and copy-paste tool for Windows and macOS. +**CoPanda** — A modern, open source clipboard manager and copy-paste tool for Windows and macOS. Copyright (C) 2026 Mario Hidalgo G. (rgdevment) This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. Distributed under the **GNU General Public License v3.0**. See [LICENSE](LICENSE) for more information. -CopyPaste is dual licensed. The GPL-3.0 covers everyone using, deploying, +CoPanda is dual licensed. The GPL-3.0 covers everyone using, deploying, auditing, packaging or forking it — which is almost everybody, and it costs nothing. Redistributing it inside a product of your own needs separate terms: see [COMMERCIAL.md](COMMERCIAL.md). @@ -733,13 +736,13 @@ work. --- -I built CopyPaste because I was tired of the alternatives — bloated, resource-hungry, or disrespectful of my privacy. This is a personal copy paste productivity tool, built from a real need, shared because others might need a better clipboard manager too. Free to use, free to inspect, free forever. No analytics, no subscription, no upsell. +I built CoPanda because I was tired of the alternatives — bloated, resource-hungry, or disrespectful of my privacy. This is a personal copy paste productivity tool, built from a real need, shared because others might need a better clipboard manager too. Free to use, free to inspect, free forever. No analytics, no subscription, no upsell. If you find it useful, I'm glad. If you want to help make it better, even better. ## Acknowledgements -CopyPaste stands on other people's open source work, every piece of it listed +CoPanda stands on other people's open source work, every piece of it listed with its licence in [THIRD-PARTY-BUNDLED.md](THIRD-PARTY-BUNDLED.md), with the licence texts in [THIRD-PARTY-LICENSES.md](THIRD-PARTY-LICENSES.md), and both shown in the app under **About**. The panel is drawn with diff --git a/RELEASING.md b/RELEASING.md index ff6199f5..ff671b36 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -1,4 +1,4 @@ -# Releasing CopyPaste +# Releasing CoPanda `.github/workflows/release.yml` builds, signs and publishes the 3.0 — modelled on the pipeline in [rgdevment/Tisty](https://github.com/rgdevment/Tisty), which @@ -22,7 +22,7 @@ before it: | `verify` | Installs what was just published and checks the update feed answers. | | `msstore` | Submits the MSIX (stable tags only). | | `winget` | Opens the pull request that adds this version to `winget-pkgs`. | -| `homebrew` | Rewrites `copypaste` (stable) or `copypaste-beta` (candidate) in the tap. | +| `homebrew` | Rewrites `copanda` (stable) or `copanda-beta` (candidate) in the tap. | `feed.yml` then watches the published manifest daily: a deleted asset, a retired release or a force-pushed branch breaks the update feed silently, and @@ -120,7 +120,7 @@ The tap repository already exists and the `homebrew` job rewrites the cask itself, so there is nothing to write by hand. Leave the frozen Linux formulae alone: the job must not sweep them. -The cask's `homepage` is `https://rgdevment.com/copypaste/`, the product page — +The cask's `homepage` is `https://www.copanda.app/`, the product page — not the repository. The same holds anywhere a store or a package manager asks for a website: the repository is where the code lives, not where a user is sent. @@ -144,7 +144,7 @@ binaries and the manifest. A candidate is tagged `vX.Y.Z-rcN` with N from 1 to 9 and nothing else: semver orders `rc.3` and `rc10` below `rc2`, so either would never be offered. The tag is refused when X.Y.Z is not above the stable already out. Candidates -publish the GitHub Release and the `copypaste-beta` cask, and skip the Store +publish the GitHub Release and the `copanda-beta` cask, and skip the Store and winget. ## Crossing from the 2.x — decided 2026-09-29 diff --git a/SECURITY.md b/SECURITY.md index a82f1e41..04cccb39 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Security Matters -**CopyPaste** handles your clipboard history—that can include sensitive stuff. I take security seriously because you're trusting this tool with content that might be personal or confidential. +**CoPanda** handles your clipboard history—that can include sensitive stuff. I take security seriously because you're trusting this tool with content that might be personal or confidential. **This isn't corporate security theater.** This is a personal project shared with the community. It's built on trust—transparency in the code, responsibility when issues come up, and treating security researchers as partners. @@ -24,7 +24,7 @@ I'm not protecting a brand or business. I'm protecting _you_ and everyone using - **Configurable Retention** — Automatically delete old clipboard items based on your retention settings. - **Open Source** — Every line of code is public. You can inspect, audit, and verify what we're doing. - **Signed Updates** — Every installer the updater offers is signed with minisign, and the public key is compiled into the application. The signature is checked before anything is installed, so a compromised mirror cannot hand you a different binary: an update that does not verify is refused rather than installed. Each signature is bound to its exact version, so an older release cannot be served under a newer number, and the download address is checked against this repository's releases before a single byte is downloaded. -- **Nothing That Locks You Out** — CopyPaste never blocks a version you already have. An update is an offer; your history is yours and stays reachable whether you take it or not. +- **Nothing That Locks You Out** — CoPanda never blocks a version you already have. An update is an offer; your history is yours and stays reachable whether you take it or not. ### Development Practices @@ -51,7 +51,7 @@ Security updates are provided for: ## 🐛 Reporting a Vulnerability -If you discover a security vulnerability in **CopyPaste**, please help us protect our users by reporting it responsibly. +If you discover a security vulnerability in **CoPanda**, please help us protect our users by reporting it responsibly. ### What Qualifies as a Security Vulnerability? @@ -97,7 +97,7 @@ This is the fastest way to reach us. We check email daily and will respond withi - **Description** — Clear explanation of the vulnerability - **Impact** — What could an attacker do? Who is affected? - **Steps to Reproduce** — How can we reproduce the issue? -- **CopyPaste Version** — Which version is affected? +- **CoPanda Version** — Which version is affected? - **OS and version** — e.g., Windows 11 23H2, macOS Sequoia 15.1 - **Proof of Concept** (optional) — Code or screenshots demonstrating the issue - **Suggested Fix** (optional) — If you have ideas on how to fix it @@ -169,7 +169,7 @@ I believe in **coordinated disclosure** to protect users: ## 🏆 Security Researchers Hall of Fame -We're grateful to the security researchers who help make **CopyPaste** safer: +We're grateful to the security researchers who help make **CoPanda** safer: @@ -183,14 +183,14 @@ We're grateful to the security researchers who help make **CopyPaste** safer: ### For Users -- **Keep CopyPaste Updated** — Nothing updates automatically: Settings → About offers a new version and installs it when you press Update. The Microsoft Store copy updates through the Store; a Homebrew copy updates itself with the same button +- **Keep CoPanda Updated** — Nothing updates automatically: Settings → About offers a new version and installs it when you press Update. The Microsoft Store copy updates through the Store; a Homebrew copy updates itself with the same button - **Review Clipboard History** — Periodically check what's being stored and delete sensitive items - **Configure Retention** — Set shorter retention periods if you handle highly sensitive data -- **Use Password Managers** — Most mark what they copy as secret, and CopyPaste never reads content marked that way. Check yours once: copy a credential and make sure no entry appears +- **Use Password Managers** — Most mark what they copy as secret, and CoPanda never reads content marked that way. Check yours once: copy a credential and make sure no entry appears ### For Developers -- **Read the Code** — The entire codebase is open source: [CopyPaste Repository](https://github.com/rgdevment/CopyPaste) +- **Read the Code** — The entire codebase is open source: [CoPanda Repository](https://github.com/rgdevment/CopyPaste) - **Review Dependencies** — Every package and crate that ships is listed in [THIRD-PARTY-BUNDLED.md](THIRD-PARTY-BUNDLED.md), with its licence text in [THIRD-PARTY-LICENSES.md](THIRD-PARTY-LICENSES.md) - **Security Best Practices** — Follow secure coding guidelines when contributing @@ -198,7 +198,7 @@ We're grateful to the security researchers who help make **CopyPaste** safer: ## 🔐 Cryptographic Disclosure -**CopyPaste does not currently use cryptographic functions for data storage.** +**CoPanda does not currently use cryptographic functions for data storage.** - Clipboard history is stored in **plaintext** in a local SQLite database - Database files are protected by **OS-level file system permissions** (Windows and macOS) @@ -225,7 +225,7 @@ We're here to help and answer questions: - **Vulnerability Reports:** Use the private channels above — never post security issues publicly - **Policy Feedback:** [Open an Issue](https://github.com/rgdevment/CopyPaste/issues/new) — help us improve this policy -**Security is everyone's responsibility.** Thank you for helping keep **CopyPaste** safe for everyone using it. +**Security is everyone's responsibility.** Thank you for helping keep **CoPanda** safe for everyone using it. **Remember:** If you're unsure whether something is a security issue, reach out anyway. I'd rather have a conversation than miss a real problem. diff --git a/THIRD-PARTY-BUNDLED.md b/THIRD-PARTY-BUNDLED.md index 1933e1e4..34e421cf 100644 --- a/THIRD-PARTY-BUNDLED.md +++ b/THIRD-PARTY-BUNDLED.md @@ -1,9 +1,9 @@ -# Third-party notices — what ships inside CopyPaste +# Third-party notices — what ships inside CoPanda -CopyPaste is GPL-3.0-only. The binaries carry the work below, each under its own -licence. Nothing of it was copied into CopyPaste's own source; what was copied in +CoPanda is GPL-3.0-only. The binaries carry the work below, each under its own +licence. Nothing of it was copied into CoPanda's own source; what was copied in is in [THIRD-PARTY.md](https://github.com/rgdevment/CopyPaste/blob/main/THIRD-PARTY.md). diff --git a/THIRD-PARTY-LICENSES.md b/THIRD-PARTY-LICENSES.md index 921216e4..4e351eaa 100644 --- a/THIRD-PARTY-LICENSES.md +++ b/THIRD-PARTY-LICENSES.md @@ -1,4 +1,4 @@ -# Licence texts — what the crates inside CopyPaste carry +# Licence texts — what the crates inside CoPanda carry diff --git a/THIRD-PARTY.md b/THIRD-PARTY.md index f036357e..f287ab2a 100644 --- a/THIRD-PARTY.md +++ b/THIRD-PARTY.md @@ -1,9 +1,9 @@ # Third-party notices -CopyPaste is GPL-3.0-only. What follows was copied into CopyPaste's own source +CoPanda is GPL-3.0-only. What follows was copied into CoPanda's own source and carries its own licence, which allows that. -CopyPaste also bundles other people's work rather than copying it. The parts +CoPanda also bundles other people's work rather than copying it. The parts that do the heavy lifting are [Slint](https://slint.dev) with [Skia](https://skia.org) for the panel, [SQLite](https://sqlite.org) through [rusqlite](https://github.com/rusqlite/rusqlite) for the history, diff --git a/app/index.html b/app/index.html index d2309dac..ed30aebb 100644 --- a/app/index.html +++ b/app/index.html @@ -3,7 +3,7 @@ - CopyPaste + CoPanda

diff --git a/app/package.json b/app/package.json index 4827820a..73b9b16c 100644 --- a/app/package.json +++ b/app/package.json @@ -2,7 +2,7 @@ "name": "copypaste-window", "private": true, "version": "3.0.0", - "homepage": "https://rgdevment.com/copypaste/", + "homepage": "https://www.copanda.app/", "type": "module", "scripts": { "dev": "vite", diff --git a/app/src-tauri/installer.nsi b/app/src-tauri/installer.nsi index 2240b8b7..c219b17d 100644 --- a/app/src-tauri/installer.nsi +++ b/app/src-tauri/installer.nsi @@ -40,6 +40,7 @@ ${StrLoc} !define MANUFACTURER "{{manufacturer}}" !define PRODUCTNAME "{{product_name}}" +!define HOMENAME "CopyPaste" !define VERSION "{{version}}" !define VERSIONWITHBUILD "{{version_with_build}}" !define HOMEPAGE "{{homepage}}" @@ -64,9 +65,9 @@ ${StrLoc} !define WEBVIEW2BOOTSTRAPPERPATH "{{webview2_bootstrapper_path}}" !define WEBVIEW2INSTALLERPATH "{{webview2_installer_path}}" !define MINIMUMWEBVIEW2VERSION "{{minimum_webview2_version}}" -!define UNINSTKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCTNAME}" +!define UNINSTKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${HOMENAME}" !define MANUKEY "Software\${MANUFACTURER}" -!define MANUPRODUCTKEY "${MANUKEY}\${PRODUCTNAME}" +!define MANUPRODUCTKEY "${MANUKEY}\${HOMENAME}" !define UNINSTALLERSIGNCOMMAND "{{uninstaller_sign_cmd}}" !define ESTIMATEDSIZE "{{estimated_size}}" !define STARTMENUFOLDER "{{start_menu_folder}}" @@ -84,7 +85,7 @@ OutFile "${OUTFILE}" ; We don't actually use this value as default install path, ; it's just for nsis to append the product name folder in the directory selector ; https://nsis.sourceforge.io/Reference/InstallDir -!define PLACEHOLDER_INSTALL_DIR "placeholder\${PRODUCTNAME}" +!define PLACEHOLDER_INSTALL_DIR "placeholder\${HOMENAME}" InstallDir "${PLACEHOLDER_INSTALL_DIR}" VIProductVersion "${VERSIONWITHBUILD}" @@ -113,7 +114,7 @@ VIAddVersionKey "ProductVersion" "${VERSION}" !if "${INSTALLMODE}" == "both" !define MULTIUSER_MUI - !define MULTIUSER_INSTALLMODE_INSTDIR "${PRODUCTNAME}" + !define MULTIUSER_INSTALLMODE_INSTDIR "${HOMENAME}" !define MULTIUSER_INSTALLMODE_COMMANDLINE !if "${ARCH}" == "x64" !define MULTIUSER_USE_PROGRAMFILES64 @@ -205,7 +206,7 @@ Function PageReinstall IntOp $0 $0 + 1 ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$1" "DisplayName" ReadRegStr $R1 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$1" "Publisher" - StrCmp "$R0$R1" "${PRODUCTNAME}${MANUFACTURER}" 0 wix_loop + StrCmp "$R0$R1" "${HOMENAME}${MANUFACTURER}" 0 wix_loop ReadRegStr $R0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$1" "UninstallString" ${StrCase} $R1 $R0 "L" ${StrLoc} $R0 $R1 "msiexec" ">" @@ -502,17 +503,17 @@ Function .onInit !if "${INSTALLMODE}" == "perMachine" ${If} ${RunningX64} !if "${ARCH}" == "x64" - StrCpy $INSTDIR "$PROGRAMFILES64\${PRODUCTNAME}" + StrCpy $INSTDIR "$PROGRAMFILES64\${HOMENAME}" !else if "${ARCH}" == "arm64" - StrCpy $INSTDIR "$PROGRAMFILES64\${PRODUCTNAME}" + StrCpy $INSTDIR "$PROGRAMFILES64\${HOMENAME}" !else - StrCpy $INSTDIR "$PROGRAMFILES\${PRODUCTNAME}" + StrCpy $INSTDIR "$PROGRAMFILES\${HOMENAME}" !endif ${Else} - StrCpy $INSTDIR "$PROGRAMFILES\${PRODUCTNAME}" + StrCpy $INSTDIR "$PROGRAMFILES\${HOMENAME}" ${EndIf} !else if "${INSTALLMODE}" == "currentUser" - StrCpy $INSTDIR "$LOCALAPPDATA\Programs\${PRODUCTNAME}" + StrCpy $INSTDIR "$LOCALAPPDATA\Programs\${HOMENAME}" !endif Call RestorePreviousInstallLocation @@ -918,6 +919,18 @@ Section Uninstall !insertmacro UnpinShortcut "$DESKTOP\${PRODUCTNAME}.lnk" Delete "$DESKTOP\${PRODUCTNAME}.lnk" ${EndIf} + !insertmacro IsShortcutTarget "$DESKTOP\${HOMENAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" + Pop $0 + ${If} $0 = 1 + !insertmacro UnpinShortcut "$DESKTOP\${HOMENAME}.lnk" + Delete "$DESKTOP\${HOMENAME}.lnk" + ${EndIf} + !insertmacro IsShortcutTarget "$SMPROGRAMS\${HOMENAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" + Pop $0 + ${If} $0 = 1 + !insertmacro UnpinShortcut "$SMPROGRAMS\${HOMENAME}.lnk" + Delete "$SMPROGRAMS\${HOMENAME}.lnk" + ${EndIf} ${EndIf} ; Remove registry information for add/remove programs @@ -934,7 +947,7 @@ Section Uninstall ; If it doesn't exist, it does nothing. ; We do this when not updating (to preserve the registry value on updates) ${If} $UpdateMode <> 1 - DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "${PRODUCTNAME}" + DeleteRegValue HKCU "Software\Microsoft\Windows\CurrentVersion\Run" "${HOMENAME}" ${EndIf} ; Delete app data if the checkbox is selected @@ -952,17 +965,17 @@ Section Uninstall SetShellVarContext current ; The 2.x keeps its history in this same folder, and it is not ours to delete. - Delete "$LOCALAPPDATA\${PRODUCTNAME}\history.db" - Delete "$LOCALAPPDATA\${PRODUCTNAME}\history.db-wal" - Delete "$LOCALAPPDATA\${PRODUCTNAME}\history.db-shm" - Delete "$LOCALAPPDATA\${PRODUCTNAME}\config.toml" - Delete "$LOCALAPPDATA\${PRODUCTNAME}\update.json" - Delete "$LOCALAPPDATA\${PRODUCTNAME}\logs\cp-gui.log" - Delete "$LOCALAPPDATA\${PRODUCTNAME}\logs\cp-panel.log" - RmDir /r "$LOCALAPPDATA\${PRODUCTNAME}\blobs" - RmDir /r "$LOCALAPPDATA\${PRODUCTNAME}\thumbs" - RmDir "$LOCALAPPDATA\${PRODUCTNAME}\logs" - RmDir "$LOCALAPPDATA\${PRODUCTNAME}" + Delete "$LOCALAPPDATA\${HOMENAME}\history.db" + Delete "$LOCALAPPDATA\${HOMENAME}\history.db-wal" + Delete "$LOCALAPPDATA\${HOMENAME}\history.db-shm" + Delete "$LOCALAPPDATA\${HOMENAME}\config.toml" + Delete "$LOCALAPPDATA\${HOMENAME}\update.json" + Delete "$LOCALAPPDATA\${HOMENAME}\logs\cp-gui.log" + Delete "$LOCALAPPDATA\${HOMENAME}\logs\cp-panel.log" + RmDir /r "$LOCALAPPDATA\${HOMENAME}\blobs" + RmDir /r "$LOCALAPPDATA\${HOMENAME}\thumbs" + RmDir "$LOCALAPPDATA\${HOMENAME}\logs" + RmDir "$LOCALAPPDATA\${HOMENAME}" RmDir /r "$LOCALAPPDATA\${BUNDLEID}" ${EndIf} @@ -995,6 +1008,17 @@ Function un.SkipIfPassive FunctionEnd Function CreateOrUpdateStartMenuShortcut + !insertmacro IsShortcutTarget "$SMPROGRAMS\$AppStartMenuFolder\${HOMENAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" + Pop $0 + ${If} $0 = 1 + Rename "$SMPROGRAMS\$AppStartMenuFolder\${HOMENAME}.lnk" "$SMPROGRAMS\$AppStartMenuFolder\${PRODUCTNAME}.lnk" + ${EndIf} + !insertmacro IsShortcutTarget "$SMPROGRAMS\${HOMENAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" + Pop $0 + ${If} $0 = 1 + Rename "$SMPROGRAMS\${HOMENAME}.lnk" "$SMPROGRAMS\${PRODUCTNAME}.lnk" + ${EndIf} + ; We used to use product name as MAINBINARYNAME ; migrate old shortcuts to target the new MAINBINARYNAME StrCpy $R0 0 @@ -1037,6 +1061,12 @@ Function CreateOrUpdateStartMenuShortcut FunctionEnd Function CreateOrUpdateDesktopShortcut + !insertmacro IsShortcutTarget "$DESKTOP\${HOMENAME}.lnk" "$INSTDIR\${MAINBINARYNAME}.exe" + Pop $0 + ${If} $0 = 1 + Rename "$DESKTOP\${HOMENAME}.lnk" "$DESKTOP\${PRODUCTNAME}.lnk" + ${EndIf} + ; We used to use product name as MAINBINARYNAME ; migrate old shortcuts to target the new MAINBINARYNAME !insertmacro IsShortcutTarget "$DESKTOP\${PRODUCTNAME}.lnk" "$INSTDIR\$OldMainBinaryName" diff --git a/app/src-tauri/msix/AppxManifest.xml.in b/app/src-tauri/msix/AppxManifest.xml.in index 7bfc2395..dc7a10f3 100644 --- a/app/src-tauri/msix/AppxManifest.xml.in +++ b/app/src-tauri/msix/AppxManifest.xml.in @@ -13,7 +13,7 @@ ProcessorArchitecture="x64" /> - CopyPaste - Clipboard Manager + CoPanda - Clipboard Manager @PUBLISHER_DISPLAY@ Assets\StoreLogo.png A clipboard history that stays on your computer @@ -31,7 +31,7 @@ - + diff --git a/app/src-tauri/src/bundle.rs b/app/src-tauri/src/bundle.rs new file mode 100644 index 00000000..89e6dfaf --- /dev/null +++ b/app/src-tauri/src/bundle.rs @@ -0,0 +1,126 @@ +use std::path::{Path, PathBuf}; + +const FORMER: &str = "CopyPaste.app"; +const NAMED: &str = "CoPanda.app"; +const OURS: &str = "com.rgdevment.copypaste"; + +#[derive(Debug, PartialEq, Eq)] +pub enum Plan { + Rename { from: PathBuf, to: PathBuf }, + Bin(PathBuf), + Stay, +} + +pub fn bundle_of(exe: &Path) -> Option { + let bundle = exe.parent()?.parent()?.parent()?; + let named = bundle.extension().is_some_and(|one| one == "app"); + named.then(|| bundle.to_path_buf()) +} + +pub fn plan(bundle: &Path) -> Plan { + let name = bundle.file_name().and_then(|one| one.to_str()); + if name == Some(FORMER) { + let to = bundle.with_file_name(NAMED); + if to.exists() { + return Plan::Stay; + } + return Plan::Rename { + from: bundle.to_path_buf(), + to, + }; + } + if name == Some(NAMED) { + let former = bundle.with_file_name(FORMER); + if ours(&former) { + return Plan::Bin(former); + } + } + Plan::Stay +} + +fn ours(bundle: &Path) -> bool { + std::fs::read_to_string(bundle.join("Contents").join("Info.plist")) + .is_ok_and(|plist| plist.contains(OURS)) +} + +pub fn brewed(roots: &[&Path]) -> bool { + roots.iter().any(|root| { + ["copypaste", "copypaste-beta", "copanda", "copanda-beta"] + .iter() + .any(|cask| root.join(cask).exists()) + }) +} + +#[cfg(target_os = "macos")] +pub fn settle() -> bool { + let Ok(exe) = std::env::current_exe() else { + return false; + }; + let Some(bundle) = bundle_of(&exe) else { + return false; + }; + let caskrooms = [ + Path::new("/opt/homebrew/Caskroom"), + Path::new("/usr/local/Caskroom"), + ]; + if crate::update::mounted(Some(&exe)) || brewed(&caskrooms) { + return false; + } + match plan(&bundle) { + Plan::Rename { from, to } => rename(&from, &to), + Plan::Bin(former) => { + bin(&former); + false + } + Plan::Stay => false, + } +} + +#[cfg(target_os = "macos")] +fn rename(from: &Path, to: &Path) -> bool { + let agent = std::env::var_os("HOME").map(|home| { + Path::new(&home) + .join("Library/LaunchAgents") + .join("com.rgdevment.copypaste.plist") + }); + if agent.is_some_and(|one| one.exists()) { + return false; + } + if let Err(why) = std::fs::rename(from, to) { + crate::note::note(&format!("the app could not take the name CoPanda: {why}")); + return false; + } + if reopen(to) { + crate::note::note(&format!("the app now lives at {}", to.display())); + return true; + } + if let Err(why) = std::fs::rename(to, from) { + crate::note::note(&format!("the app could not go back to its old name: {why}")); + } + false +} + +#[cfg(target_os = "macos")] +fn bin(former: &Path) { + if cp_mac_sys::files::running_from(former) { + return; + } + match cp_mac_sys::files::trash(former) { + Ok(()) => crate::note::note(&format!("{} went to the Trash", former.display())), + Err(why) => crate::note::note(&format!("{} stayed: {why}", former.display())), + } +} + +#[cfg(target_os = "macos")] +fn reopen(named: &Path) -> bool { + std::process::Command::new("/bin/sh") + .arg("-c") + .arg("sleep 1; /usr/bin/open \"$0\"") + .arg(named) + .spawn() + .is_ok() +} + +#[cfg(test)] +#[path = "bundle_test.rs"] +mod tests; diff --git a/app/src-tauri/src/bundle_test.rs b/app/src-tauri/src/bundle_test.rs new file mode 100644 index 00000000..a8395ca0 --- /dev/null +++ b/app/src-tauri/src/bundle_test.rs @@ -0,0 +1,76 @@ +use super::*; + +fn scratch(name: &str) -> PathBuf { + let dir = std::env::temp_dir().join(format!("cp-bundle-{name}-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).expect("scratch"); + dir +} + +fn app(at: &Path, id: &str) -> PathBuf { + std::fs::create_dir_all(at.join("Contents").join("MacOS")).expect("bundle"); + std::fs::write( + at.join("Contents").join("Info.plist"), + format!("CFBundleIdentifier\n{id}"), + ) + .expect("plist"); + at.to_path_buf() +} + +#[test] +fn the_bundle_is_three_folders_above_the_program() { + let exe = Path::new("/Applications/CopyPaste.app/Contents/MacOS/cp-gui"); + assert_eq!( + bundle_of(exe), + Some(PathBuf::from("/Applications/CopyPaste.app")) + ); + assert_eq!(bundle_of(Path::new("/usr/local/bin/cp-gui")), None); +} + +#[test] +fn a_copy_updated_in_place_is_meant_to_take_the_new_name() { + let dir = scratch("rename"); + let old = app(&dir.join("CopyPaste.app"), "com.rgdevment.copypaste"); + assert_eq!( + plan(&old), + Plan::Rename { + from: old.clone(), + to: dir.join("CoPanda.app") + } + ); +} + +#[test] +fn the_old_name_stays_put_when_the_new_one_is_already_there() { + let dir = scratch("stay"); + let old = app(&dir.join("CopyPaste.app"), "com.rgdevment.copypaste"); + app(&dir.join("CoPanda.app"), "com.rgdevment.copypaste"); + assert_eq!(plan(&old), Plan::Stay); +} + +#[test] +fn the_new_copy_means_to_bin_the_old_one() { + let dir = scratch("bin"); + let old = app(&dir.join("CopyPaste.app"), "com.rgdevment.copypaste"); + let new = app(&dir.join("CoPanda.app"), "com.rgdevment.copypaste"); + assert_eq!(plan(&new), Plan::Bin(old)); +} + +#[test] +fn an_app_of_someone_else_under_the_old_name_is_left_alone() { + let dir = scratch("theirs"); + app(&dir.join("CopyPaste.app"), "com.example.copypaste"); + let new = app(&dir.join("CoPanda.app"), "com.rgdevment.copypaste"); + assert_eq!(plan(&new), Plan::Stay); +} + +#[test] +fn a_copy_homebrew_installed_is_left_to_homebrew() { + let dir = scratch("brew"); + let empty = dir.join("empty"); + std::fs::create_dir_all(&empty).expect("empty"); + let brew = dir.join("Caskroom"); + std::fs::create_dir_all(brew.join("copypaste-beta")).expect("cask"); + assert!(!brewed(&[&empty])); + assert!(brewed(&[&empty, &brew])); +} diff --git a/app/src-tauri/src/lib.rs b/app/src-tauri/src/lib.rs index bf78823f..692e4597 100644 --- a/app/src-tauri/src/lib.rs +++ b/app/src-tauri/src/lib.rs @@ -1,4 +1,6 @@ mod backup; +#[cfg(any(target_os = "macos", test))] +mod bundle; mod keys; mod links; mod looks; @@ -15,6 +17,10 @@ mod welcome; pub fn run() { note::catch_panics(); + #[cfg(target_os = "macos")] + if bundle::settle() { + return; + } let app = tauri::Builder::default() .plugin(tauri_plugin_single_instance::init(|app, _argv, _cwd| { welcome::reopened(app); @@ -87,7 +93,7 @@ pub fn run() { Ok(()) }) .build(tauri::generate_context!()) - .expect("CopyPaste could not start"); + .expect("CoPanda could not start"); app.run(|app, event| match event { tauri::RunEvent::ExitRequested { diff --git a/app/src-tauri/src/report.rs b/app/src-tauri/src/report.rs index b6d6348d..046eeaa1 100644 --- a/app/src-tauri/src/report.rs +++ b/app/src-tauri/src/report.rs @@ -68,7 +68,7 @@ pub fn save_report( pub fn named(stamp: &str) -> String { let day = stamp.get(..10).unwrap_or("today"); - format!("copypaste-report-{day}.txt") + format!("copanda-report-{day}.txt") } fn report(version: &str) -> String { @@ -77,7 +77,7 @@ fn report(version: &str) -> String { crate::update::Route::Download => "download", }; let mut out = format!( - "CopyPaste {version}\n{}\n{} {}\ninstalled from: {route}\nwritten: {}\n", + "CoPanda {version}\n{}\n{} {}\ninstalled from: {route}\nwritten: {}\n", system(), std::env::consts::OS, std::env::consts::ARCH, diff --git a/app/src-tauri/src/report_test.rs b/app/src-tauri/src/report_test.rs index 12eb8906..b1b90d40 100644 --- a/app/src-tauri/src/report_test.rs +++ b/app/src-tauri/src/report_test.rs @@ -52,7 +52,7 @@ fn the_tail_starts_on_a_whole_line_and_keeps_the_end() { fn the_report_is_named_after_the_day_it_was_saved() { assert_eq!( named("2026-10-10 12:00:00Z"), - "copypaste-report-2026-10-10.txt" + "copanda-report-2026-10-10.txt" ); } diff --git a/app/src-tauri/src/settings.rs b/app/src-tauri/src/settings.rs index 3bca1f7d..32912452 100644 --- a/app/src-tauri/src/settings.rs +++ b/app/src-tauri/src/settings.rs @@ -59,7 +59,7 @@ pub fn policy() -> cp_store::Policy { } pub fn nowhere() -> String { - "the folder where CopyPaste keeps its own was not found".to_owned() + "the folder where CoPanda keeps its own was not found".to_owned() } pub fn settle() -> bool { diff --git a/app/src-tauri/src/tray.rs b/app/src-tauri/src/tray.rs index b848d7e6..d4d88fcc 100644 --- a/app/src-tauri/src/tray.rs +++ b/app/src-tauri/src/tray.rs @@ -23,14 +23,14 @@ fn worded(spanish: bool) -> [&'static str; 4] { "Mostrar el panel", "Ajustes…", "Reiniciar el panel", - "Salir de CopyPaste", + "Salir de CoPanda", ] } else { [ "Show the panel", "Settings…", "Restart the panel", - "Quit CopyPaste", + "Quit CoPanda", ] } } @@ -75,7 +75,7 @@ pub fn raise(app: &AppHandle, spanish: bool) -> Option<()> { let tray = TrayIconBuilder::with_id("copypaste") .icon(Image::from_bytes(BAR).ok()?) - .tooltip("CopyPaste") + .tooltip("CoPanda") .menu(&menu) .show_menu_on_left_click(false) .on_menu_event(|app, event| match event.id.as_ref() { @@ -121,7 +121,7 @@ pub fn settle_menu(app: &AppHandle) -> tauri::Result<()> { let quits = MenuItem::with_id(app, QUITS, "Close", true, Some("CmdOrCtrl+Q"))?; let ours = Submenu::with_items( app, - "CopyPaste", + "CoPanda", true, &[ &PredefinedMenuItem::hide(app, None)?, @@ -182,8 +182,8 @@ pub fn tell_in( *shown = trouble; } let said = trouble.map_or_else( - || "CopyPaste".to_owned(), - |what| format!("CopyPaste: {}", what.worded(spanish)), + || "CoPanda".to_owned(), + |what| format!("CoPanda: {}", what.worded(spanish)), ); let handle = app.clone(); let _ = app.run_on_main_thread(move || { @@ -226,7 +226,7 @@ pub fn surface_at(app: &AppHandle, rail: Option<&str>) { }); let built = framed(crate::looks::dressed( WebviewWindowBuilder::new(app, "main", page) - .title("CopyPaste") + .title("CoPanda") .inner_size(780.0, 580.0) .min_inner_size(620.0, 460.0) .center(), diff --git a/app/src-tauri/src/tray_test.rs b/app/src-tauri/src/tray_test.rs index 83741031..512ffe51 100644 --- a/app/src-tauri/src/tray_test.rs +++ b/app/src-tauri/src/tray_test.rs @@ -63,7 +63,7 @@ fn the_words_come_in_the_order_the_menu_was_built() { said[2] ); assert!( - said[3].to_lowercase().contains("copypaste"), + said[3].to_lowercase().contains("copanda"), "the last one leaves: {}", said[3] ); diff --git a/app/src-tauri/src/waking.rs b/app/src-tauri/src/waking.rs index a427629e..1ee8b93b 100644 --- a/app/src-tauri/src/waking.rs +++ b/app/src-tauri/src/waking.rs @@ -175,7 +175,7 @@ mod there { let exe = std::env::current_exe()?; if wanted && crate::update::mounted(Some(&exe)) { return Err(std::io::Error::other( - "move CopyPaste to the Applications folder before starting it with the session", + "move CoPanda to the Applications folder before starting it with the session", )); } if !wanted && let Some(old) = legacy() { diff --git a/app/src-tauri/src/welcome.rs b/app/src-tauri/src/welcome.rs index 1bf206d6..999b1186 100644 --- a/app/src-tauri/src/welcome.rs +++ b/app/src-tauri/src/welcome.rs @@ -144,7 +144,7 @@ pub fn open(app: &AppHandle) { LABEL, WebviewUrl::App("index.html#welcome".into()), )) - .title("CopyPaste") + .title("CoPanda") .inner_size(600.0, 460.0) .resizable(false) .maximizable(false) diff --git a/app/src-tauri/tauri.conf.json b/app/src-tauri/tauri.conf.json index d85878fa..71d40dfc 100644 --- a/app/src-tauri/tauri.conf.json +++ b/app/src-tauri/tauri.conf.json @@ -1,6 +1,6 @@ { "$schema": "https://schema.tauri.app/config/2", - "productName": "CopyPaste", + "productName": "CoPanda", "identifier": "com.rgdevment.copypaste", "build": { "beforeDevCommand": "npm run dev", @@ -33,7 +33,7 @@ "copyright": "Copyright © 2026 rgdevment", "category": "Productivity", "shortDescription": "Clipboard history that stays on your machine. No ads, no telemetry, no account", - "longDescription": "CopyPaste keeps what you copy within reach of a shortcut: text, images, files, links and colours, searchable in milliseconds and stored only on your own machine. No account, no subscription, no telemetry and no server.", + "longDescription": "CoPanda keeps what you copy within reach of a shortcut: text, images, files, links and colours, searchable in milliseconds and stored only on your own machine. No account, no subscription, no telemetry and no server.", "licenseFile": "../../LICENSE", "windows": { "minimumWebview2Version": "111.0.0.0", diff --git a/app/src/index.css b/app/src/index.css index 47939f33..222562ad 100644 --- a/app/src/index.css +++ b/app/src/index.css @@ -1057,15 +1057,8 @@ button:disabled { } .welcome-mark { - width: 56px; - height: 56px; - border-radius: 14px; - display: grid; - place-items: center; - background: linear-gradient(150deg, var(--accent), var(--accent-dim)); - color: var(--panel); - font-size: 26px; - font-weight: 600; + width: 64px; + height: auto; } .welcome-pills { @@ -1506,6 +1499,39 @@ button:disabled { color: var(--muted); } +.welcome-news-top { + display: flex; + flex-direction: column; + align-items: center; + gap: 6px; + text-align: center; +} + +.welcome-panda { + width: 72px; + height: auto; +} + +@media (prefers-color-scheme: dark) { + :root:not([data-theme="light"]) .welcome-panda, + :root:not([data-theme="light"]) .welcome-mark { + filter: drop-shadow(0 0 1px rgb(248 250 255 / 0.9)) + drop-shadow(0 0 10px rgb(248 250 255 / 0.25)); + } +} + +:root[data-theme="dark"] .welcome-panda, +:root[data-theme="dark"] .welcome-mark { + filter: drop-shadow(0 0 1px rgb(248 250 255 / 0.9)) drop-shadow(0 0 10px rgb(248 250 255 / 0.25)); +} + +.welcome-line { + margin: 0; + font-size: var(--fs-small); + font-weight: 500; + color: var(--accent); +} + .welcome-news-head { display: flex; align-items: center; diff --git a/app/src/locales.ts b/app/src/locales.ts index e4fc1194..9d784f76 100644 --- a/app/src/locales.ts +++ b/app/src/locales.ts @@ -59,11 +59,11 @@ const ES = { lookLight: "Claro", lookDark: "Oscuro", wake: "Arranca con la sesión", - wakeWhy: "CopyPaste se abre al iniciar sesión y espera en la bandeja", + wakeWhy: "CoPanda se abre al iniciar sesión y espera en la bandeja", wakeTheirs: - "Windows tiene el arranque de CopyPaste desactivado. Actívalo en Configuración › Aplicaciones › Inicio.", + "Windows tiene el arranque de CoPanda desactivado. Actívalo en Configuración › Aplicaciones › Inicio.", wakeManaged: - "Windows gestiona el arranque de CopyPaste. Cámbialo en Configuración › Aplicaciones › Inicio.", + "Windows gestiona el arranque de CoPanda. Cámbialo en Configuración › Aplicaciones › Inicio.", keys: "Atajo del panel", keysWhy: "Presiónalo en cualquier parte: lo que elijas se pega donde estabas escribiendo", keysChange: "Cambiar", @@ -78,9 +78,9 @@ const ES = { panelUndrawn: "no se pudo dibujar", panelUnwatched: "nada está vigilando el portapapeles", panelUnemptied: "no se pudo vaciar el historial", - panelClipboardDenied: "el sistema no deja que CopyPaste lea el portapapeles", + panelClipboardDenied: "el sistema no deja que CoPanda lea el portapapeles", panelStopped: "dejó de vigilar el portapapeles", - panelUnsteady: "no se mantiene abierto; reinicia CopyPaste", + panelUnsteady: "no se mantiene abierto; reinicia CoPanda", panelUnanswering: "no responde", panelUnknown: "algo salió mal", keysTaken: @@ -179,7 +179,7 @@ const ES = { betaWarns: "Llegan antes que a nadie y pueden fallar. Puedes salir cuando quieras.", supportTitle: "Apoyar", supportWhy: - "CopyPaste es gratis y lo seguirá siendo. Si te sirve, esto ayuda a que siga creciendo.", + "CoPanda es gratis y lo seguirá siendo. Si te sirve, esto ayuda a que siga creciendo.", supportStar: "Dale una estrella", supportRate: "Valórala en la Store", supportSponsor: "Patrocina el proyecto", @@ -190,7 +190,7 @@ const ES = { toolLinkUnboundHere: "Instalado · tus enlaces salen por él", troubleTitle: "Si algo va mal", troubleWhat: - "El informe junta en un archivo el registro de CopyPaste, su versión y qué Windows o macOS usas, con tu nombre de usuario y tu carpeta personal tapados.", + "El informe junta en un archivo el registro de CoPanda, su versión y qué Windows o macOS usas, con tu nombre de usuario y tu carpeta personal tapados.", troubleNeverSent: "No se envía a ninguna parte", troubleYours: ". Se guarda donde tú elijas y solo lo adjuntas si quieres.", troubleReport: "Guardar informe…", @@ -211,8 +211,8 @@ const ES = { updateNone: "Estás en la última versión", updateWhen: "Se mira una vez al día, y cuando tú lo pidas", updateThere: "La versión {one} ya está disponible", - updateTake: "Se descarga, se instala y CopyPaste se reinicia solo", - updateMove: "Para instalarla, arrastra CopyPaste a Aplicaciones y ábrelo desde ahí", + updateTake: "Se descarga, se instala y CoPanda se reinicia solo", + updateMove: "Para instalarla, arrastra CoPanda a Aplicaciones y ábrelo desde ahí", updateDo: "Actualizar", updateGetting: "Descargando…", updateStore: "La Microsoft Store se encarga", @@ -226,17 +226,17 @@ const ES = { updateBusy: "Ya hay una actualización en marcha.", aboutPrivacyLink: "Privacidad", keysFormer: "En CopyPaste 2 era Ctrl + Alt + C", - wakeTheirsMac: "Aprueba CopyPaste en Ajustes del Sistema › General › Ítems de inicio", + wakeTheirsMac: "Aprueba CoPanda en Ajustes del Sistema › General › Ítems de inicio", trust: "Permiso para pegar", - trustWhy: "macOS pide tu permiso para que CopyPaste escriba en la ventana donde estabas", + trustWhy: "macOS pide tu permiso para que CoPanda escriba en la ventana donde estabas", trustGranted: "Concedido: lo que elijas se pega solo", trustMissing: "Sin él, lo elegido queda en el portapapeles y lo pegas tú", trustAsk: "Conceder", trustOpen: "Abrir Ajustes del Sistema", clipboardDenied: - "macOS no deja que CopyPaste lea el portapapeles: actívalo en Ajustes del Sistema › Privacidad y seguridad › Pegar desde otras apps", + "macOS no deja que CoPanda lea el portapapeles: actívalo en Ajustes del Sistema › Privacidad y seguridad › Pegar desde otras apps", clipboardAsks: - "macOS puede preguntarte si CopyPaste puede leer el portapapeles: responde «Permitir» para que guarde tus copias", + "macOS puede preguntarte si CoPanda puede leer el portapapeles: responde «Permitir» para que guarde tus copias", trustSecure: "Hay un campo de contraseña abierto: mientras dure, nadie puede pegar por ti", outDone: "Guardado: {one}", outMissing: "faltaron {one} sin su contenido", @@ -253,7 +253,7 @@ const ES = { welcomeHello: "Tu portapapeles, con memoria", welcomeHelloWhy: - "CopyPaste guarda lo que copias (textos, imágenes, enlaces y archivos) para que lo tengas a mano cuando lo necesites. Te mostramos lo básico en un minuto.", + "CoPanda guarda lo que copias (textos, imágenes, enlaces y archivos) para que lo tengas a mano cuando lo necesites. Te mostramos lo básico en un minuto.", welcomeLocal: "Todo queda en tu equipo", welcomeNoAccount: "Sin cuenta", welcomeNoTracking: "Sin rastreo", @@ -281,10 +281,10 @@ const ES = { welcomeWhereOver: "2 · Dónde encontrarlo", welcomeWhereTitle: "Junto al reloj", welcomeWhereWhy: - "CopyPaste vive en la bandeja del sistema, abajo a la derecha. Si no lo ves, revisa la flecha de íconos ocultos; puedes arrastrarlo a la barra para tenerlo siempre visible.", + "CoPanda vive en la bandeja del sistema, abajo a la derecha. Si no lo ves, revisa la flecha de íconos ocultos; puedes arrastrarlo a la barra para tenerlo siempre visible.", welcomeWhereTitleMac: "En la barra de menús", welcomeWhereWhyMac: - "CopyPaste vive en la barra de menús, arriba a la derecha. Si tienes muchos íconos, puede quedar oculto detrás de la muesca de la pantalla.", + "CoPanda vive en la barra de menús, arriba a la derecha. Si tienes muchos íconos, puede quedar oculto detrás de la muesca de la pantalla.", welcomeClick: "Clic", welcomeClickDoes: "abre el panel", welcomeRightClick: "Clic derecho", @@ -317,19 +317,20 @@ const ES = { welcomeTrustOver: "Antes de comenzar", welcomeTrustTitle: "Un permiso para poder pegar", welcomeTrustWhy: - "Para pegar en la app donde estabas, macOS necesita que autorices a CopyPaste. No lee lo que escribes: solo envía ⌘V cuando eliges algo.", + "Para pegar en la app donde estabas, macOS necesita que autorices a CoPanda. No lee lo que escribes: solo envía ⌘V cuando eliges algo.", welcomeTrustStepOne: "1 · Abrimos Configuración del Sistema › Privacidad y seguridad › Accesibilidad", - welcomeTrustStepTwo: "2 · Activa CopyPaste en la lista", + welcomeTrustStepTwo: "2 · Activa CoPanda en la lista", welcomeTrustStepThree: "3 · Vuelve aquí: seguimos automáticamente", welcomeTrustWaiting: "Esperando el permiso…", welcomeTrustWaitingWhy: - "Activa CopyPaste en Accesibilidad. Si ya aparecía activado y no responde, quítalo con − y agrégalo de nuevo.", + "Activa CoPanda en Accesibilidad. Si ya aparecía activado y no responde, quítalo con − y agrégalo de nuevo.", welcomeTrustDone: "Listo, ya puede pegar", welcomeTrustAsk: "Dar permiso", welcomeTrustLater: "Ahora no", welcomeNewsOver: "Novedades", - welcomeNewsTitle: "Hay novedades en CopyPaste", + welcomeNewsTitle: "Hay novedades en CoPanda", + welcomeNewsLine: "Un pulgar extra para tu portapapeles", welcomeNewsAll: "Ver todas las versiones", welcomeNewsOk: "Entendido", welcomeShowAgain: "Ver la bienvenida de nuevo", @@ -398,10 +399,9 @@ const EN: Record = { lookLight: "Light", lookDark: "Dark", wake: "Start at login", - wakeWhy: "CopyPaste opens when you log in and waits in the tray", - wakeTheirs: - "Windows has CopyPaste's startup turned off. Turn it on in Settings › Apps › Startup.", - wakeManaged: "Windows manages the startup of CopyPaste. Change it in Settings › Apps › Startup.", + wakeWhy: "CoPanda opens when you log in and waits in the tray", + wakeTheirs: "Windows has CoPanda's startup turned off. Turn it on in Settings › Apps › Startup.", + wakeManaged: "Windows manages the startup of CoPanda. Change it in Settings › Apps › Startup.", keys: "Panel shortcut", keysWhy: "Press it anywhere: what you pick is pasted where you were typing", keysChange: "Change", @@ -416,9 +416,9 @@ const EN: Record = { panelUndrawn: "it could not be drawn", panelUnwatched: "nothing is watching the clipboard", panelUnemptied: "the history could not be emptied", - panelClipboardDenied: "the system does not let CopyPaste read the clipboard", + panelClipboardDenied: "the system does not let CoPanda read the clipboard", panelStopped: "it stopped watching the clipboard", - panelUnsteady: "it will not stay up; restart CopyPaste", + panelUnsteady: "it will not stay up; restart CoPanda", panelUnanswering: "it is not answering", panelUnknown: "something went wrong", keysTaken: @@ -518,7 +518,7 @@ const EN: Record = { betaWarns: "They arrive before anyone else's and they can break. You can leave whenever you like.", supportTitle: "Support", - supportWhy: "CopyPaste is free and will stay free. If it helps you, this helps it keep growing.", + supportWhy: "CoPanda is free and will stay free. If it helps you, this helps it keep growing.", supportStar: "Give it a star", supportRate: "Rate it on the Store", supportSponsor: "Sponsor the project", @@ -529,7 +529,7 @@ const EN: Record = { toolLinkUnboundHere: "Installed · your links open through it", troubleTitle: "If something goes wrong", troubleWhat: - "The report puts CopyPaste's log, its version and which Windows or macOS you use into one file, with your user name and home folder blanked out.", + "The report puts CoPanda's log, its version and which Windows or macOS you use into one file, with your user name and home folder blanked out.", troubleNeverSent: "It is never sent anywhere", troubleYours: ". It is saved where you choose, and you attach it only if you want to.", troubleReport: "Save a report…", @@ -550,8 +550,8 @@ const EN: Record = { updateNone: "You are on the latest version", updateWhen: "Looked up once a day, and whenever you ask", updateThere: "Version {one} is out", - updateTake: "It downloads, installs and CopyPaste restarts on its own", - updateMove: "To install it, drag CopyPaste to Applications and open it from there", + updateTake: "It downloads, installs and CoPanda restarts on its own", + updateMove: "To install it, drag CoPanda to Applications and open it from there", updateDo: "Update", updateGetting: "Downloading…", updateStore: "The Microsoft Store takes care of it", @@ -565,17 +565,17 @@ const EN: Record = { updateBusy: "An update is already on its way.", aboutPrivacyLink: "Privacy", keysFormer: "In CopyPaste 2 it was Ctrl + Alt + C", - wakeTheirsMac: "Allow CopyPaste in System Settings › General › Login Items", + wakeTheirsMac: "Allow CoPanda in System Settings › General › Login Items", trust: "Permission to paste", - trustWhy: "macOS asks for your permission before CopyPaste types into the window you were in", + trustWhy: "macOS asks for your permission before CoPanda types into the window you were in", trustGranted: "Granted: what you pick is pasted for you", trustMissing: "Without it, what you pick stays on the clipboard for you to paste", trustAsk: "Grant", trustOpen: "Open System Settings", clipboardDenied: - "macOS does not let CopyPaste read the clipboard: allow it in System Settings › Privacy & Security › Paste from Other Apps", + "macOS does not let CoPanda read the clipboard: allow it in System Settings › Privacy & Security › Paste from Other Apps", clipboardAsks: - "macOS may ask whether CopyPaste can read the clipboard: answer “Allow” so it can keep your copies", + "macOS may ask whether CoPanda can read the clipboard: answer “Allow” so it can keep your copies", trustSecure: "A password field is open: for as long as it is, nobody can paste for you", outDone: "Saved: {one}", outMissing: "{one} travelled without their contents", @@ -592,7 +592,7 @@ const EN: Record = { welcomeHello: "Your clipboard, with a memory", welcomeHelloWhy: - "CopyPaste keeps what you copy (text, images, links and files) so it is within reach when you need it. Here are the basics in a minute.", + "CoPanda keeps what you copy (text, images, links and files) so it is within reach when you need it. Here are the basics in a minute.", welcomeLocal: "Stays on your computer", welcomeNoAccount: "No account", welcomeNoTracking: "No tracking", @@ -620,10 +620,10 @@ const EN: Record = { welcomeWhereOver: "2 · Where to find it", welcomeWhereTitle: "Next to the clock", welcomeWhereWhy: - "CopyPaste lives in the system tray, bottom right. If you do not see it, check the hidden icons arrow; drag it onto the taskbar to keep it in sight.", + "CoPanda lives in the system tray, bottom right. If you do not see it, check the hidden icons arrow; drag it onto the taskbar to keep it in sight.", welcomeWhereTitleMac: "In the menu bar", welcomeWhereWhyMac: - "CopyPaste lives in the menu bar, top right. With many icons, it may hide behind the notch.", + "CoPanda lives in the menu bar, top right. With many icons, it may hide behind the notch.", welcomeClick: "Click", welcomeClickDoes: "opens the panel", welcomeRightClick: "Right-click", @@ -656,18 +656,19 @@ const EN: Record = { welcomeTrustOver: "Before you start", welcomeTrustTitle: "One permission, so it can paste", welcomeTrustWhy: - "To paste into the app you were using, macOS needs you to allow CopyPaste. It does not read what you type: it only sends ⌘V when you pick something.", + "To paste into the app you were using, macOS needs you to allow CoPanda. It does not read what you type: it only sends ⌘V when you pick something.", welcomeTrustStepOne: "1 · We open System Settings › Privacy & Security › Accessibility", - welcomeTrustStepTwo: "2 · Turn on CopyPaste in the list", + welcomeTrustStepTwo: "2 · Turn on CoPanda in the list", welcomeTrustStepThree: "3 · Come back here: we carry on by ourselves", welcomeTrustWaiting: "Waiting for the permission…", welcomeTrustWaitingWhy: - "Turn on CopyPaste in Accessibility. If it was already on and does not respond, remove it with − and add it again.", + "Turn on CoPanda in Accessibility. If it was already on and does not respond, remove it with − and add it again.", welcomeTrustDone: "All set, it can paste now", welcomeTrustAsk: "Allow", welcomeTrustLater: "Not now", welcomeNewsOver: "What is new", - welcomeNewsTitle: "CopyPaste has been updated", + welcomeNewsTitle: "CoPanda has been updated", + welcomeNewsLine: "An extra thumb for your clipboard", welcomeNewsAll: "See all versions", welcomeNewsOk: "Got it", welcomeShowAgain: "Show the welcome again", diff --git a/app/src/news.json b/app/src/news.json index 928b5d74..6fc1ace2 100644 --- a/app/src/news.json +++ b/app/src/news.json @@ -154,5 +154,32 @@ "said": "on a Mac, Tab reaches every button and list in Settings." } ] + }, + { + "version": "3.2.0", + "headline": { + "es": "CopyPaste ahora es CoPanda", + "en": "CopyPaste is now CoPanda" + }, + "es": [ + { + "title": "CopyPaste ahora se llama CoPanda", + "said": "es la misma app, ahora con un nombre propio que es más fácil de encontrar." + }, + { + "title": "Todo sigue en tu equipo", + "said": "sin cuenta, sin anuncios y sin rastreo, como siempre." + } + ], + "en": [ + { + "title": "CopyPaste is now CoPanda", + "said": "the same app, now under a name of its own that is easier to find." + }, + { + "title": "Everything stays on your computer", + "said": "no account, no ads and no tracking, as always." + } + ] } ] diff --git a/app/src/panda.svg b/app/src/panda.svg new file mode 100644 index 00000000..66005f94 --- /dev/null +++ b/app/src/panda.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/app/src/tests/tour.test.tsx b/app/src/tests/tour.test.tsx index 9efa457f..7b05a17f 100644 --- a/app/src/tests/tour.test.tsx +++ b/app/src/tests/tour.test.tsx @@ -50,7 +50,7 @@ describe("the welcome of a fresh install", () => { expect(await screen.findByText("Lo esencial")).toBeInTheDocument(); await press("Siguiente"); - expect(await screen.findByText("Hay novedades en CopyPaste")).toBeInTheDocument(); + expect(await screen.findByText("CopyPaste ahora es CoPanda")).toBeInTheDocument(); await press("Entendido"); expect(theWindow.close).toHaveBeenCalled(); }); @@ -66,7 +66,7 @@ describe("the welcome of a fresh install", () => { await press("Siguiente"); expect(await screen.findByText("Lo esencial")).toBeInTheDocument(); - expect(screen.queryByText("Hay novedades en CopyPaste")).toBeNull(); + expect(screen.queryByText("CopyPaste ahora es CoPanda")).toBeNull(); await press("Listo"); expect(theWindow.close).toHaveBeenCalled(); }); @@ -146,7 +146,7 @@ describe("the welcome on a Mac", () => { expect(await screen.findByText("Esperando el permiso…")).toBeInTheDocument(); expect( screen.getByText( - "Activa CopyPaste en Accesibilidad. Si ya aparecía activado y no responde, quítalo con − y agrégalo de nuevo.", + "Activa CoPanda en Accesibilidad. Si ya aparecía activado y no responde, quítalo con − y agrégalo de nuevo.", ), ).toBeInTheDocument(); @@ -234,7 +234,7 @@ describe("what changes while the window is open", () => { asked.greeting = { kind: "news", versions: ["3.0.0"] }; render(); - expect(await screen.findByText("Hay novedades en CopyPaste")).toBeInTheDocument(); + expect(await screen.findByText("Hay novedades en CoPanda")).toBeInTheDocument(); const greeting = await heardOn("greeting"); act(() => greeting({ payload: { kind: "tour", former: false } })); expect(await screen.findByText("Tu portapapeles, con memoria")).toBeInTheDocument(); @@ -272,7 +272,7 @@ describe("the news after an update", () => { asked.locale = "en"; render(); - expect(await screen.findByText("CopyPaste has been updated")).toBeInTheDocument(); + expect(await screen.findByText("CoPanda has been updated")).toBeInTheDocument(); expect(screen.getByText("Copy without pasting, and names")).toBeInTheDocument(); await press("Got it"); expect(theWindow.close).toHaveBeenCalled(); @@ -284,11 +284,22 @@ describe("news from more than one version", () => { vi.clearAllMocks(); }); + it("names the new brand when 3.2.0 is the newest, under the panda and its line", async () => { + asked.greeting = { kind: "news", versions: ["3.2.0", "3.1.0"] }; + render(); + + expect( + await screen.findByRole("heading", { level: 1, name: "CopyPaste ahora es CoPanda" }), + ).toBeInTheDocument(); + expect(screen.getByText("Un pulgar extra para tu portapapeles")).toBeInTheDocument(); + expect(screen.queryByText("Hay novedades en CoPanda")).toBeNull(); + }); + it("puts the newest first, names the older one, and still closes with its button", async () => { asked.greeting = { kind: "news", versions: ["3.1.0", "3.0.3"] }; render(); - expect(await screen.findByText("Hay novedades en CopyPaste")).toBeInTheDocument(); + expect(await screen.findByText("Hay novedades en CoPanda")).toBeInTheDocument(); const [newest, older] = screen.getAllByRole("region"); expect(newest).toHaveAccessibleName("3.1.0"); expect(within(newest).getByText("Hazlo tuyo")).toBeInTheDocument(); diff --git a/app/src/ui/About.tsx b/app/src/ui/About.tsx index 17298146..218988a5 100644 --- a/app/src/ui/About.tsx +++ b/app/src/ui/About.tsx @@ -162,7 +162,7 @@ export default function About() { C -

CopyPaste

+

CoPanda

{version ?? "—"} diff --git a/app/src/ui/Backup.tsx b/app/src/ui/Backup.tsx index 258ec7f0..a625e5a5 100644 --- a/app/src/ui/Backup.tsx +++ b/app/src/ui/Backup.tsx @@ -54,7 +54,7 @@ function onDay(at: number | null) { function named() { const day = new Date().toISOString().slice(0, 10); - return `CopyPaste-${day}.${EXTENSION}`; + return `CoPanda-${day}.${EXTENSION}`; } export default function Backup() { @@ -96,7 +96,7 @@ export default function Backup() { setBusy("out"); const where = await save({ defaultPath: named(), - filters: [{ name: "CopyPaste", extensions: [EXTENSION] }], + filters: [{ name: "CoPanda", extensions: [EXTENSION] }], }).catch(() => null); if (!where) { setBusy(null); @@ -118,7 +118,7 @@ export default function Backup() { setBusy("in"); const chosen = await open({ multiple: false, - filters: [{ name: "CopyPaste", extensions: [EXTENSION] }], + filters: [{ name: "CoPanda", extensions: [EXTENSION] }], }).catch(() => null); if (typeof chosen !== "string") { setBusy(null); diff --git a/app/src/ui/Chrome.tsx b/app/src/ui/Chrome.tsx index 1e052167..103fe1ca 100644 --- a/app/src/ui/Chrome.tsx +++ b/app/src/ui/Chrome.tsx @@ -13,7 +13,7 @@ export default function Chrome({ knobs = true }: { knobs?: boolean }) { return (
- CopyPaste + CoPanda {drawn && (
diff --git a/app/src/ui/Welcome.tsx b/app/src/ui/Welcome.tsx index eb1b7319..cd772c69 100644 --- a/app/src/ui/Welcome.tsx +++ b/app/src/ui/Welcome.tsx @@ -6,6 +6,7 @@ import { type ReactNode, useCallback, useEffect, useMemo, useState } from "react import { asKeys, caps, type Kept, onMac, type Trust, useKept, useKeys } from "../core"; import { fill, inEnglish, items, oneKey, panelKey, t } from "../locales"; import news from "../news.json"; +import panda from "../panda.svg"; import Chrome from "./Chrome"; const RELEASES = "https://github.com/rgdevment/CopyPaste/releases"; @@ -68,6 +69,14 @@ export function toldFor( }); } +export function headline(version: string | undefined, english: boolean): string { + const named = news.find((one) => one.version === version)?.headline; + if (named) { + return english ? named.en : named.es; + } + return t("welcomeNewsTitle"); +} + function leave() { void getCurrentWindow().close(); } @@ -177,7 +186,7 @@ function Tour({ right={} >
-
C
+

{t("welcomeHello")}

{t("welcomeHelloWhy")}

@@ -525,11 +534,15 @@ function News({ versions }: { versions: string[] }) { return (
-
- {t("welcomeNewsOver")} - {versions[0] && {versions[0]}} +
+ +
+ {t("welcomeNewsOver")} + {versions[0] && {versions[0]}} +
+

{headline(versions[0], inEnglish())}

+

{t("welcomeNewsLine")}

-

{t("welcomeNewsTitle")}

{told.map((one, at) => (
diff --git a/crates/cp-core/src/capture.rs b/crates/cp-core/src/capture.rs index fb2b2689..96277a55 100644 --- a/crates/cp-core/src/capture.rs +++ b/crates/cp-core/src/capture.rs @@ -22,8 +22,8 @@ pub enum Unreadable { impl Unreadable { pub fn said(self) -> &'static str { match self { - Unreadable::Asks => "the system asks before CopyPaste may read the clipboard", - Unreadable::Denied => "the system does not let CopyPaste read the clipboard", + Unreadable::Asks => "the system asks before CoPanda may read the clipboard", + Unreadable::Denied => "the system does not let CoPanda read the clipboard", } } } diff --git a/crates/cp-core/src/trouble.rs b/crates/cp-core/src/trouble.rs index 3c0b4c54..5cb1b2f2 100644 --- a/crates/cp-core/src/trouble.rs +++ b/crates/cp-core/src/trouble.rs @@ -73,16 +73,16 @@ impl Trouble { "the history could not be emptied", ], Trouble::ClipboardDenied => [ - "el sistema no deja que CopyPaste lea el portapapeles", - "the system does not let CopyPaste read the clipboard", + "el sistema no deja que CoPanda lea el portapapeles", + "the system does not let CoPanda read the clipboard", ], Trouble::Stopped => [ "el panel dejó de vigilar el portapapeles", "the panel stopped watching the clipboard", ], Trouble::Unsteady => [ - "el panel no se mantiene abierto; reinicia CopyPaste", - "the panel will not stay up; restart CopyPaste", + "el panel no se mantiene abierto; reinicia CoPanda", + "the panel will not stay up; restart CoPanda", ], Trouble::Unanswering => ["el panel no responde", "the panel is not answering"], }; diff --git a/crates/cp-core/src/trouble_test.rs b/crates/cp-core/src/trouble_test.rs index a123e35a..63331d38 100644 --- a/crates/cp-core/src/trouble_test.rs +++ b/crates/cp-core/src/trouble_test.rs @@ -74,7 +74,7 @@ fn the_english_words_are_the_ones_the_log_already_used() { ); assert_eq!( Trouble::Unsteady.worded(true), - "el panel no se mantiene abierto; reinicia CopyPaste" + "el panel no se mantiene abierto; reinicia CoPanda" ); } diff --git a/crates/cp-mac-sys/src/files.rs b/crates/cp-mac-sys/src/files.rs index c7dce53c..41491f7b 100644 --- a/crates/cp-mac-sys/src/files.rs +++ b/crates/cp-mac-sys/src/files.rs @@ -1,6 +1,6 @@ use objc2::rc::Retained; use objc2_app_kit::NSWorkspace; -use objc2_foundation::{NSArray, NSString, NSURL}; +use objc2_foundation::{NSArray, NSFileManager, NSString, NSURL}; use std::path::Path; pub fn path_of(file_url: &str) -> String { @@ -33,6 +33,21 @@ fn url_of(path: &Path) -> Retained { NSURL::fileURLWithPath(&NSString::from_str(&path.display().to_string())) } +pub fn trash(path: &Path) -> Result<(), String> { + NSFileManager::defaultManager() + .trashItemAtURL_resultingItemURL_error(&url_of(path), None) + .map_err(|why| why.localizedDescription().to_string()) +} + +pub fn running_from(bundle: &Path) -> bool { + let wanted = bundle.display().to_string(); + NSWorkspace::sharedWorkspace() + .runningApplications() + .iter() + .filter_map(|app| app.bundleURL()?.path()) + .any(|at| at.to_string().trim_end_matches('/') == wanted.trim_end_matches('/')) +} + const RUNS_WHEN_OPENED: [&str; 8] = [ "app", "command", "terminal", "pkg", "scpt", "sh", "tool", "workflow", ]; diff --git a/crates/cp-panel/src/app.rs b/crates/cp-panel/src/app.rs index 057b3b1d..947938aa 100644 --- a/crates/cp-panel/src/app.rs +++ b/crates/cp-panel/src/app.rs @@ -1100,8 +1100,8 @@ fn arm_sheet(state: &Rc>, ui: &Panel) { fn busy() -> &'static str { if crate::here::read_stuck() { return crate::say::pick( - "una app dejó de responder con lo copiado; reinicia CopyPaste", - "an app stopped answering about what it copied; restart CopyPaste", + "una app dejó de responder con lo copiado; reinicia CoPanda", + "an app stopped answering about what it copied; restart CoPanda", ); } crate::say::pick( diff --git a/crates/cp-panel/src/newer.rs b/crates/cp-panel/src/newer.rs index 5f85224d..53f3cb6b 100644 --- a/crates/cp-panel/src/newer.rs +++ b/crates/cp-panel/src/newer.rs @@ -25,9 +25,9 @@ pub fn put_away_in(dir: &Path, version: &str) -> std::io::Result<()> { pub fn line_of(version: &str, english: bool) -> String { if english { - format!("CopyPaste {version} is ready") + format!("CoPanda {version} is ready") } else { - format!("CopyPaste {version} está lista") + format!("CoPanda {version} está lista") } } diff --git a/crates/cp-panel/src/newer_test.rs b/crates/cp-panel/src/newer_test.rs index 83cb8967..ae94c80f 100644 --- a/crates/cp-panel/src/newer_test.rs +++ b/crates/cp-panel/src/newer_test.rs @@ -65,6 +65,6 @@ fn the_files_on_disk_are_read_and_putting_away_is_remembered() { #[test] fn the_line_names_the_version_in_either_language() { - assert_eq!(line_of("3.0.4", false), "CopyPaste 3.0.4 está lista"); - assert_eq!(line_of("3.0.4", true), "CopyPaste 3.0.4 is ready"); + assert_eq!(line_of("3.0.4", false), "CoPanda 3.0.4 está lista"); + assert_eq!(line_of("3.0.4", true), "CoPanda 3.0.4 is ready"); } diff --git a/crates/cp-panel/ui/panel.slint b/crates/cp-panel/ui/panel.slint index ac1581ad..32c41005 100644 --- a/crates/cp-panel/ui/panel.slint +++ b/crates/cp-panel/ui/panel.slint @@ -15,7 +15,7 @@ export component Panel inherits Window { always-on-top: true; background: Theme.apple ? Theme.panel : transparent; default-font-family: Theme.font; - title: "CopyPaste"; + title: "CoPanda"; icon: @image-url("../../../app/src-tauri/icons/128x128.png"); in property <[Card]> cards; diff --git a/crates/cp-store/src/lib.rs b/crates/cp-store/src/lib.rs index 57f86bfa..4f21ada2 100644 --- a/crates/cp-store/src/lib.rs +++ b/crates/cp-store/src/lib.rs @@ -33,7 +33,7 @@ pub enum Error { TooBig { size: usize }, #[error("there is no item {id}")] NoSuchItem { id: i64 }, - #[error("the file is not a CopyPaste backup")] + #[error("the file is not a CoPanda backup")] NotABackup, #[error("a copy cannot be written over the history it is copying")] OntoItself, diff --git a/packaging/winget/rgdevment.CopyPaste.installer.yaml b/packaging/winget/rgdevment.CoPanda.installer.yaml similarity index 72% rename from packaging/winget/rgdevment.CopyPaste.installer.yaml rename to packaging/winget/rgdevment.CoPanda.installer.yaml index 75594123..43b70287 100644 --- a/packaging/winget/rgdevment.CopyPaste.installer.yaml +++ b/packaging/winget/rgdevment.CoPanda.installer.yaml @@ -1,7 +1,7 @@ # yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.12.0.schema.json -PackageIdentifier: rgdevment.CopyPaste -PackageVersion: 3.1.3 +PackageIdentifier: rgdevment.CoPanda +PackageVersion: 3.2.0 Platform: - Windows.Desktop MinimumOSVersion: 10.0.17763.0 @@ -18,7 +18,7 @@ InstallationMetadata: DefaultInstallLocation: '%LOCALAPPDATA%\Programs\CopyPaste' Installers: - Architecture: x64 - InstallerUrl: https://github.com/rgdevment/CopyPaste/releases/download/v3.1.3/copypaste-installer-3.1.3-windows-x86_64.exe - InstallerSha256: E80BBC1A0AE3E90B533D3F7AD924EB002DFF36CBA31568E2EFD882E7B7795B80 + InstallerUrl: https://github.com/rgdevment/CopyPaste/releases/download/v3.2.0/copanda-installer-3.2.0-windows-x86_64.exe + InstallerSha256: 0000000000000000000000000000000000000000000000000000000000000000 ManifestType: installer ManifestVersion: 1.12.0 diff --git a/packaging/winget/rgdevment.CopyPaste.locale.en-US.yaml b/packaging/winget/rgdevment.CoPanda.locale.en-US.yaml similarity index 84% rename from packaging/winget/rgdevment.CopyPaste.locale.en-US.yaml rename to packaging/winget/rgdevment.CoPanda.locale.en-US.yaml index 70659746..01efb164 100644 --- a/packaging/winget/rgdevment.CopyPaste.locale.en-US.yaml +++ b/packaging/winget/rgdevment.CoPanda.locale.en-US.yaml @@ -1,27 +1,29 @@ # yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.12.0.schema.json -PackageIdentifier: rgdevment.CopyPaste -PackageVersion: 3.1.3 +PackageIdentifier: rgdevment.CoPanda +PackageVersion: 3.2.0 PackageLocale: en-US Publisher: rgdevment PublisherUrl: https://github.com/rgdevment PublisherSupportUrl: https://github.com/rgdevment/CopyPaste/issues PrivacyUrl: https://github.com/rgdevment/CopyPaste/blob/main/PRIVACY.md Author: Mario Hidalgo G. -PackageName: CopyPaste -PackageUrl: https://rgdevment.com/copypaste/ +PackageName: CoPanda +PackageUrl: https://www.copanda.app/ License: GPL-3.0-only LicenseUrl: https://github.com/rgdevment/CopyPaste/blob/main/LICENSE Copyright: Copyright (c) 2026 rgdevment CopyrightUrl: https://github.com/rgdevment/CopyPaste/blob/main/LICENSE ShortDescription: Clipboard history that stays on your machine. No ads, no telemetry, no account. Description: |- - CopyPaste keeps what you copy within reach of a shortcut: text, images, files, links and + CoPanda keeps what you copy within reach of a shortcut: text, images, files, links and colours, searchable in milliseconds and stored only on your own machine. No account, no subscription, no telemetry and no server. -Moniker: copypaste +Moniker: copanda Tags: - clipboard + - copanda + - copypaste - clipboard-history - clipboard-manager - local-first @@ -29,7 +31,7 @@ Tags: - paste - privacy - productivity -ReleaseNotesUrl: https://github.com/rgdevment/CopyPaste/releases/tag/v3.1.3 +ReleaseNotesUrl: https://github.com/rgdevment/CopyPaste/releases/tag/v3.2.0 Documentations: - DocumentLabel: Privacy DocumentUrl: https://github.com/rgdevment/CopyPaste/blob/main/PRIVACY.md diff --git a/packaging/winget/rgdevment.CopyPaste.locale.es.yaml b/packaging/winget/rgdevment.CoPanda.locale.es.yaml similarity index 82% rename from packaging/winget/rgdevment.CopyPaste.locale.es.yaml rename to packaging/winget/rgdevment.CoPanda.locale.es.yaml index d5a3ad80..4d6daa5f 100644 --- a/packaging/winget/rgdevment.CopyPaste.locale.es.yaml +++ b/packaging/winget/rgdevment.CoPanda.locale.es.yaml @@ -1,26 +1,28 @@ # yaml-language-server: $schema=https://aka.ms/winget-manifest.locale.1.12.0.schema.json -PackageIdentifier: rgdevment.CopyPaste -PackageVersion: 3.1.3 +PackageIdentifier: rgdevment.CoPanda +PackageVersion: 3.2.0 PackageLocale: es Publisher: rgdevment PublisherUrl: https://github.com/rgdevment PublisherSupportUrl: https://github.com/rgdevment/CopyPaste/issues PrivacyUrl: https://github.com/rgdevment/CopyPaste/blob/main/PRIVACY.md Author: Mario Hidalgo G. -PackageName: CopyPaste -PackageUrl: https://rgdevment.com/copypaste/ +PackageName: CoPanda +PackageUrl: https://www.copanda.app/ License: GPL-3.0-only LicenseUrl: https://github.com/rgdevment/CopyPaste/blob/main/LICENSE Copyright: Copyright (c) 2026 rgdevment CopyrightUrl: https://github.com/rgdevment/CopyPaste/blob/main/LICENSE ShortDescription: Historial del portapapeles que se queda en tu equipo. Sin anuncios, sin telemetría, sin cuenta. Description: |- - CopyPaste deja a un atajo de distancia lo que copias: texto, imágenes, archivos, + CoPanda deja a un atajo de distancia lo que copias: texto, imágenes, archivos, enlaces y colores, con búsqueda en milisegundos y guardado solo en tu propio equipo. Sin cuenta, sin suscripción, sin telemetría y sin servidor. Tags: - codigo-abierto + - copanda + - copypaste - gestor-de-portapapeles - historial-del-portapapeles - local @@ -28,6 +30,6 @@ Tags: - portapapeles - privacidad - productividad -ReleaseNotesUrl: https://github.com/rgdevment/CopyPaste/releases/tag/v3.1.3 +ReleaseNotesUrl: https://github.com/rgdevment/CopyPaste/releases/tag/v3.2.0 ManifestType: locale ManifestVersion: 1.12.0 diff --git a/packaging/winget/rgdevment.CopyPaste.yaml b/packaging/winget/rgdevment.CoPanda.yaml similarity index 72% rename from packaging/winget/rgdevment.CopyPaste.yaml rename to packaging/winget/rgdevment.CoPanda.yaml index 36de491e..7b5ff26f 100644 --- a/packaging/winget/rgdevment.CopyPaste.yaml +++ b/packaging/winget/rgdevment.CoPanda.yaml @@ -1,7 +1,7 @@ # yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.12.0.schema.json -PackageIdentifier: rgdevment.CopyPaste -PackageVersion: 3.1.3 +PackageIdentifier: rgdevment.CoPanda +PackageVersion: 3.2.0 DefaultLocale: en-US ManifestType: version ManifestVersion: 1.12.0 diff --git a/resources/3.0/en-1-hero.png b/resources/3.0/en-1-hero.png deleted file mode 100644 index 3d2d71fd..00000000 Binary files a/resources/3.0/en-1-hero.png and /dev/null differ diff --git a/resources/3.0/en-2-filters.png b/resources/3.0/en-2-filters.png deleted file mode 100644 index 8b1d85aa..00000000 Binary files a/resources/3.0/en-2-filters.png and /dev/null differ diff --git a/resources/3.0/en-3-paste-as.png b/resources/3.0/en-3-paste-as.png deleted file mode 100644 index 3eb2ca7b..00000000 Binary files a/resources/3.0/en-3-paste-as.png and /dev/null differ diff --git a/resources/3.0/en-4-privacy.png b/resources/3.0/en-4-privacy.png deleted file mode 100644 index 492d78ec..00000000 Binary files a/resources/3.0/en-4-privacy.png and /dev/null differ diff --git a/resources/3.0/en-5-settings.png b/resources/3.0/en-5-settings.png deleted file mode 100644 index a120c8f5..00000000 Binary files a/resources/3.0/en-5-settings.png and /dev/null differ diff --git a/resources/3.0/en-6-free.png b/resources/3.0/en-6-free.png deleted file mode 100644 index 13abb61e..00000000 Binary files a/resources/3.0/en-6-free.png and /dev/null differ diff --git a/resources/3.0/es-1-hero.png b/resources/3.0/es-1-hero.png deleted file mode 100644 index 720587b3..00000000 Binary files a/resources/3.0/es-1-hero.png and /dev/null differ diff --git a/resources/3.0/es-2-filters.png b/resources/3.0/es-2-filters.png deleted file mode 100644 index 2e887570..00000000 Binary files a/resources/3.0/es-2-filters.png and /dev/null differ diff --git a/resources/3.0/es-3-paste-as.png b/resources/3.0/es-3-paste-as.png deleted file mode 100644 index e597586f..00000000 Binary files a/resources/3.0/es-3-paste-as.png and /dev/null differ diff --git a/resources/3.0/es-4-privacy.png b/resources/3.0/es-4-privacy.png deleted file mode 100644 index 0efd23f8..00000000 Binary files a/resources/3.0/es-4-privacy.png and /dev/null differ diff --git a/resources/3.0/es-5-settings.png b/resources/3.0/es-5-settings.png deleted file mode 100644 index 282c997c..00000000 Binary files a/resources/3.0/es-5-settings.png and /dev/null differ diff --git a/resources/3.0/es-6-free.png b/resources/3.0/es-6-free.png deleted file mode 100644 index 153de90f..00000000 Binary files a/resources/3.0/es-6-free.png and /dev/null differ diff --git a/resources/CoPanda/copanda-guardian.svg b/resources/CoPanda/copanda-guardian.svg new file mode 100644 index 00000000..b2855a9e --- /dev/null +++ b/resources/CoPanda/copanda-guardian.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/CoPanda/copanda-head.svg b/resources/CoPanda/copanda-head.svg new file mode 100644 index 00000000..66005f94 --- /dev/null +++ b/resources/CoPanda/copanda-head.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/resources/CoPanda/copanda-mono.svg b/resources/CoPanda/copanda-mono.svg new file mode 100644 index 00000000..ed3f9645 --- /dev/null +++ b/resources/CoPanda/copanda-mono.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/resources/CoPanda/copanda-shield.svg b/resources/CoPanda/copanda-shield.svg new file mode 100644 index 00000000..2735a5e1 --- /dev/null +++ b/resources/CoPanda/copanda-shield.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/scripts/third-party.mjs b/scripts/third-party.mjs index 53b0d167..96816a35 100644 --- a/scripts/third-party.mjs +++ b/scripts/third-party.mjs @@ -314,12 +314,12 @@ const written = [...byText.values()] writeFileSync( out, - asWritten(`# Third-party notices — what ships inside CopyPaste + asWritten(`# Third-party notices — what ships inside CoPanda -CopyPaste is GPL-3.0-only. The binaries carry the work below, each under its own -licence. Nothing of it was copied into CopyPaste's own source; what was copied in +CoPanda is GPL-3.0-only. The binaries carry the work below, each under its own +licence. Nothing of it was copied into CoPanda's own source; what was copied in is in [THIRD-PARTY.md](${REPO}/THIRD-PARTY.md). @@ -357,7 +357,7 @@ ${kept} writeFileSync( texts, - asWritten(`# Licence texts — what the crates inside CopyPaste carry + asWritten(`# Licence texts — what the crates inside CoPanda carry