Add initial project structure with Apple Quarantine extension functionality

This commit is contained in:
Huakun Shen 2025-01-18 22:18:52 -05:00
commit 41371ae465
No known key found for this signature in database
10 changed files with 1779 additions and 0 deletions

48
.github/workflows/npm-publish.yml vendored Normal file
View File

@ -0,0 +1,48 @@
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
name: NPM Package Publish
on:
push:
branches: [main]
release:
types: [created]
workflow_dispatch:
jobs:
publish-npm:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
registry-url: https://registry.npmjs.org/
- uses: pnpm/action-setup@v2
with:
version: latest
- uses: oven-sh/setup-bun@v2
- run: pnpm install
- run: pnpm build
- run: |
PACKAGE_NAME=$(jq -r '.name' package.json)
PACKAGE_VERSION=$(jq -r '.version' package.json)
# Get the version from npm registry
REGISTRY_VERSION=$(npm show "$PACKAGE_NAME" version)
# Compare versions
if [ "$PACKAGE_VERSION" == "$REGISTRY_VERSION" ]; then
echo "Version $PACKAGE_VERSION already exists in the npm registry."
exit 0
else
echo "Version $PACKAGE_VERSION does not exist in the npm registry. Proceeding..."
npm publish --provenance --access public
fi
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}

25
.gitignore vendored Normal file
View File

@ -0,0 +1,25 @@
node_modules
# Output
.output
.vercel
/.svelte-kit
/build
# OS
.DS_Store
Thumbs.db
# Env
.env
.env.*
!.env.example
!.env.test
# Vite
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
extensions_support/
.pnpm-store
dist/

13
README.md Normal file
View File

@ -0,0 +1,13 @@
# Disable Apple Quarantine
Mac Apps made by developers not paying Apple's $99/year developer fee are marked as "damaged" by Apple. This is because they are not signed by an Apple Developer ID.
This extension allows you to disable Apple Quarantine on these apps.
There are 3 ways:
1. Drag and Drop damanged .app files here
2. Copy the .app file, this extension will automatically detect the copied file
3. Select the .app file in Finder, this extension will automatically detect the selected file
Method 2 and 3 require you to copy or select the file before entering this extension.

20
build.ts Normal file
View File

@ -0,0 +1,20 @@
import { watch } from "fs"
import { join } from "path"
import { refreshTemplateWorkerExtension } from "@kksh/api/dev"
import { $ } from "bun"
async function build() {
await $`bun build --minify --target=browser --outdir=./dist ./src/index.ts`
await refreshTemplateWorkerExtension()
}
const srcDir = join(import.meta.dir, "src")
await build()
if (Bun.argv.includes("dev")) {
console.log(`Watching ${srcDir} for changes...`)
watch(srcDir, { recursive: true }, async (event, filename) => {
await build()
})
}

116
index.ts Normal file
View File

@ -0,0 +1,116 @@
import {
Action,
expose,
Form,
fs,
Icon,
IconEnum,
List,
path,
shell,
toast,
ui,
WorkerExtension
} from "@kksh/api/ui/worker"
shell.executeBashScript("echo 'Hello, World!'").then(console.log)
class ExtensionTemplate extends WorkerExtension {
async onFormSubmit(value: Record<string, any>): Promise<void> {
console.log("Form submitted", value)
toast.success(`Form submitted: ${JSON.stringify(value)}`)
}
async load() {
return ui.render(
new Form.Form({
key: "form1",
fields: [
new Form.NumberField({
key: "age",
label: "Age",
placeholder: "Enter your age"
})
// new Form.NumberField({
// key: "age"
// }),
// new Form.Form({
// key: "random",
// fields: [
// new Form.BooleanField({ key: "Server On" }),
// new Form.ArrayField({
// key: "birthday",
// content: new Form.DateField({ key: "birthday" })
// })
// ]
// })
]
})
)
return toast
.info("Worker Template Extension loaded")
.then(() => {
return ui.setSearchBarPlaceholder("Enter a search term, and press enter to search")
})
.then(() => {
return ui.render(
new List.List({
sections: [
new List.Section({
title: "Section 1",
items: [
new List.Item({
title: "Hello, World!",
value: "Section 1 Hello, World!",
icon: new Icon({ type: IconEnum.Iconify, value: "gg:hello" })
}),
new List.Item({ title: "Hello, World 2!", value: "Section 1 Hello, World 2!" })
]
}),
new List.Section({
title: "Section 2",
items: [
new List.Item({
title: "Hello, World!",
value: "Section 2 Hello, World!",
icon: new Icon({ type: IconEnum.Iconify, value: "gg:hello" })
}),
new List.Item({ title: "Hello, World 2!", value: "Section 2 Hello, World 2!" })
]
})
],
items: [
new List.Item({
title: "Hello, World!",
value: "Hello, World!",
icon: new Icon({ type: IconEnum.Iconify, value: "ri:star-s-fill" })
}),
new List.Item({
title: "Hello, World 2!",
value: "Hello, World 2!",
icon: new Icon({ type: IconEnum.Iconify, value: "gg:hello" }),
actions: new Action.ActionPanel({
items: [
new Action.Action({
title: "Open",
icon: new Icon({ type: IconEnum.Iconify, value: "ion:open-outline" })
})
]
})
})
]
})
)
})
}
onSearchTermChange(term: string): Promise<void> {
return Promise.resolve()
}
onItemSelected(value: string): Promise<void> {
console.log("Item selected:", value)
return Promise.resolve()
}
}
expose(new ExtensionTemplate())

