Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ jobs:
run: |
VERSION="${{ steps.package_version.outputs.version }}"
echo "Extracting release notes for version $VERSION from CHANGELOG.md"

if [ ! -f CHANGELOG.md ]; then
echo "CHANGELOG.md not found, using PR information"
echo "## Changes" > release_notes.md
Expand Down Expand Up @@ -119,12 +119,12 @@ jobs:
fi
fi
fi

echo "Generated release notes:"
echo "========================"
cat release_notes.md
echo "========================"

# Set output for GitHub Actions
echo "notes<<EOF" >> $GITHUB_OUTPUT
cat release_notes.md >> $GITHUB_OUTPUT
Expand Down Expand Up @@ -161,4 +161,4 @@ jobs:
if: steps.check_tag.outputs.tag_exists == 'true'
run: |
echo "Tag ${{ steps.package_version.outputs.tag }} already exists, skipping release creation"
echo "If you need to create a new release, update the version in package.json"
echo "If you need to create a new release, update the version in package.json"
38 changes: 38 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.2.0] - 2026-05-06

### Added

- `unoff create penpot-plugin` — scaffold a Penpot plugin using the new `unoff-template-penpot` submodule
- Penpot plugin template (`unoff-template-penpot`) wired as a git submodule (`templates/penpot`)

### Changed

- `penpot-plugin` moved from "coming soon" to available in `create` command, `unoff help`, and README
- Quick Example in README extended with Penpot workflow and plugin loading instructions

### Fixed

- `penpot.ui.onMessage` was incorrectly assigned as a property; corrected to a method call `penpot.ui.onMessage(callback)` — resolves *"Cannot assign to read only property"* error introduced in Penpot 2.15+

### Skills (`unoff-skills`)

- Bridge and Canvas skill layers restructured into platform subdirectories:
- `bridge/figma/` + `bridge/penpot/` — communication pattern and bridge functions per platform
- `canvas/figma/` + `canvas/penpot/` — API, storage, and document generation per platform
- `app-bootstrap` skill updated with separate Figma and Penpot Canvas initialization sections
- `implement-design` skill extended with the Penpot MCP workflow (code-execution model via `@penpot/mcp`, selection-based, no URL parsing)
- Platform-specific annotations added to `app-bootstrap`, `error-handling`, `css-theming`, `i18n`, `state-management`, `payment-systems`, `types-system`, `credits-system`
- `SKILL.md` index updated to reflect the platform-split structure and improve agent routing

### Templates (Figma + Penpot)

- All AI tool rule files (CLAUDE.md, `.cursor/rules/project.mdc`, `.windsurf/rules/project.md`, `.github/copilot-instructions.md`) updated with new skill paths
- Penpot template: all Figma identity references corrected to Penpot (developer role, API calls, communication examples)
- Section comments added to all bridge files across both templates:
- `loadUI.ts` — Startup / Announcements / Preferences / Storage / Browser / Plans / Auth
- `checkCredits.ts` — 4 storage cases documented inline
- `checkTrialStatus.ts` — storage reads, trial status, plan status, send result
- `checkAnnouncementsStatus.ts` — storage reads, version comparison
- Short files (`checkUserLicense`, `checkUserPreferences`, `checkEditor`, `enableTrial`, `payProPlan`) — descriptive header comment

## [0.1.5] - 2026-03-18

### Changed
Expand Down Expand Up @@ -103,6 +140,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- 🚧 Sketch plugin template (coming soon)
- 🚧 Framer plugin template (coming soon)

