mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-01-04 20:39:06 -05:00
Compare commits
94 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b54c22012 | ||
|
|
4f7e67b106 | ||
|
|
8b637d53c4 | ||
|
|
00bf5920e3 | ||
|
|
58bf55704a | ||
|
|
c75d6b815e | ||
|
|
35a57bf7f5 | ||
|
|
118b2faa76 | ||
|
|
158164089f | ||
|
|
4cd4cb5722 | ||
|
|
52f7447f85 | ||
|
|
11694921e3 | ||
|
|
0146ee586f | ||
|
|
e751167dfc | ||
|
|
2ccee0dc70 | ||
|
|
04eec0ee05 | ||
|
|
7e239c0dd1 | ||
|
|
f1783feafc | ||
|
|
ef187373c5 | ||
|
|
8da3659be3 | ||
|
|
4d2bf9304a | ||
|
|
d544899f39 | ||
|
|
92a8da03af | ||
|
|
07ea1ea7dc | ||
|
|
e435414c2e | ||
|
|
e4bd30eb01 | ||
|
|
af3e672386 | ||
|
|
45be354625 | ||
|
|
cd65ef8dbe | ||
|
|
6b9b207e1c | ||
|
|
58eff84f43 | ||
|
|
25d51a017e | ||
|
|
f1a3ef1c11 | ||
|
|
3d919591f3 | ||
|
|
75f92bdd29 | ||
|
|
2fc8678183 | ||
|
|
1c29f4d4ad | ||
|
|
8e1959b7c3 | ||
|
|
cdd5ba3c83 | ||
|
|
3c45464e34 | ||
|
|
7446d62e39 | ||
|
|
3855058d8f | ||
|
|
07d743db21 | ||
|
|
6d5ba685f1 | ||
|
|
218fdf3715 | ||
|
|
7742e7a54c | ||
|
|
b516ca877b | ||
|
|
f3dc71a85c | ||
|
|
394fbbd55d | ||
|
|
6869aa49ec | ||
|
|
ba00274045 | ||
|
|
e32930034d | ||
|
|
26a3e88715 | ||
|
|
6a0d5d2337 | ||
|
|
271d8f29ca | ||
|
|
9c5479b206 | ||
|
|
5f8902e57b | ||
|
|
089c7e8dce | ||
|
|
7e0aa919fb | ||
|
|
5776bab288 | ||
|
|
6b52a0cbed | ||
|
|
46933059f6 | ||
|
|
e17aae246b | ||
|
|
cfbfd66eef | ||
|
|
c20c0eff32 | ||
|
|
9d40949043 | ||
|
|
d435337f2a | ||
|
|
a32145c054 | ||
|
|
e0f547b93f | ||
|
|
5d4268d6a1 | ||
|
|
0a3506f81e | ||
|
|
375b2287b7 | ||
|
|
e72c1e68e5 | ||
|
|
3484db3371 | ||
|
|
c4b559f34b | ||
|
|
ef1ba9b834 | ||
|
|
846f4d9551 | ||
|
|
4780bfe41f | ||
|
|
d0d01b3897 | ||
|
|
fc1e8baa23 | ||
|
|
d35116c494 | ||
|
|
1d257b365b | ||
|
|
1076d57e8a | ||
|
|
01904cd1c9 | ||
|
|
1c93d5775f | ||
|
|
113d0dc3c7 | ||
|
|
7b78fac24e | ||
|
|
6534b3f622 | ||
|
|
daba21fbca | ||
|
|
3b99ea1cad | ||
|
|
937d7aa72a | ||
|
|
5bf7278479 | ||
|
|
095af8cf4b | ||
|
|
e1c1ecc34d |
51
.claude/commands/release/check-out-pr.md
Normal file
51
.claude/commands/release/check-out-pr.md
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
description: Review a PR in a new worktree
|
||||
allowed-tools: Bash(git worktree:*), Bash(gh pr:*)
|
||||
---
|
||||
|
||||
Review a GitHub pull request in a new git worktree.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
/review-pr <PR_NUMBER>
|
||||
```
|
||||
|
||||
## What to do
|
||||
|
||||
1. List all open pull requests and ask the user to select one
|
||||
2. Get PR information using `gh pr view <PR_NUMBER> --json number,headRefName`
|
||||
3. Extract the branch name from the PR
|
||||
4. Create a new worktree at `../yaak-worktrees/pr-<PR_NUMBER>`
|
||||
5. Checkout the PR branch in the new worktree using `gh pr checkout <PR_NUMBER>`
|
||||
6. The post-checkout hook will automatically:
|
||||
- Create `.env.local` with unique ports
|
||||
- Copy editor config folders
|
||||
- Run `npm install && npm run bootstrap`
|
||||
7. Inform the user:
|
||||
- Where the worktree was created
|
||||
- What ports were assigned
|
||||
- How to access it (cd command)
|
||||
- How to run the dev server
|
||||
- How to remove the worktree when done
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
Created worktree for PR #123 at ../yaak-worktrees/pr-123
|
||||
Branch: feature-auth
|
||||
Ports: Vite (1421), MCP (64344)
|
||||
|
||||
To start working:
|
||||
cd ../yaak-worktrees/pr-123
|
||||
npm run app-dev
|
||||
|
||||
To remove when done:
|
||||
git worktree remove ../yaak-worktrees/pr-123
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
- If the PR doesn't exist, show a helpful error
|
||||
- If the worktree already exists, inform the user and ask if they want to remove and recreate it
|
||||
- If `gh` CLI is not available, inform the user to install it
|
||||
39
.claude/commands/release/generate-release-notes.md
Normal file
39
.claude/commands/release/generate-release-notes.md
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
description: Generate formatted release notes for Yaak releases
|
||||
allowed-tools: Bash(git tag:*)
|
||||
---
|
||||
|
||||
Generate formatted release notes for Yaak releases by analyzing git history and pull request descriptions.
|
||||
|
||||
## What to do
|
||||
|
||||
1. Identifies the version tag and previous version
|
||||
2. Retrieves all commits between versions
|
||||
- If the version is a beta version, it retrieves commits between the beta version and previous beta version
|
||||
- If the version is a stable version, it retrieves commits between the stable version and the previous stable version
|
||||
3. Fetches PR descriptions for linked issues to find:
|
||||
- Feedback URLs (feedback.yaak.app)
|
||||
- Additional context and descriptions
|
||||
- Installation links for plugins
|
||||
4. Formats the release notes using the standard Yaak format:
|
||||
- Changelog badge at the top
|
||||
- Bulleted list of changes with PR links
|
||||
- Feedback links where available
|
||||
- Full changelog comparison link at the bottom
|
||||
|
||||
## Output Format
|
||||
|
||||
The skill generates markdown-formatted release notes following this structure:
|
||||
|
||||
```markdown
|
||||
[](https://yaak.app/changelog/VERSION)
|
||||
|
||||
- Feature/fix description in by @username [#123](https://github.com/mountain-loop/yaak/pull/123)
|
||||
- [Linked feedback item](https://feedback.yaak.app/p/item) by @username in [#456](https://github.com/mountain-loop/yaak/pull/456)
|
||||
- A simple item that doesn't have a feedback or PR link
|
||||
|
||||
**Full Changelog**: https://github.com/mountain-loop/yaak/compare/vPREV...vCURRENT
|
||||
```
|
||||
|
||||
**IMPORTANT**: Always add a blank lines around the markdown code fence and output the markdown code block last
|
||||
**IMPORTANT**: PRs by `@gschier` should not mention the @username
|
||||
22
.claude/rules.md
Normal file
22
.claude/rules.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Project Rules
|
||||
|
||||
## General Development
|
||||
- **NEVER** commit or push without explicit confirmation
|
||||
|
||||
## Build and Lint
|
||||
- **ALWAYS** run `npm run lint` after modifying TypeScript or JavaScript files
|
||||
- Run `npm run bootstrap` after changing plugin runtime or MCP server code
|
||||
|
||||
## Plugin System
|
||||
|
||||
### Backend Constraints
|
||||
- Always use `UpdateSource::Plugin` when calling database methods from plugin events
|
||||
- Never send timestamps (`createdAt`, `updatedAt`) from TypeScript - Rust backend controls these
|
||||
- Backend uses `NaiveDateTime` (no timezone) so avoid sending ISO timestamp strings
|
||||
|
||||
### MCP Server
|
||||
- MCP server has **no active window context** - cannot call `window.workspaceId()`
|
||||
- Get workspace ID from `workspaceCtx.yaak.workspace.list()` instead
|
||||
|
||||
## Rust Type Generation
|
||||
- Run `cd src-tauri && cargo test --package yaak-plugins` to regenerate TypeScript bindings after modifying Rust event types
|
||||
35
.claude/skills/worktree.md
Normal file
35
.claude/skills/worktree.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Worktree Management Skill
|
||||
|
||||
## Creating Worktrees
|
||||
|
||||
When creating git worktrees for this project, ALWAYS use the path format:
|
||||
```
|
||||
../yaak-worktrees/<NAME>
|
||||
```
|
||||
|
||||
For example:
|
||||
- `git worktree add ../yaak-worktrees/feature-auth`
|
||||
- `git worktree add ../yaak-worktrees/bugfix-login`
|
||||
- `git worktree add ../yaak-worktrees/refactor-api`
|
||||
|
||||
## What Happens Automatically
|
||||
|
||||
The post-checkout hook will automatically:
|
||||
1. Create `.env.local` with unique ports (YAAK_DEV_PORT and YAAK_PLUGIN_MCP_SERVER_PORT)
|
||||
2. Copy gitignored editor config folders (.zed, .idea, etc.)
|
||||
3. Run `npm install && npm run bootstrap`
|
||||
|
||||
## Deleting Worktrees
|
||||
|
||||
```bash
|
||||
git worktree remove ../yaak-worktrees/<NAME>
|
||||
```
|
||||
|
||||
## Port Assignments
|
||||
|
||||
- Main worktree: 1420 (Vite), 64343 (MCP)
|
||||
- First worktree: 1421, 64344
|
||||
- Second worktree: 1422, 64345
|
||||
- etc.
|
||||
|
||||
Each worktree can run `npm run app-dev` simultaneously without conflicts.
|
||||
5
.gitattributes
vendored
5
.gitattributes
vendored
@@ -1,2 +1,7 @@
|
||||
src-tauri/vendored/**/* linguist-generated=true
|
||||
src-tauri/gen/schemas/**/* linguist-generated=true
|
||||
**/bindings/* linguist-generated=true
|
||||
src-tauri/yaak-templates/pkg/* linguist-generated=true
|
||||
|
||||
# Ensure consistent line endings for test files that check exact content
|
||||
src-tauri/yaak-http/tests/test.txt text eol=lf
|
||||
|
||||
12
.github/FUNDING.yml
vendored
12
.github/FUNDING.yml
vendored
@@ -1,15 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: gschier
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
polar: # Replace with a single Polar username
|
||||
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
|
||||
thanks_dev: # Replace with a single thanks.dev username
|
||||
custom: https://yaak.app/pricing
|
||||
|
||||
50
.github/workflows/claude.yml
vendored
Normal file
50
.github/workflows/claude.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Claude Code
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened, assigned]
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
|
||||
jobs:
|
||||
claude:
|
||||
if: |
|
||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
||||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
issues: read
|
||||
id-token: write
|
||||
actions: read # Required for Claude to read CI results on PRs
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude Code
|
||||
id: claude
|
||||
uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
|
||||
# This is an optional setting that allows Claude to read CI results on PRs
|
||||
additional_permissions: |
|
||||
actions: read
|
||||
|
||||
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
|
||||
# prompt: 'Update the pull request description to include a summary of changes.'
|
||||
|
||||
# Optional: Add claude_args to customize behavior and configuration
|
||||
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
# or https://code.claude.com/docs/en/cli-reference for available options
|
||||
# claude_args: '--allowed-tools Bash(gh pr:*)'
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -25,6 +25,7 @@ dist-ssr
|
||||
*.sln
|
||||
*.sw?
|
||||
.eslintcache
|
||||
out
|
||||
|
||||
*.sqlite
|
||||
*.sqlite-*
|
||||
@@ -33,3 +34,6 @@ dist-ssr
|
||||
|
||||
.tmp
|
||||
tmp
|
||||
.zed
|
||||
codebook.toml
|
||||
target
|
||||
|
||||
1
.husky/post-checkout
Executable file
1
.husky/post-checkout
Executable file
@@ -0,0 +1 @@
|
||||
node scripts/git-hooks/post-checkout.mjs "$@"
|
||||
@@ -19,10 +19,10 @@
|
||||
|
||||
|
||||
<p align="center">
|
||||
<!-- sponsors-premium --><a href="https://github.com/MVST-Solutions"><img src="https://github.com/MVST-Solutions.png" width="80px" alt="User avatar: MVST-Solutions" /></a> <a href="https://github.com/dharsanb"><img src="https://github.com/dharsanb.png" width="80px" alt="User avatar: dharsanb" /></a> <a href="https://github.com/railwayapp"><img src="https://github.com/railwayapp.png" width="80px" alt="User avatar: railwayapp" /></a> <a href="https://github.com/caseyamcl"><img src="https://github.com/caseyamcl.png" width="80px" alt="User avatar: caseyamcl" /></a> <a href="https://github.com/"><img src="https://raw.githubusercontent.com/JamesIves/github-sponsors-readme-action/dev/.github/assets/placeholder.png" width="80px" alt="User avatar: " /></a> <!-- sponsors-premium -->
|
||||
<!-- sponsors-premium --><a href="https://github.com/MVST-Solutions"><img src="https://github.com/MVST-Solutions.png" width="80px" alt="User avatar: MVST-Solutions" /></a> <a href="https://github.com/dharsanb"><img src="https://github.com/dharsanb.png" width="80px" alt="User avatar: dharsanb" /></a> <a href="https://github.com/railwayapp"><img src="https://github.com/railwayapp.png" width="80px" alt="User avatar: railwayapp" /></a> <a href="https://github.com/caseyamcl"><img src="https://github.com/caseyamcl.png" width="80px" alt="User avatar: caseyamcl" /></a> <a href="https://github.com/bytebase"><img src="https://github.com/bytebase.png" width="80px" alt="User avatar: bytebase" /></a> <a href="https://github.com/"><img src="https://raw.githubusercontent.com/JamesIves/github-sponsors-readme-action/dev/.github/assets/placeholder.png" width="80px" alt="User avatar: " /></a> <!-- sponsors-premium -->
|
||||
</p>
|
||||
<p align="center">
|
||||
<!-- sponsors-base --><a href="https://github.com/seanwash"><img src="https://github.com/seanwash.png" width="50px" alt="User avatar: seanwash" /></a> <a href="https://github.com/jerath"><img src="https://github.com/jerath.png" width="50px" alt="User avatar: jerath" /></a> <a href="https://github.com/itsa-sh"><img src="https://github.com/itsa-sh.png" width="50px" alt="User avatar: itsa-sh" /></a> <a href="https://github.com/dmmulroy"><img src="https://github.com/dmmulroy.png" width="50px" alt="User avatar: dmmulroy" /></a> <a href="https://github.com/timcole"><img src="https://github.com/timcole.png" width="50px" alt="User avatar: timcole" /></a> <a href="https://github.com/VLZH"><img src="https://github.com/VLZH.png" width="50px" alt="User avatar: VLZH" /></a> <a href="https://github.com/terasaka2k"><img src="https://github.com/terasaka2k.png" width="50px" alt="User avatar: terasaka2k" /></a> <a href="https://github.com/andriyor"><img src="https://github.com/andriyor.png" width="50px" alt="User avatar: andriyor" /></a> <a href="https://github.com/majudhu"><img src="https://github.com/majudhu.png" width="50px" alt="User avatar: majudhu" /></a> <a href="https://github.com/axelrindle"><img src="https://github.com/axelrindle.png" width="50px" alt="User avatar: axelrindle" /></a> <a href="https://github.com/jirizverina"><img src="https://github.com/jirizverina.png" width="50px" alt="User avatar: jirizverina" /></a> <a href="https://github.com/chip-well"><img src="https://github.com/chip-well.png" width="50px" alt="User avatar: chip-well" /></a> <!-- sponsors-base -->
|
||||
<!-- sponsors-base --><a href="https://github.com/seanwash"><img src="https://github.com/seanwash.png" width="50px" alt="User avatar: seanwash" /></a> <a href="https://github.com/jerath"><img src="https://github.com/jerath.png" width="50px" alt="User avatar: jerath" /></a> <a href="https://github.com/itsa-sh"><img src="https://github.com/itsa-sh.png" width="50px" alt="User avatar: itsa-sh" /></a> <a href="https://github.com/dmmulroy"><img src="https://github.com/dmmulroy.png" width="50px" alt="User avatar: dmmulroy" /></a> <a href="https://github.com/timcole"><img src="https://github.com/timcole.png" width="50px" alt="User avatar: timcole" /></a> <a href="https://github.com/VLZH"><img src="https://github.com/VLZH.png" width="50px" alt="User avatar: VLZH" /></a> <a href="https://github.com/terasaka2k"><img src="https://github.com/terasaka2k.png" width="50px" alt="User avatar: terasaka2k" /></a> <a href="https://github.com/andriyor"><img src="https://github.com/andriyor.png" width="50px" alt="User avatar: andriyor" /></a> <a href="https://github.com/majudhu"><img src="https://github.com/majudhu.png" width="50px" alt="User avatar: majudhu" /></a> <a href="https://github.com/axelrindle"><img src="https://github.com/axelrindle.png" width="50px" alt="User avatar: axelrindle" /></a> <a href="https://github.com/jirizverina"><img src="https://github.com/jirizverina.png" width="50px" alt="User avatar: jirizverina" /></a> <a href="https://github.com/chip-well"><img src="https://github.com/chip-well.png" width="50px" alt="User avatar: chip-well" /></a> <a href="https://github.com/GRAYAH"><img src="https://github.com/GRAYAH.png" width="50px" alt="User avatar: GRAYAH" /></a> <!-- sponsors-base -->
|
||||
</p>
|
||||
|
||||

|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.3.7/schema.json",
|
||||
"$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
@@ -39,13 +39,13 @@
|
||||
"!**/dist",
|
||||
"!**/build",
|
||||
"!scripts",
|
||||
"!packages/plugin-runtime",
|
||||
"!packages/plugin-runtime-types",
|
||||
"!src-tauri",
|
||||
"!src-web/tailwind.config.cjs",
|
||||
"!src-web/postcss.config.cjs",
|
||||
"!src-web/vite.config.ts",
|
||||
"!src-web/routeTree.gen.ts"
|
||||
"!src-web/routeTree.gen.ts",
|
||||
"!packages/plugin-runtime-types/lib",
|
||||
"!**/bindings"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
6484
package-lock.json
generated
6484
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
13
package.json
13
package.json
@@ -10,8 +10,11 @@
|
||||
"packages/common-lib",
|
||||
"packages/plugin-runtime",
|
||||
"packages/plugin-runtime-types",
|
||||
"plugins-external/mcp-server",
|
||||
"plugins-external/template-function-faker",
|
||||
"plugins/action-copy-curl",
|
||||
"plugins/action-copy-grpcurl",
|
||||
"plugins/action-send-folder",
|
||||
"plugins/auth-apikey",
|
||||
"plugins/auth-aws",
|
||||
"plugins/auth-basic",
|
||||
@@ -59,9 +62,11 @@
|
||||
"src-web"
|
||||
],
|
||||
"scripts": {
|
||||
"prepare": "husky",
|
||||
"init": "npm install && npm run bootstrap",
|
||||
"start": "npm run app-dev",
|
||||
"app-build": "tauri build",
|
||||
"app-dev": "tauri dev --no-watch --config ./src-tauri/tauri.development.conf.json",
|
||||
"app-dev": "node scripts/run-dev.mjs",
|
||||
"migration": "node scripts/create-migration.cjs",
|
||||
"build": "npm run --workspaces --if-present build",
|
||||
"build-plugins": "npm run --workspaces --if-present build",
|
||||
@@ -87,9 +92,11 @@
|
||||
"tauri-before-dev": "workspaces-run --parallel -- npm run --workspaces --if-present dev"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "^2.3.7",
|
||||
"@tauri-apps/cli": "^2.9.1",
|
||||
"@biomejs/biome": "^2.3.10",
|
||||
"@tauri-apps/cli": "^2.9.6",
|
||||
"@yaakapp/cli": "^0.3.4",
|
||||
"dotenv-cli": "^11.0.0",
|
||||
"husky": "^9.1.7",
|
||||
"nodejs-file-downloader": "^4.13.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"typescript": "^5.8.3",
|
||||
|
||||
47
packages/plugin-runtime-types/package-lock.json
generated
47
packages/plugin-runtime-types/package-lock.json
generated
@@ -1,47 +0,0 @@
|
||||
{
|
||||
"name": "@yaakapp/api",
|
||||
"version": "0.1.17",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@yaakapp/api",
|
||||
"version": "0.1.17",
|
||||
"dependencies": {
|
||||
"@types/node": "^22.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.6.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.5.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz",
|
||||
"integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.2"
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
|
||||
"integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.19.8",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
||||
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,18 +1,53 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type AnyModel = CookieJar | Environment | Folder | GraphQlIntrospection | GrpcConnection | GrpcEvent | GrpcRequest | HttpRequest | HttpResponse | HttpResponseEvent | KeyValue | Plugin | Settings | SyncState | WebsocketConnection | WebsocketEvent | WebsocketRequest | Workspace | WorkspaceMeta;
|
||||
|
||||
export type ClientCertificate = { host: string, port: number | null, crtFile: string | null, keyFile: string | null, pfxFile: string | null, passphrase: string | null, enabled?: boolean, };
|
||||
|
||||
export type Cookie = { raw_cookie: string, domain: CookieDomain, expires: CookieExpires, path: [string, boolean], };
|
||||
|
||||
export type CookieDomain = { "HostOnly": string } | { "Suffix": string } | "NotPresent" | "Empty";
|
||||
|
||||
export type CookieExpires = { "AtUtc": string } | "SessionEnd";
|
||||
|
||||
export type CookieJar = { model: "cookie_jar", id: string, createdAt: string, updatedAt: string, workspaceId: string, cookies: Array<Cookie>, name: string, };
|
||||
|
||||
export type EditorKeymap = "default" | "vim" | "vscode" | "emacs";
|
||||
|
||||
export type EncryptedKey = { encryptedKey: string, };
|
||||
|
||||
export type Environment = { model: "environment", id: string, workspaceId: string, createdAt: string, updatedAt: string, name: string, public: boolean, parentModel: string, parentId: string | null, variables: Array<EnvironmentVariable>, color: string | null, sortPriority: number, };
|
||||
|
||||
export type EnvironmentVariable = { enabled?: boolean, name: string, value: string, id?: string, };
|
||||
|
||||
export type Folder = { model: "folder", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record<string, any>, authenticationType: string | null, description: string, headers: Array<HttpRequestHeader>, name: string, sortPriority: number, };
|
||||
|
||||
export type GraphQlIntrospection = { model: "graphql_introspection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, content: string | null, };
|
||||
|
||||
export type GrpcConnection = { model: "grpc_connection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, elapsed: number, error: string | null, method: string, service: string, status: number, state: GrpcConnectionState, trailers: { [key in string]?: string }, url: string, };
|
||||
|
||||
export type GrpcConnectionState = "initialized" | "connected" | "closed";
|
||||
|
||||
export type GrpcEvent = { model: "grpc_event", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, connectionId: string, content: string, error: string | null, eventType: GrpcEventType, metadata: { [key in string]?: string }, status: number | null, };
|
||||
|
||||
export type GrpcEventType = "info" | "error" | "client_message" | "server_message" | "connection_start" | "connection_end";
|
||||
|
||||
export type GrpcRequest = { model: "grpc_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authenticationType: string | null, authentication: Record<string, any>, description: string, message: string, metadata: Array<HttpRequestHeader>, method: string | null, name: string, service: string | null, sortPriority: number, url: string, };
|
||||
|
||||
export type HttpRequest = { model: "http_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record<string, any>, authenticationType: string | null, body: Record<string, any>, bodyType: string | null, description: string, headers: Array<HttpRequestHeader>, method: string, name: string, sortPriority: number, url: string, urlParameters: Array<HttpUrlParameter>, };
|
||||
|
||||
export type HttpRequestHeader = { enabled?: boolean, name: string, value: string, id?: string, };
|
||||
|
||||
export type HttpResponse = { model: "http_response", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, bodyPath: string | null, contentLength: number | null, elapsed: number, elapsedHeaders: number, error: string | null, headers: Array<HttpResponseHeader>, remoteAddr: string | null, status: number, statusReason: string | null, state: HttpResponseState, url: string, version: string | null, };
|
||||
export type HttpResponse = { model: "http_response", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, bodyPath: string | null, contentLength: number | null, contentLengthCompressed: number | null, elapsed: number, elapsedHeaders: number, error: string | null, headers: Array<HttpResponseHeader>, remoteAddr: string | null, requestContentLength: number | null, requestHeaders: Array<HttpResponseHeader>, status: number, statusReason: string | null, state: HttpResponseState, url: string, version: string | null, };
|
||||
|
||||
export type HttpResponseEvent = { model: "http_response_event", id: string, createdAt: string, updatedAt: string, workspaceId: string, responseId: string, event: HttpResponseEventData, };
|
||||
|
||||
/**
|
||||
* Serializable representation of HTTP response events for DB storage.
|
||||
* This mirrors `yaak_http::sender::HttpResponseEvent` but with serde support.
|
||||
* The `From` impl is in yaak-http to avoid circular dependencies.
|
||||
*/
|
||||
export type HttpResponseEventData = { "type": "setting", name: string, value: string, } | { "type": "info", message: string, } | { "type": "redirect", url: string, status: number, behavior: string, } | { "type": "send_url", method: string, path: string, } | { "type": "receive_url", version: string, status: string, } | { "type": "header_up", name: string, value: string, } | { "type": "header_down", name: string, value: string, } | { "type": "chunk_sent", bytes: number, } | { "type": "chunk_received", bytes: number, };
|
||||
|
||||
export type HttpResponseHeader = { name: string, value: string, };
|
||||
|
||||
@@ -20,6 +55,28 @@ export type HttpResponseState = "initialized" | "connected" | "closed";
|
||||
|
||||
export type HttpUrlParameter = { enabled?: boolean, name: string, value: string, id?: string, };
|
||||
|
||||
export type KeyValue = { model: "key_value", id: string, createdAt: string, updatedAt: string, key: string, namespace: string, value: string, };
|
||||
|
||||
export type Plugin = { model: "plugin", id: string, createdAt: string, updatedAt: string, checkedAt: string | null, directory: string, enabled: boolean, url: string | null, };
|
||||
|
||||
export type ProxySetting = { "type": "enabled", http: string, https: string, auth: ProxySettingAuth | null, bypass: string, disabled: boolean, } | { "type": "disabled" };
|
||||
|
||||
export type ProxySettingAuth = { user: string, password: string, };
|
||||
|
||||
export type Settings = { model: "settings", id: string, createdAt: string, updatedAt: string, appearance: string, clientCertificates: Array<ClientCertificate>, coloredMethods: boolean, editorFont: string | null, editorFontSize: number, editorKeymap: EditorKeymap, editorSoftWrap: boolean, hideWindowControls: boolean, useNativeTitlebar: boolean, interfaceFont: string | null, interfaceFontSize: number, interfaceScale: number, openWorkspaceNewWindow: boolean | null, proxy: ProxySetting | null, themeDark: string, themeLight: string, updateChannel: string, hideLicenseBadge: boolean, autoupdate: boolean, autoDownloadUpdates: boolean, checkNotifications: boolean, };
|
||||
|
||||
export type SyncState = { model: "sync_state", id: string, workspaceId: string, createdAt: string, updatedAt: string, flushedAt: string, modelId: string, checksum: string, relPath: string, syncDir: string, };
|
||||
|
||||
export type WebsocketConnection = { model: "websocket_connection", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, elapsed: number, error: string | null, headers: Array<HttpResponseHeader>, state: WebsocketConnectionState, status: number, url: string, };
|
||||
|
||||
export type WebsocketConnectionState = "initialized" | "connected" | "closing" | "closed";
|
||||
|
||||
export type WebsocketEvent = { model: "websocket_event", id: string, createdAt: string, updatedAt: string, workspaceId: string, requestId: string, connectionId: string, isServer: boolean, message: Array<number>, messageType: WebsocketEventType, };
|
||||
|
||||
export type WebsocketEventType = "binary" | "close" | "frame" | "open" | "ping" | "pong" | "text";
|
||||
|
||||
export type WebsocketRequest = { model: "websocket_request", id: string, createdAt: string, updatedAt: string, workspaceId: string, folderId: string | null, authentication: Record<string, any>, authenticationType: string | null, description: string, headers: Array<HttpRequestHeader>, message: string, name: string, sortPriority: number, url: string, urlParameters: Array<HttpUrlParameter>, };
|
||||
|
||||
export type Workspace = { model: "workspace", id: string, createdAt: string, updatedAt: string, authentication: Record<string, any>, authenticationType: string | null, description: string, headers: Array<HttpRequestHeader>, name: string, encryptionKeyChallenge: string | null, settingValidateCertificates: boolean, settingFollowRedirects: boolean, settingRequestTimeout: number, };
|
||||
|
||||
export type WorkspaceMeta = { model: "workspace_meta", id: string, workspaceId: string, createdAt: string, updatedAt: string, encryptionKey: EncryptedKey | null, settingSyncDir: string | null, };
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {
|
||||
import type {
|
||||
CallHttpAuthenticationActionArgs,
|
||||
CallHttpAuthenticationRequest,
|
||||
CallHttpAuthenticationResponse,
|
||||
@@ -6,8 +6,8 @@ import {
|
||||
GetHttpAuthenticationSummaryResponse,
|
||||
HttpAuthenticationAction,
|
||||
} from '../bindings/gen_events';
|
||||
import { MaybePromise } from '../helpers';
|
||||
import { Context } from './Context';
|
||||
import type { MaybePromise } from '../helpers';
|
||||
import type { Context } from './Context';
|
||||
|
||||
type AddDynamicMethod<T> = {
|
||||
dynamic?: (
|
||||
@@ -16,6 +16,7 @@ type AddDynamicMethod<T> = {
|
||||
) => MaybePromise<Partial<T> | null | undefined>;
|
||||
};
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: distributive conditional type pattern
|
||||
type AddDynamic<T> = T extends any
|
||||
? T extends { inputs?: FormInput[] }
|
||||
? Omit<T, 'inputs'> & {
|
||||
|
||||
@@ -1,25 +1,33 @@
|
||||
import type {
|
||||
FindHttpResponsesRequest,
|
||||
FindHttpResponsesResponse,
|
||||
GetCookieValueRequest,
|
||||
GetCookieValueResponse,
|
||||
GetHttpRequestByIdRequest,
|
||||
GetHttpRequestByIdResponse,
|
||||
ListCookieNamesResponse,
|
||||
OpenWindowRequest,
|
||||
PromptTextRequest,
|
||||
PromptTextResponse,
|
||||
RenderGrpcRequestRequest,
|
||||
RenderGrpcRequestResponse,
|
||||
RenderHttpRequestRequest,
|
||||
RenderHttpRequestResponse,
|
||||
SendHttpRequestRequest,
|
||||
SendHttpRequestResponse,
|
||||
ShowToastRequest,
|
||||
TemplateRenderRequest,
|
||||
FindHttpResponsesRequest,
|
||||
FindHttpResponsesResponse,
|
||||
GetCookieValueRequest,
|
||||
GetCookieValueResponse,
|
||||
GetHttpRequestByIdRequest,
|
||||
GetHttpRequestByIdResponse,
|
||||
ListCookieNamesResponse,
|
||||
ListFoldersRequest,
|
||||
ListFoldersResponse,
|
||||
ListHttpRequestsRequest,
|
||||
ListHttpRequestsResponse,
|
||||
OpenWindowRequest,
|
||||
PromptTextRequest,
|
||||
PromptTextResponse,
|
||||
RenderGrpcRequestRequest,
|
||||
RenderGrpcRequestResponse,
|
||||
RenderHttpRequestRequest,
|
||||
RenderHttpRequestResponse,
|
||||
SendHttpRequestRequest,
|
||||
SendHttpRequestResponse,
|
||||
ShowToastRequest,
|
||||
TemplateRenderRequest,
|
||||
WorkspaceInfo,
|
||||
} from '../bindings/gen_events.ts';
|
||||
import type { HttpRequest } from '../bindings/gen_models.ts';
|
||||
import type { JsonValue } from '../bindings/serde_json/JsonValue';
|
||||
|
||||
export type WorkspaceHandle = Pick<WorkspaceInfo, 'id' | 'name'>;
|
||||
|
||||
export interface Context {
|
||||
clipboard: {
|
||||
copyText(text: string): Promise<void>;
|
||||
@@ -45,6 +53,7 @@ export interface Context {
|
||||
onClose?: () => void;
|
||||
},
|
||||
): Promise<{ close: () => void }>;
|
||||
openExternalUrl(url: string): Promise<void>;
|
||||
};
|
||||
cookies: {
|
||||
listNames(): Promise<ListCookieNamesResponse['names']>;
|
||||
@@ -57,6 +66,19 @@ export interface Context {
|
||||
send(args: SendHttpRequestRequest): Promise<SendHttpRequestResponse['httpResponse']>;
|
||||
getById(args: GetHttpRequestByIdRequest): Promise<GetHttpRequestByIdResponse['httpRequest']>;
|
||||
render(args: RenderHttpRequestRequest): Promise<RenderHttpRequestResponse['httpRequest']>;
|
||||
list(args?: ListHttpRequestsRequest): Promise<ListHttpRequestsResponse['httpRequests']>;
|
||||
create(
|
||||
args: Omit<Partial<HttpRequest>, 'id' | 'model' | 'createdAt' | 'updatedAt'> &
|
||||
Pick<HttpRequest, 'workspaceId' | 'url'>,
|
||||
): Promise<HttpRequest>;
|
||||
update(
|
||||
args: Omit<Partial<HttpRequest>, 'model' | 'createdAt' | 'updatedAt'> &
|
||||
Pick<HttpRequest, 'id'>,
|
||||
): Promise<HttpRequest>;
|
||||
delete(args: { id: string }): Promise<HttpRequest>;
|
||||
};
|
||||
folder: {
|
||||
list(args?: ListFoldersRequest): Promise<ListFoldersResponse['folders']>;
|
||||
};
|
||||
httpResponse: {
|
||||
find(args: FindHttpResponsesRequest): Promise<FindHttpResponsesResponse['httpResponses']>;
|
||||
@@ -67,4 +89,8 @@ export interface Context {
|
||||
plugin: {
|
||||
reload(): void;
|
||||
};
|
||||
workspace: {
|
||||
list(): Promise<WorkspaceHandle[]>;
|
||||
withContext(handle: WorkspaceHandle): Context;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FilterResponse } from '../bindings/gen_events';
|
||||
import type { FilterResponse } from '../bindings/gen_events';
|
||||
import type { Context } from './Context';
|
||||
|
||||
export type FilterPlugin = {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { CallFolderActionArgs, FolderAction } from '../bindings/gen_events';
|
||||
import type { Context } from './Context';
|
||||
|
||||
export type FolderActionPlugin = FolderAction & {
|
||||
onSelect(ctx: Context, args: CallFolderActionArgs): Promise<void> | void;
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CallGrpcRequestActionArgs, GrpcRequestAction } from '../bindings/gen_events';
|
||||
import type { CallGrpcRequestActionArgs, GrpcRequestAction } from '../bindings/gen_events';
|
||||
import type { Context } from './Context';
|
||||
|
||||
export type GrpcRequestActionPlugin = GrpcRequestAction & {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ImportResources } from '../bindings/gen_events';
|
||||
import { AtLeast, MaybePromise } from '../helpers';
|
||||
import type { ImportResources } from '../bindings/gen_events';
|
||||
import type { AtLeast, MaybePromise } from '../helpers';
|
||||
import type { Context } from './Context';
|
||||
|
||||
type RootFields = 'name' | 'id' | 'model';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CallTemplateFunctionArgs, FormInput, TemplateFunction } from '../bindings/gen_events';
|
||||
import { MaybePromise } from '../helpers';
|
||||
import { Context } from './Context';
|
||||
import type { CallTemplateFunctionArgs, FormInput, TemplateFunction } from '../bindings/gen_events';
|
||||
import type { MaybePromise } from '../helpers';
|
||||
import type { Context } from './Context';
|
||||
|
||||
type AddDynamicMethod<T> = {
|
||||
dynamic?: (
|
||||
@@ -9,6 +9,7 @@ type AddDynamicMethod<T> = {
|
||||
) => MaybePromise<Partial<T> | null | undefined>;
|
||||
};
|
||||
|
||||
// biome-ignore lint/suspicious/noExplicitAny: distributive conditional type pattern
|
||||
type AddDynamic<T> = T extends any
|
||||
? T extends { inputs?: FormInput[] }
|
||||
? Omit<T, 'inputs'> & {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
import { Theme } from '../bindings/gen_events';
|
||||
import type { Theme } from '../bindings/gen_events';
|
||||
|
||||
export type ThemePlugin = Theme;
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { CallWebsocketRequestActionArgs, WebsocketRequestAction } from '../bindings/gen_events';
|
||||
import type { Context } from './Context';
|
||||
|
||||
export type WebsocketRequestActionPlugin = WebsocketRequestAction & {
|
||||
onSelect(ctx: Context, args: CallWebsocketRequestActionArgs): Promise<void> | void;
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
import type { CallWorkspaceActionArgs, WorkspaceAction } from '../bindings/gen_events';
|
||||
import type { Context } from './Context';
|
||||
|
||||
export type WorkspaceActionPlugin = WorkspaceAction & {
|
||||
onSelect(ctx: Context, args: CallWorkspaceActionArgs): Promise<void> | void;
|
||||
};
|
||||
@@ -1,9 +1,12 @@
|
||||
import { AuthenticationPlugin } from './AuthenticationPlugin';
|
||||
import type { AuthenticationPlugin } from './AuthenticationPlugin';
|
||||
|
||||
import type { Context } from './Context';
|
||||
import type { FilterPlugin } from './FilterPlugin';
|
||||
import { GrpcRequestActionPlugin } from './GrpcRequestActionPlugin';
|
||||
import type { GrpcRequestActionPlugin } from './GrpcRequestActionPlugin';
|
||||
import type { HttpRequestActionPlugin } from './HttpRequestActionPlugin';
|
||||
import type { WebsocketRequestActionPlugin } from './WebsocketRequestActionPlugin';
|
||||
import type { WorkspaceActionPlugin } from './WorkspaceActionPlugin';
|
||||
import type { FolderActionPlugin } from './FolderActionPlugin';
|
||||
import type { ImporterPlugin } from './ImporterPlugin';
|
||||
import type { TemplateFunctionPlugin } from './TemplateFunctionPlugin';
|
||||
import type { ThemePlugin } from './ThemePlugin';
|
||||
@@ -12,6 +15,8 @@ export type { Context };
|
||||
export type { DynamicTemplateFunctionArg } from './TemplateFunctionPlugin';
|
||||
export type { DynamicAuthenticationArg } from './AuthenticationPlugin';
|
||||
export type { TemplateFunctionPlugin };
|
||||
export type { WorkspaceActionPlugin } from './WorkspaceActionPlugin';
|
||||
export type { FolderActionPlugin } from './FolderActionPlugin';
|
||||
|
||||
/**
|
||||
* The global structure of a Yaak plugin
|
||||
@@ -24,6 +29,9 @@ export type PluginDefinition = {
|
||||
filter?: FilterPlugin;
|
||||
authentication?: AuthenticationPlugin;
|
||||
httpRequestActions?: HttpRequestActionPlugin[];
|
||||
websocketRequestActions?: WebsocketRequestActionPlugin[];
|
||||
workspaceActions?: WorkspaceActionPlugin[];
|
||||
folderActions?: FolderActionPlugin[];
|
||||
grpcRequestActions?: GrpcRequestActionPlugin[];
|
||||
templateFunctions?: TemplateFunctionPlugin[];
|
||||
};
|
||||
|
||||
10
packages/plugin-runtime/package-lock.json
generated
10
packages/plugin-runtime/package-lock.json
generated
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "@yaakapp-internal/plugin-runtime",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@yaakapp-internal/plugin-runtime"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { PluginContext } from '@yaakapp-internal/plugins';
|
||||
import type { BootRequest, InternalEvent } from '@yaakapp/api';
|
||||
import type { PluginContext } from '@yaakapp-internal/plugins';
|
||||
import type { EventChannel } from './EventChannel';
|
||||
import { PluginInstance, PluginWorkerData } from './PluginInstance';
|
||||
import { PluginInstance, type PluginWorkerData } from './PluginInstance';
|
||||
|
||||
export class PluginHandle {
|
||||
#instance: PluginInstance;
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import { applyFormInputDefaults, validateTemplateFunctionArgs } from '@yaakapp-internal/lib/templateFunction';
|
||||
import console from 'node:console';
|
||||
import { type Stats, statSync, watch } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import type { Context, PluginDefinition } from '@yaakapp/api';
|
||||
import {
|
||||
applyFormInputDefaults,
|
||||
validateTemplateFunctionArgs,
|
||||
} from '@yaakapp-internal/lib/templateFunction';
|
||||
import type {
|
||||
BootRequest,
|
||||
DeleteKeyValueResponse,
|
||||
DeleteModelResponse,
|
||||
FindHttpResponsesResponse,
|
||||
GetCookieValueRequest,
|
||||
GetCookieValueResponse,
|
||||
@@ -9,23 +17,27 @@ import {
|
||||
GetKeyValueResponse,
|
||||
GrpcRequestAction,
|
||||
HttpAuthenticationAction,
|
||||
HttpRequest,
|
||||
HttpRequestAction,
|
||||
ImportResources,
|
||||
InternalEvent,
|
||||
InternalEventPayload,
|
||||
ListCookieNamesResponse,
|
||||
ListFoldersResponse,
|
||||
ListHttpRequestsRequest,
|
||||
ListHttpRequestsResponse,
|
||||
ListWorkspacesResponse,
|
||||
PluginContext,
|
||||
PromptTextResponse,
|
||||
RenderGrpcRequestResponse,
|
||||
RenderHttpRequestResponse,
|
||||
SendHttpRequestResponse,
|
||||
TemplateFunction,
|
||||
TemplateRenderRequest,
|
||||
TemplateRenderResponse,
|
||||
UpsertModelResponse,
|
||||
WindowInfoResponse,
|
||||
} from '@yaakapp-internal/plugins';
|
||||
import { Context, PluginDefinition } from '@yaakapp/api';
|
||||
import console from 'node:console';
|
||||
import { type Stats, statSync, watch } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { applyDynamicFormInput } from './common';
|
||||
import { EventChannel } from './EventChannel';
|
||||
import { migrateTemplateFunctionSelectOptions } from './migrations';
|
||||
@@ -52,20 +64,30 @@ export class PluginInstance {
|
||||
await this.#onMessage(event);
|
||||
});
|
||||
|
||||
this.#mod = {} as any;
|
||||
this.#mod = {};
|
||||
|
||||
const fileChangeCallback = async () => {
|
||||
await this.#mod?.dispose?.();
|
||||
this.#importModule();
|
||||
await this.#mod?.init?.(this.#newCtx(workerData.context));
|
||||
return this.#sendPayload(
|
||||
workerData.context,
|
||||
{
|
||||
type: 'reload_response',
|
||||
silent: false,
|
||||
},
|
||||
null,
|
||||
);
|
||||
const ctx = this.#newCtx(workerData.context);
|
||||
try {
|
||||
await this.#mod?.init?.(ctx);
|
||||
this.#sendPayload(
|
||||
workerData.context,
|
||||
{
|
||||
type: 'reload_response',
|
||||
silent: false,
|
||||
},
|
||||
null,
|
||||
);
|
||||
} catch (err: unknown) {
|
||||
ctx.toast.show({
|
||||
message: `Failed to initialize plugin ${this.#workerData.bootRequest.dir.split('/').pop()}: ${err}`,
|
||||
color: 'notice',
|
||||
icon: 'alert_triangle',
|
||||
timeout: 30000,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (this.#workerData.bootRequest.watch) {
|
||||
@@ -116,8 +138,7 @@ export class PluginInstance {
|
||||
if (reply != null) {
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'import_response',
|
||||
// deno-lint-ignore no-explicit-any
|
||||
resources: reply.resources as any,
|
||||
resources: reply.resources as ImportResources,
|
||||
};
|
||||
this.#sendPayload(context, replyPayload, replyId);
|
||||
return;
|
||||
@@ -172,6 +193,57 @@ export class PluginInstance {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'get_websocket_request_actions_request' &&
|
||||
Array.isArray(this.#mod?.websocketRequestActions)
|
||||
) {
|
||||
const reply = this.#mod.websocketRequestActions.map((a) => ({
|
||||
...a,
|
||||
onSelect: undefined,
|
||||
}));
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_websocket_request_actions_response',
|
||||
pluginRefId: this.#workerData.pluginRefId,
|
||||
actions: reply,
|
||||
};
|
||||
this.#sendPayload(context, replyPayload, replyId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'get_workspace_actions_request' &&
|
||||
Array.isArray(this.#mod?.workspaceActions)
|
||||
) {
|
||||
const reply = this.#mod.workspaceActions.map((a) => ({
|
||||
...a,
|
||||
onSelect: undefined,
|
||||
}));
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_workspace_actions_response',
|
||||
pluginRefId: this.#workerData.pluginRefId,
|
||||
actions: reply,
|
||||
};
|
||||
this.#sendPayload(context, replyPayload, replyId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'get_folder_actions_request' &&
|
||||
Array.isArray(this.#mod?.folderActions)
|
||||
) {
|
||||
const reply = this.#mod.folderActions.map((a) => ({
|
||||
...a,
|
||||
onSelect: undefined,
|
||||
}));
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_folder_actions_response',
|
||||
pluginRefId: this.#workerData.pluginRefId,
|
||||
actions: reply,
|
||||
};
|
||||
this.#sendPayload(context, replyPayload, replyId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (payload.type === 'get_themes_request' && Array.isArray(this.#mod?.themes)) {
|
||||
const replyPayload: InternalEventPayload = {
|
||||
type: 'get_themes_response',
|
||||
@@ -207,7 +279,7 @@ export class PluginInstance {
|
||||
payload.type === 'get_template_function_config_request' &&
|
||||
Array.isArray(this.#mod?.templateFunctions)
|
||||
) {
|
||||
let templateFunction = this.#mod.templateFunctions.find((f) => f.name === payload.name);
|
||||
const templateFunction = this.#mod.templateFunctions.find((f) => f.name === payload.name);
|
||||
if (templateFunction == null) {
|
||||
this.#sendEmpty(context, replyId);
|
||||
return;
|
||||
@@ -302,6 +374,39 @@ export class PluginInstance {
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'call_websocket_request_action_request' &&
|
||||
Array.isArray(this.#mod.websocketRequestActions)
|
||||
) {
|
||||
const action = this.#mod.websocketRequestActions[payload.index];
|
||||
if (typeof action?.onSelect === 'function') {
|
||||
await action.onSelect(ctx, payload.args);
|
||||
this.#sendEmpty(context, replyId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'call_workspace_action_request' &&
|
||||
Array.isArray(this.#mod.workspaceActions)
|
||||
) {
|
||||
const action = this.#mod.workspaceActions[payload.index];
|
||||
if (typeof action?.onSelect === 'function') {
|
||||
await action.onSelect(ctx, payload.args);
|
||||
this.#sendEmpty(context, replyId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (payload.type === 'call_folder_action_request' && Array.isArray(this.#mod.folderActions)) {
|
||||
const action = this.#mod.folderActions[payload.index];
|
||||
if (typeof action?.onSelect === 'function') {
|
||||
await action.onSelect(ctx, payload.args);
|
||||
this.#sendEmpty(context, replyId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
payload.type === 'call_grpc_request_action_request' &&
|
||||
Array.isArray(this.#mod.grpcRequestActions)
|
||||
@@ -541,6 +646,12 @@ export class PluginInstance {
|
||||
},
|
||||
};
|
||||
},
|
||||
openExternalUrl: async (url) => {
|
||||
await this.#sendForReply(context, {
|
||||
type: 'open_external_url_request',
|
||||
url,
|
||||
});
|
||||
},
|
||||
},
|
||||
prompt: {
|
||||
text: async (args) => {
|
||||
@@ -611,6 +722,58 @@ export class PluginInstance {
|
||||
);
|
||||
return httpRequest;
|
||||
},
|
||||
list: async (args?: { folderId?: string }) => {
|
||||
const payload: InternalEventPayload = {
|
||||
type: 'list_http_requests_request',
|
||||
folderId: args?.folderId,
|
||||
} satisfies ListHttpRequestsRequest & { type: 'list_http_requests_request' };
|
||||
const { httpRequests } = await this.#sendForReply<ListHttpRequestsResponse>(
|
||||
context,
|
||||
payload,
|
||||
);
|
||||
return httpRequests;
|
||||
},
|
||||
create: async (args) => {
|
||||
const payload = {
|
||||
type: 'upsert_model_request',
|
||||
model: {
|
||||
name: '',
|
||||
method: 'GET',
|
||||
...args,
|
||||
id: '',
|
||||
model: 'http_request',
|
||||
},
|
||||
} as InternalEventPayload;
|
||||
const response = await this.#sendForReply<UpsertModelResponse>(context, payload);
|
||||
return response.model as HttpRequest;
|
||||
},
|
||||
update: async (args) => {
|
||||
const payload = {
|
||||
type: 'upsert_model_request',
|
||||
model: {
|
||||
model: 'http_request',
|
||||
...args,
|
||||
},
|
||||
} as InternalEventPayload;
|
||||
const response = await this.#sendForReply<UpsertModelResponse>(context, payload);
|
||||
return response.model as HttpRequest;
|
||||
},
|
||||
delete: async (args) => {
|
||||
const payload = {
|
||||
type: 'delete_model_request',
|
||||
model: 'http_request',
|
||||
id: args.id,
|
||||
} as InternalEventPayload;
|
||||
const response = await this.#sendForReply<DeleteModelResponse>(context, payload);
|
||||
return response.model as HttpRequest;
|
||||
},
|
||||
},
|
||||
folder: {
|
||||
list: async () => {
|
||||
const payload = { type: 'list_folders_request' } as const;
|
||||
const { folders } = await this.#sendForReply<ListFoldersResponse>(context, payload);
|
||||
return folders;
|
||||
},
|
||||
},
|
||||
cookies: {
|
||||
getValue: async (args: GetCookieValueRequest) => {
|
||||
@@ -632,9 +795,10 @@ export class PluginInstance {
|
||||
* Invoke Yaak's template engine to render a value. If the value is a nested type
|
||||
* (eg. object), it will be recursively rendered.
|
||||
*/
|
||||
render: async (args) => {
|
||||
render: async (args: TemplateRenderRequest) => {
|
||||
const payload = { type: 'template_render_request', ...args } as const;
|
||||
const result = await this.#sendForReply<TemplateRenderResponse>(context, payload);
|
||||
// biome-ignore lint/suspicious/noExplicitAny: That's okay
|
||||
return result.data as any;
|
||||
},
|
||||
},
|
||||
@@ -664,6 +828,33 @@ export class PluginInstance {
|
||||
this.#sendPayload(context, { type: 'reload_response', silent: true }, null);
|
||||
},
|
||||
},
|
||||
workspace: {
|
||||
list: async () => {
|
||||
const payload = {
|
||||
type: 'list_workspaces_request',
|
||||
} as InternalEventPayload;
|
||||
const response = await this.#sendForReply<ListWorkspacesResponse>(context, payload);
|
||||
return response.workspaces.map((w) => {
|
||||
// Internal workspace info includes label field not in public API
|
||||
type WorkspaceInfoInternal = typeof w & { label?: string };
|
||||
return {
|
||||
id: w.id,
|
||||
name: w.name,
|
||||
// Hide label from plugin authors, but keep it for internal routing
|
||||
_label: (w as WorkspaceInfoInternal).label as string,
|
||||
};
|
||||
});
|
||||
},
|
||||
withContext: (workspaceHandle: { id: string; name: string; _label?: string }) => {
|
||||
// Create a new context with the workspace's window label
|
||||
const newContext: PluginContext = {
|
||||
...context,
|
||||
label: workspaceHandle._label || null,
|
||||
workspaceId: workspaceHandle.id,
|
||||
};
|
||||
return this.#newCtx(newContext);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { CallHttpAuthenticationActionArgs, CallTemplateFunctionArgs } from '@yaakapp-internal/plugins';
|
||||
import { Context, DynamicAuthenticationArg, DynamicTemplateFunctionArg } from '@yaakapp/api';
|
||||
import type { Context, DynamicAuthenticationArg, DynamicTemplateFunctionArg } from '@yaakapp/api';
|
||||
import type {
|
||||
CallHttpAuthenticationActionArgs,
|
||||
CallTemplateFunctionArgs,
|
||||
} from '@yaakapp-internal/plugins';
|
||||
|
||||
export async function applyDynamicFormInput(
|
||||
ctx: Context,
|
||||
@@ -18,15 +21,28 @@ export async function applyDynamicFormInput(
|
||||
args: (DynamicTemplateFunctionArg | DynamicAuthenticationArg)[],
|
||||
callArgs: CallTemplateFunctionArgs | CallHttpAuthenticationActionArgs,
|
||||
): Promise<(DynamicTemplateFunctionArg | DynamicAuthenticationArg)[]> {
|
||||
const resolvedArgs: any[] = [];
|
||||
const resolvedArgs: (DynamicTemplateFunctionArg | DynamicAuthenticationArg)[] = [];
|
||||
for (const { dynamic, ...arg } of args) {
|
||||
const newArg: any = {
|
||||
const dynamicResult =
|
||||
typeof dynamic === 'function'
|
||||
? await dynamic(
|
||||
ctx,
|
||||
callArgs as CallTemplateFunctionArgs & CallHttpAuthenticationActionArgs,
|
||||
)
|
||||
: undefined;
|
||||
|
||||
const newArg = {
|
||||
...arg,
|
||||
...(typeof dynamic === 'function' ? await dynamic(ctx, callArgs as any) : undefined),
|
||||
};
|
||||
...dynamicResult,
|
||||
} as DynamicTemplateFunctionArg | DynamicAuthenticationArg;
|
||||
|
||||
if ('inputs' in newArg && Array.isArray(newArg.inputs)) {
|
||||
try {
|
||||
newArg.inputs = await applyDynamicFormInput(ctx, newArg.inputs, callArgs as any);
|
||||
newArg.inputs = await applyDynamicFormInput(
|
||||
ctx,
|
||||
newArg.inputs as DynamicTemplateFunctionArg[],
|
||||
callArgs as CallTemplateFunctionArgs & CallHttpAuthenticationActionArgs,
|
||||
);
|
||||
} catch (e) {
|
||||
console.error('Failed to apply dynamic form input', e);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import type { InternalEvent } from '@yaakapp/api';
|
||||
import WebSocket from 'ws';
|
||||
import { EventChannel } from './EventChannel';
|
||||
import { PluginHandle } from './PluginHandle';
|
||||
import WebSocket from 'ws';
|
||||
|
||||
const port = process.env.PORT;
|
||||
if (!port) {
|
||||
throw new Error('Plugin runtime missing PORT')
|
||||
throw new Error('Plugin runtime missing PORT');
|
||||
}
|
||||
|
||||
const host = process.env.HOST;
|
||||
if (!host) {
|
||||
throw new Error('Plugin runtime missing HOST')
|
||||
throw new Error('Plugin runtime missing HOST');
|
||||
}
|
||||
|
||||
const pluginToAppEvents = new EventChannel();
|
||||
@@ -26,7 +26,7 @@ ws.on('message', async (e: Buffer) => {
|
||||
}
|
||||
});
|
||||
ws.on('open', () => console.log('Plugin runtime connected to websocket'));
|
||||
ws.on('error', (err: any) => console.error('Plugin runtime websocket error', err));
|
||||
ws.on('error', (err: unknown) => console.error('Plugin runtime websocket error', err));
|
||||
ws.on('close', (code: number) => console.log('Plugin runtime websocket closed', code));
|
||||
|
||||
// Listen for incoming events from plugins
|
||||
@@ -39,7 +39,12 @@ async function handleIncoming(msg: string) {
|
||||
const pluginEvent: InternalEvent = JSON.parse(msg);
|
||||
// Handle special event to bootstrap plugin
|
||||
if (pluginEvent.payload.type === 'boot_request') {
|
||||
const plugin = new PluginHandle(pluginEvent.pluginRefId, pluginEvent.context, pluginEvent.payload, pluginToAppEvents);
|
||||
const plugin = new PluginHandle(
|
||||
pluginEvent.pluginRefId,
|
||||
pluginEvent.context,
|
||||
pluginEvent.payload,
|
||||
pluginToAppEvents,
|
||||
);
|
||||
plugins[pluginEvent.pluginRefId] = plugin;
|
||||
}
|
||||
|
||||
@@ -62,3 +67,7 @@ async function handleIncoming(msg: string) {
|
||||
process.on('unhandledRejection', (reason, promise) => {
|
||||
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
||||
});
|
||||
|
||||
process.on('uncaughtException', (error) => {
|
||||
console.error('Uncaught Exception:', error);
|
||||
});
|
||||
|
||||
@@ -1,28 +1,20 @@
|
||||
import process from "node:process";
|
||||
import process from 'node:process';
|
||||
|
||||
export function interceptStdout(
|
||||
intercept: (text: string) => string,
|
||||
) {
|
||||
export function interceptStdout(intercept: (text: string) => string) {
|
||||
const old_stdout_write = process.stdout.write;
|
||||
const old_stderr_write = process.stderr.write;
|
||||
|
||||
process.stdout.write = (function (write) {
|
||||
return function (text: string) {
|
||||
arguments[0] = interceptor(text, intercept);
|
||||
// deno-lint-ignore no-explicit-any
|
||||
write.apply(process.stdout, arguments as any);
|
||||
process.stdout.write = ((write) =>
|
||||
((text: string, ...args: never[]) => {
|
||||
write.call(process.stdout, interceptor(text, intercept), ...args);
|
||||
return true;
|
||||
};
|
||||
})(process.stdout.write);
|
||||
}) as typeof process.stdout.write)(process.stdout.write);
|
||||
|
||||
process.stderr.write = (function (write) {
|
||||
return function (text: string) {
|
||||
arguments[0] = interceptor(text, intercept);
|
||||
// deno-lint-ignore no-explicit-any
|
||||
write.apply(process.stderr, arguments as any);
|
||||
process.stderr.write = ((write) =>
|
||||
((text: string, ...args: never[]) => {
|
||||
write.call(process.stderr, interceptor(text, intercept), ...args);
|
||||
return true;
|
||||
};
|
||||
})(process.stderr.write);
|
||||
}) as typeof process.stderr.write)(process.stderr.write);
|
||||
|
||||
// puts back to original
|
||||
return function unhook() {
|
||||
@@ -32,6 +24,5 @@ export function interceptStdout(
|
||||
}
|
||||
|
||||
function interceptor(text: string, fn: (text: string) => string) {
|
||||
return fn(text).replace(/\n$/, "") +
|
||||
(fn(text) && /\n$/.test(text) ? "\n" : "");
|
||||
return fn(text).replace(/\n$/, '') + (fn(text) && /\n$/.test(text) ? '\n' : '');
|
||||
}
|
||||
|
||||
@@ -5,10 +5,15 @@ export function migrateTemplateFunctionSelectOptions(
|
||||
): TemplateFunctionPlugin {
|
||||
const migratedArgs = f.args.map((a) => {
|
||||
if (a.type === 'select') {
|
||||
a.options = a.options.map((o) => ({
|
||||
...o,
|
||||
label: o.label || (o as any).name,
|
||||
}));
|
||||
// Migrate old options that had 'name' instead of 'label'
|
||||
type LegacyOption = { label?: string; value: string; name?: string };
|
||||
a.options = a.options.map((o) => {
|
||||
const legacy = o as LegacyOption;
|
||||
return {
|
||||
label: legacy.label ?? legacy.name ?? '',
|
||||
value: legacy.value,
|
||||
};
|
||||
});
|
||||
}
|
||||
return a;
|
||||
});
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { CallTemplateFunctionArgs } from '@yaakapp-internal/plugins';
|
||||
import { Context, DynamicTemplateFunctionArg } from '@yaakapp/api';
|
||||
import { applyFormInputDefaults } from '@yaakapp-internal/lib/templateFunction';
|
||||
import type { CallTemplateFunctionArgs } from '@yaakapp-internal/plugins';
|
||||
import type { Context, DynamicTemplateFunctionArg } from '@yaakapp/api';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import { applyDynamicFormInput, applyFormInputDefaults } from '../src/common';
|
||||
import { applyDynamicFormInput } from '../src/common';
|
||||
|
||||
describe('applyFormInputDefaults', () => {
|
||||
test('Works with top-level select', () => {
|
||||
|
||||
1
plugins-external/.gitignore
vendored
Normal file
1
plugins-external/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
*/build
|
||||
76
plugins-external/faker/README.md
Normal file
76
plugins-external/faker/README.md
Normal file
@@ -0,0 +1,76 @@
|
||||
# Yaak Faker Plugin
|
||||
|
||||
This is a template function that generates realistic fake data
|
||||
for testing and development using [FakerJS](https://fakerjs.dev).
|
||||
|
||||

|
||||
|
||||
## Example JSON Body
|
||||
|
||||
Here's an example JSON body that uses fake data:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "${[ faker.string.uuid() ]}",
|
||||
"name": "${[ faker.person.fullName() ]}",
|
||||
"email": "${[ faker.internet.email() ]}",
|
||||
"phone": "${[ faker.phone.number() ]}",
|
||||
"address": {
|
||||
"street": "${[ faker.location.streetAddress() ]}",
|
||||
"city": "${[ faker.location.city() ]}",
|
||||
"country": "${[ faker.location.country() ]}",
|
||||
"zipCode": "${[ faker.location.zipCode() ]}"
|
||||
},
|
||||
"company": "${[ faker.company.name() ]}",
|
||||
"website": "${[ faker.internet.url() ]}"
|
||||
}
|
||||
```
|
||||
|
||||
This will generate a random JSON body on every request:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "589f0aec-7310-4bf2-81c4-0b1bb7f1c3c1",
|
||||
"name": "Lucy Gottlieb-Weissnat",
|
||||
"email": "Destiny_Herzog@gmail.com",
|
||||
"phone": "411.805.2871 x699",
|
||||
"address": {
|
||||
"street": "846 Christ Mills",
|
||||
"city": "Spencerfurt",
|
||||
"country": "United Kingdom",
|
||||
"zipCode": "20354"
|
||||
},
|
||||
"company": "Emard, Kohler and Rutherford",
|
||||
"website": "https://watery-detective.org"
|
||||
}
|
||||
```
|
||||
|
||||
## Available Categories
|
||||
|
||||
The plugin provides access to all FakerJS modules and their methods:
|
||||
|
||||
| Category | Description | Example Methods |
|
||||
|------------|---------------------------|--------------------------------------------|
|
||||
| `airline` | Airline-related data | `aircraftType`, `airline`, `airplane` |
|
||||
| `animal` | Animal names and types | `bear`, `bird`, `cat`, `dog`, `fish` |
|
||||
| `color` | Colors in various formats | `human`, `rgb`, `hex`, `hsl` |
|
||||
| `commerce` | E-commerce data | `department`, `product`, `price` |
|
||||
| `company` | Company information | `name`, `catchPhrase`, `bs` |
|
||||
| `database` | Database-related data | `column`, `type`, `collation` |
|
||||
| `date` | Date and time values | `recent`, `future`, `past`, `between` |
|
||||
| `finance` | Financial data | `account`, `amount`, `currency` |
|
||||
| `git` | Git-related data | `branch`, `commitEntry`, `commitSha` |
|
||||
| `hacker` | Tech/hacker terminology | `abbreviation`, `noun`, `phrase` |
|
||||
| `image` | Image URLs and data | `avatar`, `url`, `dataUri` |
|
||||
| `internet` | Internet-related data | `email`, `url`, `ip`, `userAgent` |
|
||||
| `location` | Geographic data | `city`, `country`, `latitude`, `longitude` |
|
||||
| `lorem` | Lorem ipsum text | `word`, `sentence`, `paragraph` |
|
||||
| `person` | Personal information | `firstName`, `lastName`, `fullName` |
|
||||
| `music` | Music-related data | `genre`, `songName`, `artist` |
|
||||
| `number` | Numeric data | `int`, `float`, `binary`, `hex` |
|
||||
| `phone` | Phone numbers | `number`, `imei` |
|
||||
| `science` | Scientific data | `chemicalElement`, `unit` |
|
||||
| `string` | String utilities | `uuid`, `alpha`, `alphanumeric` |
|
||||
| `system` | System-related data | `fileName`, `mimeType`, `fileExt` |
|
||||
| `vehicle` | Vehicle information | `vehicle`, `manufacturer`, `model` |
|
||||
| `word` | Word generation | `adjective`, `adverb`, `conjunction` |
|
||||
24
plugins-external/faker/package.json
Executable file
24
plugins-external/faker/package.json
Executable file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@yaak/faker",
|
||||
"private": true,
|
||||
"version": "1.1.1",
|
||||
"displayName": "Faker",
|
||||
"description": "Template functions for generating fake data using FakerJS",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mountain-loop/yaak.git",
|
||||
"directory": "plugins-external/faker"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "yaakcli build",
|
||||
"dev": "yaakcli dev",
|
||||
"test": "vitest --run tests"
|
||||
},
|
||||
"dependencies": {
|
||||
"@faker-js/faker": "^10.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.0.3",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
105
plugins-external/faker/src/index.ts
Executable file
105
plugins-external/faker/src/index.ts
Executable file
@@ -0,0 +1,105 @@
|
||||
import { faker } from '@faker-js/faker';
|
||||
import type { DynamicTemplateFunctionArg, PluginDefinition } from '@yaakapp/api';
|
||||
|
||||
const modules = [
|
||||
'airline',
|
||||
'animal',
|
||||
'color',
|
||||
'commerce',
|
||||
'company',
|
||||
'database',
|
||||
'date',
|
||||
'finance',
|
||||
'git',
|
||||
'hacker',
|
||||
'image',
|
||||
'internet',
|
||||
'location',
|
||||
'lorem',
|
||||
'person',
|
||||
'music',
|
||||
'number',
|
||||
'phone',
|
||||
'science',
|
||||
'string',
|
||||
'system',
|
||||
'vehicle',
|
||||
'word',
|
||||
];
|
||||
|
||||
function normalizeResult(result: unknown): string {
|
||||
if (typeof result === 'string') return result;
|
||||
return JSON.stringify(result);
|
||||
}
|
||||
|
||||
// Whatever Yaak’s arg type shape is – rough example
|
||||
function args(modName: string, fnName: string): DynamicTemplateFunctionArg[] {
|
||||
return [
|
||||
{
|
||||
type: 'banner',
|
||||
color: 'info',
|
||||
inputs: [
|
||||
{
|
||||
type: 'markdown',
|
||||
content: `Need help? View documentation for [\`${modName}.${fnName}(…)\`](https://fakerjs.dev/api/${encodeURIComponent(modName)}.html#${encodeURIComponent(fnName)})`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'options',
|
||||
label: 'Arguments',
|
||||
type: 'editor',
|
||||
language: 'json',
|
||||
optional: true,
|
||||
placeholder: 'e.g. { "min": 1, "max": 10 } or 10 or ["en","US"]',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export const plugin: PluginDefinition = {
|
||||
templateFunctions: modules.flatMap((modName) => {
|
||||
const mod = faker[modName as keyof typeof faker];
|
||||
return Object.keys(mod)
|
||||
.filter((n) => n !== 'faker')
|
||||
.map((fnName) => ({
|
||||
name: ['faker', modName, fnName].join('.'),
|
||||
args: args(modName, fnName),
|
||||
async onRender(_ctx, args) {
|
||||
const fn = mod[fnName as keyof typeof mod] as (...a: unknown[]) => unknown;
|
||||
const options = args.values.options;
|
||||
|
||||
// No options supplied
|
||||
if (options == null || options === '') {
|
||||
return normalizeResult(fn());
|
||||
}
|
||||
|
||||
// Try JSON first
|
||||
let parsed: unknown = options;
|
||||
if (typeof options === 'string') {
|
||||
try {
|
||||
parsed = JSON.parse(options);
|
||||
} catch {
|
||||
// Not valid JSON – maybe just a scalar
|
||||
const n = Number(options);
|
||||
if (!Number.isNaN(n)) {
|
||||
parsed = n;
|
||||
} else {
|
||||
parsed = options;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result: unknown;
|
||||
if (Array.isArray(parsed)) {
|
||||
// Treat as positional arguments
|
||||
result = fn(...parsed);
|
||||
} else {
|
||||
// Treat as a single argument (option object or scalar)
|
||||
result = fn(parsed);
|
||||
}
|
||||
|
||||
return normalizeResult(result);
|
||||
},
|
||||
}));
|
||||
}),
|
||||
};
|
||||
9
plugins-external/faker/tests/init.test.ts
Normal file
9
plugins-external/faker/tests/init.test.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
describe('formatDatetime', () => {
|
||||
it('returns formatted current date', async () => {
|
||||
// Ensure the plugin imports properly
|
||||
const faker = await import('../src/index');
|
||||
expect(faker.plugin.templateFunctions?.length).toBe(226);
|
||||
});
|
||||
});
|
||||
3
plugins-external/faker/tsconfig.json
Executable file
3
plugins-external/faker/tsconfig.json
Executable file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json"
|
||||
}
|
||||
35
plugins-external/mcp-server/README.md
Normal file
35
plugins-external/mcp-server/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Yaak MCP Server Plugin
|
||||
|
||||
Exposes Yaak's functionality via the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/).
|
||||
|
||||
## Setup
|
||||
|
||||
Add this to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"yaak": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "mcp-remote", "http://127.0.0.1:64343/mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Restart Claude Desktop and make sure Yaak is running.
|
||||
|
||||
## Available Tools
|
||||
|
||||
- `list_http_requests` - List all HTTP requests in a workspace
|
||||
- `get_http_request` - Get details of a specific HTTP request
|
||||
- `send_http_request` - Send an HTTP request and get the response
|
||||
- `create_http_request` - Create a new HTTP request
|
||||
- `update_http_request` - Update an existing HTTP request
|
||||
- `delete_http_request` - Delete an HTTP request
|
||||
- `list_folders` - List all folders in a workspace
|
||||
- `list_workspaces` - List all open workspaces
|
||||
- `get_workspace_id` - Get the current workspace ID
|
||||
- `get_environment_id` - Get the current environment ID
|
||||
- `copy_to_clipboard` - Copy text to the system clipboard
|
||||
- `show_toast` - Show a toast notification in Yaak
|
||||
28
plugins-external/mcp-server/package.json
Normal file
28
plugins-external/mcp-server/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@yaak/mcp-server",
|
||||
"private": true,
|
||||
"version": "0.1.7",
|
||||
"displayName": "MCP Server",
|
||||
"description": "Expose Yaak functionality via Model Context Protocol",
|
||||
"minYaakVersion": "2025.10.0-beta.6",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mountain-loop/yaak.git",
|
||||
"directory": "plugins-external/mcp-server"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "yaakcli build",
|
||||
"dev": "yaakcli dev"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hono/mcp": "^0.2.3",
|
||||
"@hono/node-server": "^1.19.7",
|
||||
"@modelcontextprotocol/sdk": "^1.25.1",
|
||||
"hono": "^4.11.3",
|
||||
"zod": "^3.25.76"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^25.0.3",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
36
plugins-external/mcp-server/src/index.ts
Normal file
36
plugins-external/mcp-server/src/index.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import type { Context, PluginDefinition } from '@yaakapp/api';
|
||||
import { createMcpServer } from './server.js';
|
||||
|
||||
const serverPort = parseInt(process.env.YAAK_PLUGIN_MCP_SERVER_PORT ?? '64343', 10);
|
||||
|
||||
let mcpServer: Awaited<ReturnType<typeof createMcpServer>> | null = null;
|
||||
|
||||
export const plugin: PluginDefinition = {
|
||||
async init(ctx: Context) {
|
||||
// Start the server after waiting, so there's an active window open to do things
|
||||
// like show the startup toast.
|
||||
console.log('Initializing MCP Server plugin');
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
mcpServer = createMcpServer({ yaak: ctx }, serverPort);
|
||||
} catch (err) {
|
||||
console.error('Failed to start MCP server:', err);
|
||||
ctx.toast.show({
|
||||
message: `Failed to start MCP Server: ${err instanceof Error ? err.message : String(err)}`,
|
||||
icon: 'alert_triangle',
|
||||
color: 'danger',
|
||||
timeout: 10000,
|
||||
});
|
||||
}
|
||||
}, 5000);
|
||||
},
|
||||
|
||||
async dispose() {
|
||||
console.log('Disposing MCP Server plugin');
|
||||
|
||||
if (mcpServer) {
|
||||
await mcpServer.close();
|
||||
mcpServer = null;
|
||||
}
|
||||
},
|
||||
};
|
||||
72
plugins-external/mcp-server/src/server.ts
Normal file
72
plugins-external/mcp-server/src/server.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import { StreamableHTTPTransport } from '@hono/mcp';
|
||||
import { serve } from '@hono/node-server';
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { Hono } from 'hono';
|
||||
import { registerFolderTools } from './tools/folder.js';
|
||||
import { registerHttpRequestTools } from './tools/httpRequest.js';
|
||||
import { registerToastTools } from './tools/toast.js';
|
||||
import { registerWindowTools } from './tools/window.js';
|
||||
import { registerWorkspaceTools } from './tools/workspace.js';
|
||||
import type { McpServerContext } from './types.js';
|
||||
|
||||
export function createMcpServer(ctx: McpServerContext, port: number) {
|
||||
console.log('Creating MCP server on port', port);
|
||||
const mcpServer = new McpServer({
|
||||
name: 'yaak-mcp-server',
|
||||
version: '0.1.0',
|
||||
});
|
||||
|
||||
// Register all tools
|
||||
registerToastTools(mcpServer, ctx);
|
||||
registerHttpRequestTools(mcpServer, ctx);
|
||||
registerFolderTools(mcpServer, ctx);
|
||||
registerWindowTools(mcpServer, ctx);
|
||||
registerWorkspaceTools(mcpServer, ctx);
|
||||
|
||||
const app = new Hono();
|
||||
const transport = new StreamableHTTPTransport();
|
||||
|
||||
app.all('/mcp', async (c) => {
|
||||
if (!mcpServer.isConnected()) {
|
||||
// Connect the mcp with the transport
|
||||
await mcpServer.connect(transport);
|
||||
ctx.yaak.toast.show({
|
||||
message: `MCP Server connected`,
|
||||
icon: 'info',
|
||||
color: 'info',
|
||||
timeout: 5000,
|
||||
});
|
||||
}
|
||||
return transport.handleRequest(c);
|
||||
});
|
||||
|
||||
const honoServer = serve(
|
||||
{
|
||||
port,
|
||||
hostname: '127.0.0.1',
|
||||
fetch: app.fetch,
|
||||
},
|
||||
(info) => {
|
||||
console.log('Started MCP server on ', info.address);
|
||||
ctx.yaak.toast.show({
|
||||
message: `MCP Server running on http://127.0.0.1:${info.port}`,
|
||||
icon: 'info',
|
||||
color: 'secondary',
|
||||
timeout: 10000,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
server: mcpServer,
|
||||
close: async () => {
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
honoServer.close((err) => {
|
||||
if (err) reject(err);
|
||||
else resolve();
|
||||
});
|
||||
});
|
||||
await mcpServer.close();
|
||||
},
|
||||
};
|
||||
}
|
||||
33
plugins-external/mcp-server/src/tools/folder.ts
Normal file
33
plugins-external/mcp-server/src/tools/folder.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import * as z from 'zod';
|
||||
import type { McpServerContext } from '../types.js';
|
||||
import { getWorkspaceContext } from './helpers.js';
|
||||
|
||||
export function registerFolderTools(server: McpServer, ctx: McpServerContext) {
|
||||
server.registerTool(
|
||||
'list_folders',
|
||||
{
|
||||
title: 'List Folders',
|
||||
description: 'List all folders in a workspace',
|
||||
inputSchema: {
|
||||
workspaceId: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe('Workspace ID (required if multiple workspaces are open)'),
|
||||
},
|
||||
},
|
||||
async ({ workspaceId }) => {
|
||||
const workspaceCtx = await getWorkspaceContext(ctx, workspaceId);
|
||||
const folders = await workspaceCtx.yaak.folder.list();
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text' as const,
|
||||
text: JSON.stringify(folders, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
32
plugins-external/mcp-server/src/tools/helpers.ts
Normal file
32
plugins-external/mcp-server/src/tools/helpers.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import type { McpServerContext } from '../types.js';
|
||||
|
||||
export async function getWorkspaceContext(
|
||||
ctx: McpServerContext,
|
||||
workspaceId?: string,
|
||||
): Promise<McpServerContext> {
|
||||
const workspaces = await ctx.yaak.workspace.list();
|
||||
|
||||
if (!workspaceId && workspaces.length > 1) {
|
||||
const workspaceList = workspaces.map((w, i) => `${i + 1}. ${w.name} (ID: ${w.id})`).join('\n');
|
||||
throw new Error(
|
||||
`Multiple workspaces are open. Please specify which workspace to use.\n\n` +
|
||||
`Currently open workspaces:\n${workspaceList}\n\n` +
|
||||
`You can use the list_workspaces tool to get workspace IDs, then use other tools ` +
|
||||
`with the workspace context. For example, ask the user which workspace they want ` +
|
||||
`to work with by presenting them with the numbered list above.`,
|
||||
);
|
||||
}
|
||||
|
||||
const workspace = workspaceId ? workspaces.find((w) => w.id === workspaceId) : workspaces[0];
|
||||
if (!workspace) {
|
||||
const workspaceList = workspaces.map((w) => `- ${w.name} (ID: ${w.id})`).join('\n');
|
||||
throw new Error(
|
||||
`Workspace with ID "${workspaceId}" not found.\n\n` +
|
||||
`Available workspaces:\n${workspaceList}`,
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
yaak: ctx.yaak.workspace.withContext(workspace),
|
||||
};
|
||||
}
|
||||
298
plugins-external/mcp-server/src/tools/httpRequest.ts
Normal file
298
plugins-external/mcp-server/src/tools/httpRequest.ts
Normal file
@@ -0,0 +1,298 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import * as z from 'zod';
|
||||
import type { McpServerContext } from '../types.js';
|
||||
import { getWorkspaceContext } from './helpers.js';
|
||||
|
||||
export function registerHttpRequestTools(server: McpServer, ctx: McpServerContext) {
|
||||
server.registerTool(
|
||||
'list_http_requests',
|
||||
{
|
||||
title: 'List HTTP Requests',
|
||||
description: 'List all HTTP requests in a workspace',
|
||||
inputSchema: {
|
||||
workspaceId: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe('Workspace ID (required if multiple workspaces are open)'),
|
||||
},
|
||||
},
|
||||
async ({ workspaceId }) => {
|
||||
const workspaceCtx = await getWorkspaceContext(ctx, workspaceId);
|
||||
const requests = await workspaceCtx.yaak.httpRequest.list();
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text' as const,
|
||||
text: JSON.stringify(requests, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
'get_http_request',
|
||||
{
|
||||
title: 'Get HTTP Request',
|
||||
description: 'Get details of a specific HTTP request by ID',
|
||||
inputSchema: {
|
||||
id: z.string().describe('The HTTP request ID'),
|
||||
workspaceId: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe('Workspace ID (required if multiple workspaces are open)'),
|
||||
},
|
||||
},
|
||||
async ({ id, workspaceId }) => {
|
||||
const workspaceCtx = await getWorkspaceContext(ctx, workspaceId);
|
||||
const request = await workspaceCtx.yaak.httpRequest.getById({ id });
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text' as const,
|
||||
text: JSON.stringify(request, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
'send_http_request',
|
||||
{
|
||||
title: 'Send HTTP Request',
|
||||
description: 'Send an HTTP request and get the response',
|
||||
inputSchema: {
|
||||
id: z.string().describe('The HTTP request ID to send'),
|
||||
environmentId: z.string().optional().describe('Optional environment ID to use'),
|
||||
workspaceId: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe('Workspace ID (required if multiple workspaces are open)'),
|
||||
},
|
||||
},
|
||||
async ({ id, workspaceId }) => {
|
||||
const workspaceCtx = await getWorkspaceContext(ctx, workspaceId);
|
||||
const httpRequest = await workspaceCtx.yaak.httpRequest.getById({ id });
|
||||
if (httpRequest == null) {
|
||||
throw new Error(`HTTP request with ID ${id} not found`);
|
||||
}
|
||||
|
||||
const response = await workspaceCtx.yaak.httpRequest.send({ httpRequest });
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text' as const,
|
||||
text: JSON.stringify(response, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
'create_http_request',
|
||||
{
|
||||
title: 'Create HTTP Request',
|
||||
description: 'Create a new HTTP request',
|
||||
inputSchema: {
|
||||
workspaceId: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe('Workspace ID (required if multiple workspaces are open)'),
|
||||
name: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe('Request name (empty string to auto-generate from URL)'),
|
||||
url: z.string().describe('Request URL'),
|
||||
method: z.string().optional().describe('HTTP method (defaults to GET)'),
|
||||
folderId: z.string().optional().describe('Parent folder ID'),
|
||||
description: z.string().optional().describe('Request description'),
|
||||
headers: z
|
||||
.array(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
value: z.string(),
|
||||
enabled: z.boolean().default(true),
|
||||
}),
|
||||
)
|
||||
.optional()
|
||||
.describe('Request headers'),
|
||||
urlParameters: z
|
||||
.array(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
value: z.string(),
|
||||
enabled: z.boolean().default(true),
|
||||
}),
|
||||
)
|
||||
.optional()
|
||||
.describe('URL query parameters'),
|
||||
bodyType: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
'Body type. Supported values: "binary", "graphql", "application/x-www-form-urlencoded", "multipart/form-data", or any text-based type (e.g., "application/json", "text/plain")',
|
||||
),
|
||||
body: z
|
||||
.record(z.string(), z.any())
|
||||
.optional()
|
||||
.describe(
|
||||
'Body content object. Structure varies by bodyType:\n' +
|
||||
'- "binary": { filePath: "/path/to/file" }\n' +
|
||||
'- "graphql": { query: "{ users { name } }", variables: "{\\"id\\": \\"123\\"}" }\n' +
|
||||
'- "application/x-www-form-urlencoded": { form: [{ name: "key", value: "val", enabled: true }] }\n' +
|
||||
'- "multipart/form-data": { form: [{ name: "field", value: "text", file: "/path/to/file", enabled: true }] }\n' +
|
||||
'- text-based (application/json, etc.): { text: "raw body content" }',
|
||||
),
|
||||
authenticationType: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
'Authentication type. Common values: "basic", "bearer", "oauth2", "apikey", "jwt", "awsv4", "oauth1", "ntlm", "none". Use null to inherit from parent folder/workspace.',
|
||||
),
|
||||
authentication: z
|
||||
.record(z.string(), z.any())
|
||||
.optional()
|
||||
.describe(
|
||||
'Authentication configuration object. Structure varies by authenticationType:\n' +
|
||||
'- "basic": { username: "user", password: "pass" }\n' +
|
||||
'- "bearer": { token: "abc123", prefix: "Bearer" }\n' +
|
||||
'- "oauth2": { clientId: "...", clientSecret: "...", grantType: "authorization_code", authorizationUrl: "...", accessTokenUrl: "...", scope: "...", ... }\n' +
|
||||
'- "apikey": { location: "header" | "query", key: "X-API-Key", value: "..." }\n' +
|
||||
'- "jwt": { algorithm: "HS256", secret: "...", payload: "{ ... }" }\n' +
|
||||
'- "awsv4": { accessKeyId: "...", secretAccessKey: "...", service: "sts", region: "us-east-1", sessionToken: "..." }\n' +
|
||||
'- "none": {}',
|
||||
),
|
||||
},
|
||||
},
|
||||
async ({ workspaceId: ogWorkspaceId, ...args }) => {
|
||||
const workspaceCtx = await getWorkspaceContext(ctx, ogWorkspaceId);
|
||||
const workspaceId = await workspaceCtx.yaak.window.workspaceId();
|
||||
if (!workspaceId) {
|
||||
throw new Error('No workspace is open');
|
||||
}
|
||||
|
||||
const httpRequest = await workspaceCtx.yaak.httpRequest.create({
|
||||
workspaceId: workspaceId,
|
||||
...args,
|
||||
});
|
||||
|
||||
return {
|
||||
content: [{ type: 'text' as const, text: JSON.stringify(httpRequest, null, 2) }],
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
'update_http_request',
|
||||
{
|
||||
title: 'Update HTTP Request',
|
||||
description: 'Update an existing HTTP request',
|
||||
inputSchema: {
|
||||
id: z.string().describe('HTTP request ID to update'),
|
||||
workspaceId: z.string().describe('Workspace ID'),
|
||||
name: z.string().optional().describe('Request name'),
|
||||
url: z.string().optional().describe('Request URL'),
|
||||
method: z.string().optional().describe('HTTP method'),
|
||||
folderId: z.string().optional().describe('Parent folder ID'),
|
||||
description: z.string().optional().describe('Request description'),
|
||||
headers: z
|
||||
.array(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
value: z.string(),
|
||||
enabled: z.boolean().default(true),
|
||||
}),
|
||||
)
|
||||
.optional()
|
||||
.describe('Request headers'),
|
||||
urlParameters: z
|
||||
.array(
|
||||
z.object({
|
||||
name: z.string(),
|
||||
value: z.string(),
|
||||
enabled: z.boolean().default(true),
|
||||
}),
|
||||
)
|
||||
.optional()
|
||||
.describe('URL query parameters'),
|
||||
bodyType: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
'Body type. Supported values: "binary", "graphql", "application/x-www-form-urlencoded", "multipart/form-data", or any text-based type (e.g., "application/json", "text/plain")',
|
||||
),
|
||||
body: z
|
||||
.record(z.string(), z.any())
|
||||
.optional()
|
||||
.describe(
|
||||
'Body content object. Structure varies by bodyType:\n' +
|
||||
'- "binary": { filePath: "/path/to/file" }\n' +
|
||||
'- "graphql": { query: "{ users { name } }", variables: "{\\"id\\": \\"123\\"}" }\n' +
|
||||
'- "application/x-www-form-urlencoded": { form: [{ name: "key", value: "val", enabled: true }] }\n' +
|
||||
'- "multipart/form-data": { form: [{ name: "field", value: "text", file: "/path/to/file", enabled: true }] }\n' +
|
||||
'- text-based (application/json, etc.): { text: "raw body content" }',
|
||||
),
|
||||
authenticationType: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe(
|
||||
'Authentication type. Common values: "basic", "bearer", "oauth2", "apikey", "jwt", "awsv4", "oauth1", "ntlm", "none". Use null to inherit from parent folder/workspace.',
|
||||
),
|
||||
authentication: z
|
||||
.record(z.string(), z.any())
|
||||
.optional()
|
||||
.describe(
|
||||
'Authentication configuration object. Structure varies by authenticationType:\n' +
|
||||
'- "basic": { username: "user", password: "pass" }\n' +
|
||||
'- "bearer": { token: "abc123", prefix: "Bearer" }\n' +
|
||||
'- "oauth2": { clientId: "...", clientSecret: "...", grantType: "authorization_code", authorizationUrl: "...", accessTokenUrl: "...", scope: "...", ... }\n' +
|
||||
'- "apikey": { location: "header" | "query", key: "X-API-Key", value: "..." }\n' +
|
||||
'- "jwt": { algorithm: "HS256", secret: "...", payload: "{ ... }" }\n' +
|
||||
'- "awsv4": { accessKeyId: "...", secretAccessKey: "...", service: "sts", region: "us-east-1", sessionToken: "..." }\n' +
|
||||
'- "none": {}',
|
||||
),
|
||||
},
|
||||
},
|
||||
async ({ id, workspaceId, ...updates }) => {
|
||||
const workspaceCtx = await getWorkspaceContext(ctx, workspaceId);
|
||||
// Fetch existing request to merge with updates
|
||||
const existing = await workspaceCtx.yaak.httpRequest.getById({ id });
|
||||
if (!existing) {
|
||||
throw new Error(`HTTP request with ID ${id} not found`);
|
||||
}
|
||||
// Merge existing fields with updates
|
||||
const httpRequest = await workspaceCtx.yaak.httpRequest.update({
|
||||
...existing,
|
||||
...updates,
|
||||
id,
|
||||
});
|
||||
return {
|
||||
content: [{ type: 'text' as const, text: JSON.stringify(httpRequest, null, 2) }],
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
'delete_http_request',
|
||||
{
|
||||
title: 'Delete HTTP Request',
|
||||
description: 'Delete an HTTP request by ID',
|
||||
inputSchema: {
|
||||
id: z.string().describe('HTTP request ID to delete'),
|
||||
},
|
||||
},
|
||||
async ({ id }) => {
|
||||
const httpRequest = await ctx.yaak.httpRequest.delete({ id });
|
||||
return {
|
||||
content: [
|
||||
{ type: 'text' as const, text: `Deleted: ${httpRequest.name} (${httpRequest.id})` },
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
59
plugins-external/mcp-server/src/tools/toast.ts
Normal file
59
plugins-external/mcp-server/src/tools/toast.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import type { Color, Icon } from '@yaakapp/api';
|
||||
import * as z from 'zod';
|
||||
import type { McpServerContext } from '../types.js';
|
||||
|
||||
const ICON_VALUES = [
|
||||
'alert_triangle',
|
||||
'check',
|
||||
'check_circle',
|
||||
'chevron_down',
|
||||
'copy',
|
||||
'info',
|
||||
'pin',
|
||||
'search',
|
||||
'trash',
|
||||
] as const satisfies readonly Icon[];
|
||||
|
||||
const COLOR_VALUES = [
|
||||
'primary',
|
||||
'secondary',
|
||||
'info',
|
||||
'success',
|
||||
'notice',
|
||||
'warning',
|
||||
'danger',
|
||||
] as const satisfies readonly Color[];
|
||||
|
||||
export function registerToastTools(server: McpServer, ctx: McpServerContext) {
|
||||
server.registerTool(
|
||||
'show_toast',
|
||||
{
|
||||
title: 'Show Toast',
|
||||
description: 'Show a toast notification in Yaak',
|
||||
inputSchema: {
|
||||
message: z.string().describe('The message to display'),
|
||||
icon: z.enum(ICON_VALUES).optional().describe('Icon name'),
|
||||
color: z.enum(COLOR_VALUES).optional().describe('Toast color'),
|
||||
timeout: z.number().optional().describe('Timeout in milliseconds'),
|
||||
},
|
||||
},
|
||||
async ({ message, icon, color, timeout }) => {
|
||||
await ctx.yaak.toast.show({
|
||||
message,
|
||||
icon,
|
||||
color,
|
||||
timeout,
|
||||
});
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text' as const,
|
||||
text: `✓ Toast shown: "${message}"`,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
47
plugins-external/mcp-server/src/tools/window.ts
Normal file
47
plugins-external/mcp-server/src/tools/window.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import type { McpServerContext } from '../types.js';
|
||||
import { getWorkspaceContext } from './helpers.js';
|
||||
|
||||
export function registerWindowTools(server: McpServer, ctx: McpServerContext) {
|
||||
server.registerTool(
|
||||
'get_workspace_id',
|
||||
{
|
||||
title: 'Get Workspace ID',
|
||||
description: 'Get the current workspace ID',
|
||||
},
|
||||
async () => {
|
||||
const workspaceCtx = await getWorkspaceContext(ctx);
|
||||
const workspaceId = await workspaceCtx.yaak.window.workspaceId();
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text' as const,
|
||||
text: workspaceId || 'No workspace open',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
server.registerTool(
|
||||
'get_environment_id',
|
||||
{
|
||||
title: 'Get Environment ID',
|
||||
description: 'Get the current environment ID',
|
||||
},
|
||||
async () => {
|
||||
const workspaceCtx = await getWorkspaceContext(ctx);
|
||||
const environmentId = await workspaceCtx.yaak.window.environmentId();
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text' as const,
|
||||
text: environmentId || 'No environment selected',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
24
plugins-external/mcp-server/src/tools/workspace.ts
Normal file
24
plugins-external/mcp-server/src/tools/workspace.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import type { McpServerContext } from '../types.js';
|
||||
|
||||
export function registerWorkspaceTools(server: McpServer, ctx: McpServerContext) {
|
||||
server.registerTool(
|
||||
'list_workspaces',
|
||||
{
|
||||
title: 'List Workspaces',
|
||||
description: 'List all open workspaces in Yaak',
|
||||
},
|
||||
async () => {
|
||||
const workspaces = await ctx.yaak.workspace.list();
|
||||
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text' as const,
|
||||
text: JSON.stringify(workspaces, null, 2),
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
5
plugins-external/mcp-server/src/types.ts
Normal file
5
plugins-external/mcp-server/src/types.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import type { Context } from '@yaakapp/api';
|
||||
|
||||
export interface McpServerContext {
|
||||
yaak: Context;
|
||||
}
|
||||
7
plugins-external/mcp-server/tsconfig.json
Normal file
7
plugins-external/mcp-server/tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "Bundler"
|
||||
}
|
||||
}
|
||||
16
plugins/action-send-folder/package.json
Normal file
16
plugins/action-send-folder/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "@yaak/action-send-folder",
|
||||
"displayName": "Send All",
|
||||
"description": "Send all HTTP requests in a folder sequentially",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mountain-loop/yaak.git",
|
||||
"directory": "plugins/action-send-folder"
|
||||
},
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"scripts": {
|
||||
"build": "yaakcli build",
|
||||
"dev": "yaakcli dev"
|
||||
}
|
||||
}
|
||||
74
plugins/action-send-folder/src/index.ts
Normal file
74
plugins/action-send-folder/src/index.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import type { PluginDefinition } from '@yaakapp/api';
|
||||
|
||||
export const plugin: PluginDefinition = {
|
||||
folderActions: [
|
||||
{
|
||||
label: 'Send All',
|
||||
icon: 'send_horizontal',
|
||||
async onSelect(ctx, args) {
|
||||
const targetFolder = args.folder;
|
||||
|
||||
// Get all folders and HTTP requests
|
||||
const [allFolders, allRequests] = await Promise.all([
|
||||
ctx.folder.list(),
|
||||
ctx.httpRequest.list(),
|
||||
]);
|
||||
|
||||
// Build a set of all folder IDs that are descendants of the target folder
|
||||
const folderIds = new Set<string>([targetFolder.id]);
|
||||
const addDescendants = (parentId: string) => {
|
||||
for (const folder of allFolders) {
|
||||
if (folder.folderId === parentId && !folderIds.has(folder.id)) {
|
||||
folderIds.add(folder.id);
|
||||
addDescendants(folder.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
addDescendants(targetFolder.id);
|
||||
|
||||
// Filter HTTP requests to those in the target folder or its descendants
|
||||
const requestsToSend = allRequests.filter(
|
||||
(req) => req.folderId != null && folderIds.has(req.folderId),
|
||||
);
|
||||
|
||||
if (requestsToSend.length === 0) {
|
||||
await ctx.toast.show({
|
||||
message: 'No requests in folder',
|
||||
icon: 'info',
|
||||
color: 'info',
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Send each request sequentially
|
||||
let successCount = 0;
|
||||
let errorCount = 0;
|
||||
|
||||
for (const request of requestsToSend) {
|
||||
try {
|
||||
await ctx.httpRequest.send({ httpRequest: request });
|
||||
successCount++;
|
||||
} catch (error) {
|
||||
errorCount++;
|
||||
console.error(`Failed to send request ${request.id}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
// Show summary toast
|
||||
if (errorCount === 0) {
|
||||
await ctx.toast.show({
|
||||
message: `Sent ${successCount} request${successCount !== 1 ? 's' : ''}`,
|
||||
icon: 'send_horizontal',
|
||||
color: 'success',
|
||||
});
|
||||
} else {
|
||||
await ctx.toast.show({
|
||||
message: `Sent ${successCount}, failed ${errorCount}`,
|
||||
icon: 'alert_triangle',
|
||||
color: 'warning',
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
3
plugins/action-send-folder/tsconfig.json
Normal file
3
plugins/action-send-folder/tsconfig.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json"
|
||||
}
|
||||
@@ -71,10 +71,10 @@ export async function getOrRefreshAccessToken(
|
||||
httpRequest.authenticationType = 'none'; // Don't inherit workspace auth
|
||||
const resp = await ctx.httpRequest.send({ httpRequest });
|
||||
|
||||
if (resp.status === 401) {
|
||||
// Bad refresh token, so we'll force it to fetch a fresh access token by deleting
|
||||
// and returning null;
|
||||
console.log('[oauth2] Unauthorized refresh_token request');
|
||||
if (resp.status >= 400 && resp.status < 500) {
|
||||
// Client errors (4xx) indicate the refresh token is invalid, expired, or revoked
|
||||
// Delete the token and return null to trigger a fresh authorization flow
|
||||
console.log('[oauth2] Refresh token request failed with client error, deleting token');
|
||||
await deleteToken(ctx, tokenArgs);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -55,6 +55,34 @@ export const plugin: PluginDefinition = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes escape sequences in shell $'...' strings
|
||||
* Handles Unicode escape sequences (\uXXXX) and common escape codes
|
||||
*/
|
||||
function decodeShellString(str: string): string {
|
||||
return str
|
||||
.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
|
||||
.replace(/\\x([0-9a-fA-F]{2})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
|
||||
.replace(/\\n/g, '\n')
|
||||
.replace(/\\r/g, '\r')
|
||||
.replace(/\\t/g, '\t')
|
||||
.replace(/\\'/g, "'")
|
||||
.replace(/\\"/g, '"')
|
||||
.replace(/\\\\/g, '\\');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a string might contain escape sequences that need decoding
|
||||
* If so, decodes them; otherwise returns the string as-is
|
||||
*/
|
||||
function maybeDecodeEscapeSequences(str: string): string {
|
||||
// Check if the string contains escape sequences that shell-quote might not handle
|
||||
if (str.includes('\\u') || str.includes('\\x')) {
|
||||
return decodeShellString(str);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
export function convertCurl(rawData: string) {
|
||||
if (!rawData.match(/^\s*curl /)) {
|
||||
return null;
|
||||
@@ -86,9 +114,11 @@ export function convertCurl(rawData: string) {
|
||||
for (const parseEntry of normalizedParseEntries) {
|
||||
if (typeof parseEntry === 'string') {
|
||||
if (parseEntry.startsWith('$')) {
|
||||
currentCommand.push(parseEntry.slice(1));
|
||||
// Handle $'...' strings from shell-quote - decode escape sequences
|
||||
currentCommand.push(decodeShellString(parseEntry.slice(1)));
|
||||
} else {
|
||||
currentCommand.push(parseEntry);
|
||||
// Decode escape sequences that shell-quote might not handle
|
||||
currentCommand.push(maybeDecodeEscapeSequences(parseEntry));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -108,7 +138,7 @@ export function convertCurl(rawData: string) {
|
||||
|
||||
if (op?.startsWith('$')) {
|
||||
// Handle the case where literal like -H $'Header: \'Some Quoted Thing\''
|
||||
const str = op.slice(2, op.length - 1).replace(/\\'/g, "'");
|
||||
const str = decodeShellString(op.slice(2, op.length - 1));
|
||||
|
||||
currentCommand.push(str);
|
||||
continue;
|
||||
@@ -164,11 +194,18 @@ function importCommand(parseEntries: ParseEntry[], workspaceId: string) {
|
||||
let value: string | boolean;
|
||||
const nextEntry = parseEntries[i + 1];
|
||||
const hasValue = !BOOLEAN_FLAGS.includes(name);
|
||||
// Check if nextEntry looks like a flag:
|
||||
// - Single dash followed by a letter: -X, -H, -d
|
||||
// - Double dash followed by a letter: --data-raw, --header
|
||||
// This prevents mistaking data that starts with dashes (like multipart boundaries ------) as flags
|
||||
const nextEntryIsFlag =
|
||||
typeof nextEntry === 'string' &&
|
||||
(nextEntry.match(/^-[a-zA-Z]/) || nextEntry.match(/^--[a-zA-Z]/));
|
||||
if (isSingleDash && name.length > 1) {
|
||||
// Handle squished arguments like -XPOST
|
||||
value = name.slice(1);
|
||||
name = name.slice(0, 1);
|
||||
} else if (typeof nextEntry === 'string' && hasValue && !nextEntry.startsWith('-')) {
|
||||
} else if (typeof nextEntry === 'string' && hasValue && !nextEntryIsFlag) {
|
||||
// Next arg is not a flag, so assign it as the value
|
||||
value = nextEntry;
|
||||
i++; // Skip next one
|
||||
@@ -275,11 +312,34 @@ function importCommand(parseEntries: ParseEntry[], workspaceId: string) {
|
||||
}
|
||||
|
||||
// Body (Text or Blob)
|
||||
const dataParameters = pairsToDataParameters(flagsByName);
|
||||
const contentTypeHeader = headers.find((header) => header.name.toLowerCase() === 'content-type');
|
||||
const mimeType = contentTypeHeader ? contentTypeHeader.value.split(';')[0] : null;
|
||||
const mimeType = contentTypeHeader ? contentTypeHeader.value.split(';')[0]?.trim() : null;
|
||||
|
||||
// Body (Multipart Form Data)
|
||||
// Extract boundary from Content-Type header for multipart parsing
|
||||
const boundaryMatch = contentTypeHeader?.value.match(/boundary=([^\s;]+)/i);
|
||||
const boundary = boundaryMatch?.[1];
|
||||
|
||||
// Get raw data from --data-raw flags (before splitting by &)
|
||||
const rawDataValues = [
|
||||
...((flagsByName['data-raw'] as string[] | undefined) || []),
|
||||
...((flagsByName.d as string[] | undefined) || []),
|
||||
...((flagsByName.data as string[] | undefined) || []),
|
||||
...((flagsByName['data-binary'] as string[] | undefined) || []),
|
||||
...((flagsByName['data-ascii'] as string[] | undefined) || []),
|
||||
];
|
||||
|
||||
// Check if this is multipart form data in --data-raw (Chrome DevTools format)
|
||||
let multipartFormDataFromRaw:
|
||||
| { name: string; value?: string; file?: string; enabled: boolean }[]
|
||||
| null = null;
|
||||
if (mimeType === 'multipart/form-data' && boundary && rawDataValues.length > 0) {
|
||||
const rawBody = rawDataValues.join('');
|
||||
multipartFormDataFromRaw = parseMultipartFormData(rawBody, boundary);
|
||||
}
|
||||
|
||||
const dataParameters = pairsToDataParameters(flagsByName);
|
||||
|
||||
// Body (Multipart Form Data from -F flags)
|
||||
const formDataParams = [
|
||||
...((flagsByName.form as string[] | undefined) || []),
|
||||
...((flagsByName.F as string[] | undefined) || []),
|
||||
@@ -306,7 +366,13 @@ function importCommand(parseEntries: ParseEntry[], workspaceId: string) {
|
||||
let bodyType: string | null = null;
|
||||
const bodyAsGET = getPairValue(flagsByName, false, ['G', 'get']);
|
||||
|
||||
if (dataParameters.length > 0 && bodyAsGET) {
|
||||
if (multipartFormDataFromRaw) {
|
||||
// Handle multipart form data parsed from --data-raw (Chrome DevTools format)
|
||||
bodyType = 'multipart/form-data';
|
||||
body = {
|
||||
form: multipartFormDataFromRaw,
|
||||
};
|
||||
} else if (dataParameters.length > 0 && bodyAsGET) {
|
||||
urlParameters.push(...dataParameters);
|
||||
} else if (
|
||||
dataParameters.length > 0 &&
|
||||
@@ -443,6 +509,71 @@ function splitOnce(str: string, sep: string): string[] {
|
||||
return [str];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses multipart form data from a raw body string
|
||||
* Used when Chrome DevTools exports a cURL with --data-raw containing multipart data
|
||||
*/
|
||||
function parseMultipartFormData(
|
||||
rawBody: string,
|
||||
boundary: string,
|
||||
): { name: string; value?: string; file?: string; enabled: boolean }[] | null {
|
||||
const results: { name: string; value?: string; file?: string; enabled: boolean }[] = [];
|
||||
|
||||
// The boundary in the body typically has -- prefix
|
||||
const boundaryMarker = `--${boundary}`;
|
||||
const parts = rawBody.split(boundaryMarker);
|
||||
|
||||
for (const part of parts) {
|
||||
// Skip empty parts and the closing boundary marker
|
||||
if (!part || part.trim() === '--' || part.trim() === '--\r\n') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Each part has headers and content separated by \r\n\r\n
|
||||
const headerContentSplit = part.indexOf('\r\n\r\n');
|
||||
if (headerContentSplit === -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const headerSection = part.slice(0, headerContentSplit);
|
||||
let content = part.slice(headerContentSplit + 4); // Skip \r\n\r\n
|
||||
|
||||
// Remove trailing \r\n from content
|
||||
if (content.endsWith('\r\n')) {
|
||||
content = content.slice(0, -2);
|
||||
}
|
||||
|
||||
// Parse Content-Disposition header to get name and filename
|
||||
const contentDispositionMatch = headerSection.match(
|
||||
/Content-Disposition:\s*form-data;\s*name="([^"]+)"(?:;\s*filename="([^"]+)")?/i,
|
||||
);
|
||||
|
||||
if (!contentDispositionMatch) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const name = contentDispositionMatch[1] ?? '';
|
||||
const filename = contentDispositionMatch[2];
|
||||
|
||||
const item: { name: string; value?: string; file?: string; enabled: boolean } = {
|
||||
name,
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
if (filename) {
|
||||
// This is a file upload field
|
||||
item.file = filename;
|
||||
} else {
|
||||
// This is a regular text field
|
||||
item.value = content;
|
||||
}
|
||||
|
||||
results.push(item);
|
||||
}
|
||||
|
||||
return results.length > 0 ? results : null;
|
||||
}
|
||||
|
||||
const idCount: Partial<Record<string, number>> = {};
|
||||
|
||||
function generateId(model: string): string {
|
||||
|
||||
@@ -391,6 +391,122 @@ describe('importer-curl', () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('Imports data with Unicode escape sequences', () => {
|
||||
expect(
|
||||
convertCurl(
|
||||
`curl 'https://yaak.app' -H 'Content-Type: application/json' --data-raw $'{"query":"SearchQueryInput\\u0021"}' -X POST`,
|
||||
),
|
||||
).toEqual({
|
||||
resources: {
|
||||
workspaces: [baseWorkspace()],
|
||||
httpRequests: [
|
||||
baseRequest({
|
||||
url: 'https://yaak.app',
|
||||
method: 'POST',
|
||||
headers: [{ name: 'Content-Type', value: 'application/json', enabled: true }],
|
||||
bodyType: 'application/json',
|
||||
body: { text: '{"query":"SearchQueryInput!"}' },
|
||||
}),
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('Imports data with multiple escape sequences', () => {
|
||||
expect(
|
||||
convertCurl(
|
||||
`curl 'https://yaak.app' --data-raw $'Line1\\nLine2\\tTab\\u0021Exclamation' -X POST`,
|
||||
),
|
||||
).toEqual({
|
||||
resources: {
|
||||
workspaces: [baseWorkspace()],
|
||||
httpRequests: [
|
||||
baseRequest({
|
||||
url: 'https://yaak.app',
|
||||
method: 'POST',
|
||||
bodyType: 'application/x-www-form-urlencoded',
|
||||
body: {
|
||||
form: [{ name: 'Line1\nLine2\tTab!Exclamation', value: '', enabled: true }],
|
||||
},
|
||||
headers: [
|
||||
{
|
||||
enabled: true,
|
||||
name: 'Content-Type',
|
||||
value: 'application/x-www-form-urlencoded',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('Imports multipart form data from --data-raw (Chrome DevTools format)', () => {
|
||||
// This is the format Chrome DevTools uses when copying a multipart form submission as cURL
|
||||
const curlCommand = `curl 'http://localhost:8080/system' \
|
||||
-H 'Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryHwsXKi4rKA6P5VBd' \
|
||||
--data-raw $'------WebKitFormBoundaryHwsXKi4rKA6P5VBd\r\nContent-Disposition: form-data; name="username"\r\n\r\njsgj\r\n------WebKitFormBoundaryHwsXKi4rKA6P5VBd\r\nContent-Disposition: form-data; name="password"\r\n\r\n654321\r\n------WebKitFormBoundaryHwsXKi4rKA6P5VBd\r\nContent-Disposition: form-data; name="captcha"; filename="test.xlsx"\r\nContent-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\r\n\r\n\r\n------WebKitFormBoundaryHwsXKi4rKA6P5VBd--\r\n'`;
|
||||
|
||||
expect(convertCurl(curlCommand)).toEqual({
|
||||
resources: {
|
||||
workspaces: [baseWorkspace()],
|
||||
httpRequests: [
|
||||
baseRequest({
|
||||
url: 'http://localhost:8080/system',
|
||||
method: 'POST',
|
||||
headers: [
|
||||
{
|
||||
name: 'Content-Type',
|
||||
value: 'multipart/form-data; boundary=----WebKitFormBoundaryHwsXKi4rKA6P5VBd',
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
bodyType: 'multipart/form-data',
|
||||
body: {
|
||||
form: [
|
||||
{ name: 'username', value: 'jsgj', enabled: true },
|
||||
{ name: 'password', value: '654321', enabled: true },
|
||||
{ name: 'captcha', file: 'test.xlsx', enabled: true },
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('Imports multipart form data with text-only fields from --data-raw', () => {
|
||||
const curlCommand = `curl 'http://example.com/api' \
|
||||
-H 'Content-Type: multipart/form-data; boundary=----FormBoundary123' \
|
||||
--data-raw $'------FormBoundary123\r\nContent-Disposition: form-data; name="field1"\r\n\r\nvalue1\r\n------FormBoundary123\r\nContent-Disposition: form-data; name="field2"\r\n\r\nvalue2\r\n------FormBoundary123--\r\n'`;
|
||||
|
||||
expect(convertCurl(curlCommand)).toEqual({
|
||||
resources: {
|
||||
workspaces: [baseWorkspace()],
|
||||
httpRequests: [
|
||||
baseRequest({
|
||||
url: 'http://example.com/api',
|
||||
method: 'POST',
|
||||
headers: [
|
||||
{
|
||||
name: 'Content-Type',
|
||||
value: 'multipart/form-data; boundary=----FormBoundary123',
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
bodyType: 'multipart/form-data',
|
||||
body: {
|
||||
form: [
|
||||
{ name: 'field1', value: 'value1', enabled: true },
|
||||
{ name: 'field2', value: 'value2', enabled: true },
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const idCount: Partial<Record<string, number>> = {};
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"scripts": {
|
||||
"build": "run-p build:*",
|
||||
"build": "run-s build:*",
|
||||
"build:1-build": "yaakcli build",
|
||||
"build:2-cpywasm": "cpx '../../node_modules/@1password/sdk-core/nodejs/core_bg.*' build/",
|
||||
"build:2-cpywasm": "cpx \"../../node_modules/@1password/sdk-core/nodejs/core_bg.wasm\" build/",
|
||||
"dev": "yaakcli dev"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,26 +1,86 @@
|
||||
import crypto from 'node:crypto';
|
||||
import type { Client } from '@1password/sdk';
|
||||
import { createClient } from '@1password/sdk';
|
||||
import type { PluginDefinition } from '@yaakapp/api';
|
||||
import { createClient, DesktopAuth } from '@1password/sdk';
|
||||
import type { JsonPrimitive, PluginDefinition } from '@yaakapp/api';
|
||||
import type { CallTemplateFunctionArgs } from '@yaakapp-internal/plugins';
|
||||
|
||||
const _clients: Record<string, Client> = {};
|
||||
|
||||
async function op(args: CallTemplateFunctionArgs): Promise<Client | null> {
|
||||
const token = args.values.token;
|
||||
if (typeof token !== 'string') return null;
|
||||
async function op(args: CallTemplateFunctionArgs): Promise<{ client?: Client; error?: unknown }> {
|
||||
let authMethod: string | DesktopAuth | null = null;
|
||||
let hash: string | null = null;
|
||||
switch (args.values.authMethod) {
|
||||
case 'desktop': {
|
||||
const account = args.values.token;
|
||||
if (typeof account !== 'string' || !account) return { error: 'Missing account name' };
|
||||
|
||||
hash = crypto.createHash('sha256').update(`desktop:${account}`).digest('hex');
|
||||
authMethod = new DesktopAuth(account);
|
||||
break;
|
||||
}
|
||||
case 'token': {
|
||||
const token = args.values.token;
|
||||
if (typeof token !== 'string' || !token) return { error: 'Missing service token' };
|
||||
|
||||
hash = crypto.createHash('sha256').update(`token:${token}`).digest('hex');
|
||||
authMethod = token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hash == null || authMethod == null) return { error: 'Invalid authentication method' };
|
||||
|
||||
const tokenHash = crypto.createHash('sha256').update(token).digest('hex');
|
||||
try {
|
||||
_clients[tokenHash] ??= await createClient({
|
||||
auth: token,
|
||||
_clients[hash] ??= await createClient({
|
||||
auth: authMethod,
|
||||
integrationName: 'Yaak 1Password Plugin',
|
||||
integrationVersion: 'v1.0.0',
|
||||
});
|
||||
} catch {
|
||||
return null;
|
||||
} catch (e) {
|
||||
return { error: e };
|
||||
}
|
||||
return _clients[tokenHash];
|
||||
|
||||
return { client: _clients[hash] };
|
||||
}
|
||||
|
||||
async function getValue(
|
||||
args: CallTemplateFunctionArgs,
|
||||
vaultId?: JsonPrimitive,
|
||||
itemId?: JsonPrimitive,
|
||||
fieldId?: JsonPrimitive,
|
||||
): Promise<{ value?: string; error?: unknown }> {
|
||||
const { client, error } = await op(args);
|
||||
if (!client) return { error };
|
||||
|
||||
if (vaultId && typeof vaultId === 'string') {
|
||||
try {
|
||||
await client.vaults.getOverview(vaultId);
|
||||
} catch {
|
||||
return { error: `Vault ${vaultId} not found` };
|
||||
}
|
||||
} else {
|
||||
return { error: 'No vault specified' };
|
||||
}
|
||||
|
||||
if (itemId && typeof itemId === 'string') {
|
||||
try {
|
||||
const item = await client.items.get(vaultId, itemId);
|
||||
if (fieldId && typeof fieldId === 'string') {
|
||||
const field = item.fields.find((f) => f.id === fieldId);
|
||||
if (field) {
|
||||
return { value: field.value };
|
||||
} else {
|
||||
return { error: `Field ${fieldId} not found in item ${itemId} in vault ${vaultId}` };
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
return { error: `Item ${itemId} not found in vault ${vaultId}` };
|
||||
}
|
||||
} else {
|
||||
return { error: 'No item specified' };
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
export const plugin: PluginDefinition = {
|
||||
@@ -31,14 +91,50 @@ export const plugin: PluginDefinition = {
|
||||
previewArgs: ['field'],
|
||||
args: [
|
||||
{
|
||||
name: 'token',
|
||||
type: 'text',
|
||||
label: '1Password Service Account Token',
|
||||
description:
|
||||
'Token can be generated from the 1Password website by visiting Developer > Service Accounts',
|
||||
// biome-ignore lint/suspicious/noTemplateCurlyInString: Yaak template syntax
|
||||
defaultValue: '${[1PASSWORD_TOKEN]}',
|
||||
password: true,
|
||||
type: 'h_stack',
|
||||
inputs: [
|
||||
{
|
||||
name: 'authMethod',
|
||||
type: 'select',
|
||||
label: 'Authentication Method',
|
||||
defaultValue: 'token',
|
||||
options: [
|
||||
{
|
||||
label: 'Service Account',
|
||||
value: 'token',
|
||||
},
|
||||
{
|
||||
label: 'Desktop App',
|
||||
value: 'desktop',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'token',
|
||||
type: 'text',
|
||||
// biome-ignore lint/suspicious/noTemplateCurlyInString: Yaak template syntax
|
||||
defaultValue: '${[1PASSWORD_TOKEN]}',
|
||||
dynamic(_ctx, args) {
|
||||
switch (args.values.authMethod) {
|
||||
case 'desktop':
|
||||
return {
|
||||
label: 'Account Name',
|
||||
description:
|
||||
'Account name can be taken from the sidebar of the 1Password App. Make sure you\'re on the BETA version of the 1Password app and have "Integrate with other apps" enabled in Settings > Developer.',
|
||||
};
|
||||
case 'token':
|
||||
return {
|
||||
label: 'Token',
|
||||
description:
|
||||
'Token can be generated from the 1Password website by visiting Developer > Service Accounts',
|
||||
password: true,
|
||||
};
|
||||
}
|
||||
|
||||
return { hidden: true };
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'vault',
|
||||
@@ -46,7 +142,7 @@ export const plugin: PluginDefinition = {
|
||||
type: 'select',
|
||||
options: [],
|
||||
async dynamic(_ctx, args) {
|
||||
const client = await op(args);
|
||||
const { client } = await op(args);
|
||||
if (client == null) return { hidden: true };
|
||||
// Fetches a secret.
|
||||
const vaults = await client.vaults.list({ decryptDetails: true });
|
||||
@@ -64,18 +160,23 @@ export const plugin: PluginDefinition = {
|
||||
type: 'select',
|
||||
options: [],
|
||||
async dynamic(_ctx, args) {
|
||||
const client = await op(args);
|
||||
const { client } = await op(args);
|
||||
if (client == null) return { hidden: true };
|
||||
const vaultId = args.values.vault;
|
||||
if (typeof vaultId !== 'string') return { hidden: true };
|
||||
|
||||
const items = await client.items.list(vaultId);
|
||||
return {
|
||||
options: items.map((item) => ({
|
||||
label: `${item.title} ${item.category}`,
|
||||
value: item.id,
|
||||
})),
|
||||
};
|
||||
try {
|
||||
const items = await client.items.list(vaultId);
|
||||
return {
|
||||
options: items.map((item) => ({
|
||||
label: `${item.title} ${item.category}`,
|
||||
value: item.id,
|
||||
})),
|
||||
};
|
||||
} catch {
|
||||
// Hide as we can't list the items for this vault
|
||||
return { hidden: true };
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -84,7 +185,7 @@ export const plugin: PluginDefinition = {
|
||||
type: 'select',
|
||||
options: [],
|
||||
async dynamic(_ctx, args) {
|
||||
const client = await op(args);
|
||||
const { client } = await op(args);
|
||||
if (client == null) return { hidden: true };
|
||||
const vaultId = args.values.vault;
|
||||
const itemId = args.values.item;
|
||||
@@ -92,34 +193,28 @@ export const plugin: PluginDefinition = {
|
||||
return { hidden: true };
|
||||
}
|
||||
|
||||
const item = await client.items.get(vaultId, itemId);
|
||||
|
||||
return {
|
||||
options: item.fields.map((field) => ({ label: field.title, value: field.id })),
|
||||
};
|
||||
try {
|
||||
const item = await client.items.get(vaultId, itemId);
|
||||
return {
|
||||
options: item.fields.map((field) => ({ label: field.title, value: field.id })),
|
||||
};
|
||||
} catch {
|
||||
// Hide as we can't find the item within this vault
|
||||
return { hidden: true };
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
async onRender(_ctx, args) {
|
||||
const client = await op(args);
|
||||
if (client == null) throw new Error('Invalid token');
|
||||
const vaultId = args.values.vault;
|
||||
const itemId = args.values.item;
|
||||
const fieldId = args.values.field;
|
||||
if (
|
||||
typeof vaultId !== 'string' ||
|
||||
typeof itemId !== 'string' ||
|
||||
typeof fieldId !== 'string'
|
||||
) {
|
||||
return null;
|
||||
const { value, error } = await getValue(args, vaultId, itemId, fieldId);
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
const item = await client.items.get(vaultId, itemId);
|
||||
const field = item.fields.find((f) => f.id === fieldId);
|
||||
if (field == null) {
|
||||
throw new Error(`Field not found: ${fieldId}`);
|
||||
}
|
||||
return field.value ?? '';
|
||||
return value ?? '';
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,791 +1,116 @@
|
||||
import type { PluginDefinition } from '@yaakapp/api';
|
||||
import { andromeda } from './themes/andromeda';
|
||||
import { atomOneDark } from './themes/atom-one-dark';
|
||||
import { ayuDark, ayuLight, ayuMirage } from './themes/ayu';
|
||||
import { blulocoDark, blulocoLight } from './themes/bluloco';
|
||||
import {
|
||||
catppuccinFrappe,
|
||||
catppuccinLatte,
|
||||
catppuccinMacchiato,
|
||||
catppuccinMocha,
|
||||
} from './themes/catppuccin';
|
||||
import { cobalt2 } from './themes/cobalt2';
|
||||
import { dracula } from './themes/dracula';
|
||||
import { everforestDark, everforestLight } from './themes/everforest';
|
||||
import { fleetDark, fleetDarkPurple, fleetLight } from './themes/fleet';
|
||||
import { githubDark, githubLight } from './themes/github';
|
||||
import { githubDarkDimmed } from './themes/github-dimmed';
|
||||
import { gruvbox } from './themes/gruvbox';
|
||||
// Yaak themes
|
||||
import { highContrast, highContrastDark } from './themes/high-contrast';
|
||||
import { horizon } from './themes/horizon';
|
||||
import { hotdogStand } from './themes/hotdog-stand';
|
||||
import { materialDarker } from './themes/material-darker';
|
||||
import { materialOcean } from './themes/material-ocean';
|
||||
import { materialPalenight } from './themes/material-palenight';
|
||||
import {
|
||||
monokaiPro,
|
||||
monokaiProClassic,
|
||||
monokaiProMachine,
|
||||
monokaiProOctagon,
|
||||
monokaiProRistretto,
|
||||
monokaiProSpectrum,
|
||||
} from './themes/monokai-pro';
|
||||
import { moonlight } from './themes/moonlight';
|
||||
import { lightOwl, nightOwl } from './themes/night-owl';
|
||||
import { noctisAzureus } from './themes/noctis';
|
||||
import { nord, nordLight, nordLightBrighter } from './themes/nord';
|
||||
// VSCode themes
|
||||
import { oneDarkPro } from './themes/one-dark-pro';
|
||||
import { pandaSyntax } from './themes/panda';
|
||||
import { relaxing } from './themes/relaxing';
|
||||
import { rosePine, rosePineDawn, rosePineMoon } from './themes/rose-pine';
|
||||
import { shadesOfPurple, shadesOfPurpleSuperDark } from './themes/shades-of-purple';
|
||||
import { slackAubergine } from './themes/slack';
|
||||
import { solarizedDark, solarizedLight } from './themes/solarized';
|
||||
import { synthwave84 } from './themes/synthwave-84';
|
||||
import { tokyoNight, tokyoNightDay, tokyoNightStorm } from './themes/tokyo-night';
|
||||
import { triangle } from './themes/triangle';
|
||||
import { vitesseDark, vitesseLight } from './themes/vitesse';
|
||||
import { winterIsComing } from './themes/winter-is-coming';
|
||||
|
||||
export const plugin: PluginDefinition = {
|
||||
themes: [
|
||||
{
|
||||
id: 'high-contrast',
|
||||
label: 'High Contrast Light',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'white',
|
||||
surfaceHighlight: 'hsl(218,24%,93%)',
|
||||
text: 'black',
|
||||
textSubtle: 'hsl(217,24%,40%)',
|
||||
textSubtlest: 'hsl(217,24%,40%)',
|
||||
border: 'hsl(217,22%,50%)',
|
||||
borderSubtle: 'hsl(217,22%,60%)',
|
||||
primary: 'hsl(267,67%,47%)',
|
||||
secondary: 'hsl(218,18%,53%)',
|
||||
info: 'hsl(206,100%,36%)',
|
||||
success: 'hsl(155,100%,26%)',
|
||||
notice: 'hsl(45,100%,31%)',
|
||||
warning: 'hsl(30,99%,34%)',
|
||||
danger: 'hsl(334,100%,35%)',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'high-contrast-dark',
|
||||
label: 'High Contrast Dark',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(0,0%,0%)',
|
||||
surfaceHighlight: 'hsl(0,0%,20%)',
|
||||
text: 'hsl(0,0%,100%)',
|
||||
textSubtle: 'hsl(0,0%,90%)',
|
||||
textSubtlest: 'hsl(0,0%,80%)',
|
||||
selection: 'hsl(276,100%,30%)',
|
||||
surfaceActive: 'hsl(276,100%,30%)',
|
||||
border: 'hsl(0,0%,60%)',
|
||||
primary: 'hsl(266,100%,85%)',
|
||||
secondary: 'hsl(242,20%,72%)',
|
||||
info: 'hsl(208,100%,83%)',
|
||||
success: 'hsl(150,100%,63%)',
|
||||
notice: 'hsl(49,100%,77%)',
|
||||
warning: 'hsl(28,100%,73%)',
|
||||
danger: 'hsl(343,100%,79%)',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'catppuccin-frappe',
|
||||
label: 'Catppuccin Frappé',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(231,19%,20%)',
|
||||
text: 'hsl(227,70%,87%)',
|
||||
textSubtle: 'hsl(228,29%,73%)',
|
||||
textSubtlest: 'hsl(227,17%,58%)',
|
||||
primary: 'hsl(277,59%,76%)',
|
||||
secondary: 'hsl(228,39%,80%)',
|
||||
info: 'hsl(222,74%,74%)',
|
||||
success: 'hsl(96,44%,68%)',
|
||||
notice: 'hsl(40,62%,73%)',
|
||||
warning: 'hsl(20,79%,70%)',
|
||||
danger: 'hsl(359,68%,71%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(240,21%,12%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(229,19%,23%)',
|
||||
border: 'hsl(229,19%,27%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(229,20%,17%)',
|
||||
border: 'hsl(229,20%,25%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(229,19%,23%)',
|
||||
border: 'hsl(229,19%,27%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(277,59%,68%)',
|
||||
secondary: 'hsl(228,39%,72%)',
|
||||
info: 'hsl(222,74%,67%)',
|
||||
success: 'hsl(96,44%,61%)',
|
||||
notice: 'hsl(40,62%,66%)',
|
||||
warning: 'hsl(20,79%,63%)',
|
||||
danger: 'hsl(359,68%,64%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'catppuccin-macchiato',
|
||||
label: 'Catppuccin Macchiato',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(233,23%,15%)',
|
||||
text: 'hsl(227,68%,88%)',
|
||||
textSubtle: 'hsl(227,27%,72%)',
|
||||
textSubtlest: 'hsl(228,15%,57%)',
|
||||
primary: 'hsl(267,83%,80%)',
|
||||
secondary: 'hsl(228,39%,80%)',
|
||||
info: 'hsl(220,83%,75%)',
|
||||
success: 'hsl(105,48%,72%)',
|
||||
notice: 'hsl(40,70%,78%)',
|
||||
warning: 'hsl(21,86%,73%)',
|
||||
danger: 'hsl(351,74%,73%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(240,21%,12%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(232,23%,18%)',
|
||||
border: 'hsl(231,23%,22%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(236,23%,12%)',
|
||||
border: 'hsl(236,23%,21%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(232,23%,18%)',
|
||||
border: 'hsl(231,23%,22%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(267,82%,72%)',
|
||||
secondary: 'hsl(228,39%,72%)',
|
||||
info: 'hsl(220,83%,68%)',
|
||||
success: 'hsl(105,48%,65%)',
|
||||
notice: 'hsl(40,70%,70%)',
|
||||
warning: 'hsl(21,86%,66%)',
|
||||
danger: 'hsl(351,74%,66%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'catppuccin-mocha',
|
||||
label: 'Catppuccin Mocha',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(240,21%,12%)',
|
||||
text: 'hsl(226,64%,88%)',
|
||||
textSubtle: 'hsl(228,24%,72%)',
|
||||
textSubtlest: 'hsl(230,13%,55%)',
|
||||
primary: 'hsl(267,83%,80%)',
|
||||
secondary: 'hsl(227,35%,80%)',
|
||||
info: 'hsl(217,92%,76%)',
|
||||
success: 'hsl(115,54%,76%)',
|
||||
notice: 'hsl(41,86%,83%)',
|
||||
warning: 'hsl(23,92%,75%)',
|
||||
danger: 'hsl(343,81%,75%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(240,21%,12%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(240,21%,15%)',
|
||||
border: 'hsl(240,21%,19%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(240,23%,9%)',
|
||||
border: 'hsl(240,22%,18%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(240,21%,15%)',
|
||||
border: 'hsl(240,21%,19%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(267,67%,65%)',
|
||||
secondary: 'hsl(227,28%,64%)',
|
||||
info: 'hsl(217,74%,61%)',
|
||||
success: 'hsl(115,43%,61%)',
|
||||
notice: 'hsl(41,69%,66%)',
|
||||
warning: 'hsl(23,74%,60%)',
|
||||
danger: 'hsl(343,65%,60%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'catppuccin-latte',
|
||||
label: 'Catppuccin Latte',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'hsl(220,23%,95%)',
|
||||
text: 'hsl(234,16%,35%)',
|
||||
textSubtle: 'hsl(233,10%,47%)',
|
||||
textSubtlest: 'hsl(231,10%,59%)',
|
||||
primary: 'hsl(266,85%,58%)',
|
||||
secondary: 'hsl(233,10%,47%)',
|
||||
info: 'hsl(231,97%,72%)',
|
||||
success: 'hsl(183,74%,35%)',
|
||||
notice: 'hsl(35,77%,49%)',
|
||||
warning: 'hsl(22,99%,52%)',
|
||||
danger: 'hsl(355,76%,59%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: 'hsl(220,22%,92%)',
|
||||
border: 'hsl(220,22%,87%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(220,21%,89%)',
|
||||
border: 'hsl(220,22%,87%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'dracula',
|
||||
label: 'Dracula',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(231,15%,18%)',
|
||||
surfaceHighlight: 'hsl(230,15%,24%)',
|
||||
text: 'hsl(60,30%,96%)',
|
||||
textSubtle: 'hsl(232,14%,65%)',
|
||||
textSubtlest: 'hsl(232,14%,50%)',
|
||||
primary: 'hsl(265,89%,78%)',
|
||||
secondary: 'hsl(225,27%,51%)',
|
||||
info: 'hsl(191,97%,77%)',
|
||||
success: 'hsl(135,94%,65%)',
|
||||
notice: 'hsl(65,92%,76%)',
|
||||
warning: 'hsl(31,100%,71%)',
|
||||
danger: 'hsl(0,100%,67%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
backdrop: 'hsl(230,15%,24%)',
|
||||
},
|
||||
appHeader: {
|
||||
backdrop: 'hsl(235,14%,15%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'github-dark',
|
||||
label: 'GitHub',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(213,30%,7%)',
|
||||
surfaceHighlight: 'hsl(213,16%,13%)',
|
||||
text: 'hsl(212,27%,89%)',
|
||||
textSubtle: 'hsl(212,9%,57%)',
|
||||
textSubtlest: 'hsl(217,8%,45%)',
|
||||
border: 'hsl(215,21%,11%)',
|
||||
primary: 'hsl(262,78%,74%)',
|
||||
secondary: 'hsl(217,8%,50%)',
|
||||
info: 'hsl(215,84%,64%)',
|
||||
success: 'hsl(129,48%,52%)',
|
||||
notice: 'hsl(39,71%,58%)',
|
||||
warning: 'hsl(22,83%,60%)',
|
||||
danger: 'hsl(3,83%,65%)',
|
||||
},
|
||||
components: {
|
||||
button: {
|
||||
primary: 'hsl(262,79%,71%)',
|
||||
secondary: 'hsl(217,8%,45%)',
|
||||
info: 'hsl(215,84%,60%)',
|
||||
success: 'hsl(129,48%,47%)',
|
||||
notice: 'hsl(39,71%,53%)',
|
||||
warning: 'hsl(22,83%,56%)',
|
||||
danger: 'hsl(3,83%,61%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'github-light',
|
||||
label: 'GitHub',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'hsl(0,0%,100%)',
|
||||
surfaceHighlight: 'hsl(210,29%,94%)',
|
||||
text: 'hsl(213,13%,14%)',
|
||||
textSubtle: 'hsl(212,9%,43%)',
|
||||
textSubtlest: 'hsl(203,8%,55%)',
|
||||
border: 'hsl(210,15%,92%)',
|
||||
borderSubtle: 'hsl(210,15%,92%)',
|
||||
primary: 'hsl(261,69%,59%)',
|
||||
secondary: 'hsl(212,8%,47%)',
|
||||
info: 'hsl(212,92%,48%)',
|
||||
success: 'hsl(137,66%,32%)',
|
||||
notice: 'hsl(40,100%,40%)',
|
||||
warning: 'hsl(24,100%,44%)',
|
||||
danger: 'hsl(356,71%,48%)',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'gruvbox',
|
||||
label: 'Gruvbox',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(0,0%,16%)',
|
||||
surfaceHighlight: 'hsl(20,3%,19%)',
|
||||
text: 'hsl(53,74%,91%)',
|
||||
textSubtle: 'hsl(39,24%,66%)',
|
||||
textSubtlest: 'hsl(30,12%,51%)',
|
||||
primary: 'hsl(344,47%,68%)',
|
||||
secondary: 'hsl(157,16%,58%)',
|
||||
info: 'hsl(104,35%,62%)',
|
||||
success: 'hsl(61,66%,44%)',
|
||||
notice: 'hsl(42,95%,58%)',
|
||||
warning: 'hsl(27,99%,55%)',
|
||||
danger: 'hsl(6,96%,59%)',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'hotdog-stand',
|
||||
label: 'Hotdog Stand',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(0,100%,50%)',
|
||||
surfaceHighlight: 'hsl(0,0%,0%)',
|
||||
text: 'hsl(0,0%,100%)',
|
||||
textSubtle: 'hsl(0,0%,100%)',
|
||||
textSubtlest: 'hsl(60,100%,50%)',
|
||||
border: 'hsl(0,0%,0%)',
|
||||
primary: 'hsl(60,100%,50%)',
|
||||
secondary: 'hsl(60,100%,50%)',
|
||||
info: 'hsl(60,100%,50%)',
|
||||
success: 'hsl(60,100%,50%)',
|
||||
notice: 'hsl(60,100%,50%)',
|
||||
warning: 'hsl(60,100%,50%)',
|
||||
danger: 'hsl(60,100%,50%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(0,0%,0%)',
|
||||
text: 'hsl(0,0%,100%)',
|
||||
textSubtle: 'hsl(60,100%,50%)',
|
||||
textSubtlest: 'hsl(0,100%,50%)',
|
||||
},
|
||||
menu: {
|
||||
surface: 'hsl(0,0%,0%)',
|
||||
border: 'hsl(0,100%,50%)',
|
||||
surfaceHighlight: 'hsl(0,100%,50%)',
|
||||
text: 'hsl(0,0%,100%)',
|
||||
textSubtle: 'hsl(60,100%,50%)',
|
||||
textSubtlest: 'hsl(60,100%,50%)',
|
||||
},
|
||||
button: {
|
||||
surface: 'hsl(0,0%,0%)',
|
||||
text: 'hsl(0,0%,100%)',
|
||||
primary: 'hsl(0,0%,0%)',
|
||||
secondary: 'hsl(0,0%,100%)',
|
||||
info: 'hsl(0,0%,0%)',
|
||||
success: 'hsl(60,100%,50%)',
|
||||
notice: 'hsl(60,100%,50%)',
|
||||
warning: 'hsl(0,0%,0%)',
|
||||
danger: 'hsl(0,100%,50%)',
|
||||
},
|
||||
editor: {
|
||||
primary: 'hsl(0,0%,100%)',
|
||||
secondary: 'hsl(0,0%,100%)',
|
||||
info: 'hsl(0,0%,100%)',
|
||||
success: 'hsl(0,0%,100%)',
|
||||
notice: 'hsl(60,100%,50%)',
|
||||
warning: 'hsl(0,0%,100%)',
|
||||
danger: 'hsl(0,0%,100%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'monokai-pro',
|
||||
label: 'Monokai Pro',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(285,5%,17%)',
|
||||
text: 'hsl(60,25%,98%)',
|
||||
textSubtle: 'hsl(0,1%,75%)',
|
||||
textSubtlest: 'hsl(300,0%,57%)',
|
||||
primary: 'hsl(250,77%,78%)',
|
||||
secondary: 'hsl(0,1%,75%)',
|
||||
info: 'hsl(186,71%,69%)',
|
||||
success: 'hsl(90,59%,66%)',
|
||||
notice: 'hsl(45,100%,70%)',
|
||||
warning: 'hsl(20,96%,70%)',
|
||||
danger: 'hsl(345,100%,69%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(300,5%,13%)',
|
||||
text: 'hsl(0,1%,75%)',
|
||||
textSubtle: 'hsl(300,0%,57%)',
|
||||
textSubtlest: 'hsl(300,1%,44%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(250,77%,70%)',
|
||||
secondary: 'hsl(0,1%,68%)',
|
||||
info: 'hsl(186,71%,62%)',
|
||||
success: 'hsl(90,59%,59%)',
|
||||
notice: 'hsl(45,100%,63%)',
|
||||
warning: 'hsl(20,96%,63%)',
|
||||
danger: 'hsl(345,100%,62%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'monokai-pro-classic',
|
||||
label: 'Monokai Pro Classic',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(70,8%,15%)',
|
||||
text: 'hsl(69,100%,97%)',
|
||||
textSubtle: 'hsl(65,9%,73%)',
|
||||
textSubtlest: 'hsl(66,4%,55%)',
|
||||
primary: 'hsl(261,100%,75%)',
|
||||
secondary: 'hsl(202,8%,72%)',
|
||||
info: 'hsl(190,81%,67%)',
|
||||
success: 'hsl(80,76%,53%)',
|
||||
notice: 'hsl(54,70%,68%)',
|
||||
warning: 'hsl(32,98%,56%)',
|
||||
danger: 'hsl(338,95%,56%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(72,9%,11%)',
|
||||
text: 'hsl(202,8%,72%)',
|
||||
textSubtle: 'hsl(213,4%,48%)',
|
||||
textSubtlest: 'hsl(223,6%,44%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(261,100%,68%)',
|
||||
secondary: 'hsl(202,8%,65%)',
|
||||
info: 'hsl(190,81%,60%)',
|
||||
success: 'hsl(80,76%,48%)',
|
||||
notice: 'hsl(54,71%,61%)',
|
||||
warning: 'hsl(32,98%,50%)',
|
||||
danger: 'hsl(338,95%,50%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'monokai-pro-machine',
|
||||
label: 'Monokai Pro Machine',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(200,16%,18%)',
|
||||
text: 'hsl(173,24%,93%)',
|
||||
textSubtle: 'hsl(185,6%,57%)',
|
||||
textSubtlest: 'hsl(189,6%,45%)',
|
||||
primary: 'hsl(258,86%,80%)',
|
||||
secondary: 'hsl(175,9%,75%)',
|
||||
info: 'hsl(194,81%,72%)',
|
||||
success: 'hsl(98,67%,69%)',
|
||||
notice: 'hsl(52,100%,72%)',
|
||||
warning: 'hsl(28,100%,72%)',
|
||||
danger: 'hsl(353,100%,71%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(196,16%,14%)',
|
||||
text: 'hsl(202,8%,72%)',
|
||||
textSubtle: 'hsl(213,4%,48%)',
|
||||
textSubtlest: 'hsl(223,6%,44%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(258,86%,72%)',
|
||||
secondary: 'hsl(175,9%,68%)',
|
||||
info: 'hsl(194,80%,65%)',
|
||||
success: 'hsl(98,67%,62%)',
|
||||
notice: 'hsl(52,100%,65%)',
|
||||
warning: 'hsl(28,100%,65%)',
|
||||
danger: 'hsl(353,100%,64%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'monokai-pro-octagon',
|
||||
label: 'Monokai Pro Octagon',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(233,18%,19%)',
|
||||
text: 'hsl(173,24%,93%)',
|
||||
textSubtle: 'hsl(202,8%,72%)',
|
||||
textSubtlest: 'hsl(213,4%,48%)',
|
||||
primary: 'hsl(292,30%,70%)',
|
||||
secondary: 'hsl(202,8%,72%)',
|
||||
info: 'hsl(155,37%,72%)',
|
||||
success: 'hsl(75,60%,61%)',
|
||||
notice: 'hsl(44,100%,71%)',
|
||||
warning: 'hsl(23,100%,68%)',
|
||||
danger: 'hsl(352,100%,70%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(235,18%,14%)',
|
||||
text: 'hsl(202,8%,72%)',
|
||||
textSubtle: 'hsl(213,4%,48%)',
|
||||
textSubtlest: 'hsl(223,6%,44%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(292,26%,63%)',
|
||||
secondary: 'hsl(201,7%,65%)',
|
||||
info: 'hsl(155,33%,65%)',
|
||||
success: 'hsl(75,54%,55%)',
|
||||
notice: 'hsl(44,90%,64%)',
|
||||
warning: 'hsl(23,90%,61%)',
|
||||
danger: 'hsl(352,90%,63%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'monokai-pro-ristretto',
|
||||
label: 'Monokai Pro Ristretto',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(0,9%,16%)',
|
||||
text: 'hsl(351,100%,97%)',
|
||||
textSubtle: 'hsl(355,9%,74%)',
|
||||
textSubtlest: 'hsl(354,4%,56%)',
|
||||
primary: 'hsl(239,63%,79%)',
|
||||
secondary: 'hsl(355,9%,74%)',
|
||||
info: 'hsl(170,53%,69%)',
|
||||
success: 'hsl(88,57%,66%)',
|
||||
notice: 'hsl(41,92%,70%)',
|
||||
warning: 'hsl(13,85%,70%)',
|
||||
danger: 'hsl(349,97%,70%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(0,8%,12%)',
|
||||
text: 'hsl(355,9%,74%)',
|
||||
textSubtle: 'hsl(354,4%,56%)',
|
||||
textSubtlest: 'hsl(353,4%,43%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(239,63%,71%)',
|
||||
secondary: 'hsl(355,9%,67%)',
|
||||
info: 'hsl(170,53%,62%)',
|
||||
success: 'hsl(88,57%,59%)',
|
||||
notice: 'hsl(41,92%,63%)',
|
||||
warning: 'hsl(13,86%,63%)',
|
||||
danger: 'hsl(349,97%,63%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'monokai-pro-spectrum',
|
||||
label: 'Monokai Pro Spectrum',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(0,0%,13%)',
|
||||
text: 'hsl(266,100%,97%)',
|
||||
textSubtle: 'hsl(264,7%,73%)',
|
||||
textSubtlest: 'hsl(266,3%,55%)',
|
||||
primary: 'hsl(247,61%,72%)',
|
||||
secondary: 'hsl(264,7%,73%)',
|
||||
info: 'hsl(188,74%,63%)',
|
||||
success: 'hsl(133,54%,66%)',
|
||||
notice: 'hsl(51,96%,69%)',
|
||||
warning: 'hsl(23,98%,66%)',
|
||||
danger: 'hsl(343,96%,68%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(0,0%,10%)',
|
||||
text: 'hsl(264,7%,73%)',
|
||||
textSubtle: 'hsl(266,3%,55%)',
|
||||
textSubtlest: 'hsl(264,2%,41%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(247,61%,65%)',
|
||||
secondary: 'hsl(264,7%,66%)',
|
||||
info: 'hsl(188,74%,57%)',
|
||||
success: 'hsl(133,54%,59%)',
|
||||
notice: 'hsl(51,96%,62%)',
|
||||
warning: 'hsl(23,98%,59%)',
|
||||
danger: 'hsl(343,96%,61%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'moonlight',
|
||||
label: 'Moonlight',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(234,23%,17%)',
|
||||
text: 'hsl(225,71%,90%)',
|
||||
textSubtle: 'hsl(230,28%,62%)',
|
||||
textSubtlest: 'hsl(232,26%,43%)',
|
||||
primary: 'hsl(262,100%,82%)',
|
||||
secondary: 'hsl(232,18%,65%)',
|
||||
info: 'hsl(217,100%,74%)',
|
||||
success: 'hsl(174,66%,54%)',
|
||||
notice: 'hsl(35,100%,73%)',
|
||||
warning: 'hsl(17,100%,71%)',
|
||||
danger: 'hsl(356,100%,73%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(233,23%,15%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(233,23%,15%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'nord',
|
||||
label: 'Nord',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(220,16%,22%)',
|
||||
surfaceHighlight: 'hsl(220,14%,28%)',
|
||||
text: 'hsl(220,28%,93%)',
|
||||
textSubtle: 'hsl(220,26%,90%)',
|
||||
textSubtlest: 'hsl(220,24%,86%)',
|
||||
primary: 'hsl(193,38%,68%)',
|
||||
secondary: 'hsl(210,34%,63%)',
|
||||
info: 'hsl(174,25%,69%)',
|
||||
success: 'hsl(89,26%,66%)',
|
||||
notice: 'hsl(40,66%,73%)',
|
||||
warning: 'hsl(17,48%,64%)',
|
||||
danger: 'hsl(353,43%,56%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
backdrop: 'hsl(220,16%,22%)',
|
||||
},
|
||||
appHeader: {
|
||||
backdrop: 'hsl(220,14%,28%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'relaxing',
|
||||
label: 'Relaxing',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(267,33%,17%)',
|
||||
text: 'hsl(275,49%,92%)',
|
||||
primary: 'hsl(267,84%,81%)',
|
||||
secondary: 'hsl(227,35%,80%)',
|
||||
info: 'hsl(217,92%,76%)',
|
||||
success: 'hsl(115,54%,76%)',
|
||||
notice: 'hsl(41,86%,83%)',
|
||||
warning: 'hsl(23,92%,75%)',
|
||||
danger: 'hsl(343,81%,75%)',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'rose-pine',
|
||||
label: 'Rosé Pine',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(249,22%,12%)',
|
||||
text: 'hsl(245,50%,91%)',
|
||||
textSubtle: 'hsl(248,15%,61%)',
|
||||
textSubtlest: 'hsl(249,12%,47%)',
|
||||
primary: 'hsl(267,57%,78%)',
|
||||
secondary: 'hsl(249,12%,47%)',
|
||||
info: 'hsl(199,49%,60%)',
|
||||
success: 'hsl(180,43%,73%)',
|
||||
notice: 'hsl(35,88%,72%)',
|
||||
warning: 'hsl(1,74%,79%)',
|
||||
danger: 'hsl(343,76%,68%)',
|
||||
},
|
||||
components: {
|
||||
responsePane: {
|
||||
surface: 'hsl(247,23%,15%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(247,23%,15%)',
|
||||
},
|
||||
menu: {
|
||||
surface: 'hsl(248,21%,26%)',
|
||||
textSubtle: 'hsl(248,15%,66%)',
|
||||
textSubtlest: 'hsl(249,12%,52%)',
|
||||
border: 'hsl(248,21%,35%)',
|
||||
borderSubtle: 'hsl(248,21%,33%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'rose-pine-moon',
|
||||
label: 'Rosé Pine Moon',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(246,24%,17%)',
|
||||
text: 'hsl(245,50%,91%)',
|
||||
textSubtle: 'hsl(248,15%,61%)',
|
||||
textSubtlest: 'hsl(249,12%,47%)',
|
||||
primary: 'hsl(267,57%,78%)',
|
||||
secondary: 'hsl(248,15%,61%)',
|
||||
info: 'hsl(197,48%,60%)',
|
||||
success: 'hsl(197,48%,60%)',
|
||||
notice: 'hsl(35,88%,72%)',
|
||||
warning: 'hsl(2,66%,75%)',
|
||||
danger: 'hsl(343,76%,68%)',
|
||||
},
|
||||
components: {
|
||||
responsePane: {
|
||||
surface: 'hsl(247,24%,20%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(247,24%,20%)',
|
||||
},
|
||||
menu: {
|
||||
surface: 'hsl(248,21%,26%)',
|
||||
textSubtle: 'hsl(248,15%,61%)',
|
||||
textSubtlest: 'hsl(249,12%,55%)',
|
||||
border: 'hsl(248,21%,35%)',
|
||||
borderSubtle: 'hsl(248,21%,31%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'rose-pine-dawn',
|
||||
label: 'Rosé Pine Dawn',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'hsl(32,57%,95%)',
|
||||
border: 'hsl(10,9%,86%)',
|
||||
surfaceHighlight: 'hsl(25,35%,93%)',
|
||||
text: 'hsl(248,19%,40%)',
|
||||
textSubtle: 'hsl(248,12%,52%)',
|
||||
textSubtlest: 'hsl(257,9%,61%)',
|
||||
primary: 'hsl(271,27%,56%)',
|
||||
secondary: 'hsl(249,12%,47%)',
|
||||
info: 'hsl(197,52%,36%)',
|
||||
success: 'hsl(188,31%,45%)',
|
||||
notice: 'hsl(34,64%,49%)',
|
||||
warning: 'hsl(2,47%,64%)',
|
||||
danger: 'hsl(343,35%,55%)',
|
||||
},
|
||||
components: {
|
||||
responsePane: {
|
||||
border: 'hsl(20,12%,90%)',
|
||||
},
|
||||
sidebar: {
|
||||
border: 'hsl(20,12%,90%)',
|
||||
},
|
||||
appHeader: {
|
||||
border: 'hsl(20,12%,90%)',
|
||||
},
|
||||
input: {
|
||||
border: 'hsl(10,9%,86%)',
|
||||
},
|
||||
dialog: {
|
||||
border: 'hsl(20,12%,90%)',
|
||||
},
|
||||
menu: {
|
||||
surface: 'hsl(28,40%,92%)',
|
||||
border: 'hsl(10,9%,86%)',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'triangle',
|
||||
dark: true,
|
||||
label: 'Triangle',
|
||||
base: {
|
||||
surface: 'rgb(0,0,0)',
|
||||
surfaceHighlight: 'rgb(21,21,21)',
|
||||
surfaceActive: 'rgb(31,31,31)',
|
||||
text: 'rgb(237,237,237)',
|
||||
textSubtle: 'rgb(161,161,161)',
|
||||
textSubtlest: 'rgb(115,115,115)',
|
||||
border: 'rgb(31,31,31)',
|
||||
primary: 'rgb(196,114,251)',
|
||||
secondary: 'rgb(161,161,161)',
|
||||
info: 'rgb(71,168,255)',
|
||||
success: 'rgb(0,202,81)',
|
||||
notice: 'rgb(255,175,0)',
|
||||
warning: '#FF4C8D',
|
||||
danger: '#fd495a',
|
||||
},
|
||||
components: {
|
||||
editor: {
|
||||
danger: '#FF4C8D',
|
||||
warning: '#fd495a',
|
||||
},
|
||||
dialog: {
|
||||
surface: 'rgb(10,10,10)',
|
||||
border: 'rgb(31,31,31)',
|
||||
},
|
||||
sidebar: {
|
||||
border: 'rgb(31,31,31)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'rgb(10,10,10)',
|
||||
border: 'rgb(31,31,31)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'rgb(10,10,10)',
|
||||
border: 'rgb(31,31,31)',
|
||||
},
|
||||
},
|
||||
},
|
||||
andromeda,
|
||||
atomOneDark,
|
||||
ayuDark,
|
||||
ayuLight,
|
||||
ayuMirage,
|
||||
blulocoDark,
|
||||
blulocoLight,
|
||||
catppuccinFrappe,
|
||||
catppuccinLatte,
|
||||
catppuccinMacchiato,
|
||||
catppuccinMocha,
|
||||
cobalt2,
|
||||
dracula,
|
||||
everforestDark,
|
||||
everforestLight,
|
||||
fleetDark,
|
||||
fleetDarkPurple,
|
||||
fleetLight,
|
||||
githubDark,
|
||||
githubDarkDimmed,
|
||||
githubLight,
|
||||
gruvbox,
|
||||
highContrast,
|
||||
highContrastDark,
|
||||
horizon,
|
||||
hotdogStand,
|
||||
lightOwl,
|
||||
materialDarker,
|
||||
materialOcean,
|
||||
materialPalenight,
|
||||
monokaiPro,
|
||||
monokaiProClassic,
|
||||
monokaiProMachine,
|
||||
monokaiProOctagon,
|
||||
monokaiProRistretto,
|
||||
monokaiProSpectrum,
|
||||
moonlight,
|
||||
nightOwl,
|
||||
noctisAzureus,
|
||||
nord,
|
||||
nordLight,
|
||||
nordLightBrighter,
|
||||
oneDarkPro,
|
||||
pandaSyntax,
|
||||
relaxing,
|
||||
rosePine,
|
||||
rosePineDawn,
|
||||
rosePineMoon,
|
||||
shadesOfPurple,
|
||||
shadesOfPurpleSuperDark,
|
||||
slackAubergine,
|
||||
solarizedDark,
|
||||
solarizedLight,
|
||||
synthwave84,
|
||||
tokyoNight,
|
||||
tokyoNightDay,
|
||||
tokyoNightStorm,
|
||||
triangle,
|
||||
vitesseDark,
|
||||
vitesseLight,
|
||||
winterIsComing,
|
||||
],
|
||||
};
|
||||
|
||||
47
plugins/themes-yaak/src/themes/andromeda.ts
Normal file
47
plugins/themes-yaak/src/themes/andromeda.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const andromeda: Theme = {
|
||||
id: 'andromeda',
|
||||
label: 'Andromeda',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(251, 25%, 15%)',
|
||||
surfaceHighlight: 'hsl(251, 22%, 20%)',
|
||||
text: 'hsl(220, 10%, 85%)',
|
||||
textSubtle: 'hsl(220, 8%, 60%)',
|
||||
textSubtlest: 'hsl(220, 6%, 45%)',
|
||||
primary: 'hsl(293, 75%, 68%)',
|
||||
secondary: 'hsl(220, 8%, 60%)',
|
||||
info: 'hsl(180, 60%, 60%)',
|
||||
success: 'hsl(85, 60%, 55%)',
|
||||
notice: 'hsl(38, 100%, 65%)',
|
||||
warning: 'hsl(25, 95%, 60%)',
|
||||
danger: 'hsl(358, 80%, 60%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(251, 25%, 12%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(251, 23%, 13%)',
|
||||
border: 'hsl(251, 20%, 18%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(251, 25%, 11%)',
|
||||
border: 'hsl(251, 20%, 16%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(251, 23%, 13%)',
|
||||
border: 'hsl(251, 20%, 18%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(293, 75%, 61%)',
|
||||
secondary: 'hsl(220, 8%, 53%)',
|
||||
info: 'hsl(180, 60%, 53%)',
|
||||
success: 'hsl(85, 60%, 48%)',
|
||||
notice: 'hsl(38, 100%, 58%)',
|
||||
warning: 'hsl(25, 95%, 53%)',
|
||||
danger: 'hsl(358, 80%, 53%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
47
plugins/themes-yaak/src/themes/atom-one-dark.ts
Normal file
47
plugins/themes-yaak/src/themes/atom-one-dark.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const atomOneDark: Theme = {
|
||||
id: 'atom-one-dark',
|
||||
label: 'Atom One Dark',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(220, 13%, 18%)',
|
||||
surfaceHighlight: 'hsl(219, 13%, 22%)',
|
||||
text: 'hsl(219, 14%, 71%)',
|
||||
textSubtle: 'hsl(220, 9%, 55%)',
|
||||
textSubtlest: 'hsl(220, 8%, 45%)',
|
||||
primary: 'hsl(286, 60%, 67%)',
|
||||
secondary: 'hsl(220, 9%, 55%)',
|
||||
info: 'hsl(207, 82%, 66%)',
|
||||
success: 'hsl(95, 38%, 62%)',
|
||||
notice: 'hsl(39, 67%, 69%)',
|
||||
warning: 'hsl(29, 54%, 61%)',
|
||||
danger: 'hsl(355, 65%, 65%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(220, 13%, 14%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(220, 13%, 16%)',
|
||||
border: 'hsl(220, 13%, 20%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(220, 13%, 12%)',
|
||||
border: 'hsl(220, 13%, 18%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(220, 13%, 16%)',
|
||||
border: 'hsl(220, 13%, 20%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(286, 60%, 60%)',
|
||||
secondary: 'hsl(220, 9%, 48%)',
|
||||
info: 'hsl(207, 82%, 59%)',
|
||||
success: 'hsl(95, 38%, 55%)',
|
||||
notice: 'hsl(39, 67%, 62%)',
|
||||
warning: 'hsl(29, 54%, 54%)',
|
||||
danger: 'hsl(355, 65%, 58%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
122
plugins/themes-yaak/src/themes/ayu.ts
Normal file
122
plugins/themes-yaak/src/themes/ayu.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const ayuDark: Theme = {
|
||||
id: 'ayu-dark',
|
||||
label: 'Ayu Dark',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(220, 25%, 10%)',
|
||||
surfaceHighlight: 'hsl(220, 20%, 15%)',
|
||||
text: 'hsl(210, 22%, 78%)',
|
||||
textSubtle: 'hsl(40, 13%, 50%)',
|
||||
textSubtlest: 'hsl(220, 10%, 40%)',
|
||||
primary: 'hsl(38, 100%, 56%)',
|
||||
secondary: 'hsl(210, 15%, 55%)',
|
||||
info: 'hsl(200, 80%, 60%)',
|
||||
success: 'hsl(100, 75%, 60%)',
|
||||
notice: 'hsl(38, 100%, 56%)',
|
||||
warning: 'hsl(25, 100%, 60%)',
|
||||
danger: 'hsl(345, 80%, 60%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(220, 25%, 8%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(220, 22%, 12%)',
|
||||
border: 'hsl(220, 20%, 16%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(220, 25%, 7%)',
|
||||
border: 'hsl(220, 20%, 13%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(220, 22%, 12%)',
|
||||
border: 'hsl(220, 20%, 16%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(38, 100%, 50%)',
|
||||
secondary: 'hsl(210, 15%, 48%)',
|
||||
info: 'hsl(200, 80%, 53%)',
|
||||
success: 'hsl(100, 75%, 53%)',
|
||||
notice: 'hsl(38, 100%, 50%)',
|
||||
warning: 'hsl(25, 100%, 53%)',
|
||||
danger: 'hsl(345, 80%, 53%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const ayuMirage: Theme = {
|
||||
id: 'ayu-mirage',
|
||||
label: 'Ayu Mirage',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(226, 23%, 17%)',
|
||||
surfaceHighlight: 'hsl(226, 20%, 22%)',
|
||||
text: 'hsl(212, 15%, 81%)',
|
||||
textSubtle: 'hsl(212, 12%, 55%)',
|
||||
textSubtlest: 'hsl(212, 10%, 45%)',
|
||||
primary: 'hsl(38, 100%, 67%)',
|
||||
secondary: 'hsl(212, 12%, 55%)',
|
||||
info: 'hsl(200, 80%, 70%)',
|
||||
success: 'hsl(100, 50%, 68%)',
|
||||
notice: 'hsl(38, 100%, 67%)',
|
||||
warning: 'hsl(25, 100%, 70%)',
|
||||
danger: 'hsl(345, 80%, 70%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(226, 23%, 14%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(226, 22%, 15%)',
|
||||
border: 'hsl(226, 20%, 20%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(226, 23%, 12%)',
|
||||
border: 'hsl(226, 20%, 17%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(226, 22%, 15%)',
|
||||
border: 'hsl(226, 20%, 20%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(38, 100%, 60%)',
|
||||
info: 'hsl(200, 80%, 63%)',
|
||||
success: 'hsl(100, 50%, 61%)',
|
||||
notice: 'hsl(38, 100%, 60%)',
|
||||
warning: 'hsl(25, 100%, 63%)',
|
||||
danger: 'hsl(345, 80%, 63%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const ayuLight: Theme = {
|
||||
id: 'ayu-light',
|
||||
label: 'Ayu Light',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'hsl(40, 22%, 97%)',
|
||||
surfaceHighlight: 'hsl(40, 20%, 93%)',
|
||||
text: 'hsl(214, 10%, 35%)',
|
||||
textSubtle: 'hsl(214, 8%, 50%)',
|
||||
textSubtlest: 'hsl(214, 6%, 60%)',
|
||||
primary: 'hsl(35, 100%, 45%)',
|
||||
secondary: 'hsl(214, 8%, 50%)',
|
||||
info: 'hsl(200, 75%, 45%)',
|
||||
success: 'hsl(100, 60%, 40%)',
|
||||
notice: 'hsl(35, 100%, 45%)',
|
||||
warning: 'hsl(22, 100%, 50%)',
|
||||
danger: 'hsl(345, 70%, 55%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: 'hsl(40, 20%, 95%)',
|
||||
border: 'hsl(40, 15%, 90%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(40, 20%, 93%)',
|
||||
border: 'hsl(40, 15%, 88%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
77
plugins/themes-yaak/src/themes/bluloco.ts
Normal file
77
plugins/themes-yaak/src/themes/bluloco.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const blulocoDark: Theme = {
|
||||
id: 'bluloco-dark',
|
||||
label: 'Bluloco Dark',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(230, 20%, 14%)',
|
||||
surfaceHighlight: 'hsl(230, 17%, 19%)',
|
||||
text: 'hsl(220, 15%, 80%)',
|
||||
textSubtle: 'hsl(220, 10%, 55%)',
|
||||
textSubtlest: 'hsl(220, 8%, 42%)',
|
||||
primary: 'hsl(218, 85%, 65%)',
|
||||
secondary: 'hsl(220, 10%, 55%)',
|
||||
info: 'hsl(218, 85%, 65%)',
|
||||
success: 'hsl(95, 55%, 55%)',
|
||||
notice: 'hsl(37, 90%, 60%)',
|
||||
warning: 'hsl(22, 85%, 55%)',
|
||||
danger: 'hsl(355, 75%, 60%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(230, 20%, 11%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(230, 18%, 12%)',
|
||||
border: 'hsl(230, 16%, 17%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(230, 20%, 10%)',
|
||||
border: 'hsl(230, 16%, 15%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(230, 18%, 12%)',
|
||||
border: 'hsl(230, 16%, 17%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(218, 85%, 58%)',
|
||||
secondary: 'hsl(220, 10%, 48%)',
|
||||
info: 'hsl(218, 85%, 58%)',
|
||||
success: 'hsl(95, 55%, 48%)',
|
||||
notice: 'hsl(37, 90%, 53%)',
|
||||
warning: 'hsl(22, 85%, 48%)',
|
||||
danger: 'hsl(355, 75%, 53%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const blulocoLight: Theme = {
|
||||
id: 'bluloco-light',
|
||||
label: 'Bluloco Light',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'hsl(0, 0%, 98%)',
|
||||
surfaceHighlight: 'hsl(220, 15%, 94%)',
|
||||
text: 'hsl(228, 18%, 30%)',
|
||||
textSubtle: 'hsl(228, 10%, 48%)',
|
||||
textSubtlest: 'hsl(228, 8%, 58%)',
|
||||
primary: 'hsl(218, 80%, 48%)',
|
||||
secondary: 'hsl(228, 10%, 48%)',
|
||||
info: 'hsl(218, 80%, 48%)',
|
||||
success: 'hsl(138, 55%, 40%)',
|
||||
notice: 'hsl(35, 85%, 45%)',
|
||||
warning: 'hsl(22, 80%, 48%)',
|
||||
danger: 'hsl(355, 70%, 48%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: 'hsl(220, 15%, 96%)',
|
||||
border: 'hsl(220, 12%, 90%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(220, 15%, 94%)',
|
||||
border: 'hsl(220, 12%, 88%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
165
plugins/themes-yaak/src/themes/catppuccin.ts
Normal file
165
plugins/themes-yaak/src/themes/catppuccin.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const catppuccinFrappe: Theme = {
|
||||
id: 'catppuccin-frappe',
|
||||
label: 'Catppuccin Frappé',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(231,19%,20%)',
|
||||
text: 'hsl(227,70%,87%)',
|
||||
textSubtle: 'hsl(228,29%,73%)',
|
||||
textSubtlest: 'hsl(227,17%,58%)',
|
||||
primary: 'hsl(277,59%,76%)',
|
||||
secondary: 'hsl(228,39%,80%)',
|
||||
info: 'hsl(222,74%,74%)',
|
||||
success: 'hsl(96,44%,68%)',
|
||||
notice: 'hsl(40,62%,73%)',
|
||||
warning: 'hsl(20,79%,70%)',
|
||||
danger: 'hsl(359,68%,71%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(240,21%,12%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(229,19%,23%)',
|
||||
border: 'hsl(229,19%,27%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(229,20%,17%)',
|
||||
border: 'hsl(229,20%,25%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(229,19%,23%)',
|
||||
border: 'hsl(229,19%,27%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(277,59%,68%)',
|
||||
secondary: 'hsl(228,39%,72%)',
|
||||
info: 'hsl(222,74%,67%)',
|
||||
success: 'hsl(96,44%,61%)',
|
||||
notice: 'hsl(40,62%,66%)',
|
||||
warning: 'hsl(20,79%,63%)',
|
||||
danger: 'hsl(359,68%,64%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const catppuccinMacchiato: Theme = {
|
||||
id: 'catppuccin-macchiato',
|
||||
label: 'Catppuccin Macchiato',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(233,23%,15%)',
|
||||
text: 'hsl(227,68%,88%)',
|
||||
textSubtle: 'hsl(227,27%,72%)',
|
||||
textSubtlest: 'hsl(228,15%,57%)',
|
||||
primary: 'hsl(267,83%,80%)',
|
||||
secondary: 'hsl(228,39%,80%)',
|
||||
info: 'hsl(220,83%,75%)',
|
||||
success: 'hsl(105,48%,72%)',
|
||||
notice: 'hsl(40,70%,78%)',
|
||||
warning: 'hsl(21,86%,73%)',
|
||||
danger: 'hsl(351,74%,73%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(240,21%,12%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(232,23%,18%)',
|
||||
border: 'hsl(231,23%,22%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(236,23%,12%)',
|
||||
border: 'hsl(236,23%,21%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(232,23%,18%)',
|
||||
border: 'hsl(231,23%,22%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(267,82%,72%)',
|
||||
secondary: 'hsl(228,39%,72%)',
|
||||
info: 'hsl(220,83%,68%)',
|
||||
success: 'hsl(105,48%,65%)',
|
||||
notice: 'hsl(40,70%,70%)',
|
||||
warning: 'hsl(21,86%,66%)',
|
||||
danger: 'hsl(351,74%,66%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const catppuccinMocha: Theme = {
|
||||
id: 'catppuccin-mocha',
|
||||
label: 'Catppuccin Mocha',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(240,21%,12%)',
|
||||
text: 'hsl(226,64%,88%)',
|
||||
textSubtle: 'hsl(228,24%,72%)',
|
||||
textSubtlest: 'hsl(230,13%,55%)',
|
||||
primary: 'hsl(267,83%,80%)',
|
||||
secondary: 'hsl(227,35%,80%)',
|
||||
info: 'hsl(217,92%,76%)',
|
||||
success: 'hsl(115,54%,76%)',
|
||||
notice: 'hsl(41,86%,83%)',
|
||||
warning: 'hsl(23,92%,75%)',
|
||||
danger: 'hsl(343,81%,75%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(240,21%,12%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(240,21%,15%)',
|
||||
border: 'hsl(240,21%,19%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(240,23%,9%)',
|
||||
border: 'hsl(240,22%,18%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(240,21%,15%)',
|
||||
border: 'hsl(240,21%,19%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(267,67%,65%)',
|
||||
secondary: 'hsl(227,28%,64%)',
|
||||
info: 'hsl(217,74%,61%)',
|
||||
success: 'hsl(115,43%,61%)',
|
||||
notice: 'hsl(41,69%,66%)',
|
||||
warning: 'hsl(23,74%,60%)',
|
||||
danger: 'hsl(343,65%,60%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const catppuccinLatte: Theme = {
|
||||
id: 'catppuccin-latte',
|
||||
label: 'Catppuccin Latte',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'hsl(220,23%,95%)',
|
||||
text: 'hsl(234,16%,35%)',
|
||||
textSubtle: 'hsl(233,10%,47%)',
|
||||
textSubtlest: 'hsl(231,10%,59%)',
|
||||
primary: 'hsl(266,85%,58%)',
|
||||
secondary: 'hsl(233,10%,47%)',
|
||||
info: 'hsl(231,97%,72%)',
|
||||
success: 'hsl(183,74%,35%)',
|
||||
notice: 'hsl(35,77%,49%)',
|
||||
warning: 'hsl(22,99%,52%)',
|
||||
danger: 'hsl(355,76%,59%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: 'hsl(220,22%,92%)',
|
||||
border: 'hsl(220,22%,87%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(220,21%,89%)',
|
||||
border: 'hsl(220,22%,87%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
47
plugins/themes-yaak/src/themes/cobalt2.ts
Normal file
47
plugins/themes-yaak/src/themes/cobalt2.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const cobalt2: Theme = {
|
||||
id: 'cobalt2',
|
||||
label: 'Cobalt2',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: '#193549',
|
||||
surfaceHighlight: '#1f4662',
|
||||
text: '#d2e1f1',
|
||||
textSubtle: '#709ac8',
|
||||
textSubtlest: '#55749e',
|
||||
primary: '#ffc600',
|
||||
secondary: '#819fc3',
|
||||
info: '#0088FF',
|
||||
success: '#3AD900',
|
||||
notice: '#FFEE80',
|
||||
warning: '#FF9D00',
|
||||
danger: '#FF628C',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: '#13283a',
|
||||
border: '#102332',
|
||||
},
|
||||
input: {
|
||||
border: '#1f4561',
|
||||
},
|
||||
appHeader: {
|
||||
surface: '#13283a',
|
||||
border: '#112636',
|
||||
},
|
||||
responsePane: {
|
||||
surface: '#13283a',
|
||||
border: '#112636',
|
||||
},
|
||||
button: {
|
||||
primary: '#ffc600',
|
||||
secondary: '#709ac8',
|
||||
info: '#0088FF',
|
||||
success: '#3AD900',
|
||||
notice: '#ecdc6a',
|
||||
warning: '#FF9D00',
|
||||
danger: '#FF628C',
|
||||
},
|
||||
},
|
||||
};
|
||||
29
plugins/themes-yaak/src/themes/dracula.ts
Normal file
29
plugins/themes-yaak/src/themes/dracula.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const dracula: Theme = {
|
||||
id: 'dracula',
|
||||
label: 'Dracula',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(231,15%,18%)',
|
||||
surfaceHighlight: 'hsl(230,15%,24%)',
|
||||
text: 'hsl(60,30%,96%)',
|
||||
textSubtle: 'hsl(232,14%,65%)',
|
||||
textSubtlest: 'hsl(232,14%,50%)',
|
||||
primary: 'hsl(265,89%,78%)',
|
||||
secondary: 'hsl(225,27%,51%)',
|
||||
info: 'hsl(191,97%,77%)',
|
||||
success: 'hsl(135,94%,65%)',
|
||||
notice: 'hsl(65,92%,76%)',
|
||||
warning: 'hsl(31,100%,71%)',
|
||||
danger: 'hsl(0,100%,67%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
backdrop: 'hsl(230,15%,24%)',
|
||||
},
|
||||
appHeader: {
|
||||
backdrop: 'hsl(235,14%,15%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
77
plugins/themes-yaak/src/themes/everforest.ts
Normal file
77
plugins/themes-yaak/src/themes/everforest.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const everforestDark: Theme = {
|
||||
id: 'everforest-dark',
|
||||
label: 'Everforest Dark',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(150, 8%, 18%)',
|
||||
surfaceHighlight: 'hsl(150, 7%, 22%)',
|
||||
text: 'hsl(45, 30%, 78%)',
|
||||
textSubtle: 'hsl(145, 8%, 55%)',
|
||||
textSubtlest: 'hsl(145, 6%, 42%)',
|
||||
primary: 'hsl(142, 35%, 60%)',
|
||||
secondary: 'hsl(145, 8%, 55%)',
|
||||
info: 'hsl(200, 35%, 65%)',
|
||||
success: 'hsl(142, 35%, 60%)',
|
||||
notice: 'hsl(46, 55%, 68%)',
|
||||
warning: 'hsl(24, 55%, 65%)',
|
||||
danger: 'hsl(358, 50%, 68%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(150, 8%, 15%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(150, 7%, 16%)',
|
||||
border: 'hsl(150, 6%, 20%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(150, 8%, 14%)',
|
||||
border: 'hsl(150, 6%, 18%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(150, 7%, 16%)',
|
||||
border: 'hsl(150, 6%, 20%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(142, 35%, 53%)',
|
||||
secondary: 'hsl(145, 8%, 48%)',
|
||||
info: 'hsl(200, 35%, 58%)',
|
||||
success: 'hsl(142, 35%, 53%)',
|
||||
notice: 'hsl(46, 55%, 61%)',
|
||||
warning: 'hsl(24, 55%, 58%)',
|
||||
danger: 'hsl(358, 50%, 61%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const everforestLight: Theme = {
|
||||
id: 'everforest-light',
|
||||
label: 'Everforest Light',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'hsl(40, 32%, 93%)',
|
||||
surfaceHighlight: 'hsl(40, 28%, 89%)',
|
||||
text: 'hsl(135, 8%, 35%)',
|
||||
textSubtle: 'hsl(135, 6%, 45%)',
|
||||
textSubtlest: 'hsl(135, 4%, 55%)',
|
||||
primary: 'hsl(128, 30%, 45%)',
|
||||
secondary: 'hsl(135, 6%, 45%)',
|
||||
info: 'hsl(200, 35%, 45%)',
|
||||
success: 'hsl(128, 30%, 45%)',
|
||||
notice: 'hsl(45, 70%, 40%)',
|
||||
warning: 'hsl(22, 60%, 48%)',
|
||||
danger: 'hsl(355, 55%, 50%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: 'hsl(40, 30%, 91%)',
|
||||
border: 'hsl(40, 25%, 86%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(40, 30%, 89%)',
|
||||
border: 'hsl(40, 25%, 84%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
173
plugins/themes-yaak/src/themes/fleet.ts
Normal file
173
plugins/themes-yaak/src/themes/fleet.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const fleetLight: Theme = {
|
||||
id: 'fleet-light',
|
||||
label: 'Fleet Light',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: '#FFFFFF',
|
||||
surfaceHighlight: '#F8F8F9',
|
||||
surfaceActive: '#EEEFF0',
|
||||
border: '#18191B33',
|
||||
text: '#090909',
|
||||
textSubtle: '#6E747B',
|
||||
textSubtlest: '#898E94',
|
||||
primary: '#1D61BA',
|
||||
secondary: '#6E747B',
|
||||
info: '#4B8DEC',
|
||||
success: '#169068',
|
||||
notice: '#B07203',
|
||||
warning: '#B07203',
|
||||
danger: '#E1465E',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: '#EEEFF0',
|
||||
border: '#18191B33',
|
||||
},
|
||||
appHeader: {
|
||||
surface: '#EEEFF0',
|
||||
border: '#18191B33',
|
||||
},
|
||||
responsePane: {
|
||||
surface: '#FFFFFF',
|
||||
border: '#18191B33',
|
||||
},
|
||||
dialog: {
|
||||
surface: '#FFFFFF',
|
||||
border: '#18191B33',
|
||||
},
|
||||
button: {
|
||||
surface: '#F8F8F9',
|
||||
text: '#090909',
|
||||
primary: '#2A7DEB',
|
||||
secondary: '#6E747B',
|
||||
info: '#4B8DEC',
|
||||
success: '#169068',
|
||||
notice: '#B07203',
|
||||
warning: '#B07203',
|
||||
danger: '#E1465E',
|
||||
},
|
||||
editor: {
|
||||
primary: '#5511BF',
|
||||
secondary: '#A31D8D',
|
||||
info: '#14646E',
|
||||
success: '#086E14',
|
||||
notice: '#616605',
|
||||
warning: '#747576',
|
||||
danger: '#1749BD',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const fleetDarkPurple: Theme = {
|
||||
id: 'fleet-dark-purple',
|
||||
label: 'Fleet Dark Purple',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: '#1C1827',
|
||||
surfaceHighlight: '#262136',
|
||||
surfaceActive: '#3E3852',
|
||||
border: '#3E3852',
|
||||
text: '#E0E1E4',
|
||||
textSubtle: '#E0E1E480',
|
||||
textSubtlest: '#E0E1E44D',
|
||||
primary: '#B174D9',
|
||||
secondary: '#E0E1E480',
|
||||
info: '#4B8DEC',
|
||||
success: '#169068',
|
||||
notice: '#B07203',
|
||||
warning: '#B07203',
|
||||
danger: '#E1465E',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: '#13101B',
|
||||
border: '#3E3852',
|
||||
},
|
||||
responsePane: {
|
||||
surface: '#1C1827',
|
||||
border: '#3E3852',
|
||||
},
|
||||
dialog: {
|
||||
surface: '#262136',
|
||||
border: '#3E3852',
|
||||
},
|
||||
button: {
|
||||
surface: '#262136',
|
||||
text: '#E0E1E4',
|
||||
primary: '#A660D4',
|
||||
secondary: '#E0E1E480',
|
||||
info: '#4B8DEC',
|
||||
success: '#169068',
|
||||
notice: '#B07203',
|
||||
warning: '#B07203',
|
||||
danger: '#E1465E',
|
||||
},
|
||||
editor: {
|
||||
primary: '#C7A65D',
|
||||
secondary: '#93A6F5',
|
||||
info: '#E09B70',
|
||||
success: '#62A362',
|
||||
notice: '#85A658',
|
||||
warning: '#7e7d86',
|
||||
danger: '#4DACF0',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const fleetDark: Theme = {
|
||||
id: 'fleet-dark',
|
||||
label: 'Fleet Dark',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: '#18191B',
|
||||
surfaceHighlight: '#252629',
|
||||
surfaceActive: '#3E4147',
|
||||
border: '#3E4147',
|
||||
text: '#E0E1E4',
|
||||
textSubtle: '#898E94',
|
||||
textSubtlest: '#646B71',
|
||||
primary: '#4B8DEC',
|
||||
secondary: '#898E94',
|
||||
info: '#4B8DEC',
|
||||
success: '#169068',
|
||||
notice: '#B07203',
|
||||
warning: '#B07203',
|
||||
danger: '#E1465E',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: '#090909',
|
||||
border: '#3E4147',
|
||||
},
|
||||
responsePane: {
|
||||
surface: '#18191B',
|
||||
border: '#3E4147',
|
||||
},
|
||||
dialog: {
|
||||
surface: '#252629',
|
||||
border: '#3E4147',
|
||||
},
|
||||
button: {
|
||||
surface: '#252629',
|
||||
text: '#E0E1E4',
|
||||
primary: '#2A7DEB',
|
||||
secondary: '#898E94',
|
||||
info: '#4B8DEC',
|
||||
success: '#169068',
|
||||
notice: '#B07203',
|
||||
warning: '#B07203',
|
||||
danger: '#E1465E',
|
||||
},
|
||||
editor: {
|
||||
primary: '#EBC88D',
|
||||
secondary: '#AF9CFF',
|
||||
info: '#82D2CE',
|
||||
success: '#A8C5A0',
|
||||
notice: '#C7A65D',
|
||||
warning: '#909194',
|
||||
danger: '#87C3FF',
|
||||
},
|
||||
},
|
||||
};
|
||||
46
plugins/themes-yaak/src/themes/github-dimmed.ts
Normal file
46
plugins/themes-yaak/src/themes/github-dimmed.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const githubDarkDimmed: Theme = {
|
||||
id: 'github-dark-dimmed',
|
||||
label: 'GitHub Dark Dimmed',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(215, 15%, 16%)',
|
||||
surfaceHighlight: 'hsl(215, 13%, 20%)',
|
||||
text: 'hsl(212, 15%, 78%)',
|
||||
textSubtle: 'hsl(212, 10%, 55%)',
|
||||
textSubtlest: 'hsl(212, 8%, 42%)',
|
||||
primary: 'hsl(212, 80%, 65%)',
|
||||
secondary: 'hsl(212, 10%, 55%)',
|
||||
info: 'hsl(212, 80%, 65%)',
|
||||
success: 'hsl(140, 50%, 50%)',
|
||||
notice: 'hsl(42, 75%, 55%)',
|
||||
warning: 'hsl(27, 80%, 55%)',
|
||||
danger: 'hsl(355, 70%, 55%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(215, 15%, 13%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(215, 14%, 14%)',
|
||||
border: 'hsl(215, 12%, 19%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(215, 15%, 12%)',
|
||||
border: 'hsl(215, 12%, 17%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(215, 14%, 14%)',
|
||||
border: 'hsl(215, 12%, 19%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(212, 80%, 58%)',
|
||||
info: 'hsl(212, 80%, 58%)',
|
||||
success: 'hsl(140, 50%, 45%)',
|
||||
notice: 'hsl(42, 75%, 48%)',
|
||||
warning: 'hsl(27, 80%, 48%)',
|
||||
danger: 'hsl(355, 70%, 48%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
55
plugins/themes-yaak/src/themes/github.ts
Normal file
55
plugins/themes-yaak/src/themes/github.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const githubDark: Theme = {
|
||||
id: 'github-dark',
|
||||
label: 'GitHub',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(213,30%,7%)',
|
||||
surfaceHighlight: 'hsl(213,16%,13%)',
|
||||
text: 'hsl(212,27%,89%)',
|
||||
textSubtle: 'hsl(212,9%,57%)',
|
||||
textSubtlest: 'hsl(217,8%,45%)',
|
||||
border: 'hsl(215,21%,11%)',
|
||||
primary: 'hsl(262,78%,74%)',
|
||||
secondary: 'hsl(217,8%,50%)',
|
||||
info: 'hsl(215,84%,64%)',
|
||||
success: 'hsl(129,48%,52%)',
|
||||
notice: 'hsl(39,71%,58%)',
|
||||
warning: 'hsl(22,83%,60%)',
|
||||
danger: 'hsl(3,83%,65%)',
|
||||
},
|
||||
components: {
|
||||
button: {
|
||||
primary: 'hsl(262,79%,71%)',
|
||||
secondary: 'hsl(217,8%,45%)',
|
||||
info: 'hsl(215,84%,60%)',
|
||||
success: 'hsl(129,48%,47%)',
|
||||
notice: 'hsl(39,71%,53%)',
|
||||
warning: 'hsl(22,83%,56%)',
|
||||
danger: 'hsl(3,83%,61%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const githubLight: Theme = {
|
||||
id: 'github-light',
|
||||
label: 'GitHub',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'hsl(0,0%,100%)',
|
||||
surfaceHighlight: 'hsl(210,29%,94%)',
|
||||
text: 'hsl(213,13%,14%)',
|
||||
textSubtle: 'hsl(212,9%,43%)',
|
||||
textSubtlest: 'hsl(203,8%,55%)',
|
||||
border: 'hsl(210,15%,92%)',
|
||||
borderSubtle: 'hsl(210,15%,92%)',
|
||||
primary: 'hsl(261,69%,59%)',
|
||||
secondary: 'hsl(212,8%,47%)',
|
||||
info: 'hsl(212,92%,48%)',
|
||||
success: 'hsl(137,66%,32%)',
|
||||
notice: 'hsl(40,100%,40%)',
|
||||
warning: 'hsl(24,100%,44%)',
|
||||
danger: 'hsl(356,71%,48%)',
|
||||
},
|
||||
};
|
||||
21
plugins/themes-yaak/src/themes/gruvbox.ts
Normal file
21
plugins/themes-yaak/src/themes/gruvbox.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const gruvbox: Theme = {
|
||||
id: 'gruvbox',
|
||||
label: 'Gruvbox',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(0,0%,16%)',
|
||||
surfaceHighlight: 'hsl(20,3%,19%)',
|
||||
text: 'hsl(53,74%,91%)',
|
||||
textSubtle: 'hsl(39,24%,66%)',
|
||||
textSubtlest: 'hsl(30,12%,51%)',
|
||||
primary: 'hsl(344,47%,68%)',
|
||||
secondary: 'hsl(157,16%,58%)',
|
||||
info: 'hsl(104,35%,62%)',
|
||||
success: 'hsl(61,66%,44%)',
|
||||
notice: 'hsl(42,95%,58%)',
|
||||
warning: 'hsl(27,99%,55%)',
|
||||
danger: 'hsl(6,96%,59%)',
|
||||
},
|
||||
};
|
||||
46
plugins/themes-yaak/src/themes/high-contrast.ts
Normal file
46
plugins/themes-yaak/src/themes/high-contrast.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const highContrast: Theme = {
|
||||
id: 'high-contrast',
|
||||
label: 'High Contrast Light',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'white',
|
||||
surfaceHighlight: 'hsl(218,24%,93%)',
|
||||
text: 'black',
|
||||
textSubtle: 'hsl(217,24%,40%)',
|
||||
textSubtlest: 'hsl(217,24%,40%)',
|
||||
border: 'hsl(217,22%,50%)',
|
||||
borderSubtle: 'hsl(217,22%,60%)',
|
||||
primary: 'hsl(267,67%,47%)',
|
||||
secondary: 'hsl(218,18%,53%)',
|
||||
info: 'hsl(206,100%,36%)',
|
||||
success: 'hsl(155,100%,26%)',
|
||||
notice: 'hsl(45,100%,31%)',
|
||||
warning: 'hsl(30,99%,34%)',
|
||||
danger: 'hsl(334,100%,35%)',
|
||||
},
|
||||
};
|
||||
|
||||
export const highContrastDark: Theme = {
|
||||
id: 'high-contrast-dark',
|
||||
label: 'High Contrast Dark',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(0,0%,0%)',
|
||||
surfaceHighlight: 'hsl(0,0%,20%)',
|
||||
text: 'hsl(0,0%,100%)',
|
||||
textSubtle: 'hsl(0,0%,90%)',
|
||||
textSubtlest: 'hsl(0,0%,80%)',
|
||||
selection: 'hsl(276,100%,30%)',
|
||||
surfaceActive: 'hsl(276,100%,30%)',
|
||||
border: 'hsl(0,0%,60%)',
|
||||
primary: 'hsl(266,100%,85%)',
|
||||
secondary: 'hsl(242,20%,72%)',
|
||||
info: 'hsl(208,100%,83%)',
|
||||
success: 'hsl(150,100%,63%)',
|
||||
notice: 'hsl(49,100%,77%)',
|
||||
warning: 'hsl(28,100%,73%)',
|
||||
danger: 'hsl(343,100%,79%)',
|
||||
},
|
||||
};
|
||||
47
plugins/themes-yaak/src/themes/horizon.ts
Normal file
47
plugins/themes-yaak/src/themes/horizon.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const horizon: Theme = {
|
||||
id: 'horizon',
|
||||
label: 'Horizon',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(220, 16%, 13%)',
|
||||
surfaceHighlight: 'hsl(220, 14%, 18%)',
|
||||
text: 'hsl(220, 15%, 85%)',
|
||||
textSubtle: 'hsl(220, 10%, 55%)',
|
||||
textSubtlest: 'hsl(220, 8%, 45%)',
|
||||
primary: 'hsl(5, 85%, 68%)',
|
||||
secondary: 'hsl(220, 10%, 55%)',
|
||||
info: 'hsl(217, 70%, 68%)',
|
||||
success: 'hsl(92, 50%, 60%)',
|
||||
notice: 'hsl(34, 92%, 70%)',
|
||||
warning: 'hsl(20, 90%, 65%)',
|
||||
danger: 'hsl(355, 80%, 65%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(220, 16%, 10%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(220, 14%, 15%)',
|
||||
border: 'hsl(220, 14%, 19%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(220, 16%, 11%)',
|
||||
border: 'hsl(220, 14%, 17%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(220, 14%, 15%)',
|
||||
border: 'hsl(220, 14%, 19%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(5, 85%, 61%)',
|
||||
secondary: 'hsl(224,8%,53%)',
|
||||
info: 'hsl(217, 70%, 61%)',
|
||||
success: 'hsl(92, 50%, 53%)',
|
||||
notice: 'hsl(34, 92%, 63%)',
|
||||
warning: 'hsl(20, 90%, 58%)',
|
||||
danger: 'hsl(355, 80%, 58%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
58
plugins/themes-yaak/src/themes/hotdog-stand.ts
Normal file
58
plugins/themes-yaak/src/themes/hotdog-stand.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const hotdogStand: Theme = {
|
||||
id: 'hotdog-stand',
|
||||
label: 'Hotdog Stand',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(0,100%,50%)',
|
||||
surfaceHighlight: 'hsl(0,0%,0%)',
|
||||
text: 'hsl(0,0%,100%)',
|
||||
textSubtle: 'hsl(0,0%,100%)',
|
||||
textSubtlest: 'hsl(60,100%,50%)',
|
||||
border: 'hsl(0,0%,0%)',
|
||||
primary: 'hsl(60,100%,50%)',
|
||||
secondary: 'hsl(60,100%,50%)',
|
||||
info: 'hsl(60,100%,50%)',
|
||||
success: 'hsl(60,100%,50%)',
|
||||
notice: 'hsl(60,100%,50%)',
|
||||
warning: 'hsl(60,100%,50%)',
|
||||
danger: 'hsl(60,100%,50%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(0,0%,0%)',
|
||||
text: 'hsl(0,0%,100%)',
|
||||
textSubtle: 'hsl(60,100%,50%)',
|
||||
textSubtlest: 'hsl(0,100%,50%)',
|
||||
},
|
||||
menu: {
|
||||
surface: 'hsl(0,0%,0%)',
|
||||
border: 'hsl(0,100%,50%)',
|
||||
surfaceHighlight: 'hsl(0,100%,50%)',
|
||||
text: 'hsl(0,0%,100%)',
|
||||
textSubtle: 'hsl(60,100%,50%)',
|
||||
textSubtlest: 'hsl(60,100%,50%)',
|
||||
},
|
||||
button: {
|
||||
surface: 'hsl(0,0%,0%)',
|
||||
text: 'hsl(0,0%,100%)',
|
||||
primary: 'hsl(0,0%,0%)',
|
||||
secondary: 'hsl(0,0%,100%)',
|
||||
info: 'hsl(0,0%,0%)',
|
||||
success: 'hsl(60,100%,50%)',
|
||||
notice: 'hsl(60,100%,50%)',
|
||||
warning: 'hsl(0,0%,0%)',
|
||||
danger: 'hsl(0,100%,50%)',
|
||||
},
|
||||
editor: {
|
||||
primary: 'hsl(0,0%,100%)',
|
||||
secondary: 'hsl(0,0%,100%)',
|
||||
info: 'hsl(0,0%,100%)',
|
||||
success: 'hsl(0,0%,100%)',
|
||||
notice: 'hsl(60,100%,50%)',
|
||||
warning: 'hsl(0,0%,100%)',
|
||||
danger: 'hsl(0,0%,100%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
39
plugins/themes-yaak/src/themes/material-darker.ts
Normal file
39
plugins/themes-yaak/src/themes/material-darker.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const materialDarker: Theme = {
|
||||
id: 'material-darker',
|
||||
label: 'Material Darker',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(0, 0%, 13%)',
|
||||
surfaceHighlight: 'hsl(0, 0%, 18%)',
|
||||
text: 'hsl(0, 0%, 93%)',
|
||||
textSubtle: 'hsl(0, 0%, 65%)',
|
||||
textSubtlest: 'hsl(0, 0%, 50%)',
|
||||
primary: 'hsl(262, 100%, 75%)',
|
||||
secondary: 'hsl(0, 0%, 60%)',
|
||||
info: 'hsl(224, 100%, 75%)',
|
||||
success: 'hsl(84, 60%, 73%)',
|
||||
notice: 'hsl(43, 100%, 70%)',
|
||||
warning: 'hsl(14, 85%, 70%)',
|
||||
danger: 'hsl(1, 77%, 59%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: 'hsl(0, 0%, 11%)',
|
||||
border: 'hsl(0, 0%, 16%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(0, 0%, 9%)',
|
||||
border: 'hsl(0, 0%, 14%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(262, 100%, 68%)',
|
||||
info: 'hsl(224, 100%, 68%)',
|
||||
success: 'hsl(84, 60%, 66%)',
|
||||
notice: 'hsl(43, 100%, 63%)',
|
||||
warning: 'hsl(14, 85%, 63%)',
|
||||
danger: 'hsl(1, 77%, 52%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
43
plugins/themes-yaak/src/themes/material-ocean.ts
Normal file
43
plugins/themes-yaak/src/themes/material-ocean.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const materialOcean: Theme = {
|
||||
id: 'material-ocean',
|
||||
label: 'Material Ocean',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(230, 25%, 14%)',
|
||||
surfaceHighlight: 'hsl(230, 20%, 18%)',
|
||||
text: 'hsl(220, 53%, 85%)',
|
||||
textSubtle: 'hsl(228, 12%, 54%)',
|
||||
textSubtlest: 'hsl(228, 12%, 42%)',
|
||||
primary: 'hsl(262, 100%, 75%)',
|
||||
secondary: 'hsl(228, 12%, 60%)',
|
||||
info: 'hsl(224, 100%, 75%)',
|
||||
success: 'hsl(84, 60%, 73%)',
|
||||
notice: 'hsl(43, 100%, 70%)',
|
||||
warning: 'hsl(14, 85%, 70%)',
|
||||
danger: 'hsl(1, 77%, 59%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: 'hsl(230, 25%, 12%)',
|
||||
border: 'hsl(230, 20%, 18%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(230, 25%, 10%)',
|
||||
border: 'hsl(230, 20%, 16%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(230, 25%, 12%)',
|
||||
border: 'hsl(230, 20%, 18%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(262, 100%, 68%)',
|
||||
info: 'hsl(224, 100%, 68%)',
|
||||
success: 'hsl(84, 60%, 66%)',
|
||||
notice: 'hsl(43, 100%, 63%)',
|
||||
warning: 'hsl(14, 85%, 63%)',
|
||||
danger: 'hsl(1, 77%, 52%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
45
plugins/themes-yaak/src/themes/material-palenight.ts
Normal file
45
plugins/themes-yaak/src/themes/material-palenight.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const materialPalenight: Theme = {
|
||||
id: 'material-palenight',
|
||||
label: 'Material Palenight',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: '#292D3E',
|
||||
surfaceHighlight: '#313850',
|
||||
text: '#BFC7D5',
|
||||
textSubtle: '#697098',
|
||||
textSubtlest: '#4E5579',
|
||||
primary: '#c792ea',
|
||||
secondary: '#697098',
|
||||
info: '#82AAFF',
|
||||
success: '#C3E88D',
|
||||
notice: '#FFCB6B',
|
||||
warning: '#F78C6C',
|
||||
danger: '#ff5572',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: '#232635',
|
||||
},
|
||||
sidebar: {
|
||||
surface: '#292D3E',
|
||||
},
|
||||
appHeader: {
|
||||
surface: '#282C3D',
|
||||
},
|
||||
responsePane: {
|
||||
surface: '#313850',
|
||||
border: '#3a3f58',
|
||||
},
|
||||
button: {
|
||||
primary: '#c792ea',
|
||||
secondary: '#697098',
|
||||
info: '#82AAFF',
|
||||
success: '#C3E88D',
|
||||
notice: '#FFCB6B',
|
||||
warning: '#F78C6C',
|
||||
danger: '#ff5572',
|
||||
},
|
||||
},
|
||||
};
|
||||
217
plugins/themes-yaak/src/themes/monokai-pro.ts
Normal file
217
plugins/themes-yaak/src/themes/monokai-pro.ts
Normal file
@@ -0,0 +1,217 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const monokaiPro: Theme = {
|
||||
id: 'monokai-pro',
|
||||
label: 'Monokai Pro',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(285,5%,17%)',
|
||||
text: 'hsl(60,25%,98%)',
|
||||
textSubtle: 'hsl(0,1%,75%)',
|
||||
textSubtlest: 'hsl(300,0%,57%)',
|
||||
primary: 'hsl(250,77%,78%)',
|
||||
secondary: 'hsl(0,1%,75%)',
|
||||
info: 'hsl(186,71%,69%)',
|
||||
success: 'hsl(90,59%,66%)',
|
||||
notice: 'hsl(45,100%,70%)',
|
||||
warning: 'hsl(20,96%,70%)',
|
||||
danger: 'hsl(345,100%,69%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(300,5%,13%)',
|
||||
text: 'hsl(0,1%,75%)',
|
||||
textSubtle: 'hsl(300,0%,57%)',
|
||||
textSubtlest: 'hsl(300,1%,44%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(250,77%,70%)',
|
||||
secondary: 'hsl(0,1%,68%)',
|
||||
info: 'hsl(186,71%,62%)',
|
||||
success: 'hsl(90,59%,59%)',
|
||||
notice: 'hsl(45,100%,63%)',
|
||||
warning: 'hsl(20,96%,63%)',
|
||||
danger: 'hsl(345,100%,62%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const monokaiProClassic: Theme = {
|
||||
id: 'monokai-pro-classic',
|
||||
label: 'Monokai Pro Classic',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(70,8%,15%)',
|
||||
text: 'hsl(69,100%,97%)',
|
||||
textSubtle: 'hsl(65,9%,73%)',
|
||||
textSubtlest: 'hsl(66,4%,55%)',
|
||||
primary: 'hsl(261,100%,75%)',
|
||||
secondary: 'hsl(202,8%,72%)',
|
||||
info: 'hsl(190,81%,67%)',
|
||||
success: 'hsl(80,76%,53%)',
|
||||
notice: 'hsl(54,70%,68%)',
|
||||
warning: 'hsl(32,98%,56%)',
|
||||
danger: 'hsl(338,95%,56%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(72,9%,11%)',
|
||||
text: 'hsl(202,8%,72%)',
|
||||
textSubtle: 'hsl(213,4%,48%)',
|
||||
textSubtlest: 'hsl(223,6%,44%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(261,100%,68%)',
|
||||
secondary: 'hsl(202,8%,65%)',
|
||||
info: 'hsl(190,81%,60%)',
|
||||
success: 'hsl(80,76%,48%)',
|
||||
notice: 'hsl(54,71%,61%)',
|
||||
warning: 'hsl(32,98%,50%)',
|
||||
danger: 'hsl(338,95%,50%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const monokaiProMachine: Theme = {
|
||||
id: 'monokai-pro-machine',
|
||||
label: 'Monokai Pro Machine',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(200,16%,18%)',
|
||||
text: 'hsl(173,24%,93%)',
|
||||
textSubtle: 'hsl(185,6%,57%)',
|
||||
textSubtlest: 'hsl(189,6%,45%)',
|
||||
primary: 'hsl(258,86%,80%)',
|
||||
secondary: 'hsl(175,9%,75%)',
|
||||
info: 'hsl(194,81%,72%)',
|
||||
success: 'hsl(98,67%,69%)',
|
||||
notice: 'hsl(52,100%,72%)',
|
||||
warning: 'hsl(28,100%,72%)',
|
||||
danger: 'hsl(353,100%,71%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(196,16%,14%)',
|
||||
text: 'hsl(202,8%,72%)',
|
||||
textSubtle: 'hsl(213,4%,48%)',
|
||||
textSubtlest: 'hsl(223,6%,44%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(258,86%,72%)',
|
||||
secondary: 'hsl(175,9%,68%)',
|
||||
info: 'hsl(194,80%,65%)',
|
||||
success: 'hsl(98,67%,62%)',
|
||||
notice: 'hsl(52,100%,65%)',
|
||||
warning: 'hsl(28,100%,65%)',
|
||||
danger: 'hsl(353,100%,64%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const monokaiProOctagon: Theme = {
|
||||
id: 'monokai-pro-octagon',
|
||||
label: 'Monokai Pro Octagon',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(233,18%,19%)',
|
||||
text: 'hsl(173,24%,93%)',
|
||||
textSubtle: 'hsl(202,8%,72%)',
|
||||
textSubtlest: 'hsl(213,4%,48%)',
|
||||
primary: 'hsl(292,30%,70%)',
|
||||
secondary: 'hsl(202,8%,72%)',
|
||||
info: 'hsl(155,37%,72%)',
|
||||
success: 'hsl(75,60%,61%)',
|
||||
notice: 'hsl(44,100%,71%)',
|
||||
warning: 'hsl(23,100%,68%)',
|
||||
danger: 'hsl(352,100%,70%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(235,18%,14%)',
|
||||
text: 'hsl(202,8%,72%)',
|
||||
textSubtle: 'hsl(213,4%,48%)',
|
||||
textSubtlest: 'hsl(223,6%,44%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(292,26%,63%)',
|
||||
secondary: 'hsl(201,7%,65%)',
|
||||
info: 'hsl(155,33%,65%)',
|
||||
success: 'hsl(75,54%,55%)',
|
||||
notice: 'hsl(44,90%,64%)',
|
||||
warning: 'hsl(23,90%,61%)',
|
||||
danger: 'hsl(352,90%,63%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const monokaiProRistretto: Theme = {
|
||||
id: 'monokai-pro-ristretto',
|
||||
label: 'Monokai Pro Ristretto',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(0,9%,16%)',
|
||||
text: 'hsl(351,100%,97%)',
|
||||
textSubtle: 'hsl(355,9%,74%)',
|
||||
textSubtlest: 'hsl(354,4%,56%)',
|
||||
primary: 'hsl(239,63%,79%)',
|
||||
secondary: 'hsl(355,9%,74%)',
|
||||
info: 'hsl(170,53%,69%)',
|
||||
success: 'hsl(88,57%,66%)',
|
||||
notice: 'hsl(41,92%,70%)',
|
||||
warning: 'hsl(13,85%,70%)',
|
||||
danger: 'hsl(349,97%,70%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(0,8%,12%)',
|
||||
text: 'hsl(355,9%,74%)',
|
||||
textSubtle: 'hsl(354,4%,56%)',
|
||||
textSubtlest: 'hsl(353,4%,43%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(239,63%,71%)',
|
||||
secondary: 'hsl(355,9%,67%)',
|
||||
info: 'hsl(170,53%,62%)',
|
||||
success: 'hsl(88,57%,59%)',
|
||||
notice: 'hsl(41,92%,63%)',
|
||||
warning: 'hsl(13,86%,63%)',
|
||||
danger: 'hsl(349,97%,63%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const monokaiProSpectrum: Theme = {
|
||||
id: 'monokai-pro-spectrum',
|
||||
label: 'Monokai Pro Spectrum',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(0,0%,13%)',
|
||||
text: 'hsl(266,100%,97%)',
|
||||
textSubtle: 'hsl(264,7%,73%)',
|
||||
textSubtlest: 'hsl(266,3%,55%)',
|
||||
primary: 'hsl(247,61%,72%)',
|
||||
secondary: 'hsl(264,7%,73%)',
|
||||
info: 'hsl(188,74%,63%)',
|
||||
success: 'hsl(133,54%,66%)',
|
||||
notice: 'hsl(51,96%,69%)',
|
||||
warning: 'hsl(23,98%,66%)',
|
||||
danger: 'hsl(343,96%,68%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(0,0%,10%)',
|
||||
text: 'hsl(264,7%,73%)',
|
||||
textSubtle: 'hsl(266,3%,55%)',
|
||||
textSubtlest: 'hsl(264,2%,41%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(247,61%,65%)',
|
||||
secondary: 'hsl(264,7%,66%)',
|
||||
info: 'hsl(188,74%,57%)',
|
||||
success: 'hsl(133,54%,59%)',
|
||||
notice: 'hsl(51,96%,62%)',
|
||||
warning: 'hsl(23,98%,59%)',
|
||||
danger: 'hsl(343,96%,61%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
28
plugins/themes-yaak/src/themes/moonlight.ts
Normal file
28
plugins/themes-yaak/src/themes/moonlight.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const moonlight: Theme = {
|
||||
id: 'moonlight',
|
||||
label: 'Moonlight',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(234,23%,17%)',
|
||||
text: 'hsl(225,71%,90%)',
|
||||
textSubtle: 'hsl(230,28%,62%)',
|
||||
textSubtlest: 'hsl(232,26%,43%)',
|
||||
primary: 'hsl(262,100%,82%)',
|
||||
secondary: 'hsl(232,18%,65%)',
|
||||
info: 'hsl(217,100%,74%)',
|
||||
success: 'hsl(174,66%,54%)',
|
||||
notice: 'hsl(35,100%,73%)',
|
||||
warning: 'hsl(17,100%,71%)',
|
||||
danger: 'hsl(356,100%,73%)',
|
||||
},
|
||||
components: {
|
||||
appHeader: {
|
||||
surface: 'hsl(233,23%,15%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(233,23%,15%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
78
plugins/themes-yaak/src/themes/night-owl.ts
Normal file
78
plugins/themes-yaak/src/themes/night-owl.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const nightOwl: Theme = {
|
||||
id: 'night-owl',
|
||||
label: 'Night Owl',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(207, 95%, 8%)',
|
||||
surfaceHighlight: 'hsl(207, 50%, 14%)',
|
||||
text: 'hsl(213, 50%, 90%)',
|
||||
textSubtle: 'hsl(213, 30%, 70%)',
|
||||
textSubtlest: 'hsl(213, 20%, 50%)',
|
||||
border: 'hsl(207, 50%, 14%)',
|
||||
primary: 'hsl(261, 51%, 51%)',
|
||||
secondary: 'hsl(213, 30%, 60%)',
|
||||
info: 'hsl(220, 100%, 75%)',
|
||||
success: 'hsl(145, 100%, 43%)',
|
||||
notice: 'hsl(62, 61%, 71%)',
|
||||
warning: 'hsl(4, 90%, 58%)',
|
||||
danger: 'hsl(4, 90%, 58%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(207, 95%, 6%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(207, 95%, 8%)',
|
||||
border: 'hsl(207, 50%, 14%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(207, 95%, 5%)',
|
||||
border: 'hsl(207, 50%, 12%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(207, 70%, 10%)',
|
||||
border: 'hsl(207, 50%, 14%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(261, 51%, 45%)',
|
||||
secondary: 'hsl(213, 30%, 60%)',
|
||||
info: 'hsl(220, 100%, 68%)',
|
||||
success: 'hsl(145, 100%, 38%)',
|
||||
notice: 'hsl(62, 61%, 64%)',
|
||||
warning: 'hsl(4, 90%, 52%)',
|
||||
danger: 'hsl(4, 90%, 52%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const lightOwl: Theme = {
|
||||
id: 'light-owl',
|
||||
label: 'Light Owl',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'hsl(0, 0%, 98%)',
|
||||
surfaceHighlight: 'hsl(210, 18%, 94%)',
|
||||
text: 'hsl(224, 26%, 27%)',
|
||||
textSubtle: 'hsl(224, 15%, 45%)',
|
||||
textSubtlest: 'hsl(224, 10%, 55%)',
|
||||
primary: 'hsl(283, 100%, 41%)',
|
||||
secondary: 'hsl(224, 15%, 50%)',
|
||||
info: 'hsl(219, 75%, 40%)',
|
||||
success: 'hsl(145, 70%, 35%)',
|
||||
notice: 'hsl(36, 95%, 40%)',
|
||||
warning: 'hsl(0, 55%, 55%)',
|
||||
danger: 'hsl(0, 55%, 50%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: 'hsl(210, 20%, 96%)',
|
||||
border: 'hsl(210, 15%, 90%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(210, 20%, 94%)',
|
||||
border: 'hsl(210, 15%, 88%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
47
plugins/themes-yaak/src/themes/noctis.ts
Normal file
47
plugins/themes-yaak/src/themes/noctis.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const noctisAzureus: Theme = {
|
||||
id: 'noctis-azureus',
|
||||
label: 'Noctis Azureus',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(210, 35%, 14%)',
|
||||
surfaceHighlight: 'hsl(210, 30%, 19%)',
|
||||
text: 'hsl(180, 45%, 85%)',
|
||||
textSubtle: 'hsl(180, 25%, 60%)',
|
||||
textSubtlest: 'hsl(180, 18%, 45%)',
|
||||
primary: 'hsl(175, 60%, 55%)',
|
||||
secondary: 'hsl(200, 70%, 65%)',
|
||||
info: 'hsl(200, 70%, 65%)',
|
||||
success: 'hsl(85, 55%, 60%)',
|
||||
notice: 'hsl(45, 90%, 60%)',
|
||||
warning: 'hsl(25, 85%, 58%)',
|
||||
danger: 'hsl(355, 75%, 62%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(210, 35%, 11%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(210, 33%, 12%)',
|
||||
border: 'hsl(210, 30%, 17%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(210, 35%, 10%)',
|
||||
border: 'hsl(210, 30%, 15%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(210, 33%, 12%)',
|
||||
border: 'hsl(210, 30%, 17%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(175, 60%, 48%)',
|
||||
secondary: 'hsl(200, 70%, 58%)',
|
||||
info: 'hsl(200, 70%, 58%)',
|
||||
success: 'hsl(85, 55%, 53%)',
|
||||
notice: 'hsl(45, 90%, 53%)',
|
||||
warning: 'hsl(25, 85%, 51%)',
|
||||
danger: 'hsl(355, 75%, 55%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
85
plugins/themes-yaak/src/themes/nord.ts
Normal file
85
plugins/themes-yaak/src/themes/nord.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const nord: Theme = {
|
||||
id: 'nord',
|
||||
label: 'Nord',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(220,16%,22%)',
|
||||
surfaceHighlight: 'hsl(220,14%,28%)',
|
||||
text: 'hsl(220,28%,93%)',
|
||||
textSubtle: 'hsl(220,26%,90%)',
|
||||
textSubtlest: 'hsl(220,24%,86%)',
|
||||
primary: 'hsl(193,38%,68%)',
|
||||
secondary: 'hsl(210,34%,63%)',
|
||||
info: 'hsl(174,25%,69%)',
|
||||
success: 'hsl(89,26%,66%)',
|
||||
notice: 'hsl(40,66%,73%)',
|
||||
warning: 'hsl(17,48%,64%)',
|
||||
danger: 'hsl(353,43%,56%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: 'hsl(220,16%,22%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(220,14%,28%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const nordLight: Theme = {
|
||||
id: 'nord-light',
|
||||
label: 'Nord Light',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: '#eceff4',
|
||||
surfaceHighlight: '#e5e9f0',
|
||||
text: '#24292e',
|
||||
textSubtle: '#444d56',
|
||||
textSubtlest: '#586069',
|
||||
primary: '#2188ff',
|
||||
secondary: '#586069',
|
||||
info: '#005cc5',
|
||||
success: '#28a745',
|
||||
notice: '#e36209',
|
||||
warning: '#e36209',
|
||||
danger: '#cb2431',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: '#e5e9f0',
|
||||
},
|
||||
appHeader: {
|
||||
surface: '#e5e9f0',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const nordLightBrighter: Theme = {
|
||||
id: 'nord-light-brighter',
|
||||
label: 'Nord Light Brighter',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: '#ffffff',
|
||||
surfaceHighlight: '#f6f8fa',
|
||||
text: '#24292e',
|
||||
textSubtle: '#444d56',
|
||||
textSubtlest: '#586069',
|
||||
primary: '#2188ff',
|
||||
secondary: '#586069',
|
||||
info: '#005cc5',
|
||||
success: '#28a745',
|
||||
notice: '#e36209',
|
||||
warning: '#e36209',
|
||||
danger: '#cb2431',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: '#f6f8fa',
|
||||
},
|
||||
appHeader: {
|
||||
surface: '#f6f8fa',
|
||||
},
|
||||
},
|
||||
};
|
||||
44
plugins/themes-yaak/src/themes/one-dark-pro.ts
Normal file
44
plugins/themes-yaak/src/themes/one-dark-pro.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const oneDarkPro: Theme = {
|
||||
id: 'one-dark-pro',
|
||||
label: 'One Dark Pro',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(220, 13%, 18%)',
|
||||
surfaceHighlight: 'hsl(220, 13%, 22%)',
|
||||
text: 'hsl(219, 14%, 71%)',
|
||||
textSubtle: 'hsl(219, 10%, 53%)',
|
||||
textSubtlest: 'hsl(220, 9%, 45%)',
|
||||
primary: 'hsl(286, 60%, 67%)',
|
||||
secondary: 'hsl(219, 14%, 60%)',
|
||||
info: 'hsl(207, 82%, 66%)',
|
||||
success: 'hsl(95, 38%, 62%)',
|
||||
notice: 'hsl(39, 67%, 69%)',
|
||||
warning: 'hsl(29, 54%, 61%)',
|
||||
danger: 'hsl(355, 65%, 65%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: 'hsl(220, 13%, 16%)',
|
||||
border: 'hsl(220, 13%, 20%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(220, 13%, 14%)',
|
||||
border: 'hsl(220, 13%, 20%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(220, 13%, 16%)',
|
||||
border: 'hsl(220, 13%, 20%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(286, 60%, 60%)',
|
||||
secondary: 'hsl(219, 14%, 53%)',
|
||||
info: 'hsl(207, 82%, 59%)',
|
||||
success: 'hsl(95, 38%, 55%)',
|
||||
notice: 'hsl(39, 67%, 62%)',
|
||||
warning: 'hsl(29, 54%, 54%)',
|
||||
danger: 'hsl(355, 65%, 58%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
47
plugins/themes-yaak/src/themes/panda.ts
Normal file
47
plugins/themes-yaak/src/themes/panda.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const pandaSyntax: Theme = {
|
||||
id: 'panda',
|
||||
label: 'Panda Syntax',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(225, 15%, 15%)',
|
||||
surfaceHighlight: 'hsl(225, 12%, 20%)',
|
||||
text: 'hsl(0, 0%, 90%)',
|
||||
textSubtle: 'hsl(0, 0%, 65%)',
|
||||
textSubtlest: 'hsl(0, 0%, 50%)',
|
||||
primary: 'hsl(353, 95%, 70%)',
|
||||
secondary: 'hsl(0, 0%, 65%)',
|
||||
info: 'hsl(200, 85%, 65%)',
|
||||
success: 'hsl(175, 90%, 65%)',
|
||||
notice: 'hsl(40, 100%, 65%)',
|
||||
warning: 'hsl(40, 100%, 65%)',
|
||||
danger: 'hsl(0, 90%, 65%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(225, 15%, 12%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(225, 14%, 13%)',
|
||||
border: 'hsl(225, 12%, 18%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(225, 15%, 11%)',
|
||||
border: 'hsl(225, 12%, 16%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(225, 14%, 13%)',
|
||||
border: 'hsl(225, 12%, 18%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(353, 95%, 63%)',
|
||||
secondary: 'hsl(0, 0%, 58%)',
|
||||
info: 'hsl(200, 85%, 58%)',
|
||||
success: 'hsl(175, 90%, 58%)',
|
||||
notice: 'hsl(40, 100%, 58%)',
|
||||
warning: 'hsl(40, 100%, 58%)',
|
||||
danger: 'hsl(0, 90%, 58%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
18
plugins/themes-yaak/src/themes/relaxing.ts
Normal file
18
plugins/themes-yaak/src/themes/relaxing.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const relaxing: Theme = {
|
||||
id: 'relaxing',
|
||||
label: 'Relaxing',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(267,33%,17%)',
|
||||
text: 'hsl(275,49%,92%)',
|
||||
primary: 'hsl(267,84%,81%)',
|
||||
secondary: 'hsl(227,35%,80%)',
|
||||
info: 'hsl(217,92%,76%)',
|
||||
success: 'hsl(115,54%,76%)',
|
||||
notice: 'hsl(41,86%,83%)',
|
||||
warning: 'hsl(23,92%,75%)',
|
||||
danger: 'hsl(343,81%,75%)',
|
||||
},
|
||||
};
|
||||
111
plugins/themes-yaak/src/themes/rose-pine.ts
Normal file
111
plugins/themes-yaak/src/themes/rose-pine.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const rosePine: Theme = {
|
||||
id: 'rose-pine',
|
||||
label: 'Rosé Pine',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(249,22%,12%)',
|
||||
text: 'hsl(245,50%,91%)',
|
||||
textSubtle: 'hsl(248,15%,61%)',
|
||||
textSubtlest: 'hsl(249,12%,47%)',
|
||||
primary: 'hsl(267,57%,78%)',
|
||||
secondary: 'hsl(249,12%,47%)',
|
||||
info: 'hsl(199,49%,60%)',
|
||||
success: 'hsl(180,43%,73%)',
|
||||
notice: 'hsl(35,88%,72%)',
|
||||
warning: 'hsl(1,74%,79%)',
|
||||
danger: 'hsl(343,76%,68%)',
|
||||
},
|
||||
components: {
|
||||
responsePane: {
|
||||
surface: 'hsl(247,23%,15%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(247,23%,15%)',
|
||||
},
|
||||
menu: {
|
||||
surface: 'hsl(248,21%,26%)',
|
||||
textSubtle: 'hsl(248,15%,66%)',
|
||||
textSubtlest: 'hsl(249,12%,52%)',
|
||||
border: 'hsl(248,21%,35%)',
|
||||
borderSubtle: 'hsl(248,21%,33%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const rosePineMoon: Theme = {
|
||||
id: 'rose-pine-moon',
|
||||
label: 'Rosé Pine Moon',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(246,24%,17%)',
|
||||
text: 'hsl(245,50%,91%)',
|
||||
textSubtle: 'hsl(248,15%,61%)',
|
||||
textSubtlest: 'hsl(249,12%,47%)',
|
||||
primary: 'hsl(267,57%,78%)',
|
||||
secondary: 'hsl(248,15%,61%)',
|
||||
info: 'hsl(197,48%,60%)',
|
||||
success: 'hsl(197,48%,60%)',
|
||||
notice: 'hsl(35,88%,72%)',
|
||||
warning: 'hsl(2,66%,75%)',
|
||||
danger: 'hsl(343,76%,68%)',
|
||||
},
|
||||
components: {
|
||||
responsePane: {
|
||||
surface: 'hsl(247,24%,20%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(247,24%,20%)',
|
||||
},
|
||||
menu: {
|
||||
surface: 'hsl(248,21%,26%)',
|
||||
textSubtle: 'hsl(248,15%,61%)',
|
||||
textSubtlest: 'hsl(249,12%,55%)',
|
||||
border: 'hsl(248,21%,35%)',
|
||||
borderSubtle: 'hsl(248,21%,31%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const rosePineDawn: Theme = {
|
||||
id: 'rose-pine-dawn',
|
||||
label: 'Rosé Pine Dawn',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'hsl(32,57%,95%)',
|
||||
border: 'hsl(10,9%,86%)',
|
||||
surfaceHighlight: 'hsl(25,35%,93%)',
|
||||
text: 'hsl(248,19%,40%)',
|
||||
textSubtle: 'hsl(248,12%,52%)',
|
||||
textSubtlest: 'hsl(257,9%,61%)',
|
||||
primary: 'hsl(271,27%,56%)',
|
||||
secondary: 'hsl(249,12%,47%)',
|
||||
info: 'hsl(197,52%,36%)',
|
||||
success: 'hsl(188,31%,45%)',
|
||||
notice: 'hsl(34,64%,49%)',
|
||||
warning: 'hsl(2,47%,64%)',
|
||||
danger: 'hsl(343,35%,55%)',
|
||||
},
|
||||
components: {
|
||||
responsePane: {
|
||||
border: 'hsl(20,12%,90%)',
|
||||
},
|
||||
sidebar: {
|
||||
border: 'hsl(20,12%,90%)',
|
||||
},
|
||||
appHeader: {
|
||||
border: 'hsl(20,12%,90%)',
|
||||
},
|
||||
input: {
|
||||
border: 'hsl(10,9%,86%)',
|
||||
},
|
||||
dialog: {
|
||||
border: 'hsl(20,12%,90%)',
|
||||
},
|
||||
menu: {
|
||||
surface: 'hsl(28,40%,92%)',
|
||||
border: 'hsl(10,9%,86%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
99
plugins/themes-yaak/src/themes/shades-of-purple.ts
Normal file
99
plugins/themes-yaak/src/themes/shades-of-purple.ts
Normal file
@@ -0,0 +1,99 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const shadesOfPurple: Theme = {
|
||||
id: 'shades-of-purple',
|
||||
label: 'Shades of Purple',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: '#2D2B55',
|
||||
surfaceHighlight: '#1F1F41',
|
||||
text: '#FFFFFF',
|
||||
textSubtle: '#A599E9',
|
||||
textSubtlest: '#7E72C4',
|
||||
primary: '#FAD000',
|
||||
secondary: '#A599E9',
|
||||
info: '#80FFBB',
|
||||
success: '#3AD900',
|
||||
notice: '#FAD000',
|
||||
warning: '#FF9D00',
|
||||
danger: '#EC3A37F5',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: '#1E1E3F',
|
||||
},
|
||||
sidebar: {
|
||||
surface: '#222244',
|
||||
border: '#1E1E3F',
|
||||
},
|
||||
input: {
|
||||
border: '#7E72C4',
|
||||
},
|
||||
appHeader: {
|
||||
surface: '#1E1E3F',
|
||||
border: '#1E1E3F',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(240,33%,20%)',
|
||||
border: 'hsl(240,33%,20%)',
|
||||
},
|
||||
button: {
|
||||
primary: '#FAD000',
|
||||
secondary: '#A599E9',
|
||||
info: '#80FFBB',
|
||||
success: '#3AD900',
|
||||
notice: '#FAD000',
|
||||
warning: '#FF9D00',
|
||||
danger: '#EC3A37F5',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const shadesOfPurpleSuperDark: Theme = {
|
||||
id: 'shades-of-purple-super-dark',
|
||||
label: 'Shades of Purple (Super Dark)',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: '#191830',
|
||||
surfaceHighlight: '#1F1E3A',
|
||||
text: '#FFFFFF',
|
||||
textSubtle: '#A599E9',
|
||||
textSubtlest: '#7E72C4',
|
||||
primary: '#FAD000',
|
||||
secondary: '#A599E9',
|
||||
info: '#80FFBB',
|
||||
success: '#3AD900',
|
||||
notice: '#FAD000',
|
||||
warning: '#FF9D00',
|
||||
danger: '#EC3A37F5',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: '#15152b',
|
||||
},
|
||||
input: {
|
||||
border: '#2D2B55',
|
||||
},
|
||||
sidebar: {
|
||||
surface: '#131327',
|
||||
border: '#131327',
|
||||
},
|
||||
appHeader: {
|
||||
surface: '#15152a',
|
||||
border: '#15152a',
|
||||
},
|
||||
responsePane: {
|
||||
surface: '#131327',
|
||||
border: '#131327',
|
||||
},
|
||||
button: {
|
||||
primary: '#FAD000',
|
||||
secondary: '#A599E9',
|
||||
info: '#80FFBB',
|
||||
success: '#3AD900',
|
||||
notice: '#FAD000',
|
||||
warning: '#FF9D00',
|
||||
danger: '#EC3A37F5',
|
||||
},
|
||||
},
|
||||
};
|
||||
47
plugins/themes-yaak/src/themes/slack.ts
Normal file
47
plugins/themes-yaak/src/themes/slack.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const slackAubergine: Theme = {
|
||||
id: 'slack-aubergine',
|
||||
label: 'Slack Aubergine',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(270, 25%, 18%)',
|
||||
surfaceHighlight: 'hsl(270, 22%, 24%)',
|
||||
text: 'hsl(0, 0%, 100%)',
|
||||
textSubtle: 'hsl(270, 15%, 75%)',
|
||||
textSubtlest: 'hsl(270, 12%, 58%)',
|
||||
primary: 'hsl(165, 100%, 40%)',
|
||||
secondary: 'hsl(270, 12%, 65%)',
|
||||
info: 'hsl(195, 95%, 55%)',
|
||||
success: 'hsl(145, 80%, 50%)',
|
||||
notice: 'hsl(43, 100%, 55%)',
|
||||
warning: 'hsl(43, 100%, 50%)',
|
||||
danger: 'hsl(0, 80%, 55%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(270, 25%, 14%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(270, 23%, 15%)',
|
||||
border: 'hsl(270, 22%, 22%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(270, 25%, 13%)',
|
||||
border: 'hsl(270, 22%, 20%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(270, 23%, 15%)',
|
||||
border: 'hsl(270, 22%, 22%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(165, 100%, 35%)',
|
||||
secondary: 'hsl(270, 12%, 58%)',
|
||||
info: 'hsl(195, 95%, 48%)',
|
||||
success: 'hsl(145, 80%, 45%)',
|
||||
notice: 'hsl(43, 100%, 48%)',
|
||||
warning: 'hsl(43, 100%, 45%)',
|
||||
danger: 'hsl(0, 80%, 48%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
77
plugins/themes-yaak/src/themes/solarized.ts
Normal file
77
plugins/themes-yaak/src/themes/solarized.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const solarizedDark: Theme = {
|
||||
id: 'solarized-dark',
|
||||
label: 'Solarized Dark',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: '#002b36',
|
||||
surfaceHighlight: '#073642',
|
||||
text: '#839496',
|
||||
textSubtle: '#657b83',
|
||||
textSubtlest: '#586e75',
|
||||
primary: '#268bd2',
|
||||
secondary: '#657b83',
|
||||
info: '#268bd2',
|
||||
success: '#859900',
|
||||
notice: '#b58900',
|
||||
warning: '#cb4b16',
|
||||
danger: '#dc322f',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: '#002b36',
|
||||
},
|
||||
sidebar: {
|
||||
surface: '#073642',
|
||||
border: 'hsl(192,81%,17%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: '#002b36',
|
||||
border: 'hsl(192,81%,16%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: '#073642',
|
||||
border: 'hsl(192,81%,17%)',
|
||||
},
|
||||
button: {
|
||||
primary: '#268bd2',
|
||||
secondary: '#657b83',
|
||||
info: '#268bd2',
|
||||
success: '#859900',
|
||||
notice: '#b58900',
|
||||
warning: '#cb4b16',
|
||||
danger: '#dc322f',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const solarizedLight: Theme = {
|
||||
id: 'solarized-light',
|
||||
label: 'Solarized Light',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: '#fdf6e3',
|
||||
surfaceHighlight: '#eee8d5',
|
||||
text: '#657b83',
|
||||
textSubtle: '#839496',
|
||||
textSubtlest: '#93a1a1',
|
||||
primary: '#268bd2',
|
||||
secondary: '#839496',
|
||||
info: '#268bd2',
|
||||
success: '#859900',
|
||||
notice: '#b58900',
|
||||
warning: '#cb4b16',
|
||||
danger: '#dc322f',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: '#eee8d5',
|
||||
border: '#d3cbb7',
|
||||
},
|
||||
appHeader: {
|
||||
surface: '#eee8d5',
|
||||
border: '#d3cbb7',
|
||||
},
|
||||
},
|
||||
};
|
||||
56
plugins/themes-yaak/src/themes/synthwave-84.ts
Normal file
56
plugins/themes-yaak/src/themes/synthwave-84.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const synthwave84: Theme = {
|
||||
id: 'synthwave-84',
|
||||
label: "SynthWave '84",
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(253, 45%, 15%)',
|
||||
surfaceHighlight: 'hsl(253, 40%, 20%)',
|
||||
text: 'hsl(300, 50%, 90%)',
|
||||
textSubtle: 'hsl(280, 25%, 65%)',
|
||||
textSubtlest: 'hsl(280, 20%, 50%)',
|
||||
primary: 'hsl(320, 100%, 75%)',
|
||||
secondary: 'hsl(280, 20%, 60%)',
|
||||
info: 'hsl(177, 100%, 55%)',
|
||||
success: 'hsl(83, 100%, 60%)',
|
||||
notice: 'hsl(57, 100%, 60%)',
|
||||
warning: 'hsl(30, 100%, 60%)',
|
||||
danger: 'hsl(340, 100%, 65%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(253, 45%, 12%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(253, 42%, 18%)',
|
||||
border: 'hsl(253, 40%, 22%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(253, 45%, 11%)',
|
||||
border: 'hsl(253, 40%, 18%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(253, 42%, 18%)',
|
||||
border: 'hsl(253, 40%, 22%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(320, 100%, 68%)',
|
||||
secondary: 'hsl(280, 20%, 53%)',
|
||||
info: 'hsl(177, 100%, 48%)',
|
||||
success: 'hsl(83, 100%, 53%)',
|
||||
notice: 'hsl(57, 100%, 53%)',
|
||||
warning: 'hsl(30, 100%, 53%)',
|
||||
danger: 'hsl(340, 100%, 58%)',
|
||||
},
|
||||
editor: {
|
||||
primary: 'hsl(177, 100%, 55%)',
|
||||
secondary: 'hsl(280, 20%, 60%)',
|
||||
info: 'hsl(320, 100%, 75%)',
|
||||
success: 'hsl(83, 100%, 60%)',
|
||||
notice: 'hsl(57, 100%, 60%)',
|
||||
warning: 'hsl(30, 100%, 60%)',
|
||||
danger: 'hsl(340, 100%, 65%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
121
plugins/themes-yaak/src/themes/tokyo-night.ts
Normal file
121
plugins/themes-yaak/src/themes/tokyo-night.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const tokyoNight: Theme = {
|
||||
id: 'tokyo-night',
|
||||
label: 'Tokyo Night',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(235, 21%, 13%)',
|
||||
surfaceHighlight: 'hsl(235, 18%, 18%)',
|
||||
text: 'hsl(229, 28%, 76%)',
|
||||
textSubtle: 'hsl(232, 18%, 52%)',
|
||||
textSubtlest: 'hsl(234, 16%, 40%)',
|
||||
primary: 'hsl(266, 100%, 78%)',
|
||||
secondary: 'hsl(232, 18%, 52%)',
|
||||
info: 'hsl(217, 100%, 73%)',
|
||||
success: 'hsl(158, 57%, 63%)',
|
||||
notice: 'hsl(40, 67%, 65%)',
|
||||
warning: 'hsl(25, 75%, 58%)',
|
||||
danger: 'hsl(358, 100%, 70%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(235, 21%, 11%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(235, 21%, 11%)',
|
||||
border: 'hsl(235, 18%, 16%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(235, 21%, 9%)',
|
||||
border: 'hsl(235, 18%, 14%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(235, 21%, 11%)',
|
||||
border: 'hsl(235, 18%, 16%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(266, 100%, 71%)',
|
||||
info: 'hsl(217, 100%, 66%)',
|
||||
success: 'hsl(158, 57%, 56%)',
|
||||
notice: 'hsl(40, 67%, 58%)',
|
||||
warning: 'hsl(25, 75%, 52%)',
|
||||
danger: 'hsl(358, 100%, 63%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const tokyoNightStorm: Theme = {
|
||||
id: 'tokyo-night-storm',
|
||||
label: 'Tokyo Night Storm',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(232, 25%, 17%)',
|
||||
surfaceHighlight: 'hsl(232, 22%, 22%)',
|
||||
text: 'hsl(229, 28%, 76%)',
|
||||
textSubtle: 'hsl(232, 18%, 52%)',
|
||||
textSubtlest: 'hsl(234, 16%, 40%)',
|
||||
primary: 'hsl(266, 100%, 78%)',
|
||||
secondary: 'hsl(232, 18%, 52%)',
|
||||
info: 'hsl(217, 100%, 73%)',
|
||||
success: 'hsl(158, 57%, 63%)',
|
||||
notice: 'hsl(40, 67%, 65%)',
|
||||
warning: 'hsl(25, 75%, 58%)',
|
||||
danger: 'hsl(358, 100%, 70%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(232, 25%, 14%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(232, 25%, 14%)',
|
||||
border: 'hsl(232, 22%, 20%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(232, 25%, 12%)',
|
||||
border: 'hsl(232, 22%, 18%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(232, 25%, 14%)',
|
||||
border: 'hsl(232, 22%, 20%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(266, 100%, 71%)',
|
||||
info: 'hsl(217, 100%, 66%)',
|
||||
success: 'hsl(158, 57%, 56%)',
|
||||
notice: 'hsl(40, 67%, 58%)',
|
||||
warning: 'hsl(25, 75%, 52%)',
|
||||
danger: 'hsl(358, 100%, 63%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const tokyoNightDay: Theme = {
|
||||
id: 'tokyo-night-day',
|
||||
label: 'Tokyo Night Day',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'hsl(212, 100%, 98%)',
|
||||
surfaceHighlight: 'hsl(212, 60%, 93%)',
|
||||
text: 'hsl(233, 26%, 27%)',
|
||||
textSubtle: 'hsl(232, 18%, 45%)',
|
||||
textSubtlest: 'hsl(232, 12%, 55%)',
|
||||
primary: 'hsl(290, 80%, 45%)',
|
||||
secondary: 'hsl(232, 18%, 50%)',
|
||||
info: 'hsl(217, 88%, 52%)',
|
||||
success: 'hsl(160, 75%, 35%)',
|
||||
notice: 'hsl(41, 80%, 40%)',
|
||||
warning: 'hsl(20, 80%, 48%)',
|
||||
danger: 'hsl(359, 65%, 48%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: 'hsl(212, 60%, 95%)',
|
||||
border: 'hsl(212, 40%, 88%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(212, 60%, 93%)',
|
||||
border: 'hsl(212, 40%, 86%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
44
plugins/themes-yaak/src/themes/triangle.ts
Normal file
44
plugins/themes-yaak/src/themes/triangle.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const triangle: Theme = {
|
||||
id: 'triangle',
|
||||
dark: true,
|
||||
label: 'Triangle',
|
||||
base: {
|
||||
surface: 'rgb(0,0,0)',
|
||||
surfaceHighlight: 'rgb(21,21,21)',
|
||||
surfaceActive: 'rgb(31,31,31)',
|
||||
text: 'rgb(237,237,237)',
|
||||
textSubtle: 'rgb(161,161,161)',
|
||||
textSubtlest: 'rgb(115,115,115)',
|
||||
border: 'rgb(31,31,31)',
|
||||
primary: 'rgb(196,114,251)',
|
||||
secondary: 'rgb(161,161,161)',
|
||||
info: 'rgb(71,168,255)',
|
||||
success: 'rgb(0,202,81)',
|
||||
notice: 'rgb(255,175,0)',
|
||||
warning: '#FF4C8D',
|
||||
danger: '#fd495a',
|
||||
},
|
||||
components: {
|
||||
editor: {
|
||||
danger: '#FF4C8D',
|
||||
warning: '#fd495a',
|
||||
},
|
||||
dialog: {
|
||||
surface: 'rgb(10,10,10)',
|
||||
border: 'rgb(31,31,31)',
|
||||
},
|
||||
sidebar: {
|
||||
border: 'rgb(31,31,31)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'rgb(10,10,10)',
|
||||
border: 'rgb(31,31,31)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'rgb(10,10,10)',
|
||||
border: 'rgb(31,31,31)',
|
||||
},
|
||||
},
|
||||
};
|
||||
77
plugins/themes-yaak/src/themes/vitesse.ts
Normal file
77
plugins/themes-yaak/src/themes/vitesse.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const vitesseDark: Theme = {
|
||||
id: 'vitesse-dark',
|
||||
label: 'Vitesse Dark',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(220, 13%, 10%)',
|
||||
surfaceHighlight: 'hsl(220, 12%, 15%)',
|
||||
text: 'hsl(220, 10%, 80%)',
|
||||
textSubtle: 'hsl(220, 8%, 55%)',
|
||||
textSubtlest: 'hsl(220, 6%, 42%)',
|
||||
primary: 'hsl(143, 50%, 55%)',
|
||||
secondary: 'hsl(220, 8%, 55%)',
|
||||
info: 'hsl(214, 60%, 65%)',
|
||||
success: 'hsl(143, 50%, 55%)',
|
||||
notice: 'hsl(45, 65%, 65%)',
|
||||
warning: 'hsl(30, 60%, 60%)',
|
||||
danger: 'hsl(355, 60%, 60%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(220, 13%, 7%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(220, 12%, 8%)',
|
||||
border: 'hsl(220, 10%, 14%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(220, 13%, 6%)',
|
||||
border: 'hsl(220, 10%, 12%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(220, 12%, 8%)',
|
||||
border: 'hsl(220, 10%, 14%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(143, 50%, 48%)',
|
||||
secondary: 'hsl(220, 8%, 48%)',
|
||||
info: 'hsl(214, 60%, 58%)',
|
||||
success: 'hsl(143, 50%, 48%)',
|
||||
notice: 'hsl(45, 65%, 58%)',
|
||||
warning: 'hsl(30, 60%, 53%)',
|
||||
danger: 'hsl(355, 60%, 53%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const vitesseLight: Theme = {
|
||||
id: 'vitesse-light',
|
||||
label: 'Vitesse Light',
|
||||
dark: false,
|
||||
base: {
|
||||
surface: 'hsl(0, 0%, 100%)',
|
||||
surfaceHighlight: 'hsl(40, 20%, 96%)',
|
||||
text: 'hsl(0, 0%, 24%)',
|
||||
textSubtle: 'hsl(0, 0%, 45%)',
|
||||
textSubtlest: 'hsl(0, 0%, 55%)',
|
||||
primary: 'hsl(143, 40%, 40%)',
|
||||
secondary: 'hsl(0, 0%, 45%)',
|
||||
info: 'hsl(214, 50%, 48%)',
|
||||
success: 'hsl(143, 40%, 40%)',
|
||||
notice: 'hsl(40, 60%, 42%)',
|
||||
warning: 'hsl(25, 60%, 48%)',
|
||||
danger: 'hsl(345, 50%, 48%)',
|
||||
},
|
||||
components: {
|
||||
sidebar: {
|
||||
surface: 'hsl(40, 20%, 97%)',
|
||||
border: 'hsl(40, 15%, 92%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(40, 20%, 95%)',
|
||||
border: 'hsl(40, 15%, 90%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
47
plugins/themes-yaak/src/themes/winter-is-coming.ts
Normal file
47
plugins/themes-yaak/src/themes/winter-is-coming.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import type { Theme } from '@yaakapp/api';
|
||||
|
||||
export const winterIsComing: Theme = {
|
||||
id: 'winter-is-coming',
|
||||
label: 'Winter is Coming',
|
||||
dark: true,
|
||||
base: {
|
||||
surface: 'hsl(216, 50%, 10%)',
|
||||
surfaceHighlight: 'hsl(216, 40%, 15%)',
|
||||
text: 'hsl(210, 20%, 88%)',
|
||||
textSubtle: 'hsl(210, 15%, 60%)',
|
||||
textSubtlest: 'hsl(210, 10%, 45%)',
|
||||
primary: 'hsl(176, 85%, 60%)',
|
||||
secondary: 'hsl(210, 15%, 60%)',
|
||||
info: 'hsl(210, 65%, 65%)',
|
||||
success: 'hsl(100, 65%, 55%)',
|
||||
notice: 'hsl(45, 100%, 65%)',
|
||||
warning: 'hsl(30, 90%, 55%)',
|
||||
danger: 'hsl(350, 100%, 65%)',
|
||||
},
|
||||
components: {
|
||||
dialog: {
|
||||
surface: 'hsl(216, 50%, 7%)',
|
||||
},
|
||||
sidebar: {
|
||||
surface: 'hsl(216, 45%, 12%)',
|
||||
border: 'hsl(216, 40%, 17%)',
|
||||
},
|
||||
appHeader: {
|
||||
surface: 'hsl(216, 50%, 8%)',
|
||||
border: 'hsl(216, 40%, 14%)',
|
||||
},
|
||||
responsePane: {
|
||||
surface: 'hsl(216, 45%, 12%)',
|
||||
border: 'hsl(216, 40%, 17%)',
|
||||
},
|
||||
button: {
|
||||
primary: 'hsl(176, 85%, 53%)',
|
||||
secondary: 'hsl(210, 15%, 53%)',
|
||||
info: 'hsl(210, 65%, 58%)',
|
||||
success: 'hsl(100, 65%, 48%)',
|
||||
notice: 'hsl(45, 100%, 58%)',
|
||||
warning: 'hsl(30, 90%, 48%)',
|
||||
danger: 'hsl(350, 100%, 58%)',
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -5,3 +5,4 @@ chain_width = 100
|
||||
max_width = 100
|
||||
single_line_if_else_max_width = 100
|
||||
fn_call_width = 100
|
||||
struct_lit_width = 100
|
||||
|
||||
153
scripts/git-hooks/post-checkout.mjs
Normal file
153
scripts/git-hooks/post-checkout.mjs
Normal file
@@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Git post-checkout hook for auto-configuring worktree environments.
|
||||
* This runs after 'git checkout' or 'git worktree add'.
|
||||
*
|
||||
* Args from git:
|
||||
* process.argv[2] - previous HEAD ref
|
||||
* process.argv[3] - new HEAD ref
|
||||
* process.argv[4] - flag (1 = branch checkout, 0 = file checkout)
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { execSync, execFileSync } from 'child_process';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const isBranchCheckout = process.argv[4] === '1';
|
||||
|
||||
if (!isBranchCheckout) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Check if we're in a worktree by looking for .git file (not directory)
|
||||
const gitPath = path.join(process.cwd(), '.git');
|
||||
const isWorktree = fs.existsSync(gitPath) && fs.statSync(gitPath).isFile();
|
||||
|
||||
if (!isWorktree) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const envLocalPath = path.join(process.cwd(), '.env.local');
|
||||
|
||||
// Don't overwrite existing .env.local
|
||||
if (fs.existsSync(envLocalPath)) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
console.log('Detected new worktree - configuring ports in .env.local');
|
||||
|
||||
// Find the highest ports in use across all worktrees
|
||||
// Main worktree (first in list) is assumed to use default ports 1420/64343
|
||||
let maxMcpPort = 64343;
|
||||
let maxDevPort = 1420;
|
||||
|
||||
try {
|
||||
const worktreeList = execSync('git worktree list --porcelain', { encoding: 'utf8' });
|
||||
const worktreePaths = worktreeList
|
||||
.split('\n')
|
||||
.filter(line => line.startsWith('worktree '))
|
||||
.map(line => line.replace('worktree ', '').trim());
|
||||
|
||||
// Skip the first worktree (main) since it uses default ports
|
||||
for (let i = 1; i < worktreePaths.length; i++) {
|
||||
const worktreePath = worktreePaths[i];
|
||||
const envPath = path.join(worktreePath, '.env.local');
|
||||
|
||||
if (fs.existsSync(envPath)) {
|
||||
const content = fs.readFileSync(envPath, 'utf8');
|
||||
|
||||
const mcpMatch = content.match(/^YAAK_PLUGIN_MCP_SERVER_PORT=(\d+)/m);
|
||||
if (mcpMatch) {
|
||||
const port = parseInt(mcpMatch[1], 10);
|
||||
if (port > maxMcpPort) {
|
||||
maxMcpPort = port;
|
||||
}
|
||||
}
|
||||
|
||||
const devMatch = content.match(/^YAAK_DEV_PORT=(\d+)/m);
|
||||
if (devMatch) {
|
||||
const port = parseInt(devMatch[1], 10);
|
||||
if (port > maxDevPort) {
|
||||
maxDevPort = port;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Increment to get the next available port
|
||||
maxDevPort++;
|
||||
maxMcpPort++;
|
||||
} catch (err) {
|
||||
console.error('Warning: Could not check other worktrees for port conflicts:', err.message);
|
||||
// Continue with default ports
|
||||
}
|
||||
|
||||
// Create .env.local with unique ports
|
||||
const envContent = `# Auto-generated by git post-checkout hook
|
||||
# This file configures ports for this worktree to avoid conflicts
|
||||
|
||||
# Vite dev server port (main worktree uses 1420)
|
||||
YAAK_DEV_PORT=${maxDevPort}
|
||||
|
||||
# MCP Server port (main worktree uses 64343)
|
||||
YAAK_PLUGIN_MCP_SERVER_PORT=${maxMcpPort}
|
||||
`;
|
||||
|
||||
fs.writeFileSync(envLocalPath, envContent, 'utf8');
|
||||
console.log(`Created .env.local with YAAK_DEV_PORT=${maxDevPort} and YAAK_PLUGIN_MCP_SERVER_PORT=${maxMcpPort}`);
|
||||
|
||||
// Copy gitignored editor config folders from main worktree (.zed, .vscode, .claude, etc.)
|
||||
// This ensures your editor settings, tasks, and configurations are available in the new worktree
|
||||
// without needing to manually copy them or commit them to git.
|
||||
try {
|
||||
const worktreeList = execSync('git worktree list --porcelain', { encoding: 'utf8' });
|
||||
const mainWorktreePath = worktreeList
|
||||
.split('\n')
|
||||
.find(line => line.startsWith('worktree '))
|
||||
?.replace('worktree ', '')
|
||||
.trim();
|
||||
|
||||
if (mainWorktreePath) {
|
||||
// Find all .* folders in main worktree root that are gitignored
|
||||
const entries = fs.readdirSync(mainWorktreePath, { withFileTypes: true });
|
||||
const dotFolders = entries
|
||||
.filter(entry => entry.isDirectory() && entry.name.startsWith('.'))
|
||||
.map(entry => entry.name);
|
||||
|
||||
for (const folder of dotFolders) {
|
||||
const sourcePath = path.join(mainWorktreePath, folder);
|
||||
const destPath = path.join(process.cwd(), folder);
|
||||
|
||||
try {
|
||||
// Check if it's gitignored - run from main worktree directory
|
||||
execFileSync('git', ['check-ignore', '-q', folder], {
|
||||
stdio: 'pipe',
|
||||
cwd: mainWorktreePath
|
||||
});
|
||||
|
||||
// It's gitignored, copy it
|
||||
fs.cpSync(sourcePath, destPath, { recursive: true });
|
||||
console.log(`Copied ${folder} from main worktree`);
|
||||
} catch {
|
||||
// Not gitignored or doesn't exist, skip
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('Warning: Could not copy files from main worktree:', err.message);
|
||||
// Continue anyway
|
||||
}
|
||||
|
||||
// Run npm run init to install dependencies and bootstrap
|
||||
console.log('\nRunning npm run init to install dependencies and bootstrap...');
|
||||
try {
|
||||
execSync('npm run init', { stdio: 'inherit' });
|
||||
console.log('\n✓ Worktree setup complete!');
|
||||
} catch (err) {
|
||||
console.error('\n✗ Failed to run npm run init. You may need to run it manually.');
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -7,7 +7,7 @@ if (version.startsWith('wasm-pack ')) {
|
||||
}
|
||||
|
||||
console.log('Installing wasm-pack via cargo...');
|
||||
execSync('cargo install wasm-pack', { stdio: 'inherit' });
|
||||
execSync('cargo install wasm-pack --locked', { stdio: 'inherit' });
|
||||
|
||||
function tryExecSync(cmd) {
|
||||
try {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user