68
package.json Normal file
View File

@ -0,0 +1,68 @@
{
"$schema": "https://schema.kunkun.sh",
"name": "kunkun-ext-disable-apple-quarantine",
"license": "MIT",
"repository": "https://github.com/kunkunsh/kunkun-ext-disable-apple-quarantine",
"version": "0.0.3",
"type": "module",
"kunkun": {
"name": "Disable Apple Quarantine",
"shortDescription": "Remove .app is damaged error",
"longDescription": "Mac apps created by developer who didn't pay Apple developer program fees will be displayed as damaged. This extension helps your bypass the error with xattr command.",
"identifier": "disable-apple-quarantine",
"permissions": [
"clipboard:read-files",
{
"permission": "shell:execute",
"allow": [
{
"cmd": {
"program": "xattr",
"args": [
"-cr",
".+"
]
}
}
]
},
"system:fs",
"event:drag-drop",
"dialog:all"
],
"demoImages": [],
"icon": {
"type": "iconify",
"value": "openmoji:hacker-cat"
},
"customUiCmds": [],
"templateUiCmds": [
{
"name": "Disable Apple Quarantine",
"main": "dist/index.js",
"cmds": [],
"platforms": [
"macos"
]
}
]
},
"scripts": {
"dev": "bun build.ts dev",
"build": "bun build.ts"
},
"dependencies": {
"@kksh/api": "^0.0.48"
},
"devDependencies": {
"@types/bun": "latest"
},
"peerDependencies": {
"typescript": "^5.0.0"
},
"files": [
"./dist",
".gitignore"
],
"packageManager": "pnpm@9.10.0+sha512.73a29afa36a0d092ece5271de5177ecbf8318d454ecd701343131b8ebc0c1a91c487da46ab77c8e596d6acf1461e3594ced4becedf8921b074fbd8653ed7051c"
}

1347
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

100
src/index.ts Normal file
View File

@ -0,0 +1,100 @@
import {
Action,
clipboard,
dialog,
event,
expose,
Form,
fs,
Icon,
IconEnum,
List,
Markdown,
path,
shell,
system,
toast,
ui,
WorkerExtension
} from "@kksh/api/ui/worker"
import { markdownInstruction } from "./instruction"
async function disableAppleQuarantine(path: string) {
const confirm = await dialog.confirm(
`Are you sure you want to disable Apple Quarantine on this file? Will run "xattr -cr ${path}"`
)
if (!confirm) {
return
}
const ret = await shell.createCommand("xattr", ["-cr", path]).execute()
if (ret.code === 0) {
toast.success(`Disabled Apple Quarantine on ${path}`)
} else {
toast.error(`Error disabling Apple Quarantine on ${path}`)
}
}
async function disableMultipleAppleQuarantine(paths: string[]) {
for (const path of paths) {
await disableAppleQuarantine(path)
}
}
class ExtensionTemplate extends WorkerExtension {
async load() {
event.onDragDrop(async (files) => {
console.log("Dropped Files: ", files)
disableMultipleAppleQuarantine(files.paths.filter((path) => /\.app\/?$/.test(path)))
})
clipboard.readFiles().then((files) => {
console.log("Clipboard Copied Files", files)
disableMultipleAppleQuarantine(files.filter((path) => /\.app\/?$/.test(path)))
})
system.getSelectedFilesInFileExplorer().then((files) => {
console.log("Finder Selected Files", files)
disableMultipleAppleQuarantine(files.filter((path) => /\.app\/?$/.test(path)))
})
return ui.render(new Markdown(markdownInstruction))
// return ui.render(
// new Form.Form({
// key: "form1",
// fields: [
// new Form.NumberField({
// key: "age",
// label: "Age",
// placeholder: "Enter your age"
// })
// // new Form.NumberField({
// // key: "age"
// // }),
// // new Form.Form({
// // key: "random",
// // fields: [
// // new Form.BooleanField({ key: "Server On" }),
// // new Form.ArrayField({
// // key: "birthday",
// // content: new Form.DateField({ key: "birthday" })
// // })
// // ]
// // })
// ]
// })
// )
}
async onFormSubmit(value: Record<string, any>): Promise<void> {
console.log("Form submitted", value)
toast.success(`Form submitted: ${JSON.stringify(value)}`)
}
onSearchTermChange(term: string): Promise<void> {
return Promise.resolve()
}
onItemSelected(value: string): Promise<void> {
console.log("Item selected:", value)
return Promise.resolve()
}
}
expose(new ExtensionTemplate())

15
src/instruction.ts Normal file
View File

@ -0,0 +1,15 @@
export const markdownInstruction = `
# Disable Apple Quarantine
Mac Apps made by developers not paying Apple's $99/year developer fee are marked as "damaged" by Apple. This is because they are not signed by an Apple Developer ID.
This extension allows you to disable Apple Quarantine on these apps.
There are 3 ways:
1. Drag and Drop damanged .app files here
2. Copy the .app file, this extension will automatically detect the copied file
3. Select the .app file in Finder, this extension will automatically detect the selected file
Method 2 and 3 require you to copy or select the file before entering this extension.
`

27
tsconfig.json Normal file
View File

@ -0,0 +1,27 @@
{
"compilerOptions": {
// Enable latest features
"lib": [
"ESNext",
"DOM"
],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,
// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": false,
"verbatimModuleSyntax": true,
"noEmit": true,
// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
// Some stricter flags (disabled by default)
"noUnusedLocals": false,
"noUnusedParameters": false,
"noPropertyAccessFromIndexSignature": false
}
}