[0.2.0]: https://github.com/yelbolt/unoff-cli/compare/v0.1.5...v0.2.0
[0.1.5]: https://github.com/yelbolt/unoff-cli/compare/v0.1.4...v0.1.5
[0.1.4]: https://github.com/yelbolt/unoff-cli/compare/v0.1.3...v0.1.4
[0.1.3]: https://github.com/yelbolt/unoff-cli/compare/v0.1.2...v0.1.3
Expand Down
51 changes: 31 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ If you don't have Homebrew installed, open **Terminal** and install it:
```

Then verify:

```bash
brew --version
```
Expand All @@ -27,12 +28,14 @@ brew --version

**On macOS:**
Open **Terminal** and run:

```bash
# Using Homebrew (requires Homebrew to be installed)
brew install node
```

**On Windows:**

1. Download the installer from [nodejs.org](https://nodejs.org)
2. Run the installer and follow the setup wizard
3. Open **Command Prompt** (cmd.exe) or **PowerShell** and verify installation:
Expand All @@ -43,13 +46,15 @@ brew install node

**On Linux (Ubuntu/Debian):**
Open **Terminal** and run:

```bash
sudo apt update
sudo apt install nodejs npm
```

**On Linux (Fedora/CentOS):**
Open **Terminal** and run:

```bash
sudo dnf install nodejs npm
```
Expand All @@ -58,12 +63,14 @@ sudo dnf install nodejs npm

**On macOS:**
Open **Terminal** and run:

```bash
# Using Homebrew
brew install git
```

**On Windows:**

1. Download the installer from [git-scm.com](https://git-scm.com)
2. Run the installer and follow the setup wizard
3. Open **Command Prompt** (cmd.exe) or **PowerShell** and verify installation:
Expand All @@ -73,13 +80,15 @@ brew install git

**On Linux (Ubuntu/Debian):**
Open **Terminal** and run:

```bash
sudo apt update
sudo apt install git
```

**On Linux (Fedora/CentOS):**
Open **Terminal** and run:

```bash
sudo dnf install git
```
Expand Down Expand Up @@ -107,18 +116,20 @@ npm install -g @unoff/cli
# Create a new Figma plugin (will prompt for name)
unoff create figma-plugin

# Or create a Penpot plugin
unoff create penpot-plugin

# Navigate to the plugin directory
cd color-palette-generator
cd my-plugin

# Install dependencies
npm install

# Start development
unoff dev

# Open Figma and load the plugin:
# Plugins > Development > Import plugin from manifest...
# Select manifest.json from the plugin folder
# Figma: Plugins > Development > Import plugin from manifest...
# Penpot: Plugins > Add custom plugin > http://localhost:4400/manifest.json
```

## CLI Commands
Expand All @@ -131,21 +142,21 @@ Show all commands, available platforms, and workers.

Scaffold a new plugin project.

| Platform | Status |
| -------- | ------ |
| `figma-plugin` | ✅ Available |
| `penpot-plugin` | 🚧 Coming soon |
| Platform | Status |
| --------------- | -------------- |
| `figma-plugin` | ✅ Available |
| `penpot-plugin` | ✅ Available |
| `sketch-plugin` | 🚧 Coming soon |
| `framer-plugin` | 🚧 Coming soon |

The interactive prompt will ask for plugin name, output directory, GitHub username, author, license, and which external services to enable:

| Service | Default |
| ------- | ------- |
| Supabase (Database & Authentication) | ✅ |
| Mixpanel (Analytics) | ✅ |
| Sentry (Error Monitoring) | ✅ |
| Notion (Announcements & Onboarding) | ✅ |
| Service | Default |
| ------------------------------------ | ------- |
| Supabase (Database & Authentication) | ✅ |
| Mixpanel (Analytics) | ✅ |
| Sentry (Error Monitoring) | ✅ |
| Notion (Announcements & Onboarding) | ✅ |

Selected services update the `is*Enabled` flags in `global.config.ts`. All environment variable placeholders are always generated in `.env.local`.

Expand Down Expand Up @@ -173,11 +184,11 @@ Format source code with Prettier.

Add a Cloudflare Worker as a git submodule. Automatically updates `package.json` workspaces and injects the corresponding start script. You will be prompted for the destination path.

| Worker | Script | Port |
| --------------- | --------------------- | ---- |
| `announcement` | `start:announcements` | 8888 |
| `auth` | `start:token` | 8787 |
| `cors` | `start:cors` | 8989 |
| Worker | Script | Port |
| -------------- | --------------------- | ---- |
| `announcement` | `start:announcements` | 8888 |
| `auth` | `start:token` | 8787 |
| `cors` | `start:cors` | 8989 |

```bash
unoff add worker announcement
Expand Down Expand Up @@ -231,7 +242,7 @@ unoff remove specs
## Features

- 🚀 Quick setup with interactive CLI
- 📦 Multiple platform support (Figma ✅, Penpot 🚧, Sketch 🚧, Framer 🚧)
- 📦 Multiple platform support (Figma ✅, Penpot , Sketch 🚧, Framer 🚧)
- 🔧 Built-in development server with hot reload
- 🏗️ Production-ready build system
- 🎛️ Toggleable external services (Supabase, Mixpanel, Sentry, Notion)
Expand Down
9 changes: 5 additions & 4 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,11 @@ Add a Cloudflare Worker as a git submodule, register it in `package.json` worksp

**Available workers:**

| Worker | Script added | Port |
|---|---|---|
| Worker | Script added | Port |
| --------------------- | --------------------- | ---- |
| `announcement-worker` | `start:announcements` | 8888 |
| `auth-worker` | `start:token` | 8787 |
| `cors-worker` | `start:cors` | 8989 |
| `auth-worker` | `start:token` | 8787 |
| `cors-worker` | `start:cors` | 8989 |

**Examples:**

Expand Down Expand Up @@ -142,6 +142,7 @@ unoff remove announcement-worker
```

