clippa 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +105 -0
- package/bin/install-clippa.js +201 -0
- package/docs/assets/app-icon.png +0 -0
- package/docs/assets/screenshot-panel.svg +39 -0
- package/outputs/Clippa.app.zip +0 -0
- package/package.json +36 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ivan Dovhosheia
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/app-icon.png" width="96" height="96" alt="Clippa icon">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Clippa</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
A small, private macOS clipboard app built around one shortcut: press Command-Shift-W, choose a clip, paste.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://vaniawl.github.io/Clippa/">Website</a>
|
|
13
|
+
·
|
|
14
|
+
<a href="https://github.com/Vaniawl/Clippa/releases">Releases</a>
|
|
15
|
+
·
|
|
16
|
+
<a href="#privacy">Privacy</a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<p align="center">
|
|
20
|
+
<img src="docs/assets/screenshot-panel.svg" alt="Clippa clipboard panel" width="900">
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
## Install Clippa
|
|
24
|
+
|
|
25
|
+
Install the current GitHub build:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npx github:Vaniawl/Clippa
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
After npm publish, the public install command will be:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx clippa
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
After it opens, grant Accessibility access when macOS asks. Clippa needs that permission only to paste the selected item into the app where your cursor is already active.
|
|
38
|
+
|
|
39
|
+
Useful installer options:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npx github:Vaniawl/Clippa -- --no-open
|
|
43
|
+
npx github:Vaniawl/Clippa -- --install-dir ~/Applications
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
You can also download `Clippa.app.zip` from the latest GitHub release, unzip it, move `Clippa.app` to `/Applications`, and open it.
|
|
47
|
+
|
|
48
|
+
## How It Works
|
|
49
|
+
|
|
50
|
+
- Runs quietly in the background as a menu-bar app.
|
|
51
|
+
- Press `Command-Shift-W` while your cursor is in a text field.
|
|
52
|
+
- Use `Up` / `Down` to choose a clipboard item.
|
|
53
|
+
- Press `Enter` or click an item to paste it.
|
|
54
|
+
- Press `Esc` or click outside the panel to close it.
|
|
55
|
+
- Stores recent text, links, images, and file references locally on your Mac.
|
|
56
|
+
|
|
57
|
+
## Privacy
|
|
58
|
+
|
|
59
|
+
Clippa does not upload clipboard contents, does not use analytics, and does not require an account. Clipboard history is stored only on your Mac and encrypted locally with a per-user AES-GCM key file in Application Support. Clippa does not read or write Keychain items at startup, so locally signed reinstall builds do not trigger Keychain password prompts.
|
|
60
|
+
|
|
61
|
+
Accessibility permission is only used to confirm there is an editable field under the cursor and to paste the selected clip into that frontmost app.
|
|
62
|
+
|
|
63
|
+
## Requirements
|
|
64
|
+
|
|
65
|
+
- macOS 26.0 or newer
|
|
66
|
+
- Xcode 26.6 or newer, only if you want to build from source
|
|
67
|
+
|
|
68
|
+
## Build From Source
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
git clone https://github.com/Vaniawl/Clippa.git
|
|
72
|
+
cd Clippa
|
|
73
|
+
xcodebuild -project Clippa.xcodeproj -scheme Clippa -destination 'platform=macOS' test
|
|
74
|
+
SMOKE_LAUNCH=1 ./scripts/release.sh
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The packaged app is written to:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
outputs/Clippa.app.zip
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## npm Publish
|
|
84
|
+
|
|
85
|
+
The npm installer package is prepared as `clippa`. Publishing to npm requires an authenticated npm session:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npm adduser
|
|
89
|
+
npm publish --access public
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Update From Git
|
|
93
|
+
|
|
94
|
+
For an existing checkout:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
git pull origin main
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Production Notes
|
|
101
|
+
|
|
102
|
+
- Bundle identifier: `com.ivandovhosheia.Clippa`
|
|
103
|
+
- Version: `1.0.0`
|
|
104
|
+
- Release builds use hardened runtime.
|
|
105
|
+
- Recent history is limited to 100 active items and stored only on this Mac.
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execFileSync } = require("node:child_process");
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const os = require("node:os");
|
|
6
|
+
const path = require("node:path");
|
|
7
|
+
const https = require("node:https");
|
|
8
|
+
|
|
9
|
+
const appName = "Clippa";
|
|
10
|
+
const bundleIdentifier = "com.ivandovhosheia.Clippa";
|
|
11
|
+
const localZipPath = path.resolve(__dirname, "../outputs/Clippa.app.zip");
|
|
12
|
+
const packageJson = require("../package.json");
|
|
13
|
+
const defaultZipUrl = "https://github.com/Vaniawl/Clippa/releases/download/v1.0.0/Clippa.app.zip";
|
|
14
|
+
const zipUrl = process.env.CLIPPA_ZIP_URL || defaultZipUrl;
|
|
15
|
+
|
|
16
|
+
function usage() {
|
|
17
|
+
console.log(`Install Clippa for macOS.
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
npx github:Vaniawl/Clippa
|
|
21
|
+
npx clippa
|
|
22
|
+
|
|
23
|
+
Options:
|
|
24
|
+
--install-dir <path> Copy Clippa.app into a custom applications folder.
|
|
25
|
+
--no-open Install without opening Clippa afterwards.
|
|
26
|
+
--version Show installer version.
|
|
27
|
+
--help Show this help.
|
|
28
|
+
|
|
29
|
+
The installer copies Clippa.app to /Applications when possible, otherwise to ~/Applications.
|
|
30
|
+
Press Command-Shift-W in a text field to open Clippa.
|
|
31
|
+
`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function run(command, args, options = {}) {
|
|
35
|
+
execFileSync(command, args, { stdio: "inherit", ...options });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function parseArgs(argv) {
|
|
39
|
+
const options = {
|
|
40
|
+
help: false,
|
|
41
|
+
version: false,
|
|
42
|
+
noOpen: false,
|
|
43
|
+
installDir: null
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
47
|
+
const arg = argv[index];
|
|
48
|
+
switch (arg) {
|
|
49
|
+
case "--help":
|
|
50
|
+
case "-h":
|
|
51
|
+
options.help = true;
|
|
52
|
+
break;
|
|
53
|
+
case "--version":
|
|
54
|
+
case "-v":
|
|
55
|
+
options.version = true;
|
|
56
|
+
break;
|
|
57
|
+
case "--no-open":
|
|
58
|
+
options.noOpen = true;
|
|
59
|
+
break;
|
|
60
|
+
case "--install-dir":
|
|
61
|
+
index += 1;
|
|
62
|
+
if (!argv[index]) {
|
|
63
|
+
throw new Error("--install-dir requires a path.");
|
|
64
|
+
}
|
|
65
|
+
options.installDir = expandHome(argv[index]);
|
|
66
|
+
break;
|
|
67
|
+
default:
|
|
68
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return options;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function expandHome(value) {
|
|
76
|
+
if (value === "~") {
|
|
77
|
+
return os.homedir();
|
|
78
|
+
}
|
|
79
|
+
if (value.startsWith("~/")) {
|
|
80
|
+
return path.join(os.homedir(), value.slice(2));
|
|
81
|
+
}
|
|
82
|
+
return path.resolve(value);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function download(url, destination) {
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
const request = https.get(url, response => {
|
|
88
|
+
if ([301, 302, 303, 307, 308].includes(response.statusCode)) {
|
|
89
|
+
response.resume();
|
|
90
|
+
download(response.headers.location, destination).then(resolve, reject);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (response.statusCode !== 200) {
|
|
95
|
+
response.resume();
|
|
96
|
+
reject(new Error(`Download failed with HTTP ${response.statusCode}`));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const file = fs.createWriteStream(destination);
|
|
101
|
+
response.pipe(file);
|
|
102
|
+
file.on("finish", () => file.close(resolve));
|
|
103
|
+
file.on("error", reject);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
request.on("error", reject);
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function copyApp(source, destination) {
|
|
111
|
+
if (fs.existsSync(destination)) {
|
|
112
|
+
fs.rmSync(destination, { recursive: true, force: true });
|
|
113
|
+
}
|
|
114
|
+
run("/usr/bin/ditto", [source, destination]);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function quitRunningApp() {
|
|
118
|
+
try {
|
|
119
|
+
run("/usr/bin/osascript", ["-e", `tell application id "${bundleIdentifier}" to quit`], {
|
|
120
|
+
stdio: "ignore",
|
|
121
|
+
timeout: 3000
|
|
122
|
+
});
|
|
123
|
+
} catch {
|
|
124
|
+
try {
|
|
125
|
+
run("/usr/bin/killall", [appName], { stdio: "ignore", timeout: 3000 });
|
|
126
|
+
} catch {
|
|
127
|
+
// The app may not be running yet.
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async function main() {
|
|
133
|
+
const options = parseArgs(process.argv.slice(2));
|
|
134
|
+
if (options.help) {
|
|
135
|
+
usage();
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (options.version) {
|
|
139
|
+
console.log(packageJson.version);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (process.platform !== "darwin") {
|
|
144
|
+
console.error("Clippa is a macOS app. Run this installer on macOS.");
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "clippa-install-"));
|
|
149
|
+
const zipPath = path.join(tempDir, "Clippa.app.zip");
|
|
150
|
+
const extractDir = path.join(tempDir, "extract");
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
fs.mkdirSync(extractDir, { recursive: true });
|
|
154
|
+
|
|
155
|
+
if (fs.existsSync(localZipPath)) {
|
|
156
|
+
fs.copyFileSync(localZipPath, zipPath);
|
|
157
|
+
} else {
|
|
158
|
+
console.log(`Downloading Clippa from ${zipUrl}`);
|
|
159
|
+
await download(zipUrl, zipPath);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
run("/usr/bin/ditto", ["-x", "-k", zipPath, extractDir]);
|
|
163
|
+
|
|
164
|
+
const appPath = path.join(extractDir, `${appName}.app`);
|
|
165
|
+
if (!fs.existsSync(appPath)) {
|
|
166
|
+
throw new Error(`Archive did not contain ${appName}.app`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
quitRunningApp();
|
|
170
|
+
|
|
171
|
+
let installDir = options.installDir || "/Applications";
|
|
172
|
+
let installPath = path.join(installDir, `${appName}.app`);
|
|
173
|
+
if (options.installDir) {
|
|
174
|
+
fs.mkdirSync(installDir, { recursive: true });
|
|
175
|
+
copyApp(appPath, installPath);
|
|
176
|
+
} else {
|
|
177
|
+
try {
|
|
178
|
+
copyApp(appPath, installPath);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
installDir = path.join(os.homedir(), "Applications");
|
|
181
|
+
fs.mkdirSync(installDir, { recursive: true });
|
|
182
|
+
installPath = path.join(installDir, `${appName}.app`);
|
|
183
|
+
copyApp(appPath, installPath);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
console.log(`Installed ${appName} to ${installPath}`);
|
|
188
|
+
if (!options.noOpen) {
|
|
189
|
+
console.log("Opening Clippa...");
|
|
190
|
+
run("/usr/bin/open", [installPath]);
|
|
191
|
+
console.log("Press Command-Shift-W in a text field to open Clippa. Grant Accessibility access if macOS asks.");
|
|
192
|
+
}
|
|
193
|
+
} finally {
|
|
194
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
main().catch(error => {
|
|
199
|
+
console.error(error.message);
|
|
200
|
+
process.exit(1);
|
|
201
|
+
});
|
|
Binary file
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<svg width="1440" height="900" viewBox="0 0 1440 900" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<rect width="1440" height="900" fill="#111414"/>
|
|
3
|
+
<rect x="340" y="164" width="760" height="520" rx="30" fill="#181C1D"/>
|
|
4
|
+
<rect x="340.5" y="164.5" width="759" height="519" rx="29.5" stroke="#3A4242"/>
|
|
5
|
+
<filter id="shadow" x="300" y="124" width="840" height="600" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse">
|
|
6
|
+
<feDropShadow dx="0" dy="26" stdDeviation="28" flood-color="#000000" flood-opacity=".34"/>
|
|
7
|
+
</filter>
|
|
8
|
+
<g filter="url(#shadow)">
|
|
9
|
+
<rect x="340" y="164" width="760" height="520" rx="30" fill="#181C1D"/>
|
|
10
|
+
<rect x="340.5" y="164.5" width="759" height="519" rx="29.5" stroke="#3A4242"/>
|
|
11
|
+
</g>
|
|
12
|
+
<circle cx="388" cy="221" r="24" fill="#0A84FF"/>
|
|
13
|
+
<path d="M379 230l29-29a10 10 0 0 1 14 14l-32 32a17 17 0 0 1-24-24l31-31" stroke="#06131F" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/>
|
|
14
|
+
<text x="430" y="215" fill="#F4F7F5" font-family="-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" font-size="25" font-weight="760">Clippa</text>
|
|
15
|
+
<text x="430" y="244" fill="#9BA6A2" font-family="-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" font-size="16" font-weight="620">4 Items</text>
|
|
16
|
+
<line x1="380" y1="282" x2="1060" y2="282" stroke="#303838"/>
|
|
17
|
+
<rect x="380" y="314" width="680" height="72" rx="14" fill="#12365B"/>
|
|
18
|
+
<rect x="380.5" y="314.5" width="679" height="71" rx="13.5" stroke="#0A84FF" stroke-opacity=".62"/>
|
|
19
|
+
<rect x="402" y="330" width="42" height="42" rx="10" fill="#20364F"/>
|
|
20
|
+
<path d="M414 361h20M414 351h25M414 341h18" stroke="#B6C2C9" stroke-width="4" stroke-linecap="round"/>
|
|
21
|
+
<text x="464" y="346" fill="#F5F8F6" font-family="-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" font-size="21" font-weight="720">Release checklist</text>
|
|
22
|
+
<text x="464" y="371" fill="#B1BEC8" font-family="-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" font-size="15" font-weight="610">Text / Notes</text>
|
|
23
|
+
<rect x="380" y="398" width="680" height="72" rx="14" fill="#202526"/>
|
|
24
|
+
<rect x="402" y="414" width="42" height="42" rx="10" fill="#143C38"/>
|
|
25
|
+
<path d="M413 447l14-17 10 12 6-7 13 17h-43v-5z" fill="#64D2C8"/>
|
|
26
|
+
<text x="464" y="430" fill="#F5F8F6" font-family="-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" font-size="21" font-weight="720">Clipboard image</text>
|
|
27
|
+
<text x="464" y="455" fill="#98A4A0" font-family="-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" font-size="15" font-weight="610">1280 x 720 / 482 KB / Preview</text>
|
|
28
|
+
<rect x="380" y="482" width="680" height="72" rx="14" fill="#202526"/>
|
|
29
|
+
<rect x="402" y="498" width="42" height="42" rx="10" fill="#223B58"/>
|
|
30
|
+
<path d="M413 522c7-9 13-9 20 0s13 9 20 0" stroke="#8EC5FF" stroke-width="5" stroke-linecap="round"/>
|
|
31
|
+
<text x="464" y="514" fill="#F5F8F6" font-family="-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" font-size="21" font-weight="720">https://example.com/research</text>
|
|
32
|
+
<text x="464" y="539" fill="#98A4A0" font-family="-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" font-size="15" font-weight="610">URL / Safari</text>
|
|
33
|
+
<rect x="380" y="566" width="680" height="72" rx="14" fill="#202526"/>
|
|
34
|
+
<rect x="402" y="582" width="42" height="42" rx="10" fill="#3A3324"/>
|
|
35
|
+
<path d="M414 595h18l8 8v20h-26v-28z" stroke="#FFD479" stroke-width="4" stroke-linejoin="round"/>
|
|
36
|
+
<text x="464" y="598" fill="#F5F8F6" font-family="-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" font-size="21" font-weight="720">invoice.pdf</text>
|
|
37
|
+
<text x="464" y="623" fill="#98A4A0" font-family="-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" font-size="15" font-weight="610">File / Finder</text>
|
|
38
|
+
<text x="380" y="724" fill="#75817D" font-family="-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif" font-size="18" font-weight="650">Command-Shift-W opens Clippa. Enter or click pastes the selected item.</text>
|
|
39
|
+
</svg>
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clippa",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Installer for Clippa, a private macOS paste panel.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"install-clippa": "bin/install-clippa.js",
|
|
7
|
+
"clippa": "bin/install-clippa.js",
|
|
8
|
+
"Clippa": "bin/install-clippa.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"release": "./scripts/release.sh",
|
|
12
|
+
"test": "xcodebuild -project Clippa.xcodeproj -scheme Clippa -destination 'platform=macOS' test"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"bin",
|
|
16
|
+
"docs/assets",
|
|
17
|
+
"outputs/Clippa.app.zip",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/Vaniawl/Clippa.git"
|
|
24
|
+
},
|
|
25
|
+
"homepage": "https://vaniawl.github.io/Clippa/",
|
|
26
|
+
"bugs": {
|
|
27
|
+
"url": "https://github.com/Vaniawl/Clippa/issues"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"macos",
|
|
31
|
+
"clipboard",
|
|
32
|
+
"swiftui",
|
|
33
|
+
"productivity"
|
|
34
|
+
],
|
|
35
|
+
"license": "MIT"
|
|
36
|
+
}
|