This command:

1. Looks up the submodule path from `.gitmodules`
2. Asks for confirmation
3. Runs `git submodule deinit` + `git rm`
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@unoff/cli",
"version": "0.1.6",
"version": "0.2.0",
"description": "A CLI tool to create plugins for Figma, Penpot, Sketch, and Framer",
"main": "dist/index.js",
"type": "module",
Expand Down
6 changes: 3 additions & 3 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ program
.description(
'CLI tool to create plugins for Figma, Penpot, Sketch, and Framer'
)
.version('0.1.0')
.version('0.2.0')

program
.command('create <platform>')
.description('Create a new plugin for a specific platform')
.action(async (platform: string) => {
const availablePlatforms = ['figma-plugin']
const comingSoonPlatforms = ['penpot-plugin', 'sketch-plugin', 'framer-plugin']
const availablePlatforms = ['figma-plugin', 'penpot-plugin']
const comingSoonPlatforms = ['sketch-plugin', 'framer-plugin']
const allPlatforms = [...availablePlatforms, ...comingSoonPlatforms]

if (!allPlatforms.includes(platform)) {
Expand Down
22 changes: 11 additions & 11 deletions src/commands/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,23 @@ Your content here.
`

export function toTitleCase(str: string): string {
return str
.replace(/-/g, ' ')
.replace(/\b\w/g, (c) => c.toUpperCase())
return str.replace(/-/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase())
}

export const WORKERS: Record<string, string> = {
'announcement':
'https://github.com/a-ng-d/announcements-yelbolt-worker',
'auth': 'https://github.com/a-ng-d/auth-yelbolt-worker',
'cors': 'https://github.com/a-ng-d/cors-yelbolt-worker',
announcement: 'https://github.com/a-ng-d/announcements-yelbolt-worker',
auth: 'https://github.com/a-ng-d/auth-yelbolt-worker',
cors: 'https://github.com/a-ng-d/cors-yelbolt-worker',
}

export const WORKER_SCRIPTS: Record<string, Record<string, string>> = {
'announcement': {
announcement: {
'start:announcements': 'npm run start:8888 -w announcements-yelbolt-worker',
},
'auth': {
auth: {
'start:token': 'npm run start:8787 -w auth-yelbolt-worker',
},
'cors': {
cors: {
'start:cors': 'npm run start:8989 -w cors-yelbolt-worker',
},
}
Expand Down Expand Up @@ -326,7 +323,10 @@ export async function addSpecs() {
const spinner = ora('Creating spec...').start()

await fs.ensureDir(specsPath)
await fs.writeFile(specFilePath, SPEC_TEMPLATE(specName, toTitleCase(specName)))
await fs.writeFile(
specFilePath,
SPEC_TEMPLATE(specName, toTitleCase(specName))
)

spinner.succeed(
chalk.green(
Expand Down
20 changes: 17 additions & 3 deletions src/commands/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,14 +271,26 @@ export async function createPlugin(platform: string) {
encoding: 'utf-8',
})
if (gitInit.status === 0) {
spinner.succeed(chalk.green('Plugin created successfully! Git repository initialized.'))
spinner.succeed(
chalk.green(
'Plugin created successfully! Git repository initialized.'
)
)
} else {
spinner.succeed(chalk.green('Plugin created successfully!'))
console.warn(chalk.yellow('⚠️ Could not initialize git repository. Run `git init` manually.'))
console.warn(
chalk.yellow(
'⚠️ Could not initialize git repository. Run `git init` manually.'
)
)
}
} else {
spinner.succeed(chalk.green('Plugin created successfully!'))
console.warn(chalk.yellow('⚠️ git is not available. Run `git init` manually before using `unoff add`.'))
console.warn(
chalk.yellow(
'⚠️ git is not available. Run `git init` manually before using `unoff add`.'
)
)
}

console.log(chalk.cyan('\n📦 Next steps:\n'))
Expand Down Expand Up @@ -434,6 +446,8 @@ VITE_TOLGEE_API_KEY='YOUR_TOLGEE_API_KEY'
// Generate .env.sentry-build-plugin
const envSentryContent = `# Sentry Build Plugin Configuration
# Generate your auth token from: https://sentry.io/settings/account/api/auth-tokens/
SENTRY_ORG='YOUR_SENTRY_ORG'
SENTRY_PROJECT='YOUR_SENTRY_PROJECT'
SENTRY_AUTH_TOKEN='YOUR_SENTRY_AUTH_TOKEN'
`
await fs.writeFile(envSentryPath, envSentryContent, 'utf-8')
Expand Down
Loading
Loading