994 Commits

Author SHA1 Message Date
Fatih Kadir Akın 0d25ab70fd feat(presentation): align lightning talk with Build theme
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-02 16:38:49 -07:00
Fatih Kadir Akın 44abe71542 feat(presentation): add PresenterNotesPage component and update metadata for prompts.chat talk 2026-06-02 09:27:43 -07:00
Fatih Kadir Akın 098d444b32 Add Turkish prompt design presentation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-18 09:48:27 +03:00
ayoubelouardi3710@gmail.com d50dcd8fb6 Add prompt: senior market research analyst specializing in digital advertising and cross-border e-commerce. 2026-05-11 04:30:46 +00:00
nihalbhushantallati@gmail.com 1c46df505c Add prompt: AIM summarized pdf 2026-05-11 04:30:45 +00:00
deeppanjab 80ac5d713d Add prompt: Black Effect on person 2026-05-11 04:30:45 +00:00
cloudexam99@gmail.com 37343dcbeb Add prompt: Job search agent 2026-05-11 04:30:44 +00:00
624406266@qq.com 8329dc8141 Update prompt: Code Review Specialist 2026-05-11 04:30:44 +00:00
fede.gazzelloni@gmail.com 96f293d240 Update prompt: Article Summarizer 2026-05-11 04:30:44 +00:00
debashis.sarker@gmail.com 4a00af18fe Update prompt: The Technical Co-Founder: Building Real Products Together 2026-05-11 04:30:43 +00:00
aymanrabeemac@gmail.com 4e1ffd3ec4 Update prompt: Code Review Specialist 2026-05-11 04:30:43 +00:00
nolanneff 1f4e2975cf Update prompt: Code Review Specialist 2 2026-05-11 04:30:42 +00:00
ersinkoc 7fbd064fd2 Update prompt: Echoes of the Rust Age 2026-05-11 04:30:42 +00:00
cnwdy888@gmail.com 7f2d921136 Update prompt: Interview Preparation Coach 2026-05-11 04:30:41 +00:00
guangzhongzhang978@gmail.com 7799c1f0dc Update prompt: Virtual Doctor 2026-05-11 04:30:41 +00:00
f 2a93382700 Update prompt: Code Review Assistant 2026-05-11 04:30:41 +00:00
devisasari 2f8a00e1a5 Update prompt: Astrologer 2026-05-11 04:30:40 +00:00
iuzn 058d667ac5 Update prompt: Prompt Generator 2026-05-11 04:30:40 +00:00
ppppatel05@gmail.com 4b7c63206a Add prompt: Mothers day 2026-05-10 04:25:14 +00:00
bc238dev@gmail.com e989f78434 Add prompt: The Pleasure of Finding Things Out 2026-05-10 04:25:13 +00:00
md.raut111@gmail.com e51ea247a8 Add prompt: prompt for powerpoint slides generation 2026-05-10 04:25:13 +00:00
xiaoyucunx 38a78fa0b8 Update prompt: Code Review Specialist 2026-05-10 04:25:13 +00:00
cperalesg@gmail.com 88ecdf85f3 Update prompt: Prompt Generator 2026-05-10 04:25:12 +00:00
panda667 114c781083 Update prompt: Astrologer 2026-05-10 04:25:12 +00:00
joembolinas 1755d6dae9 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-05-10 04:25:11 +00:00
aymanrabeemac@gmail.com 76baa05539 Update prompt: Code Review Specialist 2026-05-10 04:25:11 +00:00
aitank2020@gmail.com f4e3559036 Update prompt: Echoes of the Rust Age 2026-05-10 04:25:10 +00:00
dragoy18@gmail.com 637751cf7c Update prompt: Code Review Specialist 2 2026-05-10 04:25:10 +00:00
lior1976@gmail.com c14eb1724f Update prompt: Article Summarizer 2026-05-10 04:25:09 +00:00
beresasis@gmail.com 10e2dbbf04 Update prompt: Interview Preparation Coach 2026-05-10 04:25:09 +00:00
sinansonmez 0c0cdd2110 Update prompt: Code Review Assistant 2026-05-10 04:25:08 +00:00
giorgiop 36ca5ca4cd Update prompt: Virtual Doctor 2026-05-10 04:25:08 +00:00
suyua9 d629c8fc14 docs: clarify interactive book license scope (#1175)
* docs: clarify interactive book license scope

* docs: restore license docs plaintext
2026-05-09 23:20:49 +03:00
farias.andreluiz@gmail.com a129a614e1 Add prompt: Prompt 101 (full) 2026-05-09 04:12:57 +00:00
lokki29400@gmail.com cbab243e32 Add prompt: Anime 2026-05-09 04:12:56 +00:00
Wiiarewe333 812c3d368f Add prompt: Socially Neutral Social Media Commentary Prompt 2026-05-09 04:12:56 +00:00
archairez85@gmail.com f0d8a6b987 Add prompt: YouTube Script Engine — High Retention 2026-05-09 04:12:55 +00:00
janedmentalist@gmail.com 9bb52366ff Add prompt: Reverse-Engineering Vox's Hybrid Video Strategy 2026-05-09 04:12:55 +00:00
624406266@qq.com 172976e65e Update prompt: Code Review Specialist 2026-05-09 04:12:55 +00:00
fede.gazzelloni@gmail.com 2ab3f1d0c7 Update prompt: Article Summarizer 2026-05-09 04:12:54 +00:00
debashis.sarker@gmail.com 6cd1858708 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-05-09 04:12:54 +00:00
aymanrabeemac@gmail.com 9ad9a91d11 Update prompt: Code Review Specialist 2026-05-09 04:12:53 +00:00
nolanneff 4230f1542d Update prompt: Code Review Specialist 2 2026-05-09 04:12:53 +00:00
ersinkoc 69c13e1442 Update prompt: Echoes of the Rust Age 2026-05-09 04:12:52 +00:00
cnwdy888@gmail.com 097830c082 Update prompt: Interview Preparation Coach 2026-05-09 04:12:52 +00:00
guangzhongzhang978@gmail.com 8f59af0c64 Update prompt: Virtual Doctor 2026-05-09 04:12:52 +00:00
f f375374525 Update prompt: Code Review Assistant 2026-05-09 04:12:51 +00:00
devisasari e06e2c2dbe Update prompt: Astrologer 2026-05-09 04:12:51 +00:00
iuzn ebd898902d Update prompt: Prompt Generator 2026-05-09 04:12:50 +00:00
Fatih Kadir Akın 417eb9500d fix(ci): unblock CI lint by allowing any in OIDC/OAuth test files
The OIDC and OAuth test files (added in #1056) inspect the dynamic
NextAuth provider object and use `any` for ergonomic property access.
That trips @typescript-eslint/no-explicit-any (error level), which has
been failing CI on main since 2026-05-02.

Add a file-level eslint-disable for that rule in both test files.
This is the standard pattern for tests that poke runtime-shaped
objects, and keeps the rule strict everywhere else.

Local: npm run lint -> 0 errors, npm test -> 709/709 passing.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-08 15:04:44 +03:00
Fatih Kadir Akın 7e2fa61037 feat(about): add John Phamous, add Security section with Mehmet Ince
- Add JohnPhamous as a core contributor for performance work (Vercel)
- Introduce a new Security section between Core Contributors and Ideation
- Credit Mehmet Ince (@mdisec) for security fixes
- Add securityTitle translation across all 17 supported locales

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-08 14:33:06 +03:00
Fatih Kadir Akın b1d19ca43a chore: remove entire.io hooks and cached session data
Drop the entire.io CLI integration that was auto-committing full agent
session transcripts (including OAuth client secrets) to a public branch.

- Remove .claude/settings.json (Claude Code PreToolUse/PostToolUse and
  SessionStart/Stop hooks delegating to `entire hooks claude-code`).
- Remove .entire/.gitignore and .entire/settings.json; the local
  .entire/ cache directory and the four .git/hooks/ stubs are deleted
  on disk as well.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-08 14:14:22 +03:00
bharatimadhavi195@gmail.com 25f1a2044f Add prompt: Horror Story in Hindi
Co-authored-by: aishachatgpt@gmail.com <aishachatgpt@gmail.com>
2026-05-08 04:08:16 +00:00
xiaoyucunx ad88aa7b52 Update prompt: Code Review Specialist 2026-05-08 04:08:16 +00:00
cperalesg@gmail.com 61ecb939dc Update prompt: Prompt Generator 2026-05-08 04:08:15 +00:00
panda667 28888e1de0 Update prompt: Astrologer 2026-05-08 04:08:15 +00:00
joembolinas 3310b692dc Update prompt: The Technical Co-Founder: Building Real Products Together 2026-05-08 04:08:14 +00:00
aymanrabeemac@gmail.com 83633bdae3 Update prompt: Code Review Specialist 2026-05-08 04:08:14 +00:00
aitank2020@gmail.com a262d8efe3 Update prompt: Echoes of the Rust Age 2026-05-08 04:08:14 +00:00
dragoy18@gmail.com 5bb91b773d Update prompt: Code Review Specialist 2 2026-05-08 04:08:13 +00:00
lior1976@gmail.com eab26a90a7 Update prompt: Article Summarizer 2026-05-08 04:08:13 +00:00
beresasis@gmail.com 3edac3d2d6 Update prompt: Interview Preparation Coach 2026-05-08 04:08:12 +00:00
sinansonmez 0436afeec4 Update prompt: Code Review Assistant 2026-05-08 04:08:12 +00:00
giorgiop 98626359aa Update prompt: Virtual Doctor 2026-05-08 04:08:11 +00:00
kyakhloufi@gmail.com f50253f09f Add prompt: Email Lead Generator & Tracker 2026-05-07 04:19:28 +00:00
archairez85@gmail.com fd433a07d6 Add prompt: Reply-Focused Cold Email Builder 2026-05-07 04:19:28 +00:00
kyakhloufi@gmail.com 32d2297700 Add prompt: Lead Generator & Tracker for WordPilot.pro 2026-05-07 04:19:27 +00:00
kyakhloufi@gmail.com 45b8457f85 Add prompt: Lead Generator & Tracker (WordPilot.pro) 2026-05-07 04:19:27 +00:00
instagram.default00@gmail.com 53362903c2 Add prompt: Dress 2026-05-07 04:19:27 +00:00
ccchaos12 f7c3ed9610 Add prompt: Literature Reading Assistant 2026-05-07 04:19:26 +00:00
ogaburna8@gmail.com 18328537ef Add prompt: Context-Aware Email Assistant 2026-05-07 04:19:26 +00:00
624406266@qq.com 6c516172bf Update prompt: Code Review Specialist 2026-05-07 04:19:26 +00:00
fede.gazzelloni@gmail.com 38a0f33200 Update prompt: Article Summarizer 2026-05-07 04:19:25 +00:00
debashis.sarker@gmail.com a8cbd40a78 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-05-07 04:19:25 +00:00
aymanrabeemac@gmail.com c0fcaec52b Update prompt: Code Review Specialist 2026-05-07 04:19:25 +00:00
nolanneff 0825623e7a Update prompt: Code Review Specialist 2 2026-05-07 04:19:24 +00:00
ersinkoc f367b9c5d8 Update prompt: Echoes of the Rust Age 2026-05-07 04:19:24 +00:00
cnwdy888@gmail.com ae33724440 Update prompt: Interview Preparation Coach 2026-05-07 04:19:23 +00:00
guangzhongzhang978@gmail.com 034945e8ea Update prompt: Virtual Doctor 2026-05-07 04:19:23 +00:00
f 8f1da46986 Update prompt: Code Review Assistant 2026-05-07 04:19:23 +00:00
devisasari 7a344581af Update prompt: Astrologer 2026-05-07 04:19:22 +00:00
iuzn d110b5ecfc Update prompt: Prompt Generator 2026-05-07 04:19:22 +00:00
matheuspgamba 4acd114e31 Add prompt: Fantasy Dataset Creator for Machine Learning 2026-05-06 04:20:02 +00:00
adediwuratemitope9-tech 6532e30b1b Add prompt: Note 2026-05-06 04:20:02 +00:00
houseflyy 47409585d3 Add prompt: Adaptive Socratic Learning Coach 2026-05-06 04:20:01 +00:00
xiaoyucunx ee0431487f Update prompt: Code Review Specialist 2026-05-06 04:20:01 +00:00
cperalesg@gmail.com 4ff2f56ffe Update prompt: Prompt Generator 2026-05-06 04:20:01 +00:00
panda667 c518ed857e Update prompt: Astrologer 2026-05-06 04:20:00 +00:00
joembolinas fe2983ccba Update prompt: The Technical Co-Founder: Building Real Products Together 2026-05-06 04:20:00 +00:00
aitank2020@gmail.com c2ef089c07 Update prompt: Echoes of the Rust Age 2026-05-06 04:19:59 +00:00
dragoy18@gmail.com 2bb4a81f1c Update prompt: Code Review Specialist 2 2026-05-06 04:19:59 +00:00
lior1976@gmail.com e7eaf3a4b2 Update prompt: Article Summarizer 2026-05-06 04:19:58 +00:00
beresasis@gmail.com 496d254fcf Update prompt: Interview Preparation Coach 2026-05-06 04:19:58 +00:00
sinansonmez aa70c13985 Update prompt: Code Review Assistant 2026-05-06 04:19:57 +00:00
giorgiop 675a760e44 Update prompt: Virtual Doctor 2026-05-06 04:19:57 +00:00
mdevender9966@gmail.com c095c39b1c Add prompt: My Kalashala 2026-05-05 04:07:19 +00:00
abhishekparab301@gmail.com 6c0f9d6d8d Add prompt: Finding the company 2026-05-05 04:07:19 +00:00
st897339@gmail.com ae3397f9a9 Add prompt: adding these development in a gasifier design tool 2026-05-05 04:07:18 +00:00
m.azeem@aljameel.com.qa 502a38f770 Add prompt: Wonder Land Adventure 2026-05-05 04:07:18 +00:00
rohitthakkar22933@gmail.com 3375bac60c Add prompt: Horoscope l 2026-05-05 04:07:17 +00:00
semihkislar 3c495a12ee Add prompt: Photorealistic 4K Reference Image Enhancement 2026-05-05 04:07:17 +00:00
fede.gazzelloni@gmail.com 9ec0cb2be6 Update prompt: Article Summarizer 2026-05-05 04:07:16 +00:00
debashis.sarker@gmail.com f537e2e27a Update prompt: The Technical Co-Founder: Building Real Products Together 2026-05-05 04:07:16 +00:00
aymanrabeemac@gmail.com 4df711c7d1 Update prompt: Code Review Specialist 2026-05-05 04:07:16 +00:00
nolanneff 009b982060 Update prompt: Code Review Specialist 2 2026-05-05 04:07:15 +00:00
ersinkoc 45e818f691 Update prompt: Echoes of the Rust Age 2026-05-05 04:07:15 +00:00
cnwdy888@gmail.com 1ef8f6dcbb Update prompt: Interview Preparation Coach 2026-05-05 04:07:14 +00:00
guangzhongzhang978@gmail.com e7585e09ec Update prompt: Virtual Doctor 2026-05-05 04:07:14 +00:00
f 01b019dc80 Update prompt: Code Review Assistant 2026-05-05 04:07:13 +00:00
devisasari 3fcde2c55e Update prompt: Astrologer 2026-05-05 04:07:13 +00:00
iuzn a4f52b2064 Update prompt: Prompt Generator 2026-05-05 04:07:12 +00:00
yigitgurler 129f9957e5 Add prompt: Opus-Driven Deep Thinking System 2026-05-04 04:22:48 +00:00
m.azeem@aljameel.com.qa 3428ff6f3d Add prompt: Create High-Demand AI Images for Stock 2026-05-04 04:22:48 +00:00
yahyahamad79@gmail.com 25a8c5476b Add prompt: Academic PowerPoint Presentation Designer 2026-05-04 04:22:48 +00:00
Bornduck e76920fa6b Add prompt: Split Word Rejoin 2026-05-04 04:22:47 +00:00
xiaoyucunx 4ed56ed38d Update prompt: Code Review Specialist 2026-05-04 04:22:47 +00:00
cperalesg@gmail.com 81f972aefb Update prompt: Prompt Generator 2026-05-04 04:22:46 +00:00
panda667 db25fa357b Update prompt: Astrologer 2026-05-04 04:22:46 +00:00
joembolinas 6034ce8e0c Update prompt: The Technical Co-Founder: Building Real Products Together 2026-05-04 04:22:45 +00:00
aitank2020@gmail.com 73aed95d87 Update prompt: Echoes of the Rust Age 2026-05-04 04:22:45 +00:00
dragoy18@gmail.com 2ac13ef9db Update prompt: Code Review Specialist 2 2026-05-04 04:22:45 +00:00
lior1976@gmail.com e6ba070e55 Update prompt: Article Summarizer 2026-05-04 04:22:44 +00:00
beresasis@gmail.com 5eea3c10f7 Update prompt: Interview Preparation Coach 2026-05-04 04:22:44 +00:00
sinansonmez d346e72c98 Update prompt: Code Review Assistant 2026-05-04 04:22:43 +00:00
giorgiop a4824d6973 Update prompt: Virtual Doctor 2026-05-04 04:22:43 +00:00
karthigeyanbaskaran 205a2448f3 Add prompt: English Grammar and Style Corrector 2026-05-03 04:22:45 +00:00
oasiszeng 712c9a78ff Add prompt: Git Repository Analysis and Knowledge Base Construction 2026-05-03 04:22:45 +00:00
fede.gazzelloni@gmail.com 56d92ccd67 Update prompt: Article Summarizer 2026-05-03 04:22:44 +00:00
debashis.sarker@gmail.com b039b38e61 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-05-03 04:22:44 +00:00
aymanrabeemac@gmail.com 8ea300b777 Update prompt: Code Review Specialist 2026-05-03 04:22:43 +00:00
nolanneff 3a5b2d03ac Update prompt: Code Review Specialist 2 2026-05-03 04:22:43 +00:00
ersinkoc 485c6c9d90 Update prompt: Echoes of the Rust Age 2026-05-03 04:22:43 +00:00
cnwdy888@gmail.com 1d20bf3e79 Update prompt: Interview Preparation Coach 2026-05-03 04:22:42 +00:00
guangzhongzhang978@gmail.com 53af53a01c Update prompt: Virtual Doctor 2026-05-03 04:22:42 +00:00
f 2adb88e9a1 Update prompt: Code Review Assistant 2026-05-03 04:22:41 +00:00
devisasari 869cfdffcd Update prompt: Astrologer 2026-05-03 04:22:41 +00:00
iuzn 27a768e10d Update prompt: Prompt Generator 2026-05-03 04:22:40 +00:00
Amayaranjan Das 918fa71a1c feat(auth): honour AUTH_OIDC/OAUTH_NAME and _LOGO env vars in login button (#1177) 2026-05-02 23:18:45 +03:00
Amayaranjan Das bf1de55c8d feat(auth): add generic OIDC and OAuth 2.0 plugins (#1056) 2026-05-02 09:24:07 +03:00
bishopdavies98@gmail.com fdf407a3e4 Add prompt: Grok customization 2026-05-02 04:09:46 +00:00
senoldak e5b4b7296c Add prompt: 🚀 STRATEGIC MODE 2026-05-02 04:09:46 +00:00
goodyer123@gmail.com 268bd594eb Add prompt: Learn Rust Programming 2026-05-02 04:09:45 +00:00
sanjoxavier888@gmail.com 0ad8f01404 Add prompt: 3D Cartoon Animation: Baby Bunny Adventure 2026-05-02 04:09:45 +00:00
xiaoyucunx 378d5dc764 Update prompt: Code Review Specialist 2026-05-02 04:09:45 +00:00
cperalesg@gmail.com 20a0ec1f0e Update prompt: Prompt Generator 2026-05-02 04:09:44 +00:00
panda667 ad9b42df41 Update prompt: Astrologer 2026-05-02 04:09:44 +00:00
joembolinas 0130c4e456 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-05-02 04:09:43 +00:00
aitank2020@gmail.com 05e7f12db1 Update prompt: Echoes of the Rust Age 2026-05-02 04:09:43 +00:00
dragoy18@gmail.com 3e9a209552 Update prompt: Code Review Specialist 2 2026-05-02 04:09:43 +00:00
lior1976@gmail.com 8d338ca2c6 Update prompt: Article Summarizer 2026-05-02 04:09:42 +00:00
beresasis@gmail.com 37124ba29a Update prompt: Interview Preparation Coach 2026-05-02 04:09:42 +00:00
sinansonmez 4f4ca63454 Update prompt: Code Review Assistant 2026-05-02 04:09:41 +00:00
giorgiop f0406d8181 Update prompt: Virtual Doctor 2026-05-02 04:09:41 +00:00
fede.gazzelloni@gmail.com 0f981717dd Update prompt: Article Summarizer 2026-05-01 04:27:44 +00:00
debashis.sarker@gmail.com 9ecf416fb0 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-05-01 04:27:43 +00:00
aymanrabeemac@gmail.com 3c132527f9 Update prompt: Code Review Specialist 2026-05-01 04:27:43 +00:00
nolanneff 54e5da26d1 Update prompt: Code Review Specialist 2 2026-05-01 04:27:43 +00:00
ersinkoc 0bdbced718 Update prompt: Echoes of the Rust Age 2026-05-01 04:27:42 +00:00
cnwdy888@gmail.com 1571490408 Update prompt: Interview Preparation Coach 2026-05-01 04:27:42 +00:00
guangzhongzhang978@gmail.com 366798154b Update prompt: Virtual Doctor 2026-05-01 04:27:41 +00:00
f 7fd9087c56 Update prompt: Code Review Assistant 2026-05-01 04:27:41 +00:00
devisasari b0f98485ca Update prompt: Astrologer 2026-05-01 04:27:40 +00:00
iuzn 61d836b01d Update prompt: Prompt Generator 2026-05-01 04:27:40 +00:00
kc-optimal-computing b3620c23fb Add prompt: App Feature - Focused Readiness Audit 2026-04-30 04:19:11 +00:00
kc-optimal-computing 29a32041a8 Add prompt: Borrow Skill 2026-04-30 04:19:10 +00:00
kc-optimal-computing 84f609dda4 Add prompt: Grok Research Agent
Co-authored-by: Nick040791 <Nick040791@users.noreply.github.com>
2026-04-30 04:19:10 +00:00
ajillell_uhg 0826f1a858 Add prompt: Data Lineage Agent Skill 2026-04-30 04:19:09 +00:00
xiaoyucunx 210e578157 Update prompt: Code Review Specialist 2026-04-30 04:19:09 +00:00
cperalesg@gmail.com dd5055ea20 Update prompt: Prompt Generator 2026-04-30 04:19:08 +00:00
panda667 c87a429b2a Update prompt: Astrologer 2026-04-30 04:19:08 +00:00
joembolinas 1a8659cdaa Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-30 04:19:08 +00:00
aitank2020@gmail.com 3faffa65ff Update prompt: Echoes of the Rust Age 2026-04-30 04:19:07 +00:00
dragoy18@gmail.com ae5b86a3af Update prompt: Code Review Specialist 2 2026-04-30 04:19:07 +00:00
lior1976@gmail.com 4a0cd0a61c Update prompt: Article Summarizer 2026-04-30 04:19:06 +00:00
beresasis@gmail.com 8c26e456c6 Update prompt: Interview Preparation Coach 2026-04-30 04:19:06 +00:00
sinansonmez 647a91cea3 Update prompt: Code Review Assistant 2026-04-30 04:19:05 +00:00
giorgiop 6dd7302e7f Update prompt: Virtual Doctor 2026-04-30 04:19:05 +00:00
loshu2000 3af7049234 Add prompt: Grid-Based Match-3 Chain Reaction Logic 2026-04-29 04:17:16 +00:00
loshu2000 619c76c96d Add prompt: Vector-Based Space Combat System 2026-04-29 04:17:16 +00:00
loshu2000 b09b4dc0ae Add prompt: Act as a Procedural Content Generator 2026-04-29 04:17:16 +00:00
loshu2000 e1811ae163 Add prompt: Act as a Game Physics Architect 2026-04-29 04:17:15 +00:00
senoldak 784bb22672 Add prompt: 🛡️ RED TEAM MODE 2026-04-29 04:17:15 +00:00
senoldak ba370693eb Add prompt: ⚙️ CONSTRAINT SOLVER MODE 2026-04-29 04:17:14 +00:00
senoldak 7117c90cda Add prompt: 🧠 FORMAL VERIFICATION MODE 2026-04-29 04:17:14 +00:00
thomas.adamson.16@gmail.com 53848b31bf Add prompt: Claude Deep Prompt 2026-04-29 04:17:14 +00:00
mertssmnoglu 206c4c8b84 Add prompt: Alternative Text Generator 2026-04-29 04:17:13 +00:00
shamanthreddy57@gmail.com 33dd5ac6c8 Add prompt: Comprehensive VC Fundraising Analysis 2026-04-29 04:17:13 +00:00
shamanthreddy57@gmail.com 8ff3d62b5e Add prompt: Competitor Awareness 2026-04-29 04:17:12 +00:00
fede.gazzelloni@gmail.com 2ff7d190a7 Update prompt: Article Summarizer 2026-04-29 04:17:12 +00:00
debashis.sarker@gmail.com 2227078c9a Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-29 04:17:11 +00:00
aymanrabeemac@gmail.com ccf44242c3 Update prompt: Code Review Specialist 2026-04-29 04:17:11 +00:00
nolanneff 6933a8e0fc Update prompt: Code Review Specialist 2 2026-04-29 04:17:11 +00:00
ersinkoc 5009ba6862 Update prompt: Echoes of the Rust Age 2026-04-29 04:17:10 +00:00
cnwdy888@gmail.com 0daf1b6aab Update prompt: Interview Preparation Coach 2026-04-29 04:17:10 +00:00
guangzhongzhang978@gmail.com 1dcf5fba85 Update prompt: Virtual Doctor 2026-04-29 04:17:09 +00:00
f 2608425343 Update prompt: Code Review Assistant 2026-04-29 04:17:09 +00:00
devisasari e5e7cc2c5b Update prompt: Astrologer 2026-04-29 04:17:08 +00:00
iuzn f5f084f663 Update prompt: Prompt Generator 2026-04-29 04:17:08 +00:00
ah0sman 2107e0942c Add prompt: Oracle Payroll Unsupported Localization Guide 2026-04-28 04:19:59 +00:00
dmytrokovych@gmail.com ff25e6ec87 Add prompt: Street-art punk poster 2026-04-28 04:19:58 +00:00
semihkislar da13c7e71e Add prompt: Lost in [Country] with ChatGPT Image 2 2026-04-28 04:19:58 +00:00
dishantpatel624@gmail.com 88f5bcd81f Add prompt: details of the given bug 2026-04-28 04:19:58 +00:00
dishantpatel624@gmail.com 7b62aa5ff4 Add prompt: handle bug in feature 2026-04-28 04:19:57 +00:00
xiaoyucunx f05abf53f3 Update prompt: Code Review Specialist 2026-04-28 04:19:57 +00:00
cperalesg@gmail.com 9741c79b03 Update prompt: Prompt Generator 2026-04-28 04:19:56 +00:00
panda667 5f5d6c230b Update prompt: Astrologer 2026-04-28 04:19:56 +00:00
joembolinas f1d0f7cff2 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-28 04:19:55 +00:00
aitank2020@gmail.com e9c959371b Update prompt: Echoes of the Rust Age 2026-04-28 04:19:55 +00:00
dragoy18@gmail.com 1533a04680 Update prompt: Code Review Specialist 2 2026-04-28 04:19:55 +00:00
lior1976@gmail.com b61234cea9 Update prompt: Article Summarizer 2026-04-28 04:19:54 +00:00
beresasis@gmail.com 3e41df5c9e Update prompt: Interview Preparation Coach 2026-04-28 04:19:54 +00:00
sinansonmez 2d7ebe83a0 Update prompt: Code Review Assistant 2026-04-28 04:19:53 +00:00
giorgiop f00537afae Update prompt: Virtual Doctor 2026-04-28 04:19:53 +00:00
senoldak 4870438dcd Add prompt: 🕶️ INCOGNITO / PRIVATE BROWSING MODE 2026-04-27 04:17:50 +00:00
senoldak 13c79a9814 Add prompt: 🔒 ULTRA-STRICT MODE 2026-04-27 04:17:49 +00:00
senoldak 843a7bfa98 Add prompt: 🧪 Sandbox Mode 2026-04-27 04:17:49 +00:00
343300327@qq.com a106b45e0d Add prompt: 电影视觉指导与AIGC分镜生成器 2026-04-27 04:17:48 +00:00
prksinbox@gmail.com 333b2652f5 Add prompt: The Paradoxical Soundscape: Ancient Acoustic Mysteries Video Exploration 2026-04-27 04:17:48 +00:00
fede.gazzelloni@gmail.com 8a0e87fc46 Update prompt: Article Summarizer 2026-04-27 04:17:48 +00:00
debashis.sarker@gmail.com b1083f2bf5 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-27 04:17:47 +00:00
aymanrabeemac@gmail.com d8a84a02eb Update prompt: Code Review Specialist 2026-04-27 04:17:47 +00:00
nolanneff a403e7afcc Update prompt: Code Review Specialist 2 2026-04-27 04:17:46 +00:00
ersinkoc 59e68349dc Update prompt: Echoes of the Rust Age 2026-04-27 04:17:46 +00:00
cnwdy888@gmail.com 43bb3a1b35 Update prompt: Interview Preparation Coach 2026-04-27 04:17:46 +00:00
guangzhongzhang978@gmail.com 4977ed62c9 Update prompt: Virtual Doctor 2026-04-27 04:17:45 +00:00
f 6adaf05680 Update prompt: Code Review Assistant 2026-04-27 04:17:45 +00:00
devisasari a70d99a3a9 Update prompt: Astrologer 2026-04-27 04:17:44 +00:00
iuzn db41db65fa Update prompt: Prompt Generator 2026-04-27 04:17:44 +00:00
suyua9 3e40878a88 fix: avoid GitHub links for email contributors (#1167)
* fix: avoid GitHub links for email contributors

* test: address contributor formatter review

* test: leave generated prompts untouched
2026-04-27 01:16:34 +03:00
amvicioushecs e74d129e83 Add prompt: 6-Panel Storyboard Mastery 2026-04-26 04:13:18 +00:00
mtberkcelik@gmail.com 4708674033 Add prompt: Photorealistic Webcam Bedroom Scene Prompt 2026-04-26 04:13:18 +00:00
mtberkcelik@gmail.com 54af72adf1 Add prompt: Rooftop Lifestyle Portrait Prompt 2026-04-26 04:13:18 +00:00
mtberkcelik@gmail.com 6fee4c32ba Add prompt: Café Portrait Prompt Description 2026-04-26 04:13:17 +00:00
dishantpatel624@gmail.com f99fc3eb56 Add prompt: create app screenshots 2026-04-26 04:13:17 +00:00
adediwuratemitope9-tech cccd2b2480 Add prompt: Video 2026-04-26 04:13:16 +00:00
rajeshrock544117@gmail.com 83bdbd658b Add prompt: operating system exam preparation 2026-04-26 04:13:16 +00:00
esat54 28f4c2235d Add prompt: Oxford 3000: Step-by-Step Vocabulary Coach 2026-04-26 04:13:16 +00:00
amvicioushecs b3ae69df9d Update prompt: Vibe Coding with Commands and Skills 2026-04-26 04:13:15 +00:00
xiaoyucunx e72312a403 Update prompt: Code Review Specialist 2026-04-26 04:13:15 +00:00
cperalesg@gmail.com b2d51aa6ab Update prompt: Prompt Generator 2026-04-26 04:13:14 +00:00
panda667 d0098ae093 Update prompt: Astrologer 2026-04-26 04:13:14 +00:00
joembolinas b378f2ff77 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-26 04:13:14 +00:00
aitank2020@gmail.com 5ce0e14ea6 Update prompt: Echoes of the Rust Age 2026-04-26 04:13:13 +00:00
dragoy18@gmail.com 8698ab9431 Update prompt: Code Review Specialist 2 2026-04-26 04:13:13 +00:00
lior1976@gmail.com 900d046c24 Update prompt: Article Summarizer 2026-04-26 04:13:12 +00:00
beresasis@gmail.com 66f882eac8 Update prompt: Interview Preparation Coach 2026-04-26 04:13:12 +00:00
sinansonmez 9a8333e537 Update prompt: Code Review Assistant 2026-04-26 04:13:11 +00:00
giorgiop 237eaf85cb Update prompt: Virtual Doctor 2026-04-26 04:13:11 +00:00
Fatih Kadir Akın 887b3f3f3a feat(home): replace industries grid with Open Source Friday video (#1170)
* feat(home): replace industries grid with Open Source Friday video

Replaces the rotating industries section under the hero search bar with
an embed of the GitHub Open Source Friday episode (starting at 6:12).
Also widens the hero's right column and tightens the left text column
so the video sits comfortably without overflowing on standard laptop
viewports.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore(i18n): remove unused heroIndustries keys

The industries grid was replaced by a YouTube embed; only
'searchPlaceholder' is still referenced. Drop the prefix,
clickToExplore, and 36 industry labels across all 17 locales.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(home): i18n iframe title, lazy load, nocookie, width parity

Addresses PR review feedback on the YouTube embed:
- Translate iframe title via next-intl (new heroIndustries.videoTitle key)
- Add loading="lazy" to defer ~1MB of player JS
- Switch embed to youtube-nocookie.com for better cookie/privacy hygiene
- Restore max-w-lg so the video matches the search bar width

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* chore: stop tracking local .env.docker

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-25 16:44:47 +03:00
suyua9 fee294e35b fix(docker): use prebuilt image by default in compose (#1169) 2026-04-25 09:08:25 +03:00
amvicioushecs 9df9d81b64 Add prompt: Vibe Coding with Commands and Skills 2026-04-25 04:01:24 +00:00
amvicioushecs c37daf3b8d Add prompt: Sniper-Precision Debugging Skill 2026-04-25 04:01:24 +00:00
amvicioushecs ae63ebe2e8 Add prompt: Hypnotherapist Guidance for Stress Management 2026-04-25 04:01:23 +00:00
thanos0000@gmail.com 38f1bc1546 Add prompt: Car Buying Intake Interview 2026-04-25 04:01:23 +00:00
alex.dadaev@gmail.com b9e4a8783a Add prompt: User Acquisition Data Analysis 2026-04-25 04:01:23 +00:00
dishantpatel624@gmail.com 6045ea3988 Add prompt: low risk to uplift income 2026-04-25 04:01:22 +00:00
dishantpatel624@gmail.com 373557030d Add prompt: Handle the bug in feature 2026-04-25 04:01:22 +00:00
fede.gazzelloni@gmail.com 1434338774 Update prompt: Article Summarizer 2026-04-25 04:01:21 +00:00
debashis.sarker@gmail.com ddf42cb705 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-25 04:01:21 +00:00
aymanrabeemac@gmail.com 0757c70445 Update prompt: Code Review Specialist 2026-04-25 04:01:21 +00:00
nolanneff 59e0729ec1 Update prompt: Code Review Specialist 2 2026-04-25 04:01:20 +00:00
ersinkoc 564c906ebb Update prompt: Echoes of the Rust Age 2026-04-25 04:01:20 +00:00
cnwdy888@gmail.com 757b593355 Update prompt: Interview Preparation Coach 2026-04-25 04:01:19 +00:00
guangzhongzhang978@gmail.com 6ee24c0de2 Update prompt: Virtual Doctor 2026-04-25 04:01:19 +00:00
f 7e22e06fc8 Update prompt: Code Review Assistant 2026-04-25 04:01:18 +00:00
devisasari 6629ee671f Update prompt: Astrologer 2026-04-25 04:01:18 +00:00
iuzn ed3bcc3669 Update prompt: Prompt Generator 2026-04-25 04:01:18 +00:00
loshu2000 c93bf66fcb Add prompt: High-Velocity Dogfight 2026-04-24 04:08:54 +00:00
loshu2000 5af4ea1a2f Add prompt: Logic-Flow Educational Puzzle 2026-04-24 04:08:54 +00:00
loshu2000 1bcf7c12ed Add prompt: Star-Marshal: Raycast Tactical Shooter 2026-04-24 04:08:54 +00:00
loshu2000 43c8aec9bc Add prompt: Gravity Shift: Low-Poly Physics Platformer 2026-04-24 04:08:53 +00:00
loshu2000 54aac0b785 Add prompt: Cyber-Pulse: 3D Neon Particle Swarm 2026-04-24 04:08:53 +00:00
donato.castagna@gmail.com 705231857c Add prompt: Code Review Professional 2026-04-24 04:08:52 +00:00
1079065558 044837b871 Add prompt: Modify Front-End Webpage with Codex and Image Input 2026-04-24 04:08:52 +00:00
yigitgurler 0e0a88e516 Add prompt: RPA/Agentic AI Process Developer Portfolio Design for Claude 2026-04-24 04:08:52 +00:00
1079065558 5246860a12 Add prompt: High-End Technology-Inspired Website UI Redesign 2026-04-24 04:08:51 +00:00
1079065558 5cc55ed0c0 Add prompt: Redesign Front-End with Codex 2026-04-24 04:08:51 +00:00
ZhenjieZhao66 52fb8a8d8f Add prompt: Designing a Feature Testing Page for Enterprise WeChat/DingTalk 2026-04-24 04:08:50 +00:00
chinnarinestam@gmail.com 359e970083 Add prompt: story 2026-04-24 04:08:50 +00:00
xiaoyucunx 82fa5fffda Update prompt: Code Review Specialist 2026-04-24 04:08:50 +00:00
cperalesg@gmail.com 658c850a60 Update prompt: Prompt Generator 2026-04-24 04:08:49 +00:00
panda667 543447b31b Update prompt: Astrologer 2026-04-24 04:08:49 +00:00
joembolinas 2a2211d0c7 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-24 04:08:48 +00:00
aitank2020@gmail.com 4ea20a0f43 Update prompt: Echoes of the Rust Age 2026-04-24 04:08:48 +00:00
dragoy18@gmail.com 133cf4f979 Update prompt: Code Review Specialist 2 2026-04-24 04:08:47 +00:00
lior1976@gmail.com a7920e0b27 Update prompt: Article Summarizer 2026-04-24 04:08:47 +00:00
beresasis@gmail.com 80bf70a9d4 Update prompt: Interview Preparation Coach 2026-04-24 04:08:47 +00:00
sinansonmez 53c3ac1777 Update prompt: Code Review Assistant 2026-04-24 04:08:46 +00:00
giorgiop 6eb47ebd6e Update prompt: Virtual Doctor 2026-04-24 04:08:46 +00:00
Fatih Kadir Akın dc161feb81 Fix 404 on user profiles with uppercase usernames (#1166)
* Add announcement banner with MS Build 2026 talk

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix 404 on user profile when username has uppercase letters

Use case-insensitive match instead of forcing username to lowercase, since
usernames are stored with their original casing (e.g., SatishB15).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-23 22:22:54 +03:00
Fatih Kadir Akın 82783a7cc6 Add announcement banner with MS Build 2026 talk (#1165)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-23 21:46:51 +03:00
Fatih Kadir Akın 628b90a284 Merge pull request #1164 from SatishB15/fix/bio-link-parsing
fix(bio): handle trailing comma in URLs
2026-04-23 21:43:39 +03:00
Satish Birhade 7a07039ad7 fix(bio): use cleaned URL for href while preserving original text rendering 2026-04-23 17:20:58 +05:30
Satish Birhade 35b0d90fd2 fix(bio): handle trailing comma in URLs 2026-04-23 16:43:21 +05:30
oluwasegunolorungbeja@gmail.com f9cf8c533c Add prompt: What friendship should be all about 2026-04-23 04:06:22 +00:00
oluwasegunolorungbeja@gmail.com 5502d5a2e1 Add prompt: Building a community 2026-04-23 04:06:21 +00:00
narrivodigital f6b39f795a Add prompt: Realistic İmage JSON Prompt 2026-04-23 04:06:21 +00:00
naveen@upfinzo.in 52302c1453 Add prompt: suitable sunglasses using gemini 2026-04-23 04:06:21 +00:00
fede.gazzelloni@gmail.com c40d37ec52 Update prompt: Article Summarizer 2026-04-23 04:06:20 +00:00
debashis.sarker@gmail.com de9b06d9f3 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-23 04:06:20 +00:00
aymanrabeemac@gmail.com 6afd93b403 Update prompt: Code Review Specialist 2026-04-23 04:06:19 +00:00
nolanneff 92c24d031a Update prompt: Code Review Specialist 2 2026-04-23 04:06:19 +00:00
ersinkoc 4a00f8a5c3 Update prompt: Echoes of the Rust Age 2026-04-23 04:06:19 +00:00
cnwdy888@gmail.com daba7d782c Update prompt: Interview Preparation Coach 2026-04-23 04:06:18 +00:00
guangzhongzhang978@gmail.com 69dd7918da Update prompt: Virtual Doctor 2026-04-23 04:06:18 +00:00
f 0349f7d60f Update prompt: Code Review Assistant 2026-04-23 04:06:17 +00:00
devisasari b808c5d340 Update prompt: Astrologer 2026-04-23 04:06:17 +00:00
iuzn 0b24961e14 Update prompt: Prompt Generator 2026-04-23 04:06:17 +00:00
Fatih Kadir Akın 9f33f30f6a Merge pull request #1162 from f/f/remove-ezoic
Remove Ezoic ad integration
2026-04-23 00:24:07 +03:00
Fatih Kadir Akın dbd2eed8bc Remove Ezoic ad integration
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-23 00:22:56 +03:00
cperalesg@gmail.com a4632f1a55 Add prompt: Key Concepts and Essential Definitions for Exam 2026-04-22 04:05:09 +00:00
amvicioushecs adf0d3fda8 Add prompt: Chain of Thought for Podcast Guest Analysis 2026-04-22 04:05:08 +00:00
amvicioushecs 22987f8e75 Add prompt: Augmented Reality Real Estate Staging 2026-04-22 04:05:08 +00:00
kemedt25@gmail.com 4290885b2e Add prompt: Good for us 2026-04-22 04:05:07 +00:00
ngattu7044@gmail.com 8c523c4f45 Add prompt: Rocket launcher 2026-04-22 04:05:07 +00:00
tullapeople@gmail.com f6b861e5e7 Add prompt: Create a CAN Simulation in Python 2026-04-22 04:05:07 +00:00
amvicioushecs 5a747a2c5b Add prompt: Grant Finder 2026-04-22 04:05:06 +00:00
senoldak 908e06a043 Add prompt: ⚙️ PromptForge 2026-04-22 04:05:06 +00:00
maikelwally78@gmail.com 75060011db Add prompt: School Report Management System for SMP Negeri 7 Sentani 2026-04-22 04:05:05 +00:00
xiaoyucunx 4c66355607 Update prompt: Code Review Specialist 2026-04-22 04:05:05 +00:00
cperalesg@gmail.com 898a55c4d8 Update prompt: Prompt Generator 2026-04-22 04:05:04 +00:00
panda667 2ca2eac30a Update prompt: Astrologer 2026-04-22 04:05:04 +00:00
joembolinas eff4dedc47 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-22 04:05:04 +00:00
aitank2020@gmail.com bc28d61c9b Update prompt: Echoes of the Rust Age 2026-04-22 04:05:03 +00:00
dragoy18@gmail.com f9119a6fc6 Update prompt: Code Review Specialist 2 2026-04-22 04:05:03 +00:00
lior1976@gmail.com 077dc119b0 Update prompt: Article Summarizer 2026-04-22 04:05:02 +00:00
beresasis@gmail.com 1cfbf7c301 Update prompt: Interview Preparation Coach 2026-04-22 04:05:02 +00:00
sinansonmez fe508cdc0d Update prompt: Code Review Assistant 2026-04-22 04:05:01 +00:00
giorgiop 294da3e1bc Update prompt: Virtual Doctor 2026-04-22 04:05:01 +00:00
Fatih Kadir Akın bf0c10fc79 Update README with source link for the guide
Added source link to the interactive guide.
2026-04-21 11:17:17 +03:00
samsungeindia@gmail.com f1f2df98e2 Add prompt: Ee 2026-04-21 04:06:04 +00:00
senoldak 4a34d2855a Add prompt: 🛡 Financial Compliance Auditor 2026-04-21 04:06:03 +00:00
attawaycuningham-ctrl 2d9b08d462 Add prompt: Feynman’s Nitpick Game 2026-04-21 04:06:03 +00:00
fede.gazzelloni@gmail.com b5c803d75f Update prompt: Article Summarizer 2026-04-21 04:06:02 +00:00
debashis.sarker@gmail.com c9e77d408a Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-21 04:06:02 +00:00
aymanrabeemac@gmail.com 667c30fb3a Update prompt: Code Review Specialist 2026-04-21 04:06:02 +00:00
nolanneff bf197fbd0f Update prompt: Code Review Specialist 2 2026-04-21 04:06:01 +00:00
ersinkoc a7cbdcc6bd Update prompt: Echoes of the Rust Age 2026-04-21 04:06:01 +00:00
cnwdy888@gmail.com 29831a5a38 Update prompt: Interview Preparation Coach 2026-04-21 04:06:00 +00:00
guangzhongzhang978@gmail.com 6b9cd41461 Update prompt: Virtual Doctor 2026-04-21 04:06:00 +00:00
f 04c3852e15 Update prompt: Code Review Assistant 2026-04-21 04:06:00 +00:00
devisasari eadd1acd57 Update prompt: Astrologer 2026-04-21 04:05:59 +00:00
iuzn 92ebea092f Update prompt: Prompt Generator 2026-04-21 04:05:59 +00:00
mustafasevim.dev@gmail.com 24d6a652b5 Add prompt: Create Content from Discord Blog for Hazel's Website 2026-04-20 04:10:41 +00:00
adediwuratemitope9-tech 64c9feaf63 Add prompt: Lecturer 2026-04-20 04:10:41 +00:00
xiaoyucunx f4ae4ee256 Update prompt: Code Review Specialist 2026-04-20 04:10:41 +00:00
cperalesg@gmail.com a8d8a09660 Update prompt: Prompt Generator 2026-04-20 04:10:40 +00:00
panda667 4d5a2a1f11 Update prompt: Astrologer 2026-04-20 04:10:40 +00:00
joembolinas 6c42da91fc Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-20 04:10:39 +00:00
aitank2020@gmail.com 877f127b39 Update prompt: Echoes of the Rust Age 2026-04-20 04:10:39 +00:00
dragoy18@gmail.com 2ce1c95de0 Update prompt: Code Review Specialist 2 2026-04-20 04:10:39 +00:00
lior1976@gmail.com b0032caef4 Update prompt: Article Summarizer 2026-04-20 04:10:38 +00:00
beresasis@gmail.com 15df4b5a89 Update prompt: Interview Preparation Coach 2026-04-20 04:10:38 +00:00
sinansonmez c3c6af9680 Update prompt: Code Review Assistant 2026-04-20 04:10:37 +00:00
giorgiop e0df66f2d7 Update prompt: Virtual Doctor 2026-04-20 04:10:37 +00:00
senoldak 5b2ac47aa9 Add prompt: GitHub SSH Setup for Students (Existing Repository, Clone & Push Ready) 2026-04-19 04:06:48 +00:00
senoldak 52f4e19cab Add prompt: Setup and Bootstrap a Flutter Development Environment 2026-04-19 04:06:47 +00:00
mvel20342@gmail.com 7ebc0dd98e Add prompt: MDCT Step-by-Step Calculation 2026-04-19 04:06:47 +00:00
fede.gazzelloni@gmail.com f333176ea4 Update prompt: Article Summarizer 2026-04-19 04:06:47 +00:00
debashis.sarker@gmail.com bd69b8a0d4 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-19 04:06:46 +00:00
aymanrabeemac@gmail.com df145c3642 Update prompt: Code Review Specialist 2026-04-19 04:06:46 +00:00
nolanneff 89f6383f46 Update prompt: Code Review Specialist 2 2026-04-19 04:06:45 +00:00
ersinkoc 7ca05c249c Update prompt: Echoes of the Rust Age 2026-04-19 04:06:45 +00:00
cnwdy888@gmail.com ff3be1ccb8 Update prompt: Interview Preparation Coach 2026-04-19 04:06:44 +00:00
guangzhongzhang978@gmail.com 3fd43091d7 Update prompt: Virtual Doctor 2026-04-19 04:06:44 +00:00
f 6bf6ebd3c8 Update prompt: Code Review Assistant 2026-04-19 04:06:44 +00:00
devisasari 8cf0e58adb Update prompt: Astrologer 2026-04-19 04:06:43 +00:00
iuzn bf33cd262b Update prompt: Prompt Generator 2026-04-19 04:06:43 +00:00
amvicioushecs 191973a988 Add prompt: Brandable Domain Name Finder 2026-04-18 04:00:00 +00:00
amvicioushecs 5c5a812e6e Add prompt: Business Idea Evaluation and Scoring 2026-04-18 04:00:00 +00:00
xiaoyucunx 97037d059d Update prompt: Code Review Specialist 2026-04-18 03:59:59 +00:00
cperalesg@gmail.com 32eae5997d Update prompt: Prompt Generator 2026-04-18 03:59:59 +00:00
panda667 c31cf70e60 Update prompt: Astrologer 2026-04-18 03:59:58 +00:00
joembolinas e4e39e99b3 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-18 03:59:58 +00:00
aitank2020@gmail.com 8173153a96 Update prompt: Echoes of the Rust Age 2026-04-18 03:59:57 +00:00
dragoy18@gmail.com 496543eefd Update prompt: Code Review Specialist 2 2026-04-18 03:59:57 +00:00
lior1976@gmail.com 1b14efee19 Update prompt: Article Summarizer 2026-04-18 03:59:57 +00:00
beresasis@gmail.com 0580f7e799 Update prompt: Interview Preparation Coach 2026-04-18 03:59:56 +00:00
sinansonmez 89f3171525 Update prompt: Code Review Assistant 2026-04-18 03:59:56 +00:00
giorgiop b845777235 Update prompt: Virtual Doctor 2026-04-18 03:59:55 +00:00
serinityconya@gmail.com ac10a7b084 Add prompt: Alexa Said THIS… and Miss Nancy Didn’t Like It 😳 2026-04-17 04:06:02 +00:00
youssefkhalafabdullatif@gmail.com 40f3816d19 Add prompt: Notion Transcript Designer Prompt 2026-04-17 04:06:02 +00:00
senoldak 5aa8a804b7 Add prompt: 🧠 PromptAudit 2026-04-17 04:06:02 +00:00
fede.gazzelloni@gmail.com 590275cbc9 Update prompt: Article Summarizer 2026-04-17 04:06:01 +00:00
debashis.sarker@gmail.com 5c2fbbbe76 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-17 04:06:01 +00:00
aymanrabeemac@gmail.com 2cfd9b366b Update prompt: Code Review Specialist 2026-04-17 04:06:00 +00:00
nolanneff 5f238a8d89 Update prompt: Code Review Specialist 2 2026-04-17 04:06:00 +00:00
ersinkoc d54c09f2a8 Update prompt: Echoes of the Rust Age 2026-04-17 04:06:00 +00:00
cnwdy888@gmail.com 4d1b8aa407 Update prompt: Interview Preparation Coach 2026-04-17 04:05:59 +00:00
guangzhongzhang978@gmail.com 100d21e7b3 Update prompt: Virtual Doctor 2026-04-17 04:05:59 +00:00
f 9525632ada Update prompt: Code Review Assistant 2026-04-17 04:05:58 +00:00
devisasari d2d05531f8 Update prompt: Astrologer 2026-04-17 04:05:58 +00:00
iuzn eab3a138af Update prompt: Prompt Generator 2026-04-17 04:05:58 +00:00
Fatih Kadir Akın 4407fa25f4 docs(book): update author bio to Automattic across all locales 2026-04-16 21:03:59 +03:00
mrgrey565-ux db42383830 Add prompt: Mbbs 2026-04-16 04:06:45 +00:00
lopezanth661@gmail.com 721729577a Add prompt: Audio Routing Automation Engineer 2026-04-16 04:06:45 +00:00
lopezanth661@gmail.com d046b9d32f Add prompt: ubuntu audio input/output,loop/virtual connection specialist 2026-04-16 04:06:44 +00:00
kevjones7563@gmail.com 6c04cf4d2d Add prompt: MAP 2026-04-16 04:06:44 +00:00
balajiforaix@gmail.com d2d46b27db Add prompt: create prompt for audit purpose on password configuartion file for linux 2026-04-16 04:06:43 +00:00
senoldak f8b71770a9 Add prompt: Cinematic Sunset Boat Scene 2026-04-16 04:06:43 +00:00
senoldak 8cb0b44b94 Add prompt: Dramatic Horse Silhouette in Cinematic Lighting 2026-04-16 04:06:43 +00:00
senoldak 4de3925110 Add prompt: Serene Autumn Lakeside Illustration 2026-04-16 04:06:42 +00:00
adediwuratemitope9-tech f55a499676 Add prompt: Picture 2026-04-16 04:06:42 +00:00
xiaoyucunx 716a3e318d Update prompt: Code Review Specialist 2026-04-16 04:06:41 +00:00
cperalesg@gmail.com d72fb97041 Update prompt: Prompt Generator 2026-04-16 04:06:41 +00:00
panda667 34553d8da3 Update prompt: Astrologer 2026-04-16 04:06:41 +00:00
joembolinas e5bd9b894d Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-16 04:06:40 +00:00
aitank2020@gmail.com db0aebe7ca Update prompt: Echoes of the Rust Age 2026-04-16 04:06:40 +00:00
dragoy18@gmail.com 522bb0f5e8 Update prompt: Code Review Specialist 2 2026-04-16 04:06:39 +00:00
lior1976@gmail.com 971758ccee Update prompt: Article Summarizer 2026-04-16 04:06:39 +00:00
beresasis@gmail.com bc0edd3b8a Update prompt: Interview Preparation Coach 2026-04-16 04:06:38 +00:00
sinansonmez c47187c18e Update prompt: Code Review Assistant 2026-04-16 04:06:38 +00:00
giorgiop 392086f671 Update prompt: Virtual Doctor 2026-04-16 04:06:38 +00:00
kriptoburak 244ad5568b Add prompt: X Twitter Scraper 2026-04-15 04:05:09 +00:00
tcyjg 41927597f0 Add prompt: prd-and-technical-documentation-generator 2026-04-15 04:05:09 +00:00
yazz4444 f6a56a61be Add prompt: karpathy-guidelines 2026-04-15 04:05:08 +00:00
papanito b533cd4266 Update prompt: Terraform Platform Engineer 2026-04-15 04:05:08 +00:00
fede.gazzelloni@gmail.com f8b9642e55 Update prompt: Article Summarizer 2026-04-15 04:05:07 +00:00
debashis.sarker@gmail.com 125b8220a4 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-15 04:05:07 +00:00
aymanrabeemac@gmail.com d4a57af24d Update prompt: Code Review Specialist 2026-04-15 04:05:07 +00:00
nolanneff 9b42956b0f Update prompt: Code Review Specialist 2 2026-04-15 04:05:06 +00:00
ersinkoc d715f2616e Update prompt: Echoes of the Rust Age 2026-04-15 04:05:06 +00:00
cnwdy888@gmail.com b14c80af1c Update prompt: Interview Preparation Coach 2026-04-15 04:05:05 +00:00
guangzhongzhang978@gmail.com bc8e7abf26 Update prompt: Virtual Doctor 2026-04-15 04:05:05 +00:00
f 8484e74dea Update prompt: Code Review Assistant 2026-04-15 04:05:04 +00:00
devisasari 63e9a34d73 Update prompt: Astrologer 2026-04-15 04:05:04 +00:00
iuzn 20a0380e47 Update prompt: Prompt Generator 2026-04-15 04:05:04 +00:00
aufa.g07@gmail.com ff2310a0de Add prompt: Mockup Interview using Gemini Live 2026-04-14 04:05:22 +00:00
c.aksan@gmail.com 244ccd1b03 Add prompt: Web Typography 2026-04-14 04:05:22 +00:00
xiaoyucunx 9d0650d555 Update prompt: Code Review Specialist 2026-04-14 04:05:21 +00:00
cperalesg@gmail.com 3039834e85 Update prompt: Prompt Generator 2026-04-14 04:05:21 +00:00
panda667 5f7b91f233 Update prompt: Astrologer 2026-04-14 04:05:20 +00:00
joembolinas bb77b06047 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-14 04:05:20 +00:00
aitank2020@gmail.com 33b252b533 Update prompt: Echoes of the Rust Age 2026-04-14 04:05:19 +00:00
dragoy18@gmail.com fb5336bf15 Update prompt: Code Review Specialist 2 2026-04-14 04:05:19 +00:00
lior1976@gmail.com c15340d5fd Update prompt: Article Summarizer 2026-04-14 04:05:18 +00:00
beresasis@gmail.com 82515da893 Update prompt: Interview Preparation Coach 2026-04-14 04:05:18 +00:00
sinansonmez c2fa700dc1 Update prompt: Code Review Assistant 2026-04-14 04:05:18 +00:00
giorgiop 9e9794ece3 Update prompt: Virtual Doctor 2026-04-14 04:05:17 +00:00
Nick2bad4u eb7167bb4f Add prompt: Stylelint Plugin Author 2026-04-13 04:10:21 +00:00
fede.gazzelloni@gmail.com 546af4b7c6 Update prompt: Article Summarizer 2026-04-13 04:10:21 +00:00
debashis.sarker@gmail.com 6df8c63144 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-13 04:10:21 +00:00
aymanrabeemac@gmail.com 445c968279 Update prompt: Code Review Specialist 2026-04-13 04:10:20 +00:00
nolanneff d54d57ec63 Update prompt: Code Review Specialist 2 2026-04-13 04:10:20 +00:00
ersinkoc e79e8899a1 Update prompt: Echoes of the Rust Age 2026-04-13 04:10:19 +00:00
cnwdy888@gmail.com 8c453beeca Update prompt: Interview Preparation Coach 2026-04-13 04:10:19 +00:00
guangzhongzhang978@gmail.com d7c95f285e Update prompt: Virtual Doctor 2026-04-13 04:10:18 +00:00
f 5f5df223e8 Update prompt: Code Review Assistant 2026-04-13 04:10:18 +00:00
devisasari 115a1a1c1f Update prompt: Astrologer 2026-04-13 04:10:17 +00:00
iuzn 28ffd9510d Update prompt: Prompt Generator 2026-04-13 04:10:17 +00:00
joembolinas bc39bce60d Add prompt: AI Productivity Artifact Generator 2026-04-12 04:07:01 +00:00
raselggg2@gmail.com 080088e8eb Add prompt: Meta Agent Builder for Letta Platform 2026-04-12 04:07:00 +00:00
xiaoyucunx 47df8696a6 Update prompt: Code Review Specialist 2026-04-12 04:07:00 +00:00
cperalesg@gmail.com f322f5e1d3 Update prompt: Prompt Generator 2026-04-12 04:06:59 +00:00
panda667 01c8e764b2 Update prompt: Astrologer 2026-04-12 04:06:59 +00:00
joembolinas 119927b565 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-12 04:06:59 +00:00
aitank2020@gmail.com 5a31ae302f Update prompt: Echoes of the Rust Age 2026-04-12 04:06:58 +00:00
dragoy18@gmail.com b7f4a3a574 Update prompt: Code Review Specialist 2 2026-04-12 04:06:58 +00:00
lior1976@gmail.com 83792fd623 Update prompt: Article Summarizer 2026-04-12 04:06:57 +00:00
beresasis@gmail.com 6993af2416 Update prompt: Interview Preparation Coach 2026-04-12 04:06:57 +00:00
sinansonmez 6385bc9efe Update prompt: Code Review Assistant 2026-04-12 04:06:56 +00:00
giorgiop 551934cf6a Update prompt: Virtual Doctor 2026-04-12 04:06:56 +00:00
traouiicho@gmail.com f03a255314 Add prompt: Expert en Analyse du Marché eCommerce en Algérie 2026-04-11 03:53:08 +00:00
oscar.nesis@gmail.com 6d07da5661 Add prompt: Potato Critic 2026-04-11 03:53:08 +00:00
jinz8848@gmail.com 5c51243f9c Add prompt: Low Voltage Electrical Theory Guide 2026-04-11 03:53:07 +00:00
fede.gazzelloni@gmail.com 7df98ae282 Update prompt: Article Summarizer 2026-04-11 03:53:07 +00:00
debashis.sarker@gmail.com ab5f2336bc Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-11 03:53:06 +00:00
aymanrabeemac@gmail.com a1a65012f2 Update prompt: Code Review Specialist 2026-04-11 03:53:06 +00:00
nolanneff 43b01089cc Update prompt: Code Review Specialist 2 2026-04-11 03:53:06 +00:00
ersinkoc 2d2ae2f269 Update prompt: Echoes of the Rust Age 2026-04-11 03:53:05 +00:00
cnwdy888@gmail.com 1473468b4c Update prompt: Interview Preparation Coach 2026-04-11 03:53:05 +00:00
guangzhongzhang978@gmail.com e01a0b1b8b Update prompt: Virtual Doctor 2026-04-11 03:53:04 +00:00
f d2602b765d Update prompt: Code Review Assistant 2026-04-11 03:53:04 +00:00
devisasari 885e136f16 Update prompt: Astrologer 2026-04-11 03:53:03 +00:00
iuzn f241b7047c Update prompt: Prompt Generator 2026-04-11 03:53:03 +00:00
arimerzhu1@gmail.com 25a286b0b7 Add prompt: Adaptive Thinking Framework 2026-04-10 04:05:10 +00:00
traouiicho@gmail.com b66ce33ced Add prompt: Research and Presentation on Energy Forms 2026-04-10 04:05:10 +00:00
vj.briceno89@gmail.com 3083097885 Add prompt: Web App Security Code Review (OWASP) - Public Test 2026-04-10 04:05:09 +00:00
phambichha55684@gmail.com e9df744b5e Add prompt: AI-Generated Patent Illustration Instructions 2026-04-10 04:05:09 +00:00
phambichha55684@gmail.com 62799acdb6 Add prompt: Patent Illustration Design with SolidWorks and Origin Styles 2026-04-10 04:05:08 +00:00
Isha2790 c21c7917ce Add prompt: Instagram Profile Search Navigator 2026-04-10 04:05:08 +00:00
sonucahmet@gmail.com 47bd0b446a Add prompt: Celebratory Student Exam Result Reveal 2026-04-10 04:05:08 +00:00
sonucahmet@gmail.com fc48e88628 Add prompt: Cute Family Cartoon Sticker Design 2026-04-10 04:05:07 +00:00
sonucahmet@gmail.com 9738ad3029 Add prompt: 1950s Diner Photo Transformation 2026-04-10 04:05:07 +00:00
sonucahmet@gmail.com 5e9a47ec2e Add prompt: Transforming a Photo into a Post-Apocalyptic Scene 2026-04-10 04:05:06 +00:00
sonucahmet@gmail.com 97f3d1be35 Add prompt: Galactic Smuggler 2026-04-10 04:05:06 +00:00
sonucahmet@gmail.com f76f989937 Add prompt: Paint 2026-04-10 04:05:06 +00:00
sonucahmet@gmail.com 7f916a402f Add prompt: Japan 2026-04-10 04:05:05 +00:00
sonucahmet@gmail.com f0a1faa3ab Add prompt: Atari 2026-04-10 04:05:05 +00:00
sonucahmet@gmail.com 6616c8fc88 Add prompt: Cowboy 2026-04-10 04:05:04 +00:00
sonucahmet@gmail.com d72e82e156 Add prompt: Viking 2026-04-10 04:05:04 +00:00
xiaoyucunx 3eda5a6c5c Update prompt: Code Review Specialist 2026-04-10 04:05:04 +00:00
cperalesg@gmail.com 85e989b024 Update prompt: Prompt Generator 2026-04-10 04:05:03 +00:00
panda667 26ea905cae Update prompt: Astrologer 2026-04-10 04:05:03 +00:00
joembolinas c8e5c25579 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-10 04:05:02 +00:00
aitank2020@gmail.com b686783c84 Update prompt: Echoes of the Rust Age 2026-04-10 04:05:02 +00:00
dragoy18@gmail.com 337e8d6da9 Update prompt: Code Review Specialist 2 2026-04-10 04:05:01 +00:00
lior1976@gmail.com d079830824 Update prompt: Article Summarizer 2026-04-10 04:05:01 +00:00
beresasis@gmail.com ef26867bce Update prompt: Interview Preparation Coach 2026-04-10 04:05:01 +00:00
sinansonmez fd5c81cb96 Update prompt: Code Review Assistant 2026-04-10 04:05:00 +00:00
giorgiop f16c0cbb2c Update prompt: Virtual Doctor 2026-04-10 04:05:00 +00:00
davidmytton 9e93f161df Add prompt: Add AI protection 2026-04-09 04:00:00 +00:00
eng.mohammed.3499@gmail.com df49ad34f7 Add prompt: pdfcount 2026-04-09 03:59:59 +00:00
samsungeindia@gmail.com cf636d5b2d Add prompt: Tr 2026-04-09 03:59:59 +00:00
macro4lifeahk@gmail.com 845075fb5b Add prompt: mc 2026-04-09 03:59:59 +00:00
fede.gazzelloni@gmail.com c69ce3e1b9 Update prompt: Article Summarizer 2026-04-09 03:59:58 +00:00
debashis.sarker@gmail.com 784fd069b2 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-09 03:59:58 +00:00
aymanrabeemac@gmail.com 990830213d Update prompt: Code Review Specialist 2026-04-09 03:59:58 +00:00
nolanneff f1dc6c9189 Update prompt: Code Review Specialist 2 2026-04-09 03:59:57 +00:00
ersinkoc e944bde4b9 Update prompt: Echoes of the Rust Age 2026-04-09 03:59:57 +00:00
cnwdy888@gmail.com e05a450b1f Update prompt: Interview Preparation Coach 2026-04-09 03:59:56 +00:00
guangzhongzhang978@gmail.com ad403cf0e1 Update prompt: Virtual Doctor 2026-04-09 03:59:56 +00:00
f ffe11ff7d2 Update prompt: Code Review Assistant 2026-04-09 03:59:56 +00:00
devisasari 5695064fd6 Update prompt: Astrologer 2026-04-09 03:59:55 +00:00
iuzn c8b88d36c3 Update prompt: Prompt Generator 2026-04-09 03:59:55 +00:00
Fatih Kadir Akın 7d123764be docs(governance): Add governance model for prompts.chat
Entire-Checkpoint: f46e55e56e6d
2026-04-08 21:47:03 +03:00
senoldak 34f95c35cc Add prompt: Typographic Portrait Artwork Creation 2026-04-08 04:01:38 +00:00
mbaigrace1@gmail.com 875e3d75ff Add prompt: Sacrifice in obedience 2026-04-08 04:01:38 +00:00
achen8208@gmail.com 3b40564ebe Add prompt: Game design 2026-04-08 04:01:37 +00:00
Mre4321 2f9da25028 Add prompt: WEB Product Architect 2026-04-08 04:01:37 +00:00
xiaoyucunx 01535692cf Update prompt: Code Review Specialist 2026-04-08 04:01:36 +00:00
cperalesg@gmail.com cb996aee38 Update prompt: Prompt Generator 2026-04-08 04:01:36 +00:00
panda667 d755438db3 Update prompt: Astrologer 2026-04-08 04:01:36 +00:00
joembolinas d38bf8ac5f Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-08 04:01:35 +00:00
aitank2020@gmail.com 0fc15712ca Update prompt: Echoes of the Rust Age 2026-04-08 04:01:35 +00:00
dragoy18@gmail.com ef1b2eeb88 Update prompt: Code Review Specialist 2 2026-04-08 04:01:34 +00:00
lior1976@gmail.com 7adfba1d25 Update prompt: Article Summarizer 2026-04-08 04:01:34 +00:00
beresasis@gmail.com 84ede7d286 Update prompt: Interview Preparation Coach 2026-04-08 04:01:34 +00:00
sinansonmez c0df4475f9 Update prompt: Code Review Assistant 2026-04-08 04:01:33 +00:00
giorgiop 8cb38f19ee Update prompt: Virtual Doctor 2026-04-08 04:01:33 +00:00
Fatih Kadir Akın f59be0bbfc Merge pull request #1132 from suyua9/suyua9-prompts-docs-runtime-requirements
docs: align runtime requirements with current setup
2026-04-07 14:06:29 +03:00
dishantpatel624@gmail.com dfa9d65201 Add prompt: 🔧 AI App Improvement Loop Prompt 2026-04-07 04:00:47 +00:00
senoldak 2960fececf Add prompt: Interstellar Movie Poster Illustration 2026-04-07 04:00:47 +00:00
nguyenphonglc2004@gmail.com ccbc30f1b2 Add prompt: Futuristic Alps in 2150 2026-04-07 04:00:47 +00:00
fede.gazzelloni@gmail.com a1c9221feb Update prompt: Article Summarizer 2026-04-07 04:00:46 +00:00
debashis.sarker@gmail.com a132207741 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-07 04:00:46 +00:00
aymanrabeemac@gmail.com b1b7c92177 Update prompt: Code Review Specialist 2026-04-07 04:00:46 +00:00
nolanneff 87f3416ff6 Update prompt: Code Review Specialist 2 2026-04-07 04:00:45 +00:00
ersinkoc 1cdc12e5cd Update prompt: Echoes of the Rust Age 2026-04-07 04:00:45 +00:00
cnwdy888@gmail.com 5f7f48a3d5 Update prompt: Interview Preparation Coach 2026-04-07 04:00:44 +00:00
guangzhongzhang978@gmail.com 960c6f311d Update prompt: Virtual Doctor 2026-04-07 04:00:44 +00:00
f f244d173da Update prompt: Code Review Assistant 2026-04-07 04:00:44 +00:00
devisasari e8b78194ab Update prompt: Astrologer 2026-04-07 04:00:43 +00:00
iuzn b3343588a8 Update prompt: Prompt Generator 2026-04-07 04:00:43 +00:00
c.burke0327@gmail.com 71a512717c Add prompt: Ultimate Stake.us Dice Wagering Strategy Builder — Rollover & Playthrough Completion 2026-04-06 04:04:39 +00:00
papanito c7b99eb58d Add prompt: Packer Automation & Imaging Expert 2026-04-06 04:04:39 +00:00
senoldak a6b31edde9 Add prompt: Ocean’s Eleven Movie Poster Illustration 2026-04-06 04:04:38 +00:00
softdsk@gmail.com 22128ad609 Add prompt: DOE Framework - Directions Template 2026-04-06 04:04:38 +00:00
luis-c2255 2218679430 Add prompt: Birthday Message Generator – 3 Styles 2026-04-06 04:04:38 +00:00
luis-c2255 6720d8e98e Add prompt: Customizable Birthday Message Generator 2026-04-06 04:04:37 +00:00
overb0355@gmail.com ffebf6f7aa Add prompt: Professional photo editor 2026-04-06 04:04:37 +00:00
ia-kobos 8ab8f315e4 Add prompt: Online Job Search Assistant 2026-04-06 04:04:36 +00:00
xiaoyucunx 8d0cd68cf1 Update prompt: Code Review Specialist 2026-04-06 04:04:36 +00:00
cperalesg@gmail.com 608370d289 Update prompt: Prompt Generator 2026-04-06 04:04:36 +00:00
panda667 3be780ed1b Update prompt: Astrologer 2026-04-06 04:04:35 +00:00
joembolinas 67f15ed17d Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-06 04:04:35 +00:00
aitank2020@gmail.com 31b32ada8e Update prompt: Echoes of the Rust Age 2026-04-06 04:04:34 +00:00
dragoy18@gmail.com 6c065a7250 Update prompt: Code Review Specialist 2 2026-04-06 04:04:34 +00:00
lior1976@gmail.com c04537b77a Update prompt: Article Summarizer 2026-04-06 04:04:33 +00:00
beresasis@gmail.com 32853142de Update prompt: Interview Preparation Coach 2026-04-06 04:04:33 +00:00
sinansonmez a64c8168ac Update prompt: Code Review Assistant 2026-04-06 04:04:33 +00:00
giorgiop 34d2b25be5 Update prompt: Virtual Doctor 2026-04-06 04:04:32 +00:00
ezezpeer@gmail.com 92d9d6cd0d Add prompt: Creating PWA AI Chatbot 2026-04-05 04:03:00 +00:00
hakanak54@gmail.com 3687e57cbd Add prompt: site analiz 2026-04-05 04:03:00 +00:00
1753932465@qq.com 3253864d4c Add prompt: 创设情境串联知识 2026-04-05 04:02:59 +00:00
fede.gazzelloni@gmail.com 2cd9fd2406 Update prompt: Article Summarizer 2026-04-05 04:02:59 +00:00
debashis.sarker@gmail.com 73fd0fa17e Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-05 04:02:58 +00:00
aymanrabeemac@gmail.com b6b1065517 Update prompt: Code Review Specialist 2026-04-05 04:02:58 +00:00
nolanneff 39d32e52ae Update prompt: Code Review Specialist 2 2026-04-05 04:02:58 +00:00
ersinkoc d5ace59c9b Update prompt: Echoes of the Rust Age 2026-04-05 04:02:57 +00:00
cnwdy888@gmail.com 290d512537 Update prompt: Interview Preparation Coach 2026-04-05 04:02:57 +00:00
guangzhongzhang978@gmail.com cd00f2aa3e Update prompt: Virtual Doctor 2026-04-05 04:02:56 +00:00
f f09d1e5f8f Update prompt: Code Review Assistant 2026-04-05 04:02:56 +00:00
devisasari df192b8e25 Update prompt: Astrologer 2026-04-05 04:02:56 +00:00
iuzn 665d761265 Update prompt: Prompt Generator 2026-04-05 04:02:55 +00:00
seymayasar468@gmail.com 812c71dc7a Add prompt: The Colorful Fish Learning Emotions 2026-04-04 03:51:10 +00:00
xiaoyucunx 4f4428a647 Update prompt: Code Review Specialist 2026-04-04 03:51:09 +00:00
cperalesg@gmail.com 3a106af89c Update prompt: Prompt Generator 2026-04-04 03:51:09 +00:00
panda667 e755eacd46 Update prompt: Astrologer 2026-04-04 03:51:09 +00:00
joembolinas 785662faab Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-04 03:51:08 +00:00
aitank2020@gmail.com 02dc8dd179 Update prompt: Echoes of the Rust Age 2026-04-04 03:51:08 +00:00
dragoy18@gmail.com 308e9c4bb3 Update prompt: Code Review Specialist 2 2026-04-04 03:51:07 +00:00
lior1976@gmail.com d70c4c642a Update prompt: Article Summarizer 2026-04-04 03:51:07 +00:00
beresasis@gmail.com 02f6b226fb Update prompt: Interview Preparation Coach 2026-04-04 03:51:07 +00:00
sinansonmez 9bc1a5ef37 Update prompt: Code Review Assistant 2026-04-04 03:51:06 +00:00
giorgiop ef7491bd2d Update prompt: Virtual Doctor 2026-04-04 03:51:06 +00:00
Fatih Kadir Akın 00ccf118be Merge pull request #1133 from Albin5jiji/main
docs: clarify memory requirements to prevent OOM (exit code 137)
2026-04-04 01:10:09 +03:00
Albin Thomas Jiji 7b3ef0c5b0 Merge pull request #1 from Albin5jiji/docs/clarify-build-memory-requirements
docs: clarify memory requirements to prevent OOM (exit code 137)
2026-04-04 01:52:22 +05:30
suyua9 c8d6fdf321 fix: localize self-hosting prerequisites 2026-04-03 23:53:57 +08:00
suyua9 eb7812761b docs: align runtime requirements with current setup 2026-04-03 23:44:06 +08:00
Albin Thomas Jiji 657a32f1e1 docs: clarify memory requirements to prevent OOM (exit code 137)
Clarifies higher memory usage during the first-run Next.js build step to prevent confusion when encountering exit code 137.
2026-04-03 09:42:28 +05:30
joshuawalker9988@gmail.com 4ab7cf10ea Add prompt: AI Cloning #1 - RAW 2026-04-03 03:59:00 +00:00
musatoktas 141a5d41f7 Add prompt: Claude Opus as SEO Auditor 2026-04-03 03:58:59 +00:00
fede.gazzelloni@gmail.com b4992b8186 Update prompt: Article Summarizer 2026-04-03 03:58:59 +00:00
debashis.sarker@gmail.com 8043b3fe53 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-03 03:58:59 +00:00
aymanrabeemac@gmail.com d210e4ed28 Update prompt: Code Review Specialist 2026-04-03 03:58:58 +00:00
nolanneff 1aec69d936 Update prompt: Code Review Specialist 2 2026-04-03 03:58:58 +00:00
ersinkoc 8ce2f5c94c Update prompt: Echoes of the Rust Age 2026-04-03 03:58:57 +00:00
cnwdy888@gmail.com 0800b99579 Update prompt: Interview Preparation Coach 2026-04-03 03:58:57 +00:00
guangzhongzhang978@gmail.com 638390af46 Update prompt: Virtual Doctor 2026-04-03 03:58:56 +00:00
f 32398dc581 Update prompt: Code Review Assistant 2026-04-03 03:58:56 +00:00
devisasari f0c6d6f163 Update prompt: Astrologer 2026-04-03 03:58:56 +00:00
iuzn 9c83cbc0f0 Update prompt: Prompt Generator 2026-04-03 03:58:55 +00:00
xiaoyucunx 872757a6ad Update prompt: Code Review Specialist 2026-04-02 03:58:32 +00:00
cperalesg@gmail.com 6bdbde18b5 Update prompt: Prompt Generator 2026-04-02 03:58:32 +00:00
panda667 c295e141e1 Update prompt: Astrologer 2026-04-02 03:58:32 +00:00
joembolinas 314507c5d1 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-02 03:58:31 +00:00
aitank2020@gmail.com ac62f192d6 Update prompt: Echoes of the Rust Age 2026-04-02 03:58:31 +00:00
dragoy18@gmail.com 28a9c19435 Update prompt: Code Review Specialist 2 2026-04-02 03:58:30 +00:00
lior1976@gmail.com f3c1b13d38 Update prompt: Article Summarizer 2026-04-02 03:58:30 +00:00
beresasis@gmail.com 8907a558c5 Update prompt: Interview Preparation Coach 2026-04-02 03:58:30 +00:00
sinansonmez ba4c9472c2 Update prompt: Code Review Assistant 2026-04-02 03:58:29 +00:00
giorgiop 325717871f Update prompt: Virtual Doctor 2026-04-02 03:58:29 +00:00
Fatih Kadir Akın 7119c0b95e Merge pull request #1122 from murataslan1/fix/cli-missing-full-content-param
fix(cli): add missing full_content param to API URL
2026-04-02 02:04:15 +03:00
ahmadawais 41b3ef58de Add prompt: aa/cli taste
Entire-Checkpoint: 4fb2dee7e542
2026-04-02 02:02:25 +03:00
matthew.growth.ng@gmail.com 7d5f71d8b7 Add prompt: Realistic Selfie of Girl with Transparent Glasses and Pink Hair
Entire-Checkpoint: fbed924fec92
2026-04-02 02:02:24 +03:00
parsherr e8cc186265 Add prompt: Realistic Mirror-Selfie Image Prompt
Entire-Checkpoint: d53ee5bb3c8c
2026-04-02 02:02:24 +03:00
privatemailgateway@gmail.com d3a5df905e Add prompt: Research Prompt (Mistral)
Entire-Checkpoint: 8df92fcf5e6e
2026-04-02 02:02:23 +03:00
tuankiet.infotech@gmail.com e7212c8eb6 Add prompt: Prompt Refiner
Entire-Checkpoint: fe690c74817f
2026-04-02 02:02:22 +03:00
fede.gazzelloni@gmail.com 87df0b2865 Update prompt: Article Summarizer
Entire-Checkpoint: 033eabb96831
2026-04-02 02:02:16 +03:00
debashis.sarker@gmail.com 6e52dc0cac Update prompt: The Technical Co-Founder: Building Real Products Together
Entire-Checkpoint: 8e51d57cee5e
2026-04-02 02:02:06 +03:00
aymanrabeemac@gmail.com 49f51459c5 Update prompt: Code Review Specialist
Entire-Checkpoint: f446120d7c7d
2026-04-02 02:01:57 +03:00
nolanneff d38bf619a5 Update prompt: Code Review Specialist 2
Entire-Checkpoint: 0d8121eecdb5
2026-04-02 02:01:47 +03:00
ersinkoc 7d8760ead1 Update prompt: Echoes of the Rust Age
Entire-Checkpoint: 5dc92302e473
2026-04-02 02:01:37 +03:00
cnwdy888@gmail.com 1799582f1f Update prompt: Interview Preparation Coach
Entire-Checkpoint: 54a36b9d1d3e
2026-04-02 02:01:28 +03:00
guangzhongzhang978@gmail.com 1eb4046261 Update prompt: Virtual Doctor
Entire-Checkpoint: c7c999e23fea
2026-04-02 02:01:18 +03:00
f 66ce235d30 Update prompt: Code Review Assistant
Entire-Checkpoint: 3e6cb616241a
2026-04-02 02:01:09 +03:00
devisasari b897498356 Update prompt: Astrologer
Entire-Checkpoint: 967b69be7526
2026-04-02 02:00:59 +03:00
iuzn 7ce28bea47 Update prompt: Prompt Generator
Entire-Checkpoint: 381a0a28701e
2026-04-02 02:00:50 +03:00
mehmet@mehmetince.net f46f69c0a1 Remove prompt: Step 1: Prepare your data
Entire-Checkpoint: 6f81999331e6
2026-04-02 02:00:40 +03:00
gokbeyinac 0765240fb4 Remove prompt: Kickstart Prompt for UX & UI Design
Entire-Checkpoint: ef5a2d1de5a6
2026-04-02 02:00:30 +03:00
Fatih Kadir Akın 491facec2e fix: rewrite contributor script to maintain row order and correct author attribution
The update loop previously rewrote the entire CSV in remote order, bundling
all row reordering and premature deletions into the first contributor's commit.
Now maintains an ordered list, mutating only the specific row per operation.
Also fixes double-@ emails for email-based contributors.

Made-with: Cursor
Entire-Checkpoint: d550254f429d
2026-04-02 01:58:05 +03:00
Fatih Kadir Akın 8976ddab13 Merge pull request #1123 from f/cursor/add-commandcode-runner
feat: add Command Code as sponsored code runner with clipboard flow
2026-04-02 01:48:13 +03:00
Fatih Kadir Akın 5db2734513 feat: add Command Code as sponsored code runner with clipboard flow
Made-with: Cursor
Entire-Checkpoint: e195189bbf0c
2026-04-02 01:46:42 +03:00
Murat Aslan 51ab7ebf4b fix(cli): add missing full_content param to API URL
The CLI was fetching prompts.json without ?full_content=true, so the
API returned contentPreview instead of the full content field. This
caused a crash when accessing prompt.content in PromptDetail.

Also added defensive null checks on prompt.content accesses in case
the API response is incomplete.

Closes #1107
2026-04-01 23:33:44 +03:00
gokbeyinac 8f120e826c Remove prompt: Kickstart Prompt for UX & UI Design 2026-04-01 04:06:51 +00:00
hrishirajnagawade@gmail.com c10f7fed99 Add prompt: Premium Classy Interview Presentation Design 2026-04-01 04:06:51 +00:00
DoguD 859d1879cf Add prompt: Version Review 2026-04-01 04:06:51 +00:00
mellowdrastic@gmail.com f60c1e1326 Add prompt: Bikini_Girl 2026-04-01 04:06:50 +00:00
rodelph0903@gmail.com 1d754b82b9 Add prompt: making ppt 2026-04-01 04:06:50 +00:00
amvicioushecs 1f176bd719 Add prompt: Voice Cloning Assistant 2026-04-01 04:06:50 +00:00
mellowdrastic@gmail.com cf58b4e07a Add prompt: Lonely cry 2026-04-01 04:06:50 +00:00
mellowdrastic@gmail.com b41371f917 Add prompt: Sapiosessuale 2026-04-01 04:06:49 +00:00
dewayanto1969@gmail.com 7f3298dc15 Add prompt: Accounting Information System 2026-04-01 04:06:49 +00:00
agsergio 7f178ddc61 Add prompt: Network Router emulator 2026-04-01 04:06:49 +00:00
sandraosemeke442@gmail.com 5611bdec4a Add prompt: Picture design 2026-04-01 04:06:48 +00:00
faizanshakilf@gmail.com 5d1c9810e7 Add prompt: Ben 2026-04-01 04:06:48 +00:00
xiaoyucunx d118835c46 Update prompt: Code Review Specialist 2026-04-01 04:06:48 +00:00
cperalesg@gmail.com 56934ab064 Update prompt: Prompt Generator 2026-04-01 04:06:47 +00:00
panda667 6e443ce487 Update prompt: Astrologer 2026-04-01 04:06:47 +00:00
joembolinas ccb204aca8 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-04-01 04:06:47 +00:00
aitank2020@gmail.com 0ab4405951 Update prompt: Echoes of the Rust Age 2026-04-01 04:06:46 +00:00
dragoy18@gmail.com 5d109caf19 Update prompt: Code Review Specialist 2 2026-04-01 04:06:46 +00:00
lior1976@gmail.com 1d1c3f1df4 Update prompt: Article Summarizer 2026-04-01 04:06:45 +00:00
beresasis@gmail.com 9e9e90a9df Update prompt: Interview Preparation Coach 2026-04-01 04:06:45 +00:00
sinansonmez fa5f421521 Update prompt: Code Review Assistant 2026-04-01 04:06:45 +00:00
giorgiop 7642974a3b Update prompt: Virtual Doctor 2026-04-01 04:06:44 +00:00
Fatih Kadir Akın 571587ceac Merge pull request #1120 from Ardakilic/feat/docker-compose
feat: docker compose
2026-03-31 17:13:23 +03:00
Arda Kilicdagi a147e99933 chore: address additional nitpick coderabbitai feedback 2026-03-31 16:24:43 +03:00
Arda Kilicdagi 956a3e9acb chore: address coderabbitai feedback 2026-03-31 16:03:08 +03:00
Arda Kilicdagi 1bbac4f879 feat: docker compose 2026-03-31 15:09:10 +03:00
Arda Kilicdagi b05b5dd788 feat: docker compose 2026-03-31 15:08:05 +03:00
Fatih Kadir Akın fc08dbdefe Merge pull request #1119 from JohnPhamous/perf/prompts-isr 2026-03-31 08:38:45 +03:00
Fatih Kadir Akın a7177656a4 Merge pull request #1118 from JohnPhamous/perf/mcp-handler-optimization 2026-03-31 08:38:12 +03:00
Fatih Kadir Akın 07a43c119e Merge pull request #1117 from JohnPhamous/fix/mcp-get-405 2026-03-31 08:37:12 +03:00
gokbeyinac eeed2ac7cd Remove prompt: Kickstart Prompt for UX & UI Design 2026-03-31 04:01:21 +00:00
ah0sman 3b18df78b2 Add prompt: Translate Document to Arabic 2026-03-31 04:01:21 +00:00
evg1n 835fa2b9e7 Add prompt: Apple App Store Review Compliance Agent 2026-03-31 04:01:21 +00:00
fede.gazzelloni@gmail.com cff5e73e4b Update prompt: Article Summarizer 2026-03-31 04:01:20 +00:00
debashis.sarker@gmail.com 5087d4c985 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-03-31 04:01:20 +00:00
aymanrabeemac@gmail.com d023f46031 Update prompt: Code Review Specialist 2026-03-31 04:01:19 +00:00
nolanneff ec37a8f49f Update prompt: Code Review Specialist 2 2026-03-31 04:01:19 +00:00
ersinkoc 94c22a6928 Update prompt: Echoes of the Rust Age 2026-03-31 04:01:19 +00:00
cnwdy888@gmail.com 2c91ac1be1 Update prompt: Interview Preparation Coach 2026-03-31 04:01:18 +00:00
guangzhongzhang978@gmail.com 9e56c46717 Update prompt: Virtual Doctor 2026-03-31 04:01:18 +00:00
f 5ae825cec2 Update prompt: Code Review Assistant 2026-03-31 04:01:17 +00:00
devisasari f47813face Update prompt: Astrologer 2026-03-31 04:01:17 +00:00
iuzn 5b5ea22964 Update prompt: Prompt Generator 2026-03-31 04:01:17 +00:00
John Pham a89b2e1aa0 perf: add ISR to /prompts page (60s revalidation)
This page has no auth() dependency and gets high traffic with
0% cache hit rate. ISR with 60s revalidation serves most
requests from cache while keeping content fresh.
2026-03-30 16:27:37 -07:00
John Pham 09aca8cf54 perf: optimize MCP handler DB queries and response sizes
- Remove content field from prompts/list DB query (was fetching
  2-10KB per prompt just to extract variables, never returned)
- Drop arguments from prompts/list response (optional per spec,
  clients get variables when they call GetPrompt)
- Replace 500-row slug fallback scan with indexed title query
- Reduce search_prompts contentPreview from 1000 to 300 chars
- Add in-memory auth cache (5-min TTL) for warm function instances
2026-03-30 16:26:30 -07:00
John Pham 2672888031 fix: return 405 on MCP GET per Streamable HTTP spec
The MCP Streamable HTTP spec requires servers to return either
text/event-stream (SSE) or 405 on GET requests. The previous
200 application/json response violated the spec and caused MCP
clients to enter SSE reconnection loops.

This server is stateless (no sessions, listChanged: false) and
never pushes notifications. Returning 405 tells clients no SSE
support and they stop retrying.

Ref: https://modelcontextprotocol.io/specification/2025-03-26/basic/transports
2026-03-30 16:22:49 -07:00
Fatih Kadir Akın 9c714ffaed Merge pull request #1091 from yoloni-9527/fix/remove-redundant-non-null-assertions-in-ezoic
fix: remove redundant non-null assertions in ezoic.ts
2026-03-30 22:04:17 +03:00
Fatih Kadir Akın 2161843876 Merge pull request #1113 from tech-architecti/fix/seed-missing-content
fix: seed script fails due to missing content field
2026-03-30 22:02:43 +03:00
Aldo Jimenez e4686cb9ee fix: seed script fails due to missing content field
The seed script fetches from /prompts.json without the ?full_content=true
parameter. The API only returns contentPreview by default, so the content
field is undefined, causing PrismaClientValidationError for every prompt.

Changes:
- Add ?full_content=true to the fetch URL
- Make content optional in RemotePrompt interface
- Skip prompts without content instead of failing

Before: Created 0 prompts (1595 skipped) with validation errors
After: Created 1576 prompts (19 skipped - no content)
2026-03-30 13:56:31 -04:00
gokbeyinac a25886cc9f Remove prompt: Kickstart Prompt for UX & UI Design 2026-03-30 04:05:04 +00:00
umutcanyildiz@gmail.com 0ab2e14ba9 Add prompt: Pixar-Style Family Wallpaper Prompt 2026-03-30 04:05:03 +00:00
helix-77 e39b33de04 Add prompt: Academic analyst and exam pattern extractor 2026-03-30 04:05:03 +00:00
etnologiaus2022@gmail.com a48aaafb92 Add prompt: question list for reaserch 2026-03-30 04:05:03 +00:00
etnologiaus2022@gmail.com 68613b8e5b Add prompt: comparison of social groups 2026-03-30 04:05:02 +00:00
etnologiaus2022@gmail.com ba061cf47a Add prompt: subculture 2026-03-30 04:05:02 +00:00
sanjanaganesh125@gmail.com 4d857b758a Add prompt: blood grouping detection using image processing 2026-03-30 04:05:02 +00:00
zhaoliminlawyer@gmail.com 64f3d6b0ae Add prompt: Expert Legal Analyst in Tax and Commercial Law 2026-03-30 04:05:01 +00:00
xiaoyucunx 8a7c529ede Update prompt: Code Review Specialist 2026-03-30 04:05:01 +00:00
cperalesg@gmail.com 0e5691ef18 Update prompt: Prompt Generator 2026-03-30 04:05:01 +00:00
panda667 c1f877932d Update prompt: Astrologer 2026-03-30 04:05:00 +00:00
joembolinas ae88a3004d Update prompt: The Technical Co-Founder: Building Real Products Together 2026-03-30 04:05:00 +00:00
aitank2020@gmail.com b7b4ffd2f0 Update prompt: Echoes of the Rust Age 2026-03-30 04:04:59 +00:00
dragoy18@gmail.com 4ff0b9405d Update prompt: Code Review Specialist 2 2026-03-30 04:04:59 +00:00
lior1976@gmail.com 22379515e3 Update prompt: Article Summarizer 2026-03-30 04:04:58 +00:00
beresasis@gmail.com d7156fa614 Update prompt: Interview Preparation Coach 2026-03-30 04:04:58 +00:00
sinansonmez 59f5760708 Update prompt: Code Review Assistant 2026-03-30 04:04:58 +00:00
giorgiop b44598b685 Update prompt: Virtual Doctor 2026-03-30 04:04:57 +00:00
gokbeyinac 41e4a95556 Remove prompt: Kickstart Prompt for UX & UI Design 2026-03-29 04:03:02 +00:00
senoldak c8172b605c Add prompt: Impressionistic Urban Solitude 2026-03-29 04:03:01 +00:00
senoldak 638ffee508 Add prompt: Abstract Geometric Art Prompt Inspired by Wassily Kandinsky 2026-03-29 04:03:01 +00:00
senoldak 6982b40688 Add prompt: Minimalist Graphic Illustration of a Stylized Dachshund 2026-03-29 04:03:01 +00:00
surendharnadh280709@gmail.com 027585f737 Add prompt: Architecture & UI/UX Audit 2026-03-29 04:03:00 +00:00
fede.gazzelloni@gmail.com acb64b9066 Update prompt: Article Summarizer 2026-03-29 04:03:00 +00:00
debashis.sarker@gmail.com a857cc862e Update prompt: The Technical Co-Founder: Building Real Products Together 2026-03-29 04:03:00 +00:00
aymanrabeemac@gmail.com 6821823fbd Update prompt: Code Review Specialist 2026-03-29 04:02:59 +00:00
nolanneff 08fa2687e6 Update prompt: Code Review Specialist 2 2026-03-29 04:02:59 +00:00
ersinkoc 75ffed8918 Update prompt: Echoes of the Rust Age 2026-03-29 04:02:58 +00:00
cnwdy888@gmail.com 379d0af081 Update prompt: Interview Preparation Coach 2026-03-29 04:02:58 +00:00
guangzhongzhang978@gmail.com 3dc8efe5e1 Update prompt: Virtual Doctor 2026-03-29 04:02:58 +00:00
f 35c4841d19 Update prompt: Code Review Assistant 2026-03-29 04:02:57 +00:00
devisasari 4f352a4dad Update prompt: Astrologer 2026-03-29 04:02:57 +00:00
iuzn 873622e3e4 Update prompt: Prompt Generator 2026-03-29 04:02:56 +00:00
Fatih Kadir Akın 233858f447 Merge pull request #1104 from mdisec/fix-private-prompt-history 2026-03-29 06:29:24 +03:00
Fatih Kadir Akın 7707781f0f Merge pull request #1101 from mdisec/fix-path-traversal-rce 2026-03-29 06:27:04 +03:00
gokbeyinac 4e6928edd4 Remove prompt: Kickstart Prompt for UX & UI Design 2026-03-28 03:51:36 +00:00
aliwattook966@gmail.com c755282408 Add prompt: psy 2026-03-28 03:51:35 +00:00
bortch d28959a637 Add prompt: Ultra-micro Functional Analyst Prompt 2026-03-28 03:51:35 +00:00
bortch 2b197551d6 Add prompt: Small Functional Analyst mode 2026-03-28 03:51:35 +00:00
bortch 01539ffdf4 Add prompt: Functional Analyst 2026-03-28 03:51:34 +00:00
iremaydas f00190aa20 Add prompt: base-R 2026-03-28 03:51:34 +00:00
papanito 1c585cd307 Add prompt: GitHub Enterprise Cloud (GHEC) administrator and power user 2026-03-28 03:51:34 +00:00
kyakhloufi@gmail.com bc67fa9e66 Add prompt: Scientific Paper Drafting Assistant 2026-03-28 03:51:34 +00:00
hrishirajnagawade@gmail.com a5d8c2bf14 Update prompt: In-Depth Paper and Exam Prediction Analyzer 2026-03-28 03:51:33 +00:00
xiaoyucunx 5df85eeb64 Update prompt: Code Review Specialist 2026-03-28 03:51:33 +00:00
cperalesg@gmail.com 43b22f36b9 Update prompt: Prompt Generator 2026-03-28 03:51:33 +00:00
panda667 33f150df11 Update prompt: Astrologer 2026-03-28 03:51:32 +00:00
joembolinas 4463fa3a94 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-03-28 03:51:32 +00:00
aitank2020@gmail.com d5440e93f2 Update prompt: Echoes of the Rust Age 2026-03-28 03:51:31 +00:00
dragoy18@gmail.com 35d7cb1abc Update prompt: Code Review Specialist 2 2026-03-28 03:51:31 +00:00
lior1976@gmail.com de22a3fd1f Update prompt: Article Summarizer 2026-03-28 03:51:31 +00:00
beresasis@gmail.com d4de119db4 Update prompt: Interview Preparation Coach 2026-03-28 03:51:30 +00:00
sinansonmez 7cf33cb8fb Update prompt: Code Review Assistant 2026-03-28 03:51:30 +00:00
giorgiop 0ef72929f4 Update prompt: Virtual Doctor 2026-03-28 03:51:29 +00:00
gokbeyinac adb9e6fcca Remove prompt: Kickstart Prompt for UX & UI Design 2026-03-27 04:00:37 +00:00
papanito 0bf229c5ef Add prompt: Lazyvim expert 2026-03-27 04:00:36 +00:00
hrishirajnagawade@gmail.com c589742201 Add prompt: Website Design Recreator Skill 2026-03-27 04:00:36 +00:00
hrishirajnagawade@gmail.com 3e4b8a43b8 Add prompt: Website Design Recreation Workflow 2026-03-27 04:00:36 +00:00
fede.gazzelloni@gmail.com 0dd6521a9d Update prompt: Article Summarizer 2026-03-27 04:00:35 +00:00
debashis.sarker@gmail.com 05878ed7b3 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-03-27 04:00:35 +00:00
aymanrabeemac@gmail.com b9683050fb Update prompt: Code Review Specialist 2026-03-27 04:00:35 +00:00
nolanneff b1e7d48714 Update prompt: Code Review Specialist 2 2026-03-27 04:00:34 +00:00
ersinkoc 57181398dc Update prompt: Echoes of the Rust Age 2026-03-27 04:00:34 +00:00
cnwdy888@gmail.com d970f349c2 Update prompt: Interview Preparation Coach 2026-03-27 04:00:34 +00:00
guangzhongzhang978@gmail.com e65790ed24 Update prompt: Virtual Doctor 2026-03-27 04:00:33 +00:00
f b983d57a39 Update prompt: Code Review Assistant 2026-03-27 04:00:33 +00:00
devisasari d74f71c49e Update prompt: Astrologer 2026-03-27 04:00:32 +00:00
iuzn 5fb7d29f78 Update prompt: Prompt Generator 2026-03-27 04:00:32 +00:00
gokbeyinac 3a17b27abf Remove prompt: Kickstart Prompt for UX & UI Design 2026-03-26 04:00:40 +00:00
ia-kobos fda723fdb7 Add prompt: Refine Your Resume for Professionalism and ATS Compatibility 2026-03-26 04:00:39 +00:00
vandanaparik4@gmail.com 4efa758797 Add prompt: presentation making 2026-03-26 04:00:39 +00:00
papanito d138a2c01e Add prompt: NixOS Linux Specialist 2026-03-26 04:00:39 +00:00
papanito 3e652d8777 Update prompt: Terraform Platform Engineer 2026-03-26 04:00:38 +00:00
xiaoyucunx 06d6005ffb Update prompt: Code Review Specialist 2026-03-26 04:00:38 +00:00
cperalesg@gmail.com 3a2f0e7114 Update prompt: Prompt Generator 2026-03-26 04:00:38 +00:00
panda667 4d635b4933 Update prompt: Astrologer 2026-03-26 04:00:37 +00:00
joembolinas a7c233c0a8 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-03-26 04:00:37 +00:00
aitank2020@gmail.com 29f11a6074 Update prompt: Echoes of the Rust Age 2026-03-26 04:00:36 +00:00
dragoy18@gmail.com b1ab51b68a Update prompt: Code Review Specialist 2 2026-03-26 04:00:36 +00:00
lior1976@gmail.com 9fa925fd16 Update prompt: Article Summarizer 2026-03-26 04:00:36 +00:00
beresasis@gmail.com 8ce5bc60b7 Update prompt: Interview Preparation Coach 2026-03-26 04:00:35 +00:00
sinansonmez f9e6b5e3d2 Update prompt: Code Review Assistant 2026-03-26 04:00:35 +00:00
giorgiop 3b8d7d3d06 Update prompt: Virtual Doctor 2026-03-26 04:00:34 +00:00
Mehmet INCE d887c49b53 fix the prompt view perm issue for admin and adding unit tests 2026-03-25 21:05:06 +00:00
Mehmet INCE 20c6c26764 fix unit tests 2026-03-25 20:58:44 +00:00
Mehmet INCE 7b81836b21 -fix(security): enforce isPrivate checks on prompt sub-resource endpoints 2026-03-25 20:51:49 +00:00
Fatih Kadir Akın 289c52c2cb Merge pull request #1102 from mdisec/fix-ssrf-wiro 2026-03-25 18:23:47 +00:00
Mehmet INCE 66de14d3cf fix(security): wiro ssrf 2026-03-25 16:31:13 +00:00
Mehmet INCE 0f8d4c381a fix(security): harden skill zip packaging against path traversal and control char injection 2026-03-25 13:12:22 +00:00
Mehmet INCE 6d0bf7fffa fix path traversal leads to rce 2026-03-25 12:11:58 +00:00
Fatih Kadir Akın 30a8f0470e fix(security): prevent SSRF & credential leakage via Fal.ai status polling
Add assertFalOrigin() validation to getFalRequestStatus and
getFalRequestResult to ensure URLs point to trusted Fal.ai hosts
(queue.fal.run, fal.run) before attaching the API key.

Ref: https://gist.github.com/mdisec/27c0cac0ec6a8f3c8f85a18987ddb942
2026-03-25 10:55:54 +03:00
Fatih Kadir Akın 01f0587b42 chore(prompts): enable AI-powered search and generation features 2026-03-25 10:53:53 +03:00
Fatih Kadir Akın 9fe76ea4eb feat: add tiered rate limiting for MCP tool call endpoints 2026-03-25 10:50:07 +03:00
Fatih Kadir Akın 810de4d160 fix: replace explicit any types in prompts.json route 2026-03-25 10:35:30 +03:00
Fatih Kadir Akın 61abe5d8bc Merge pull request #1098 from mdisec/case-insensitive-exploit-fix
Fix username case-collision vulnerability across write and read paths
2026-03-25 07:23:41 +00:00
mellowdrastic@gmail.com ae41315c8f Remove prompt: Entagled IR 2026-03-25 03:52:15 +00:00
joshuawalker9988@gmail.com 4fb5d7787b Remove prompt: TEST 2026-03-25 03:52:15 +00:00
gokbeyinac 888c5260eb Remove prompt: Kickstart Prompt for UX & UI Design 2026-03-25 03:52:15 +00:00
hduggan72@gmail.com dbe1c98c13 Add prompt: Lifelike Face Mask 2026-03-25 03:52:14 +00:00
papanito 927e31471c Add prompt: Terraform Platform Engineer 2026-03-25 03:52:14 +00:00
mcyenerr@gmail.com 520ee79498 Add prompt: Professional Betting Predictions 2026-03-25 03:52:14 +00:00
dev.aniketlodh@gmail.com 32f2bb98e1 Add prompt: Linkedin Post Create Prompt 2026-03-25 03:52:13 +00:00
monapdx ebc1121c3f Add prompt: Fringe Ideology Quiz 2026-03-25 03:52:13 +00:00
monapdx d255cc342b Add prompt: Moral Dilemma Choices 2026-03-25 03:52:13 +00:00
monapdx 73004f638b Add prompt: Self-summary 2026-03-25 03:52:12 +00:00
monapdx a154ba9e0d Add prompt: Analyze Chat History With User 2026-03-25 03:52:12 +00:00
mehmet@mehmetince.net f2d6ae813c Add prompt: Step 1: Prepare your data 2026-03-25 03:52:12 +00:00
mohsamhef@gmail.com 0690e61da1 Add prompt: Researchers in the Library 2026-03-25 03:52:12 +00:00
mellowdrastic@gmail.com c13b3fb110 Add prompt: Odalisque 2026-03-25 03:52:11 +00:00
XiaoStore b521c8bdd1 Add prompt: GitHub Stars Fetcher with Agent Browser 2026-03-25 03:52:11 +00:00
fede.gazzelloni@gmail.com 03cf85dd7a Update prompt: Article Summarizer 2026-03-25 03:52:11 +00:00
debashis.sarker@gmail.com 0bdba06181 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-03-25 03:52:10 +00:00
aymanrabeemac@gmail.com e6f6227e59 Update prompt: Code Review Specialist 2026-03-25 03:52:10 +00:00
thanos0000@gmail.com f7d592aecc Update prompt: I Think I Need a Lawyer — Neutral Legal Intake Organizer 2026-03-25 03:52:09 +00:00
nolanneff 13876fbb69 Update prompt: Code Review Specialist 2 2026-03-25 03:52:09 +00:00
ersinkoc 14e3b5a933 Update prompt: Echoes of the Rust Age 2026-03-25 03:52:09 +00:00
cnwdy888@gmail.com 5d7c79e168 Update prompt: Interview Preparation Coach 2026-03-25 03:52:08 +00:00
guangzhongzhang978@gmail.com 08c7844047 Update prompt: Virtual Doctor 2026-03-25 03:52:08 +00:00
f 75e7a4650d Update prompt: Code Review Assistant 2026-03-25 03:52:07 +00:00
devisasari 2f9d102d02 Update prompt: Astrologer 2026-03-25 03:52:07 +00:00
iuzn 465cb9286f Update prompt: Prompt Generator 2026-03-25 03:52:07 +00:00
Mehmet Ince cb0be62c40 adding migration files to lower index username and email 2026-03-24 18:27:55 +00:00
Mehmet Ince 30784e0740 drop case sensitive approach to the username and email across the app 2026-03-24 17:56:27 +00:00
Fatih Kadir Akın 283353a71a Merge pull request #1096 from sean-roberts/main
feat: Add support for running prompts on Netlify Agent Runners
2026-03-24 16:02:36 +00:00
Fatih Kadir Akın a934d3ead7 Merge pull request #1097 from mdisec/patch-1
Enhance security policy with reporting and disclosure details
2026-03-24 16:02:13 +00:00
Mehmet Ince 1464475df2 Fix username case-collision vulnerability across write and read paths 2026-03-24 16:00:26 +00:00
Mehmet INCE a4cfef1740 Enhance security policy with reporting and disclosure details
Expanded the security policy to include details on reporting vulnerabilities, CVE coordination, scope of issues, and disclosure policy.
2026-03-24 15:47:35 +00:00
Sean Roberts ecee044716 feat: Add support for running prompts on Netlify Agent Runners 2026-03-24 10:51:22 -04:00
mellowdrastic@gmail.com 0bd2b10706 Remove prompt: Love Shop 2026-03-24 03:51:07 +00:00
gokbeyinac e0cf29a07a Remove prompt: Kickstart Prompt for UX & UI Design 2026-03-24 03:51:06 +00:00
mellowdrastic@gmail.com feffd8a93c Add prompt: Entagled IR 2026-03-24 03:51:06 +00:00
this-is-lab 3c050db5c3 Add prompt: writer 2026-03-24 03:51:06 +00:00
joshuawalker9988@gmail.com 8c615d6233 Add prompt: TEST 2026-03-24 03:51:05 +00:00
xiaoyucunx 194bbd5996 Update prompt: Code Review Specialist 2026-03-24 03:51:05 +00:00
cperalesg@gmail.com 3002f6bb99 Update prompt: Prompt Generator 2026-03-24 03:51:05 +00:00
panda667 022c085241 Update prompt: Astrologer 2026-03-24 03:51:04 +00:00
joembolinas d71b78b20b Update prompt: The Technical Co-Founder: Building Real Products Together 2026-03-24 03:51:04 +00:00
aitank2020@gmail.com 6627d1020a Update prompt: Echoes of the Rust Age 2026-03-24 03:51:03 +00:00
dragoy18@gmail.com 9454df0585 Update prompt: Code Review Specialist 2 2026-03-24 03:51:03 +00:00
lior1976@gmail.com 3cd2facb7f Update prompt: Article Summarizer 2026-03-24 03:51:03 +00:00
beresasis@gmail.com 1e2d460583 Update prompt: Interview Preparation Coach 2026-03-24 03:51:02 +00:00
sinansonmez 6bb35a2494 Update prompt: Code Review Assistant 2026-03-24 03:51:01 +00:00
giorgiop 7ab16f4858 Update prompt: Virtual Doctor 2026-03-24 03:51:01 +00:00
gokbeyinac f14bb05f1f Remove prompt: Kickstart Prompt for UX & UI Design 2026-03-23 03:57:32 +00:00
mellowdrastic@gmail.com 0a1145fce7 Add prompt: Love Shop 2026-03-23 03:57:31 +00:00
paul-cine 749fd6caf5 Add prompt: Midjourney 2026-03-23 03:57:31 +00:00
tuanductran 8db94647df Add prompt: Astro.js 2026-03-23 03:57:31 +00:00
fede.gazzelloni@gmail.com 7bf5b07f60 Update prompt: Article Summarizer 2026-03-23 03:57:30 +00:00
debashis.sarker@gmail.com 31fefe12ac Update prompt: The Technical Co-Founder: Building Real Products Together 2026-03-23 03:57:30 +00:00
aymanrabeemac@gmail.com 05d3ea95da Update prompt: Code Review Specialist 2026-03-23 03:57:30 +00:00
nolanneff d7b1fb3e7a Update prompt: Code Review Specialist 2 2026-03-23 03:57:29 +00:00
ersinkoc eb97c5d393 Update prompt: Echoes of the Rust Age 2026-03-23 03:57:29 +00:00
cnwdy888@gmail.com 39c2bab09f Update prompt: Interview Preparation Coach 2026-03-23 03:57:28 +00:00
guangzhongzhang978@gmail.com 88c1115034 Update prompt: Virtual Doctor 2026-03-23 03:57:28 +00:00
akykaan ab6171d6c9 Update prompt: 3D City Prompt
Co-authored-by: panda667 <panda667@users.noreply.github.com>
2026-03-23 03:57:28 +00:00
f 19f9f6ca81 Update prompt: Code Review Assistant 2026-03-23 03:57:27 +00:00
devisasari aecd86b56b Update prompt: Astrologer 2026-03-23 03:57:27 +00:00
iuzn ed5ddb3d1f Update prompt: Prompt Generator 2026-03-23 03:57:27 +00:00
Fatih Kadir Akın f724bb7951 style(components/ads): update ezoic ad container styling 2026-03-22 18:27:51 +03:00
gokbeyinac 47f085b0ce Remove prompt: Kickstart Prompt for UX & UI Design 2026-03-22 03:52:31 +00:00
sametheredge85@gmail.com 024307a329 Add prompt: KJV Harmony Companion 2026-03-22 03:52:31 +00:00
c.burke0327@gmail.com d25abace00 Add prompt: Ultimate Stake.us Dice Strategy Builder — All Risk Levels & Bankrolls 2026-03-22 03:52:31 +00:00
tuanductran 84bc3cf9a9 Add prompt: Reflective Companion, Not Advice 2026-03-22 03:52:30 +00:00
gamaleldientarek@gmail.com 900da199cc Add prompt: Illustrator Style Describer Weavy 2026-03-22 03:52:30 +00:00
xiaoyucunx 7ce8778c7d Update prompt: Code Review Specialist 2026-03-22 03:52:30 +00:00
cperalesg@gmail.com 46abdcc528 Update prompt: Prompt Generator 2026-03-22 03:52:29 +00:00
panda667 af75cf7116 Update prompt: Astrologer 2026-03-22 03:52:29 +00:00
joembolinas 46b3d86dbb Update prompt: The Technical Co-Founder: Building Real Products Together 2026-03-22 03:52:29 +00:00
aitank2020@gmail.com 0b61819b2d Update prompt: Echoes of the Rust Age 2026-03-22 03:52:28 +00:00
dragoy18@gmail.com 21eede5c27 Update prompt: Code Review Specialist 2 2026-03-22 03:52:28 +00:00
lior1976@gmail.com 5d284ddb55 Update prompt: Article Summarizer 2026-03-22 03:52:27 +00:00
beresasis@gmail.com 9b3ea0bf7c Update prompt: Interview Preparation Coach 2026-03-22 03:52:27 +00:00
sinansonmez f89656b582 Update prompt: Code Review Assistant 2026-03-22 03:52:27 +00:00
giorgiop 7691c30bd5 Update prompt: Virtual Doctor 2026-03-22 03:52:26 +00:00
Fatih Kadir Akın 622b02bb80 Merge pull request #1094 from Goro2030/fix/docker-supervisord-socket 2026-03-21 21:40:23 +00:00
Mariano Silva 9156cece88 Fix Docker bootstrap: supervisord socket not configured
supervisord.conf was missing [unix_http_server], [supervisorctl], and
[rpcinterface:supervisor] sections, so the Unix socket was never created.
This caused the readiness check to always fail and the container to exit
with "Supervisord failed to start".

- Add missing supervisord socket and RPC configuration sections
- Improve bootstrap readiness check to verify both process and socket
- Add early exit if supervisord process dies unexpectedly
- Simplify supervisorctl calls (config path no longer needed)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 18:38:42 -03:00
yoloni 256e4339f5 fix: remove redundant non-null assertions in ezoic.ts
The ??= operator already guarantees that `ez` is non-null by the time
it is assigned, so the subsequent non-null assertions (!.) on `ez.cmd`
are redundant and can be safely removed.

Before:
  ez!.cmd = ez!.cmd || [];
  ez!.cmd.push(fn);

After:
  ez.cmd = ez.cmd || [];
  ez.cmd.push(fn);
2026-03-21 17:07:40 +08:00
gokbeyinac 08e85a3827 Remove prompt: Kickstart Prompt for UX & UI Design 2026-03-21 03:47:00 +00:00
mcyenerr@gmail.com 85969a537b Add prompt: Betting Prediction
Co-authored-by: devisasari <devisasari@users.noreply.github.com>
2026-03-21 03:46:59 +00:00
mmogdeveloper 0e8a742dd9 Add prompt: Stock 2026-03-21 03:46:59 +00:00
fede.gazzelloni@gmail.com e9b8d6c6a5 Update prompt: Article Summarizer 2026-03-21 03:46:59 +00:00
debashis.sarker@gmail.com c103d1d708 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-03-21 03:46:58 +00:00
aymanrabeemac@gmail.com 279890f962 Update prompt: Code Review Specialist 2026-03-21 03:46:58 +00:00
nolanneff f4b1be8330 Update prompt: Code Review Specialist 2 2026-03-21 03:46:57 +00:00
ersinkoc f0f05357ca Update prompt: Echoes of the Rust Age 2026-03-21 03:46:57 +00:00
cnwdy888@gmail.com 2d6a628391 Update prompt: Interview Preparation Coach 2026-03-21 03:46:57 +00:00
guangzhongzhang978@gmail.com cfef0bfc4b Update prompt: Virtual Doctor 2026-03-21 03:46:56 +00:00
f 9943bbe4b7 Update prompt: Code Review Assistant 2026-03-21 03:46:56 +00:00
devisasari 4f26d270ed Update prompt: Astrologer 2026-03-21 03:46:55 +00:00
iuzn 6c66be57a6 Update prompt: Prompt Generator 2026-03-21 03:46:55 +00:00
wkaandemir 7bc643c889 Remove prompt: video-analysis-expert 2026-03-20 03:50:52 +00:00
wkaandemir b77c8ed13d Remove prompt: performance-engineer 2026-03-20 03:50:52 +00:00
wkaandemir 7e6d9ff4a2 Remove prompt: frontend-architect 2026-03-20 03:50:51 +00:00
wkaandemir d237a6a7f3 Remove prompt: security-engineer 2026-03-20 03:50:51 +00:00
wkaandemir ec63c8e3ff Remove prompt: root-cause-analyst 2026-03-20 03:50:51 +00:00
wkaandemir bc1960f1a5 Remove prompt: repo-indexer 2026-03-20 03:50:50 +00:00
wkaandemir b3b2a4a09c Remove prompt: refactoring-expert 2026-03-20 03:50:50 +00:00
wkaandemir 7f02c0fa8a Remove prompt: quality-engineer 2026-03-20 03:50:49 +00:00
wkaandemir 6d0b72ebd4 Remove prompt: devops-architect 2026-03-20 03:50:49 +00:00
wkaandemir 9972e8b2b4 Remove prompt: bug-risk-analysis 2026-03-20 03:50:49 +00:00
wkaandemir 22cef958c6 Remove prompt: deep-research-agent 2026-03-20 03:50:48 +00:00
winningt25-ux c234ed3f38 Add prompt: Grok customize 2026-03-20 03:50:48 +00:00
mmanisaligil 1c810f3e28 Add prompt: Business Risk & Scenario Analyzer 2026-03-20 03:50:47 +00:00
mmanisaligil 6043696ca7 Add prompt: Go-To-Market Execution Planner 2026-03-20 03:50:47 +00:00
mmanisaligil e7f81e24dc Add prompt: Revenue Model & Unit Economics Analyzer 2026-03-20 03:50:47 +00:00
mmanisaligil 28a2806d4b Add prompt: Market Entry Strategy Engine 2026-03-20 03:50:47 +00:00
mmanisaligil 9683bef22e Add prompt: Strategic Business Blueprint Generator 2026-03-20 03:50:46 +00:00
mmanisaligil 3e53eebcf4 Add prompt: High-Stakes Decision Support System 2026-03-20 03:50:46 +00:00
mmanisaligil b406431755 Add prompt: Legal Risk Minimization Tool for Freelancers 2026-03-20 03:50:46 +00:00
mmanisaligil caf297283c Add prompt: Zero to One Solo-Founder Launch System 2026-03-20 03:50:45 +00:00
mmanisaligil 9f7c200e69 Add prompt: Personal Knowledge & Narrative Tool 2026-03-20 03:50:45 +00:00
mmanisaligil 4f26d0e120 Add prompt: Trading & Investing Simulation Platform 2026-03-20 03:50:45 +00:00
mmanisaligil 039a4028a3 Add prompt: Private Group Coaching Infrastructure 2026-03-20 03:50:45 +00:00
mmanisaligil e11a167a55 Add prompt: Personalized Digital Avatar Generator 2026-03-20 03:50:44 +00:00
mmanisaligil 4639de7157 Add prompt: Dating Profile Optimization Suite 2026-03-20 03:50:44 +00:00
mmanisaligil 1462653763 Add prompt: AI-Powered Personal Compliment & Coaching Engine 2026-03-20 03:50:44 +00:00
mmanisaligil ebdabfefb4 Add prompt: Apple-Level UI System Designer (2026 Standard) 2026-03-20 03:50:43 +00:00
mmanisaligil 560dc17883 Add prompt: Design System Consistency Auditor 2026-03-20 03:50:43 +00:00
mmanisaligil ea715bc2b8 Add prompt: AI-First Design Handoff Generator (Dev-Ready Spec) 2026-03-20 03:50:43 +00:00
mmanisaligil 1189277f46 Add prompt: UX Conversion Deconstruction Engine 2026-03-20 03:50:42 +00:00
wkaandemir 73e017bb6f Add prompt: Visual Media Analysis Expert Agent Role 2026-03-20 03:50:42 +00:00
wkaandemir 11e6c3f440 Add prompt: Repository Indexer Agent Role 2026-03-20 03:50:42 +00:00
wkaandemir 50a97c0729 Add prompt: Deep Research Agent Role 2026-03-20 03:50:42 +00:00
wkaandemir b991170aec Add prompt: Bug Risk Analyst Agent Role 2026-03-20 03:50:41 +00:00
wkaandemir 6d1fbd3152 Add prompt: TypeScript Type Expert Agent Role 2026-03-20 03:50:41 +00:00
wkaandemir 07005ec619 Add prompt: Tool Evaluator Agent Role 2026-03-20 03:50:41 +00:00
wkaandemir 818ac2f32e Add prompt: Shell Script Agent Role 2026-03-20 03:50:40 +00:00
wkaandemir 246418367f Add prompt: Refactoring Expert Agent Role 2026-03-20 03:50:40 +00:00
wkaandemir 2b5ff2c672 Add prompt: Root Cause Analysis Agent Role 2026-03-20 03:50:40 +00:00
wkaandemir 1e032ed819 Add prompt: Rapid Prototyper Agent Role 2026-03-20 03:50:40 +00:00
wkaandemir a7112fa127 Add prompt: Product Planner Agent Role 2026-03-20 03:50:39 +00:00
wkaandemir b529c1b275 Add prompt: Post-Implementation Audit Agent Role 2026-03-20 03:50:39 +00:00
wkaandemir 345989463f Add prompt: Error Handler Agent Role 2026-03-20 03:50:39 +00:00
wkaandemir fbf2a69203 Add prompt: Dependency Manager Agent Role 2026-03-20 03:50:38 +00:00
wkaandemir b45918c4c3 Add prompt: Code Reviewer Agent Role 2026-03-20 03:50:38 +00:00
wkaandemir 60410ea046 Add prompt: Code Review Agent Role 2026-03-20 03:50:38 +00:00
wkaandemir 9db18e74b7 Add prompt: Code Formatter Agent Role 2026-03-20 03:50:38 +00:00
wkaandemir 954fbea6ba Add prompt: Test Engineer Agent Role 2026-03-20 03:50:37 +00:00
wkaandemir 402016da36 Add prompt: Test Analyzer Agent Role 2026-03-20 03:50:37 +00:00
wkaandemir 2fac69e1f7 Add prompt: Quality Engineering Agent Role 2026-03-20 03:50:37 +00:00
wkaandemir 05c32f93ab Add prompt: API Tester Agent Role 2026-03-20 03:50:37 +00:00
wkaandemir 0e8d8e2449 Add prompt: Vulnerability Auditor Agent Role 2026-03-20 03:50:36 +00:00
wkaandemir d55748d291 Add prompt: Diff Security Auditor Agent Role 2026-03-20 03:50:36 +00:00
wkaandemir 612114beaf Add prompt: Performance Tuning Agent Role 2026-03-20 03:50:36 +00:00
wkaandemir 6a1d232347 Add prompt: Optimization Auditor Agent Role 2026-03-20 03:50:35 +00:00
wkaandemir 437be3d61d Add prompt: Caching Architect Agent Role 2026-03-20 03:50:35 +00:00
wkaandemir 008698943a Add prompt: Legal Document Generator Agent Role 2026-03-20 03:50:35 +00:00
wkaandemir 62b5767bc9 Add prompt: UI Architect Agent Role 2026-03-20 03:50:35 +00:00
wkaandemir 8496265084 Add prompt: SEO Optimization Agent Role 2026-03-20 03:50:34 +00:00
wkaandemir a3ee86b65b Add prompt: SEO Auditor Agent Role 2026-03-20 03:50:34 +00:00
wkaandemir 2379887c93 Add prompt: Frontend Developer Agent Role 2026-03-20 03:50:34 +00:00
wkaandemir 1e029580c6 Add prompt: Accessibility Auditor Agent Role 2026-03-20 03:50:34 +00:00
wkaandemir e52826f731 Add prompt: Documentation Maintainer Agent Role 2026-03-20 03:50:33 +00:00
wkaandemir b428739a19 Add prompt: Repository Workflow Editor Agent Role 2026-03-20 03:50:33 +00:00
wkaandemir 867147829b Add prompt: Git Workflow Expert Agent Role 2026-03-20 03:50:33 +00:00
wkaandemir 42c6125e94 Add prompt: Environment Configuration Agent Role 2026-03-20 03:50:33 +00:00
wkaandemir 63b0b66739 Add prompt: DevOps Automator Agent Role 2026-03-20 03:50:32 +00:00
wkaandemir cfdb8726d8 Add prompt: Backup & Restore Agent Role 2026-03-20 03:50:32 +00:00
wkaandemir b04295fa90 Add prompt: Mock Data Generator Agent Role 2026-03-20 03:50:32 +00:00
wkaandemir 77799aadcc Add prompt: Data Validator Agent Role 2026-03-20 03:50:32 +00:00
wkaandemir f51e399dcb Add prompt: Database Architect Agent Role 2026-03-20 03:50:31 +00:00
wkaandemir 63b371b678 Add prompt: Backend Architect Agent Role 2026-03-20 03:50:31 +00:00
wkaandemir d26692fbf2 Add prompt: API Design Expert Agent Role 2026-03-20 03:50:31 +00:00
wkaandemir 0034dc39b5 Add prompt: System Architect Agent Role 2026-03-20 03:50:31 +00:00
jovemexausto 36e73e4ad2 Add prompt: Entropy peer reviews 2026-03-20 03:50:30 +00:00
xiaoyucunx 05ed853084 Update prompt: Code Review Specialist 2026-03-20 03:50:30 +00:00
cperalesg@gmail.com 59bf6f13fe Update prompt: Prompt Generator 2026-03-20 03:50:30 +00:00
panda667 dcc5c5cbbf Update prompt: Astrologer 2026-03-20 03:50:29 +00:00
joembolinas 1803c8e297 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-03-20 03:50:29 +00:00
aitank2020@gmail.com 14f7cfadf8 Update prompt: Echoes of the Rust Age 2026-03-20 03:50:29 +00:00
dragoy18@gmail.com 1d93108df9 Update prompt: Code Review Specialist 2 2026-03-20 03:50:28 +00:00
lior1976@gmail.com cde0e0724c Update prompt: Article Summarizer 2026-03-20 03:50:28 +00:00
beresasis@gmail.com ee712a0c8c Update prompt: Interview Preparation Coach 2026-03-20 03:50:28 +00:00
sinansonmez 721da5e226 Update prompt: Code Review Assistant 2026-03-20 03:50:27 +00:00
giorgiop e3c658bd79 Update prompt: Virtual Doctor 2026-03-20 03:50:27 +00:00
Fatih Kadir Akın 3b49211aab refactor(components): update EzoicPlaceholder to optimize DOM handling 2026-03-20 01:40:06 +03:00
Fatih Kadir Akın b991f8fe10 feat(public/sponsors, src/app): add Vercel OSS dark mode sponsor logo 2026-03-20 01:35:41 +03:00
Fatih Kadir Akın 9fbeddf8f4 refactor(components): update Ezoic ad handling and scripts placement
Entire-Checkpoint: afbec17cde9f
2026-03-20 01:23:52 +03:00
Fatih Kadir Akın 252bcb5de3 refactor(components): refactor Ezoic ad and placeholder components
Entire-Checkpoint: afbec17cde9f
2026-03-20 01:12:46 +03:00
Fatih Kadir Akın 4ef6246284 feat(components): add EzoicAd component for displaying ads 2026-03-20 00:53:42 +03:00
Fatih Kadir Akın a253e6524a fix(api): resolve TypeScript _count type error in prompts.json route 2026-03-20 00:44:19 +03:00
Fatih Kadir Akın f34113302f refactor(components): update Ezoic ad rendering logic 2026-03-20 00:34:12 +03:00
Fatih Kadir Akın 1c287d3a0f Merge pull request #1086 from mksglu/fix/vercel-cost-optimization
perf: reduce Vercel costs with 12 targeted optimizations ($6.4K → $800-1.5K/mo)
2026-03-19 21:23:17 +00:00
Fatih Kadir Akın 29064d6ada refactor(ads): improve Ezoic ad rendering logic 2026-03-20 00:20:51 +03:00
Mert Koseoglu c95f80dd75 fix: ReDoS prevention + bound slugify fallback scan
- Validate elicitation keys match variable name format before regex construction
  (prevents ReDoS via user-controlled regex metacharacters — CWE-1333)
- Narrow slugify fallback to only prompts with slug=null, cap at 500 results
- Add TODO to backfill slug column so fallback can be removed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:40:18 +03:00
Mert Koseoglu 0e9258c300 fix: parseBody uses byte-accurate size check and returns 413
- Track bytes with Buffer.byteLength instead of string code units
- Return 413 Payload Too Large instead of generic 500
- Custom PayloadTooLargeError class for handler discrimination

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:28:17 +03:00
Mert Koseoglu 08a9c26ed2 fix: address CodeRabbit review — backward compat + slugify fallback
- prompts.json: Always include `content` field alongside `contentPreview`
  (Raycast extension reads `item.content` — removing it breaks the extension)
- mcp.ts GetPromptRequestSchema: Add slugify(title) fallback for prompts
  without a stored slug (getPromptName() advertises slugified titles in
  prompts/list, so the resolver must handle them too)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:25:08 +03:00
Mert Koseoglu 1dbdb88717 perf: reduce Vercel costs — 12 optimizations across MCP endpoint, prompts.json, and infra
Addresses $6,478/month Vercel bill with 12 targeted fixes based on forensic
bill analysis and 7-expert review. See #1085 for full analysis.

MCP endpoint (src/pages/api/mcp.ts):
- Fix GetPromptRequestSchema P0 full table scan (findMany→findFirst)
- Remove all JSON pretty-printing (13 occurrences, ~30% payload reduction)
- Add Cache-Control headers to GET discovery endpoint
- Set tools.listChanged=false to prevent client polling
- Add 1MB body size limit to parseBody (DoS protection)
- Make elicitation opt-in via fill_variables param (saves 10s CPU/request)
- Fix timer leak in elicitation setTimeout
- Cap search content at 1,000 chars (contentPreview)
- Remove structuredFormat from search results
- Dynamic import for improve_prompt (reduces cold start)
- Optimize search_skills to return fileNames only

prompts.json:
- Add pagination (?page=&limit=) with backward compatibility
- Add ETag support for 304 Not-Modified responses
- Truncate content to 500-char preview by default

Infrastructure:
- Remove Sentry tunnelRoute (was proxying all browser events through edge)
- Add slug + composite database indexes for MCP query patterns

Closes #1085

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 21:04:34 +03:00
Fatih Kadir Akın cd1715e703 chore(env): update EZOIC_ENABLED to NEXT_PUBLIC_EZOIC_ENABLED in environment variables 2026-03-19 18:21:51 +03:00
Fatih Kadir Akın d9fe66299a feat(prompts): enable Ezoic ads based on environment variable 2026-03-19 18:11:52 +03:00
Fatih Kadir Akın e1741b528e feat(prompts): add Ezoic ad placeholder to prompt page 2026-03-19 17:38:11 +03:00
Fatih Kadir Akın 68bf2e9be8 chore(widgets): update maxCount to 20 in ezoicWidget 2026-03-19 17:30:41 +03:00
Fatih Kadir Akın 266ffe9b9e Merge pull request #1082 from ogzgl/fix/reduce-vercel-costs 2026-03-19 12:26:59 +00:00
Oğuz Gül a46ef57a60 fix: reduce vercel costs 2026-03-19 15:16:07 +03:00
Fatih Kadir Akın 6505f7601f fix(page.tsx): update JSON-LD serialization to escape special characters 2026-03-19 10:29:41 +03:00
Fatih Kadir Akın 9684a58dbc fix(seo): update structured data script to escape special characters 2026-03-19 10:28:58 +03:00
gokbeyinac f50c843cb7 Remove prompt: Kickstart Prompt for UX & UI Design 2026-03-19 03:54:46 +00:00
mal4thia@gmail.com 7f34e89107 Add prompt: Professional photo restoration expert 2026-03-19 03:54:46 +00:00
priyalvijay108@gmail.com 4315ccba98 Add prompt: Review the social media content 2026-03-19 03:54:46 +00:00
fede.gazzelloni@gmail.com 6759e17f1c Update prompt: Article Summarizer 2026-03-19 03:54:45 +00:00
debashis.sarker@gmail.com b1d591c946 Update prompt: The Technical Co-Founder: Building Real Products Together 2026-03-19 03:54:45 +00:00
aymanrabeemac@gmail.com fad9ea6a5d Update prompt: Code Review Specialist 2026-03-19 03:54:45 +00:00
nolanneff 5e5d20b705 Update prompt: Code Review Specialist 2 2026-03-19 03:54:44 +00:00
thanos0000@gmail.com fa5e180371 Update prompt: Question Quality Lab Game 2026-03-19 03:54:44 +00:00
ersinkoc ba3a120f6d Update prompt: Echoes of the Rust Age 2026-03-19 03:54:44 +00:00
cnwdy888@gmail.com 8c54e612ac Update prompt: Interview Preparation Coach 2026-03-19 03:54:43 +00:00
guangzhongzhang978@gmail.com 239119a12e Update prompt: Virtual Doctor 2026-03-19 03:54:43 +00:00
f 34e529cc70 Update prompt: Code Review Assistant 2026-03-19 03:54:42 +00:00
devisasari e2a494e39d Update prompt: Astrologer 2026-03-19 03:54:42 +00:00
iuzn cee1e2d521 Update prompt: Prompt Generator 2026-03-19 03:54:42 +00:00
141 changed files with 63096 additions and 5524 deletions
-84
View File
@@ -1,84 +0,0 @@
{
"hooks": {
"PostToolUse": [
{
"matcher": "Task",
"hooks": [
{
"type": "command",
"command": "entire hooks claude-code post-task"
}
]
},
{
"matcher": "TodoWrite",
"hooks": [
{
"type": "command",
"command": "entire hooks claude-code post-todo"
}
]
}
],
"PreToolUse": [
{
"matcher": "Task",
"hooks": [
{
"type": "command",
"command": "entire hooks claude-code pre-task"
}
]
}
],
"SessionEnd": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "entire hooks claude-code session-end"
}
]
}
],
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "entire hooks claude-code session-start"
}
]
}
],
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "entire hooks claude-code stop"
}
]
}
],
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "entire hooks claude-code user-prompt-submit"
}
]
}
]
},
"permissions": {
"deny": [
"Read(./.entire/metadata/**)"
]
}
}
+5 -1
View File
@@ -10,6 +10,7 @@ dist
# Git
.git
.gitignore
.gitattributes
# IDE
.vscode
@@ -23,10 +24,11 @@ dist
.env.development.local
.env.test.local
.env.production.local
.env.sentry-build-plugin
# Docker
compose.yml
docker-compose*.yml
Dockerfile*
# Development files
.github
@@ -38,6 +40,8 @@ packages
# Test files
coverage
.nyc_output
vitest.config.ts
vitest.setup.ts
# OS files
.DS_Store
-4
View File
@@ -1,4 +0,0 @@
tmp/
settings.local.json
metadata/
logs/
-5
View File
@@ -1,5 +0,0 @@
{
"strategy": "manual-commit",
"enabled": true,
"telemetry": true
}
+48 -2
View File
@@ -66,5 +66,51 @@ CRON_SECRET="your-secret-key-here"
# SENTRY_AUTH_TOKEN=sentry-auth-token
# GOOGLE_ADSENSE_ACCOUNT=ca-pub-xxxxxxxxxxxxxxxx
# EZOIC_ENABLED=true
# EZOIC_SITE_DOMAIN=prompts.chat
# ==============================================================================
# SSO Authentication Configurations
#
# Why two generic providers (OIDC vs OAuth 2.0)?
# - "OIDC" (OpenID Connect) performs strict cryptographic validation on the
# ID Token (verifying 'aud' matching the client ID, 'iss' matching issuer, etc).
# Use this for standard providers like Google, Auth0, Okta, Keycloak.
# - "OAuth 2.0" bypasses strict OIDC validation. Use this for legacy or
# enterprise systems that do not return OIDC ID Tokens
# ==============================================================================
# Generic OIDC Config (Strict Validation)
# ⚠️ Ensure you add "oidc" to the `providers` array in your prompts.config.ts file
# Callback URL to whitelist: <your-domain>/api/auth/callback/oidc
# AUTH_OIDC_ID="dummy-oidc-client-id"
# AUTH_OIDC_SECRET="dummy-oidc-client-secret"
# AUTH_OIDC_ISSUER="https://oidc.example.com"
# AUTH_OIDC_WELLKNOWN="https://oidc.example.com/.well-known/openid-configuration"
# AUTH_OIDC_SCOPE="openid email profile"
# AUTH_OIDC_NAME="Company OIDC"
# Optional overrides (uncomment to use):
# AUTH_OIDC_LOGO="https://your-domain.com/oidc-logo.png" # Local path or full URL to button image
# AUTH_OIDC_AUTHORIZATION_URL="https://oidc.example.com/authorize"
# AUTH_OIDC_TOKEN_URL="https://oidc.example.com/token"
# AUTH_OIDC_USERINFO_URL="https://oidc.example.com/userinfo"
# AUTH_OIDC_JWKS_URL="https://oidc.example.com/jwks"
# AUTH_OIDC_TOKEN_AUTH_METHOD="client_secret_post" # Allowed values: "client_secret_basic", "client_secret_post", "none"
# AUTH_OIDC_ENABLE_PKCE="true" # PKCE is enabled by default. Set to "false" to disable.
# Generic OAuth 2.0 Config (Loose Validation)
# ⚠️ Ensure you add "oauth" to the `providers` array in your prompts.config.ts file
# Callback URL to whitelist: <your-domain>/api/auth/callback/oauth
# AUTH_OAUTH_ID="dummy-oauth-client-id"
# AUTH_OAUTH_SECRET="dummy-oauth-client-secret"
# AUTH_OAUTH_ISSUER="https://sso.example.com"
# AUTH_OAUTH_WELLKNOWN="https://sso.example.com/.well-known/openid-configuration"
# AUTH_OAUTH_SCOPE="email profile"
# AUTH_OAUTH_NAME="Company SSO"
# Optional overrides (uncomment to use):
# AUTH_OAUTH_LOGO="https://your-domain.com/sso-logo.png" # Local path or full URL to button image
# AUTH_OAUTH_AUTHORIZATION_URL="https://sso.example.com/authorize"
# AUTH_OAUTH_TOKEN_URL="https://sso.example.com/token"
# AUTH_OAUTH_USERINFO_URL="https://sso.example.com/userinfo"
# AUTH_OAUTH_JWKS_URL="https://sso.example.com/jwks"
# AUTH_OAUTH_TOKEN_AUTH_METHOD="client_secret_basic" # Allowed values: "client_secret_basic", "client_secret_post", "none"
# AUTH_OAUTH_ENABLE_PKCE="true" # PKCE is enabled by default. Set to "false" to disable.
+1
View File
@@ -48,3 +48,4 @@ next-env.d.ts
# Sentry Config File
.env.sentry-build-plugin
.env.docker
+194 -135
View File
@@ -1,45 +1,68 @@
# Docker Deployment Guide
Run your own prompts.chat instance with a single command.
Run your own prompts.chat instance using Docker Compose.
## Quick Start
```bash
docker run -d \
--name prompts \
-p 4444:3000 \
-v prompts-data:/data \
ghcr.io/f/prompts.chat
git clone https://github.com/f/prompts.chat.git
cd prompts.chat
docker compose up -d
```
**First run:** The container will clone the repository and build the app (~3-5 minutes).
**Subsequent runs:** Starts immediately using the cached build.
Open http://localhost:4444 in your browser.
## Custom Branding
## Using a Pre-built Image
Customize your instance with environment variables:
Edit `compose.yml` and replace the `build` block with the published image:
```bash
docker run -d \
--name my-prompts \
-p 4444:3000 \
-v prompts-data:/data \
-e PCHAT_NAME="Acme Prompts" \
-e PCHAT_DESCRIPTION="Our team's AI prompt library" \
-e PCHAT_COLOR="#ff6600" \
-e PCHAT_AUTH_PROVIDERS="github,google" \
-e PCHAT_LOCALES="en,es,fr" \
ghcr.io/f/prompts.chat
```yaml
services:
app:
# build:
# context: .
# dockerfile: docker/Dockerfile
image: ghcr.io/f/prompts.chat:latest
```
> **Note:** Branding is applied during the first build. To change branding later, delete the volume and re-run:
> ```bash
> docker rm -f my-prompts
> docker volume rm prompts-data
> docker run ... # with new env vars
> ```
Then run:
```bash
docker compose up -d
```
## Standalone (Bring Your Own Database)
If you already have a PostgreSQL instance, you can run just the app container:
```bash
docker build -f docker/Dockerfile -t prompts.chat .
docker run -d \
--name prompts \
-p 4444:3000 \
-e DATABASE_URL="postgresql://user:pass@your-db-host:5432/prompts?schema=public" \
-e AUTH_SECRET="$(openssl rand -base64 32)" \
prompts.chat
```
## Custom Branding
All branding is configured via `PCHAT_*` environment variables at runtime -- no rebuild needed.
```yaml
# compose.yml
services:
app:
environment:
# ... existing vars ...
PCHAT_NAME: "Acme Prompts"
PCHAT_DESCRIPTION: "Our team's AI prompt library"
PCHAT_COLOR: "#ff6600"
PCHAT_AUTH_PROVIDERS: "github,google"
PCHAT_LOCALES: "en,es,fr"
```
Then restart: `docker compose up -d`
## Configuration Variables
@@ -95,103 +118,102 @@ All variables are prefixed with `PCHAT_` to avoid conflicts.
| Variable | Description | Default |
|----------|-------------|---------|
| `AUTH_SECRET` | Secret for authentication tokens | Auto-generated |
| `PORT` | Internal container port | `3000` |
| `DATABASE_URL` | PostgreSQL connection string | Internal DB |
| `AUTH_SECRET` | Secret for authentication tokens | Auto-generated (set explicitly for production) |
| `DATABASE_URL` | PostgreSQL connection string | Set in compose.yml |
| `DIRECT_URL` | Direct PostgreSQL URL (bypasses poolers) | Same as DATABASE_URL |
| `PORT` | Host port mapping | `4444` |
## Production Setup
For production, set `AUTH_SECRET` explicitly:
For production, always set `AUTH_SECRET` explicitly:
```bash
docker run -d \
--name prompts \
-p 4444:3000 \
-v prompts-data:/data \
-e AUTH_SECRET="$(openssl rand -base64 32)" \
-e PCHAT_NAME="My Company Prompts" \
ghcr.io/f/prompts.chat
# Generate a secret
export AUTH_SECRET=$(openssl rand -base64 32)
# Start with explicit secret
docker compose up -d
```
Or add it to a `.env` file next to `compose.yml`:
```env
AUTH_SECRET=your-secret-key-here
```
### With OAuth Providers
```bash
docker run -d \
--name prompts \
-p 4444:3000 \
-v prompts-data:/data \
-e AUTH_SECRET="your-secret-key" \
-e PCHAT_AUTH_PROVIDERS="github,google" \
-e AUTH_GITHUB_ID="your-github-client-id" \
-e AUTH_GITHUB_SECRET="your-github-client-secret" \
-e AUTH_GOOGLE_ID="your-google-client-id" \
-e AUTH_GOOGLE_SECRET="your-google-client-secret" \
ghcr.io/f/prompts.chat
```yaml
# compose.yml
services:
app:
environment:
# ... existing vars ...
PCHAT_AUTH_PROVIDERS: "github,google"
AUTH_GITHUB_ID: "your-github-client-id"
AUTH_GITHUB_SECRET: "your-github-client-secret"
AUTH_GOOGLE_ID: "your-google-client-id"
AUTH_GOOGLE_SECRET: "your-google-client-secret"
```
### With AI Features (OpenAI)
```yaml
# compose.yml
services:
app:
environment:
# ... existing vars ...
PCHAT_FEATURE_AI_SEARCH: "true"
OPENAI_API_KEY: "sk-..."
```
## Database Seeding
Seed the database with example prompts:
```bash
docker run -d \
--name prompts \
-p 4444:3000 \
-v prompts-data:/data \
-e PCHAT_FEATURE_AI_SEARCH="true" \
-e OPENAI_API_KEY="sk-..." \
ghcr.io/f/prompts.chat
docker compose exec app npx prisma db seed
```
## Custom Logo
Mount your logo file:
Mount your logo file into the app container:
```bash
docker run -d \
--name prompts \
-p 4444:3000 \
-v prompts-data:/data \
-v ./my-logo.svg:/data/app/public/logo.svg \
-e PCHAT_NAME="My App" \
ghcr.io/f/prompts.chat
```yaml
# compose.yml
services:
app:
volumes:
- ./my-logo.svg:/app/public/logo.svg
environment:
PCHAT_LOGO: "/logo.svg"
```
## Data Persistence
### All-in-One Image
Data is stored in `/data` inside the container:
- `/data/postgres` - PostgreSQL database files
Mount a volume to persist data:
```bash
docker run -d \
-v prompts-data:/data \
ghcr.io/f/prompts.chat
```
PostgreSQL data is stored in the `postgres_data` named volume and persists across container restarts, rebuilds, and image updates.
### Backup
```bash
# Backup database
docker exec prompts pg_dump -U prompts prompts > backup.sql
docker compose exec db pg_dump -U prompts prompts > backup.sql
# Restore database
docker exec -i prompts psql -U prompts prompts < backup.sql
docker compose exec -T db psql -U prompts prompts < backup.sql
```
## Building Locally
Build and run locally:
```bash
docker build -f docker/Dockerfile -t prompts.chat .
docker run -p 4444:3000 -v prompts-data:/data prompts.chat
docker compose build
docker compose up -d
```
## Health Check
The container includes a health check endpoint:
The app container includes a health check endpoint:
```bash
curl http://localhost:4444/api/health
@@ -211,88 +233,108 @@ Response:
### View Logs
```bash
# All logs
docker logs prompts
# All services
docker compose logs
# Follow logs
docker logs -f prompts
docker compose logs -f
# PostgreSQL logs (inside container)
docker exec prompts cat /var/log/supervisor/postgresql.log
# App logs only
docker compose logs app
# Next.js logs (inside container)
docker exec prompts cat /var/log/supervisor/nextjs.log
# Database logs only
docker compose logs db
```
### Database Access
```bash
# Connect to PostgreSQL
docker exec -it prompts psql -U prompts -d prompts
docker compose exec db psql -U prompts -d prompts
# Run SQL query
docker exec prompts psql -U prompts -d prompts -c "SELECT COUNT(*) FROM \"Prompt\""
# Run a query
docker compose exec db psql -U prompts -d prompts -c "SELECT COUNT(*) FROM \"Prompt\""
```
### Container Shell
```bash
docker exec -it prompts bash
docker compose exec app sh
docker compose exec db bash
```
### Common Issues
**Container won't start:**
- Check logs: `docker logs prompts`
- Ensure port 4444 is available: `lsof -i :4444`
**App container keeps restarting:**
- Check logs: `docker compose logs app`
- Database may not be ready yet -- the entrypoint retries for up to 60 seconds
**Database connection errors:**
- Wait for PostgreSQL to initialize (can take 30-60 seconds on first run)
- Check database logs: `docker exec prompts cat /var/log/supervisor/postgresql.log`
- Verify the `db` service is healthy: `docker compose ps`
- Check database logs: `docker compose logs db`
**Authentication issues:**
- Ensure `AUTH_SECRET` is set for production
- For OAuth, verify callback URLs are configured correctly
## Resource Requirements
Minimum:
- 1 CPU core
- 1GB RAM
- 2GB disk space
Recommended:
- 2 CPU cores
- 2GB RAM
- 10GB disk space
- Set `AUTH_SECRET` explicitly for production
- For OAuth, verify callback URLs match your domain
## Updating
```bash
# Pull latest image
docker pull ghcr.io/f/prompts.chat
# If using pre-built images
docker compose pull
docker compose up -d
# Stop and remove old container
docker stop prompts && docker rm prompts
# Start new container (data persists in volume)
docker run -d \
--name prompts \
-p 4444:3000 \
-v prompts-data:/data \
-e AUTH_SECRET="your-secret-key" \
ghcr.io/f/prompts.chat
# If building locally
git pull
docker compose build
docker compose up -d
```
## Security Considerations
Data persists in the `postgres_data` volume across updates.
1. **Always set AUTH_SECRET** in production
2. **Use HTTPS** - put a reverse proxy (nginx, Caddy, Traefik) in front
3. **Limit exposed ports** - only expose what's needed
4. **Regular updates** - pull the latest image regularly
5. **Backup data** - regularly backup the `/data` volume
## Migrating from the Old Single-Image Setup
## Example: Running Behind Nginx
If you were using the previous all-in-one Docker image:
```bash
# 1. Export your database from the old container
docker exec prompts pg_dump -U prompts prompts > backup.sql
# 2. Stop and remove the old container
docker stop prompts && docker rm prompts
# 3. Start the new compose setup
docker compose up -d
# 4. Import your data
docker compose exec -T db psql -U prompts prompts < backup.sql
```
## Resource Requirements
**Runtime** (after first build):
- 1 CPU core
- 1GB RAM
- 2GB disk space
**First-run build** (Next.js compilation on startup):
- 1 CPU core
- Higher memory required (OOM may occur with low limits)
- 2GB disk space
> ⚠️ If you see `Killed` followed by `exited with code 137` during first startup,
> your Docker container likely ran out of memory during the build step.
> Increasing Docker's memory allocation (e.g., ~4GB or more) can help resolve this.
> On Docker Desktop: Settings → Resources → Memory.
**Recommended for production:**
- 2 CPU cores
- 2GB RAM (runtime)
- 10GB disk space
## Running Behind a Reverse Proxy
### Nginx
```nginx
server {
@@ -316,6 +358,23 @@ server {
}
```
### Caddy
```caddyfile
prompts.example.com {
reverse_proxy localhost:4444
}
```
## Security Considerations
1. **Always set AUTH_SECRET** in production
2. **Use HTTPS** -- put a reverse proxy (Nginx, Caddy, Traefik) in front
3. **Change default database password** -- update `POSTGRES_PASSWORD` in compose.yml and the connection strings
4. **Limit exposed ports** -- only expose what's needed
5. **Regular updates** -- pull the latest image regularly
6. **Backup data** -- regularly backup the database
## License
MIT
+61
View File
@@ -0,0 +1,61 @@
# Governance
This document describes the governance model for prompts.chat.
## Overview
prompts.chat is an open-source project that welcomes contributions from anyone. The project operates with a small group of maintainers who are responsible for the overall direction, code review, and release process. We aim to grow this group over time and welcome new maintainers who demonstrate sustained, quality contributions.
## Roles
### Users
Anyone who uses prompts.chat, whether by browsing the website, self-hosting the platform, using the CLI, or integrating with the MCP server. Users are encouraged to file issues, suggest features, and contribute prompts.
### Contributors
Anyone who contributes to the project. This includes submitting prompts through the web platform, opening pull requests, reporting bugs, improving documentation, or helping other users. All contributors are listed at https://github.com/f/prompts.chat/graphs/contributors.
### Maintainers
People with commit access to the repository. Maintainers review and merge pull requests, triage issues, and participate in project decisions. The current list of maintainers is in [OWNERS.md](OWNERS.md).
Maintainers are expected to:
- Review pull requests in a timely manner
- Help triage and respond to issues
- Follow the project's code of conduct
- Participate in governance discussions when they arise
### Project Lead
The project lead has final decision-making authority on project direction, releases, and governance changes. The project lead is responsible for ensuring the project stays aligned with its mission and the broader community's needs.
## Becoming a Maintainer
New maintainers are added based on sustained, high-quality contributions and demonstrated understanding of the project. There is no fixed checklist, but the following signals are considered:
- A track record of accepted pull requests over several months
- Thoughtful code reviews on other people's contributions
- Constructive participation in issue discussions
- Reliability and follow-through on commitments
Any existing maintainer can nominate a contributor for maintainer status. The nomination is discussed among the current maintainers, and the project lead makes the final decision. We are actively looking to grow the maintainer team, especially from contributors at different organizations.
## Decision Making
Most day-to-day decisions (bug fixes, small features, documentation updates) are made through the standard pull request review process. Any maintainer can approve and merge a PR.
For larger decisions (new features with broad impact, architectural changes, governance changes, dependency additions), we use a "lazy consensus" approach:
1. A proposal is opened as a GitHub issue or discussion.
2. The proposal is left open for at least 7 days to allow feedback.
3. If there are no objections from maintainers, the proposal is accepted.
4. If there are objections, the maintainers discuss and try to reach agreement. The project lead has final say if consensus cannot be reached.
## Changing This Document
Changes to this governance document follow the same decision-making process described above. Any maintainer or contributor can propose changes by opening a pull request.
## Code of Conduct
All participants in the project are expected to be respectful, constructive, and welcoming. We do not tolerate harassment, discrimination, or abusive behavior in any form. Violations can be reported to the project lead or through the channels listed in [SECURITY.md](SECURITY.md).
+11 -118
View File
@@ -1,121 +1,14 @@
Creative Commons Legal Code
This project uses a dual-license model:
CC0 1.0 Universal
- **Source code and site-authored content** (everything under src/,
prisma/, scripts/, and all configuration/build files) is licensed under
the MIT License. This includes the interactive book content in
src/content/book/.
See LICENSE-MIT for the full text.
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
- **Prompt content and data** (prompts.csv, PROMPTS.md, and all user-submitted
prompt text) is dedicated to the public domain under CC0 1.0 Universal.
See LICENSE-CC0 for the full text.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
If you are unsure which license applies to a particular file, the MIT License
applies by default.
+121
View File
@@ -0,0 +1,121 @@
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022-present Fatih Kadir Akin and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+23
View File
@@ -0,0 +1,23 @@
# Owners
This file lists the current maintainers and emeritus maintainers of prompts.chat.
## Project Lead
| Name | GitHub | Affiliation |
|------|--------|-------------|
| Fatih Kadir Akin | [@f](https://github.com/f) | Independent |
## Maintainers
| Name | GitHub | Affiliation | Since |
|------|--------|-------------|-------|
| Fatih Kadir Akin | [@f](https://github.com/f) | Independent | Dec 2022 |
## Emeritus Maintainers
None yet.
---
We are actively looking to grow the maintainer team. If you are interested in becoming a maintainer, please see [GOVERNANCE.md](GOVERNANCE.md) for how the process works. Sustained contributions and involvement in code review are the best way to get started.
+31244 -1403
View File
File diff suppressed because it is too large Load Diff
+16 -10
View File
@@ -34,12 +34,12 @@
<p align="center">
<sub>
🏆 Featured in <a href="https://www.forbes.com/sites/tjmccue/2023/01/19/chatgpt-success-completely-depends-on-your-prompt/">Forbes</a> ·
🎓 Referenced by <a href="https://www.huit.harvard.edu/news/ai-prompts">Harvard</a>, <a href="https://etc.cuit.columbia.edu/news/columbia-prompt-library-effective-academic-ai-use">Columbia</a> ·
📄 <a href="https://scholar.google.com/citations?user=AZ0Dg8YAAAAJ&hl=en">40+ academic citations</a> ·
🏆 Featured in <a href="https://www.forbes.com/sites/tjmccue/2023/01/19/chatgpt-success-completely-depends-on-your-prompt/">Forbes</a> ·
🎓 Referenced by <a href="https://www.huit.harvard.edu/news/ai-prompts">Harvard</a>, <a href="https://etc.cuit.columbia.edu/news/columbia-prompt-library-effective-academic-ai-use">Columbia</a> ·
📄 <a href="https://scholar.google.com/citations?user=AZ0Dg8YAAAAJ&hl=en">40+ academic citations</a> ·
❤️ <a href="https://huggingface.co/datasets/fka/prompts.chat">Most liked dataset</a> on Hugging Face<br>
⭐ 143k+ GitHub stars ·
🏅 <a href="https://spotlights-feed.github.com/spotlights/prompts-chat/index/">GitHub Staff Pick</a> ·
⭐ 143k+ GitHub stars ·
🏅 <a href="https://spotlights-feed.github.com/spotlights/prompts-chat/index/">GitHub Staff Pick</a> ·
🚀 First prompt library (Dec 2022)
</sub>
</p>
@@ -47,9 +47,9 @@
<p align="center">
<sub><strong>Loved by AI pioneers:</strong></sub><br>
<sub>
<a href="https://x.com/gdb/status/1602072566671110144"><strong>Greg Brockman</strong></a> (OpenAI Co-Founder) ·
<a href="https://x.com/woj_zaremba/status/1601362952841760769"><strong>Wojciech Zaremba</strong></a> (OpenAI Co-Founder) ·
<a href="https://x.com/clementdelangue/status/1830976369389642059"><strong>Clement Delangue</strong></a> (Hugging Face CEO) ·
<a href="https://x.com/gdb/status/1602072566671110144"><strong>Greg Brockman</strong></a> (OpenAI Co-Founder) ·
<a href="https://x.com/woj_zaremba/status/1601362952841760769"><strong>Wojciech Zaremba</strong></a> (OpenAI Co-Founder) ·
<a href="https://x.com/clementdelangue/status/1830976369389642059"><strong>Clement Delangue</strong></a> (Hugging Face CEO) ·
<a href="https://x.com/ashtom/status/1887250944427237816"><strong>Thomas Dohmke</strong></a> (Former GitHub CEO)
</sub>
</p>
@@ -73,7 +73,7 @@ A curated collection of **prompt examples** for AI chat models. Originally creat
Learn prompt engineering with our **free, interactive guide** — 25+ chapters covering everything from basics to advanced techniques like chain-of-thought reasoning, few-shot learning, and AI agents.
**[Start Reading →](https://fka.gumroad.com/l/art-of-chatgpt-prompting)**
**[Start Reading →](https://fka.gumroad.com/l/art-of-chatgpt-prompting)** (Source: https://github.com/f/prompts.chat/tree/main/src/content/book)
---
@@ -238,4 +238,10 @@ Use prompts.chat as an MCP server in your AI tools.
## 📜 License
**[CC0 1.0 Universal (Public Domain)](https://creativecommons.org/publicdomain/zero/1.0/)** — Copy, modify, distribute, and use freely. No attribution required.
This project is dual-licensed:
- **Source code and site-authored content** is licensed under the [MIT License](LICENSE-MIT),
including the interactive book content in [`src/content/book`](src/content/book).
- **Prompt content and data** (prompts.csv, PROMPTS.md, user-submitted prompts) is dedicated to the public domain under [CC0 1.0 Universal](LICENSE-CC0).
See [LICENSE](LICENSE) for details.
+47
View File
@@ -0,0 +1,47 @@
# Security Policy
## Supported Versions
| Version | Supported |
|---------|-----------|
| Latest | Yes |
## Reporting a Vulnerability
If you discover a security vulnerability in prompts.chat, please report it responsibly.
**Do NOT open a public GitHub issue for security vulnerabilities.**
Instead, please report vulnerabilities by emailing **security@prompts.chat**.
Include the following in your report:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)
## CVE Coordination
We coordinate the CVE identification and disclosure process with the GitHub Security team. Confirmed
vulnerabilities will be tracked through GitHub Security Advisories, and CVE IDs will be requested
and assigned as appropriate.
## Scope
The following are **out of scope**:
- Denial of service attacks
- Social engineering
- Issues in third-party dependencies (report these upstream)
- Attacks requiring physical access
## Disclosure Policy
We ask that you give us reasonable time to address the issue before any public disclosure. We are
committed to working with security researchers and will credit reporters (unless anonymity is
preferred) once the issue is resolved.
## Thank You
We appreciate the security research community's efforts in helping keep prompts.chat and its users
safe.
+2 -2
View File
@@ -32,9 +32,9 @@ This guide explains how to deploy **prompts.chat** on your own private server fo
## Prerequisites
- **Node.js** 18+
- **Node.js** 24.x
- **PostgreSQL** database
- **npm** or **yarn**
- **npm**
## Environment Variables
+45
View File
@@ -0,0 +1,45 @@
services:
db:
image: postgres:17-bookworm
restart: unless-stopped
environment:
POSTGRES_USER: prompts
# Change this for production — see Security Considerations in DOCKER.md
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:-prompts}"
POSTGRES_DB: prompts
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U prompts -d prompts"]
interval: 5s
timeout: 5s
retries: 10
start_period: 10s
app:
image: ghcr.io/f/prompts.chat:latest
# To build locally instead of using the pre-built image, comment out
# the 'image' line above and uncomment the build block below:
# build:
# context: .
# dockerfile: docker/Dockerfile
restart: unless-stopped
ports:
- "${PORT:-4444}:3000"
environment:
DATABASE_URL: "postgresql://prompts:${POSTGRES_PASSWORD:-prompts}@db:5432/prompts?schema=public"
DIRECT_URL: "postgresql://prompts:${POSTGRES_PASSWORD:-prompts}@db:5432/prompts?schema=public"
AUTH_SECRET: "${AUTH_SECRET:-}"
NODE_ENV: production
# Branding (all optional — set any PCHAT_* variable to customize at runtime)
# PCHAT_NAME: "My Prompt Library"
# PCHAT_DESCRIPTION: "Our team's AI prompt collection"
# PCHAT_COLOR: "#6366f1"
# PCHAT_AUTH_PROVIDERS: "credentials"
# PCHAT_LOCALES: "en"
depends_on:
db:
condition: service_healthy
volumes:
postgres_data:
+73 -28
View File
@@ -1,49 +1,94 @@
# prompts.chat Bootstrap Docker Image
# Lightweight image that clones and builds on first run
# prompts.chat Docker Image
# Multi-stage build for a production-ready Next.js application
#
# Usage:
# docker run -p 4444:3000 -v prompts-data:/data ghcr.io/f/prompts.chat
# docker run -p 4444:3000 -v prompts-data:/data -e PCHAT_NAME="My App" ghcr.io/f/prompts.chat
# Usage with Docker Compose:
# docker compose up -d
#
# Usage standalone (bring your own PostgreSQL):
# docker build -f docker/Dockerfile -t prompts.chat .
# docker run -p 4444:3000 -e DATABASE_URL="postgresql://..." prompts.chat
FROM node:24-bookworm-slim
# ---- Stage 1: Base ----
FROM node:24-bookworm-slim AS base
RUN apt-get update && apt-get install -y --no-install-recommends \
openssl \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# ---- Stage 2: Dependencies ----
FROM base AS deps
# Copy dependency manifests and Prisma schema (postinstall runs prisma generate)
COPY package.json package-lock.json ./
COPY prisma/schema.prisma prisma/schema.prisma
COPY prisma.config.ts tsconfig.json ./
# Dummy DATABASE_URL for prisma generate (no actual connection is made)
ENV DATABASE_URL="postgresql://dummy:dummy@localhost:5432/dummy"
RUN npm ci
# ---- Stage 3: Builder ----
FROM base AS builder
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
ENV DATABASE_URL="postgresql://dummy:dummy@localhost:5432/dummy"
RUN npm run build
# ---- Stage 4: Runner ----
FROM node:24-bookworm-slim AS runner
LABEL org.opencontainers.image.source="https://github.com/f/prompts.chat"
LABEL org.opencontainers.image.description="prompts.chat - Self-hosted AI prompt library"
LABEL org.opencontainers.image.licenses="MIT"
# Install PostgreSQL, git, and utilities
RUN apt-get update && apt-get install -y --no-install-recommends \
postgresql-15 \
postgresql-contrib-15 \
supervisor \
git \
curl \
openssl \
curl \
ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir -p /var/run/postgresql /var/log/supervisor \
&& chown -R postgres:postgres /var/run/postgresql
&& rm -rf /var/lib/apt/lists/*
# Create directories
WORKDIR /app
RUN mkdir -p /data/postgres /data/app && chown -R postgres:postgres /data/postgres
# Copy bootstrap scripts
COPY docker/bootstrap.sh /bootstrap.sh
COPY docker/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
RUN chmod +x /bootstrap.sh
RUN groupadd --system --gid 1001 nodejs && \
useradd --system --uid 1001 --gid nodejs nextjs
# Copy standalone build output
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
# Copy Prisma schema, migrations, and config for runtime migrations
COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma
COPY --from=builder --chown=nextjs:nodejs /app/prisma.config.ts ./prisma.config.ts
COPY --from=builder --chown=nextjs:nodejs /app/package.json ./package.json
COPY --from=builder --chown=nextjs:nodejs /app/tsconfig.json ./tsconfig.json
# Install only Prisma CLI and its dependencies for runtime migrations
RUN npm install --no-save prisma@6.19 dotenv
# Copy entrypoint script
COPY --chown=nextjs:nodejs docker/entrypoint.sh ./entrypoint.sh
RUN chmod +x ./entrypoint.sh
# Environment defaults
ENV NODE_ENV=production
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
ENV DATABASE_URL="postgresql://prompts:prompts@localhost:5432/prompts?schema=public"
ENV DIRECT_URL="postgresql://prompts:prompts@localhost:5432/prompts?schema=public"
ENV REPO_URL="https://github.com/f/prompts.chat.git"
ENV HOSTNAME=0.0.0.0
ENV NEXT_TELEMETRY_DISABLED=1
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=10s --start-period=180s --retries=3 \
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost:3000/api/health || exit 1
ENTRYPOINT ["/bootstrap.sh"]
USER nextjs
ENTRYPOINT ["./entrypoint.sh"]
-177
View File
@@ -1,177 +0,0 @@
#!/bin/bash
set -e
echo ""
echo "╔═══════════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ 🚀 prompts.chat - AI Prompt Library ║"
echo "║ ║"
echo "╚═══════════════════════════════════════════════════════════════╝"
echo ""
# Paths
APP_DIR="/data/app"
PGDATA="/data/postgres"
PGBIN="/usr/lib/postgresql/15/bin"
BUILD_MARKER="/data/.built"
# Generate AUTH_SECRET if not provided
if [ -z "$AUTH_SECRET" ]; then
if [ -f "/data/.auth_secret" ]; then
export AUTH_SECRET=$(cat /data/.auth_secret)
else
export AUTH_SECRET=$(openssl rand -base64 32)
echo "$AUTH_SECRET" > /data/.auth_secret
echo "⚠ AUTH_SECRET generated and saved"
fi
fi
# Initialize PostgreSQL if needed
if [ ! -f "$PGDATA/PG_VERSION" ]; then
echo "▶ Initializing PostgreSQL..."
su postgres -c "$PGBIN/initdb -D $PGDATA"
cat >> "$PGDATA/postgresql.conf" << EOF
listen_addresses = 'localhost'
port = 5432
max_connections = 100
shared_buffers = 128MB
EOF
cat > "$PGDATA/pg_hba.conf" << EOF
local all all trust
host all all 127.0.0.1/32 trust
host all all ::1/128 trust
EOF
su postgres -c "$PGBIN/pg_ctl -D $PGDATA -l /tmp/pg.log start"
sleep 3
su postgres -c "$PGBIN/createuser -s prompts 2>/dev/null" || true
su postgres -c "$PGBIN/createdb -O prompts prompts 2>/dev/null" || true
su postgres -c "$PGBIN/pg_ctl -D $PGDATA stop"
sleep 2
echo "✓ PostgreSQL initialized"
fi
# Clone and build on first run
if [ ! -f "$BUILD_MARKER" ]; then
echo ""
echo "▶ First run detected - building prompts.chat..."
echo ""
# Clone repository
if [ ! -d "$APP_DIR/.git" ]; then
echo "▶ Cloning repository..."
rm -rf "$APP_DIR"
git clone --depth 1 "$REPO_URL" "$APP_DIR"
echo "✓ Repository cloned"
fi
cd "$APP_DIR"
# Clean up unnecessary files
rm -rf .github .claude packages .git
# Install dependencies (including devDependencies needed for build)
echo "▶ Installing dependencies..."
NODE_ENV=development npm ci
echo "✓ Dependencies installed"
# Run docker-setup.js to generate config with branding
echo "▶ Generating configuration..."
node scripts/docker-setup.js
echo "✓ Configuration generated"
# Generate Prisma client
echo "▶ Generating Prisma client..."
npx prisma generate
echo "✓ Prisma client generated"
# Build Next.js
echo "▶ Building Next.js application (this may take a few minutes)..."
npm run build
echo "✓ Build complete"
# Copy static files for standalone mode
echo "▶ Copying static assets..."
cp -r .next/static .next/standalone/.next/
cp -r public .next/standalone/
echo "✓ Static assets copied"
# Mark as built
touch "$BUILD_MARKER"
echo ""
echo "✅ Build complete! Starting application..."
echo ""
else
echo "✓ Using existing build"
cd "$APP_DIR"
fi
# Start supervisord (manages PostgreSQL and Next.js)
echo "▶ Starting services..."
/usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf &
SUPERVISOR_PID=$!
# Wait for PostgreSQL
echo "▶ Waiting for PostgreSQL..."
for i in $(seq 1 30); do
if $PGBIN/pg_isready -h localhost -p 5432 >/dev/null 2>&1; then
echo "✓ PostgreSQL is ready"
break
fi
if [ $i -eq 30 ]; then
echo "✗ PostgreSQL failed to start"
exit 1
fi
sleep 1
done
# Run migrations
echo "▶ Running database migrations..."
cd "$APP_DIR"
npx prisma migrate deploy
echo "✓ Migrations complete"
# Seed on first run only
SEED_MARKER="/data/.seeded"
if [ ! -f "$SEED_MARKER" ]; then
echo "▶ Seeding database..."
if npx tsx prisma/seed.ts 2>/dev/null; then
touch "$SEED_MARKER"
echo "✓ Database seeded"
else
echo "⚠ Seeding skipped"
fi
fi
# Wait for supervisord socket to be ready
echo "▶ Waiting for supervisord..."
for i in $(seq 1 30); do
if supervisorctl -c /etc/supervisor/conf.d/supervisord.conf status >/dev/null 2>&1; then
echo "✓ Supervisord is ready"
break
fi
if [ $i -eq 30 ]; then
echo "✗ Supervisord failed to start"
exit 1
fi
sleep 1
done
# Start Next.js
echo "▶ Starting Next.js..."
supervisorctl -c /etc/supervisor/conf.d/supervisord.conf start nextjs
echo ""
echo "╔═══════════════════════════════════════════════════════════════╗"
echo "║ ║"
echo "║ ✅ prompts.chat is running! ║"
echo "║ ║"
echo "║ 🌐 Open http://localhost:${PORT:-80} in your browser ║"
echo "║ ║"
echo "╚═══════════════════════════════════════════════════════════════╝"
echo ""
wait $SUPERVISOR_PID
+41
View File
@@ -0,0 +1,41 @@
#!/bin/sh
set -e
# Generate AUTH_SECRET if not provided
if [ -z "$AUTH_SECRET" ]; then
AUTH_SECRET=$(openssl rand -base64 32)
export AUTH_SECRET
echo "[prompts.chat] AUTH_SECRET not set -- generated a random value."
echo "[prompts.chat] Set AUTH_SECRET explicitly for production to persist sessions across restarts."
fi
# Wait for PostgreSQL to be ready
echo "[prompts.chat] Waiting for database..."
MAX_RETRIES=30
RETRY_COUNT=0
until node -e "
const net = require('net');
const url = new URL(process.env.DATABASE_URL);
const sock = net.createConnection({ host: url.hostname, port: url.port || 5432 });
sock.setTimeout(2000);
sock.on('connect', () => { sock.setTimeout(0); sock.destroy(); process.exit(0); });
sock.on('timeout', () => { sock.destroy(); process.exit(1); });
sock.on('error', () => process.exit(1));
" 2>/dev/null; do
RETRY_COUNT=$((RETRY_COUNT + 1))
if [ "$RETRY_COUNT" -ge "$MAX_RETRIES" ]; then
echo "[prompts.chat] ERROR: Database not reachable after ${MAX_RETRIES} attempts."
exit 1
fi
echo "[prompts.chat] Database not ready (attempt ${RETRY_COUNT}/${MAX_RETRIES}), retrying in 2s..."
sleep 2
done
# Run database migrations
echo "[prompts.chat] Running database migrations..."
npx prisma migrate deploy
echo "[prompts.chat] Migrations applied successfully."
# Start the application
echo "[prompts.chat] Starting application on port ${PORT:-3000}..."
exec node server.js
-28
View File
@@ -1,28 +0,0 @@
[supervisord]
nodaemon=true
user=root
logfile=/var/log/supervisor/supervisord.log
pidfile=/var/run/supervisord.pid
childlogdir=/var/log/supervisor
[program:postgresql]
command=/usr/lib/postgresql/15/bin/postgres -D /data/postgres
user=postgres
autostart=true
autorestart=true
priority=10
stdout_logfile=/var/log/supervisor/postgresql.log
stderr_logfile=/var/log/supervisor/postgresql-error.log
[program:nextjs]
command=node /data/app/.next/standalone/server.js
directory=/data/app
user=root
autostart=false
autorestart=true
priority=20
startsecs=10
startretries=3
environment=NODE_ENV="production",PORT="%(ENV_PORT)s",HOSTNAME="0.0.0.0",DATABASE_URL="%(ENV_DATABASE_URL)s",AUTH_SECRET="%(ENV_AUTH_SECRET)s"
stdout_logfile=/var/log/supervisor/nextjs.log
stderr_logfile=/var/log/supervisor/nextjs-error.log
+9 -38
View File
@@ -1030,45 +1030,8 @@
}
},
"heroIndustries": {
"prefix": "أو استكشف حسب المجال",
"clickToExplore": "انقر للاستكشاف",
"searchPlaceholder": "ابحث عن برومبتات...",
"teachers": "المعلمون",
"developers": "المطورون",
"marketers": "المسوقون",
"designers": "المصممون",
"writers": "الكتّاب",
"analysts": "المحللون",
"entrepreneurs": "رواد الأعمال",
"researchers": "الباحثون",
"students": "الطلاب",
"consultants": "المستشارون",
"engineers": "المهندسون",
"creators": "المبدعون",
"lawyers": "المحامون",
"doctors": "الأطباء",
"nurses": "الممرضون",
"accountants": "المحاسبون",
"salespeople": "المبيعات",
"recruiters": "التوظيف",
"managers": "المدراء",
"executives": "التنفيذيون",
"freelancers": "المستقلون",
"photographers": "المصورون",
"musicians": "الموسيقيون",
"artists": "الفنانون",
"architects": "المعماريون",
"scientists": "العلماء",
"journalists": "الصحفيون",
"editors": "المحررون",
"translators": "المترجمون",
"coaches": "المدربون",
"therapists": "المعالجون",
"trainers": "المدربون",
"chefs": "الطهاة",
"realtors": "العقاريون",
"investors": "المستثمرون",
"traders": "المتداولون"
"videoTitle": "GitHub Open Source Friday"
},
"notFound": {
"title": "الصفحة غير موجودة",
@@ -1489,6 +1452,7 @@
"supportNow": "ادعم الآن",
"techStackTitle": "تطور التقنية",
"coreContributorsTitle": "المساهمون الأساسيون",
"securityTitle": "الأمان",
"designCreditsTitle": "التصميم",
"ideationTitle": "الأفكار",
"communityContributorsTitle": "مساهمو المجتمع",
@@ -2263,5 +2227,12 @@
"submit": "إرسال",
"communityExamples": "أمثلة المجتمع",
"userExample": "مثال المستخدم"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1025,45 +1025,8 @@
}
},
"heroIndustries": {
"prefix": "və ya sahəyə görə kəşf edin",
"clickToExplore": "Kəşf etmək üçün klikləyin",
"searchPlaceholder": "Promptları axtar...",
"teachers": "Müəllimlər",
"developers": "Tərtibatçılar",
"marketers": "Marketoloqlar",
"designers": "Dizaynerlər",
"writers": "Yazıçılar",
"analysts": "Analitiklər",
"entrepreneurs": "Sahibkarlar",
"researchers": "Tədqiqatçılar",
"students": "Tələbələr",
"consultants": "Məsləhətçilər",
"engineers": "Mühəndislər",
"creators": "Yaradıcılar",
"lawyers": "Vəkillər",
"doctors": "Həkimlər",
"nurses": "Tibb bacıları",
"accountants": "Mühasiblər",
"salespeople": "Satıcılar",
"recruiters": "İşə götürənlər",
"managers": "Menecerlər",
"executives": "İcraçılar",
"freelancers": "Frilanslər",
"photographers": "Fotoqraflar",
"musicians": "Musiqiçilər",
"artists": "Rəssamlar",
"architects": "Memarlar",
"scientists": "Alimlər",
"journalists": "Jurnalistlər",
"editors": "Redaktorlar",
"translators": "Tərcüməçilər",
"coaches": "Məşqçilər",
"therapists": "Terapevtlər",
"trainers": "Təlimçilər",
"chefs": "Aşpazlar",
"realtors": "Rieltorlar",
"investors": "İnvestorlar",
"traders": "Treyderlər"
"videoTitle": "GitHub Open Source Friday"
},
"promptBuilder": {
"title": "Prompt Qurma Agenti",
@@ -1489,6 +1452,7 @@
"supportNow": "İndi Dəstəklə",
"techStackTitle": "Texnoloji Təkamül",
"coreContributorsTitle": "Əsas Töhfəçilər",
"securityTitle": "Təhlükəsizlik",
"designCreditsTitle": "Dizayn",
"ideationTitle": "İdeya",
"communityContributorsTitle": "İcma Töhfəçiləri",
@@ -2277,5 +2241,12 @@
"submit": "Göndər",
"communityExamples": "İcma Nümunələri",
"userExample": "İstifadəçi nümunəsi"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1030,45 +1030,8 @@
}
},
"heroIndustries": {
"prefix": "oder nach Branche erkunden",
"clickToExplore": "Klicke zum Erkunden",
"searchPlaceholder": "Prompts suchen...",
"teachers": "Lehrer",
"developers": "Entwickler",
"marketers": "Marketer",
"designers": "Designer",
"writers": "Autoren",
"analysts": "Analysten",
"entrepreneurs": "Unternehmer",
"researchers": "Forscher",
"students": "Studenten",
"consultants": "Berater",
"engineers": "Ingenieure",
"creators": "Creator",
"lawyers": "Anwälte",
"doctors": "Ärzte",
"nurses": "Krankenpfleger",
"accountants": "Buchhalter",
"salespeople": "Verkäufer",
"recruiters": "Recruiter",
"managers": "Manager",
"executives": "Führungskräfte",
"freelancers": "Freelancer",
"photographers": "Fotografen",
"musicians": "Musiker",
"artists": "Künstler",
"architects": "Architekten",
"scientists": "Wissenschaftler",
"journalists": "Journalisten",
"editors": "Redakteure",
"translators": "Übersetzer",
"coaches": "Coaches",
"therapists": "Therapeuten",
"trainers": "Trainer",
"chefs": "Köche",
"realtors": "Makler",
"investors": "Investoren",
"traders": "Händler"
"videoTitle": "GitHub Open Source Friday"
},
"notFound": {
"title": "Seite nicht gefunden",
@@ -1489,6 +1452,7 @@
"supportNow": "Jetzt unterstützen",
"techStackTitle": "Technologie-Evolution",
"coreContributorsTitle": "Kern-Mitwirkende",
"securityTitle": "Sicherheit",
"designCreditsTitle": "Design",
"ideationTitle": "Ideenfindung",
"communityContributorsTitle": "Community-Mitwirkende",
@@ -2277,5 +2241,12 @@
"submit": "Absenden",
"communityExamples": "Community-Beispiele",
"userExample": "Benutzerbeispiel"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1051,45 +1051,8 @@
}
},
"heroIndustries": {
"prefix": "ή εξερευνήστε ανά κλάδο",
"clickToExplore": "Κάντε κλικ για εξερεύνηση",
"searchPlaceholder": "Αναζήτηση prompts...",
"teachers": "Εκπαιδευτικούς",
"developers": "Προγραμματιστές",
"marketers": "Μάρκετερ",
"designers": "Σχεδιαστές",
"writers": "Συγγραφείς",
"analysts": "Αναλυτές",
"entrepreneurs": "Επιχειρηματίες",
"researchers": "Ερευνητές",
"students": "Φοιτητές",
"consultants": "Συμβούλους",
"engineers": "Μηχανικούς",
"creators": "Δημιουργούς",
"lawyers": "Δικηγόρους",
"doctors": "Γιατρούς",
"nurses": "Νοσηλευτές",
"accountants": "Λογιστές",
"salespeople": "Πωλητές",
"recruiters": "Recruiters",
"managers": "Διευθυντές",
"executives": "Στελέχη",
"freelancers": "Ελεύθερους",
"photographers": "Φωτογράφους",
"musicians": "Μουσικούς",
"artists": "Καλλιτέχνες",
"architects": "Αρχιτέκτονες",
"scientists": "Επιστήμονες",
"journalists": "Δημοσιογράφους",
"editors": "Συντάκτες",
"translators": "Μεταφραστές",
"coaches": "Προπονητές",
"therapists": "Θεραπευτές",
"trainers": "Εκπαιδευτές",
"chefs": "Σεφ",
"realtors": "Μεσίτες",
"investors": "Επενδυτές",
"traders": "Traders"
"videoTitle": "GitHub Open Source Friday"
},
"promptBuilder": {
"title": "Prompt Building Agent",
@@ -1489,6 +1452,7 @@
"supportNow": "Υποστηρίξτε Τώρα",
"techStackTitle": "Εξέλιξη Τεχνολογίας",
"coreContributorsTitle": "Κύριοι Συνεισφέροντες",
"securityTitle": "Ασφάλεια",
"designCreditsTitle": "Σχεδιασμός",
"ideationTitle": "Ιδέες",
"communityContributorsTitle": "Συνεισφέροντες Κοινότητας",
@@ -2268,5 +2232,12 @@
"submit": "Υποβολή",
"communityExamples": "Παραδείγματα Κοινότητας",
"userExample": "Παράδειγμα Χρήστη"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1025,45 +1025,8 @@
}
},
"heroIndustries": {
"prefix": "or explore by industry",
"clickToExplore": "Click to explore",
"searchPlaceholder": "Search prompts...",
"teachers": "Teachers",
"developers": "Developers",
"marketers": "Marketers",
"designers": "Designers",
"writers": "Writers",
"analysts": "Analysts",
"entrepreneurs": "Entrepreneurs",
"researchers": "Researchers",
"students": "Students",
"consultants": "Consultants",
"engineers": "Engineers",
"creators": "Creators",
"lawyers": "Lawyers",
"doctors": "Doctors",
"nurses": "Nurses",
"accountants": "Accountants",
"salespeople": "Salespeople",
"recruiters": "Recruiters",
"managers": "Managers",
"executives": "Executives",
"freelancers": "Freelancers",
"photographers": "Photographers",
"musicians": "Musicians",
"artists": "Artists",
"architects": "Architects",
"scientists": "Scientists",
"journalists": "Journalists",
"editors": "Editors",
"translators": "Translators",
"coaches": "Coaches",
"therapists": "Therapists",
"trainers": "Trainers",
"chefs": "Chefs",
"realtors": "Realtors",
"investors": "Investors",
"traders": "Traders"
"videoTitle": "GitHub Open Source Friday"
},
"promptBuilder": {
"title": "Prompt Building Agent",
@@ -1489,6 +1452,7 @@
"supportNow": "Support Now",
"techStackTitle": "Tech Evolution",
"coreContributorsTitle": "Core Contributors",
"securityTitle": "Security",
"designCreditsTitle": "Design",
"ideationTitle": "Ideation",
"communityContributorsTitle": "Community Contributors",
@@ -2281,5 +2245,12 @@
"submit": "Submit",
"communityExamples": "Community Examples",
"userExample": "User example"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1030,45 +1030,8 @@
}
},
"heroIndustries": {
"prefix": "o explora por industria",
"clickToExplore": "Haz clic para explorar",
"searchPlaceholder": "Buscar prompts...",
"teachers": "Profesores",
"developers": "Desarrolladores",
"marketers": "Marketers",
"designers": "Diseñadores",
"writers": "Escritores",
"analysts": "Analistas",
"entrepreneurs": "Emprendedores",
"researchers": "Investigadores",
"students": "Estudiantes",
"consultants": "Consultores",
"engineers": "Ingenieros",
"creators": "Creadores",
"lawyers": "Abogados",
"doctors": "Médicos",
"nurses": "Enfermeros",
"accountants": "Contadores",
"salespeople": "Vendedores",
"recruiters": "Reclutadores",
"managers": "Gerentes",
"executives": "Ejecutivos",
"freelancers": "Freelancers",
"photographers": "Fotógrafos",
"musicians": "Músicos",
"artists": "Artistas",
"architects": "Arquitectos",
"scientists": "Científicos",
"journalists": "Periodistas",
"editors": "Editores",
"translators": "Traductores",
"coaches": "Coaches",
"therapists": "Terapeutas",
"trainers": "Entrenadores",
"chefs": "Chefs",
"realtors": "Agentes",
"investors": "Inversores",
"traders": "Traders"
"videoTitle": "GitHub Open Source Friday"
},
"notFound": {
"title": "Página No Encontrada",
@@ -1489,6 +1452,7 @@
"supportNow": "Apoyar Ahora",
"techStackTitle": "Evolución Tecnológica",
"coreContributorsTitle": "Contribuidores Principales",
"securityTitle": "Seguridad",
"designCreditsTitle": "Diseño",
"ideationTitle": "Ideación",
"communityContributorsTitle": "Contribuidores de la Comunidad",
@@ -2280,5 +2244,12 @@
"submit": "Enviar",
"communityExamples": "Ejemplos de la Comunidad",
"userExample": "Ejemplo de usuario"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1025,45 +1025,8 @@
}
},
"heroIndustries": {
"prefix": "یا بر اساس صنعت کاوش کنید",
"clickToExplore": "برای کاوش کلیک کنید",
"searchPlaceholder": "جستجوی پرامپت...",
"teachers": "معلمان",
"developers": "توسعه‌دهندگان",
"marketers": "بازاریابان",
"designers": "طراحان",
"writers": "نویسندگان",
"analysts": "تحلیلگران",
"entrepreneurs": "کارآفرینان",
"researchers": "پژوهشگران",
"students": "دانشجویان",
"consultants": "مشاوران",
"engineers": "مهندسان",
"creators": "خالقان",
"lawyers": "وکلا",
"doctors": "پزشکان",
"nurses": "پرستاران",
"accountants": "حسابداران",
"salespeople": "فروشندگان",
"recruiters": "استخدام‌کنندگان",
"managers": "مدیران",
"executives": "مدیران ارشد",
"freelancers": "فریلنسرها",
"photographers": "عکاسان",
"musicians": "موسیقیدانان",
"artists": "هنرمندان",
"architects": "معماران",
"scientists": "دانشمندان",
"journalists": "روزنامه‌نگاران",
"editors": "ویراستاران",
"translators": "مترجمان",
"coaches": "مربیان",
"therapists": "درمانگران",
"trainers": "آموزش‌دهندگان",
"chefs": "سرآشپزها",
"realtors": "مشاوران املاک",
"investors": "سرمایه‌گذاران",
"traders": "معامله‌گران"
"videoTitle": "GitHub Open Source Friday"
},
"promptBuilder": {
"title": "عامل ساخت پرامپت",
@@ -1489,6 +1452,7 @@
"supportNow": "همین الان حمایت کنید",
"techStackTitle": "تکامل فناوری",
"coreContributorsTitle": "مشارکت‌کنندگان اصلی",
"securityTitle": "امنیت",
"designCreditsTitle": "طراحی",
"ideationTitle": "ایده‌پردازی",
"communityContributorsTitle": "مشارکت‌کنندگان جامعه",
@@ -2261,5 +2225,12 @@
"submit": "ارسال",
"communityExamples": "مثال‌های جامعه",
"userExample": "مثال کاربر"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1030,45 +1030,8 @@
}
},
"heroIndustries": {
"prefix": "ou explorez par secteur",
"clickToExplore": "Cliquez pour explorer",
"searchPlaceholder": "Rechercher des prompts...",
"teachers": "Enseignants",
"developers": "Développeurs",
"marketers": "Marketeurs",
"designers": "Designers",
"writers": "Écrivains",
"analysts": "Analystes",
"entrepreneurs": "Entrepreneurs",
"researchers": "Chercheurs",
"students": "Étudiants",
"consultants": "Consultants",
"engineers": "Ingénieurs",
"creators": "Créateurs",
"lawyers": "Avocats",
"doctors": "Médecins",
"nurses": "Infirmiers",
"accountants": "Comptables",
"salespeople": "Commerciaux",
"recruiters": "Recruteurs",
"managers": "Managers",
"executives": "Dirigeants",
"freelancers": "Freelances",
"photographers": "Photographes",
"musicians": "Musiciens",
"artists": "Artistes",
"architects": "Architectes",
"scientists": "Scientifiques",
"journalists": "Journalistes",
"editors": "Rédacteurs",
"translators": "Traducteurs",
"coaches": "Coachs",
"therapists": "Thérapeutes",
"trainers": "Formateurs",
"chefs": "Chefs",
"realtors": "Agents",
"investors": "Investisseurs",
"traders": "Traders"
"videoTitle": "GitHub Open Source Friday"
},
"notFound": {
"title": "Page Non Trouvée",
@@ -1489,6 +1452,7 @@
"supportNow": "Soutenir Maintenant",
"techStackTitle": "Évolution Technologique",
"coreContributorsTitle": "Contributeurs Principaux",
"securityTitle": "Sécurité",
"designCreditsTitle": "Design",
"ideationTitle": "Idéation",
"communityContributorsTitle": "Contributeurs de la Communauté",
@@ -2280,5 +2244,12 @@
"submit": "Soumettre",
"communityExamples": "Exemples de la Communauté",
"userExample": "Exemple utilisateur"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1051,45 +1051,8 @@
}
},
"heroIndustries": {
"prefix": "או חקור לפי תעשייה",
"clickToExplore": "לחץ לחקירה",
"searchPlaceholder": "חפש פרומפטים...",
"teachers": "מורים",
"developers": "מפתחים",
"marketers": "משווקים",
"designers": "מעצבים",
"writers": "סופרים",
"analysts": "אנליסטים",
"entrepreneurs": "יזמים",
"researchers": "חוקרים",
"students": "סטודנטים",
"consultants": "יועצים",
"engineers": "מהנדסים",
"creators": "יוצרים",
"lawyers": "עורכי דין",
"doctors": "רופאים",
"nurses": "אחיות",
"accountants": "רואי חשבון",
"salespeople": "אנשי מכירות",
"recruiters": "מגייסים",
"managers": "מנהלים",
"executives": "בכירים",
"freelancers": "פרילנסרים",
"photographers": "צלמים",
"musicians": "מוזיקאים",
"artists": "אמנים",
"architects": "אדריכלים",
"scientists": "מדענים",
"journalists": "עיתונאים",
"editors": "עורכים",
"translators": "מתרגמים",
"coaches": "מאמנים",
"therapists": "מטפלים",
"trainers": "מדריכים",
"chefs": "שפים",
"realtors": "סוכני נדל״ן",
"investors": "משקיעים",
"traders": "סוחרים"
"videoTitle": "GitHub Open Source Friday"
},
"promptBuilder": {
"title": "סוכן בניית פרומפטים",
@@ -1489,6 +1452,7 @@
"supportNow": "תמכו עכשיו",
"techStackTitle": "התפתחות טכנולוגית",
"coreContributorsTitle": "תורמים מרכזיים",
"securityTitle": "אבטחה",
"designCreditsTitle": "עיצוב",
"ideationTitle": "רעיונות",
"communityContributorsTitle": "תורמי קהילה",
@@ -2261,5 +2225,12 @@
"submit": "שלח",
"communityExamples": "דוגמאות קהילה",
"userExample": "דוגמת משתמש"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1030,45 +1030,8 @@
}
},
"heroIndustries": {
"prefix": "o esplora per settore",
"clickToExplore": "Clicca per esplorare",
"searchPlaceholder": "Cerca prompt...",
"teachers": "Insegnanti",
"developers": "Sviluppatori",
"marketers": "Marketer",
"designers": "Designer",
"writers": "Scrittori",
"analysts": "Analisti",
"entrepreneurs": "Imprenditori",
"researchers": "Ricercatori",
"students": "Studenti",
"consultants": "Consulenti",
"engineers": "Ingegneri",
"creators": "Creatori",
"lawyers": "Avvocati",
"doctors": "Medici",
"nurses": "Infermieri",
"accountants": "Contabili",
"salespeople": "Venditori",
"recruiters": "Recruiter",
"managers": "Manager",
"executives": "Dirigenti",
"freelancers": "Freelancer",
"photographers": "Fotografi",
"musicians": "Musicisti",
"artists": "Artisti",
"architects": "Architetti",
"scientists": "Scienziati",
"journalists": "Giornalisti",
"editors": "Redattori",
"translators": "Traduttori",
"coaches": "Coach",
"therapists": "Terapeuti",
"trainers": "Formatori",
"chefs": "Chef",
"realtors": "Agenti",
"investors": "Investitori",
"traders": "Trader"
"videoTitle": "GitHub Open Source Friday"
},
"notFound": {
"title": "Pagina Non Trovata",
@@ -1489,6 +1452,7 @@
"supportNow": "Supporta Ora",
"techStackTitle": "Evoluzione Tecnologica",
"coreContributorsTitle": "Contributori Principali",
"securityTitle": "Sicurezza",
"designCreditsTitle": "Design",
"ideationTitle": "Ideazione",
"communityContributorsTitle": "Contributori della Community",
@@ -2283,5 +2247,12 @@
"submit": "Invia",
"communityExamples": "Esempi della Community",
"userExample": "Esempio utente"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1030,45 +1030,8 @@
}
},
"heroIndustries": {
"prefix": "または業種で探す",
"clickToExplore": "クリックして探索",
"searchPlaceholder": "プロンプトを検索...",
"teachers": "教師",
"developers": "開発者",
"marketers": "マーケター",
"designers": "デザイナー",
"writers": "ライター",
"analysts": "アナリスト",
"entrepreneurs": "起業家",
"researchers": "研究者",
"students": "学生",
"consultants": "コンサルタント",
"engineers": "エンジニア",
"creators": "クリエイター",
"lawyers": "弁護士",
"doctors": "医師",
"nurses": "看護師",
"accountants": "会計士",
"salespeople": "営業",
"recruiters": "採用担当",
"managers": "マネージャー",
"executives": "経営者",
"freelancers": "フリーランス",
"photographers": "写真家",
"musicians": "ミュージシャン",
"artists": "アーティスト",
"architects": "建築家",
"scientists": "科学者",
"journalists": "ジャーナリスト",
"editors": "編集者",
"translators": "翻訳者",
"coaches": "コーチ",
"therapists": "セラピスト",
"trainers": "トレーナー",
"chefs": "シェフ",
"realtors": "不動産業者",
"investors": "投資家",
"traders": "トレーダー"
"videoTitle": "GitHub Open Source Friday"
},
"notFound": {
"title": "ページが見つかりません",
@@ -1489,6 +1452,7 @@
"supportNow": "今すぐサポート",
"techStackTitle": "技術スタックの進化",
"coreContributorsTitle": "コアコントリビューター",
"securityTitle": "セキュリティ",
"designCreditsTitle": "デザイン",
"ideationTitle": "アイデア",
"communityContributorsTitle": "コミュニティコントリビューター",
@@ -2265,5 +2229,12 @@
"submit": "送信",
"communityExamples": "コミュニティの例",
"userExample": "ユーザーの例"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1030,45 +1030,8 @@
}
},
"heroIndustries": {
"prefix": "또는 업종별 탐색",
"clickToExplore": "클릭하여 탐색",
"searchPlaceholder": "프롬프트 검색...",
"teachers": "교사",
"developers": "개발자",
"marketers": "마케터",
"designers": "디자이너",
"writers": "작가",
"analysts": "분석가",
"entrepreneurs": "창업가",
"researchers": "연구자",
"students": "학생",
"consultants": "컨설턴트",
"engineers": "엔지니어",
"creators": "크리에이터",
"lawyers": "변호사",
"doctors": "의사",
"nurses": "간호사",
"accountants": "회계사",
"salespeople": "영업사원",
"recruiters": "채용담당자",
"managers": "매니저",
"executives": "임원",
"freelancers": "프리랜서",
"photographers": "사진작가",
"musicians": "음악가",
"artists": "아티스트",
"architects": "건축가",
"scientists": "과학자",
"journalists": "기자",
"editors": "편집자",
"translators": "번역가",
"coaches": "코치",
"therapists": "치료사",
"trainers": "트레이너",
"chefs": "셰프",
"realtors": "부동산",
"investors": "투자자",
"traders": "트레이더"
"videoTitle": "GitHub Open Source Friday"
},
"notFound": {
"title": "페이지를 찾을 수 없습니다",
@@ -1489,6 +1452,7 @@
"supportNow": "지금 후원하기",
"techStackTitle": "기술 스택 진화",
"coreContributorsTitle": "핵심 기여자",
"securityTitle": "보안",
"designCreditsTitle": "디자인",
"ideationTitle": "아이디어",
"communityContributorsTitle": "커뮤니티 기여자",
@@ -2265,5 +2229,12 @@
"submit": "제출",
"communityExamples": "커뮤니티 예제",
"userExample": "사용자 예제"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1025,45 +1025,8 @@
}
},
"heroIndustries": {
"prefix": "of verken per industrie",
"clickToExplore": "Klik om te verkennen",
"searchPlaceholder": "Prompts zoeken...",
"teachers": "Docenten",
"developers": "Ontwikkelaars",
"marketers": "Marketeers",
"designers": "Ontwerpers",
"writers": "Schrijvers",
"analysts": "Analisten",
"entrepreneurs": "Ondernemers",
"researchers": "Onderzoekers",
"students": "Studenten",
"consultants": "Consultants",
"engineers": "Ingenieurs",
"creators": "Creators",
"lawyers": "Advocaten",
"doctors": "Artsen",
"nurses": "Verpleegkundigen",
"accountants": "Accountants",
"salespeople": "Verkopers",
"recruiters": "Recruiters",
"managers": "Managers",
"executives": "Directeuren",
"freelancers": "Freelancers",
"photographers": "Fotografen",
"musicians": "Muzikanten",
"artists": "Kunstenaars",
"architects": "Architecten",
"scientists": "Wetenschappers",
"journalists": "Journalisten",
"editors": "Redacteuren",
"translators": "Vertalers",
"coaches": "Coaches",
"therapists": "Therapeuten",
"trainers": "Trainers",
"chefs": "Chefs",
"realtors": "Makelaars",
"investors": "Investeerders",
"traders": "Handelaren"
"videoTitle": "GitHub Open Source Friday"
},
"promptBuilder": {
"title": "Prompt Building Agent",
@@ -1489,6 +1452,7 @@
"supportNow": "Steun nu",
"techStackTitle": "Tech-evolutie",
"coreContributorsTitle": "Kernbijdragers",
"securityTitle": "Beveiliging",
"designCreditsTitle": "Ontwerp",
"ideationTitle": "Ideeën",
"communityContributorsTitle": "Community-bijdragers",
@@ -2268,5 +2232,12 @@
"submit": "Versturen",
"communityExamples": "Community Voorbeelden",
"userExample": "Gebruikers Voorbeeld"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1030,45 +1030,8 @@
}
},
"heroIndustries": {
"prefix": "ou explore por setor",
"clickToExplore": "Clique para explorar",
"searchPlaceholder": "Pesquisar prompts...",
"teachers": "Professores",
"developers": "Desenvolvedores",
"marketers": "Marketers",
"designers": "Designers",
"writers": "Escritores",
"analysts": "Analistas",
"entrepreneurs": "Empreendedores",
"researchers": "Pesquisadores",
"students": "Estudantes",
"consultants": "Consultores",
"engineers": "Engenheiros",
"creators": "Criadores",
"lawyers": "Advogados",
"doctors": "Médicos",
"nurses": "Enfermeiros",
"accountants": "Contadores",
"salespeople": "Vendedores",
"recruiters": "Recrutadores",
"managers": "Gerentes",
"executives": "Executivos",
"freelancers": "Freelancers",
"photographers": "Fotógrafos",
"musicians": "Músicos",
"artists": "Artistas",
"architects": "Arquitetos",
"scientists": "Cientistas",
"journalists": "Jornalistas",
"editors": "Editores",
"translators": "Tradutores",
"coaches": "Coaches",
"therapists": "Terapeutas",
"trainers": "Treinadores",
"chefs": "Chefs",
"realtors": "Corretores",
"investors": "Investidores",
"traders": "Traders"
"videoTitle": "GitHub Open Source Friday"
},
"notFound": {
"title": "Página Não Encontrada",
@@ -1489,6 +1452,7 @@
"supportNow": "Apoiar Agora",
"techStackTitle": "Evolução Tecnológica",
"coreContributorsTitle": "Contribuidores Principais",
"securityTitle": "Segurança",
"designCreditsTitle": "Design",
"ideationTitle": "Ideação",
"communityContributorsTitle": "Contribuidores da Comunidade",
@@ -2279,5 +2243,12 @@
"submit": "Enviar",
"communityExamples": "Exemplos da Comunidade",
"userExample": "Exemplo do usuário"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1051,45 +1051,8 @@
}
},
"heroIndustries": {
"prefix": "или исследуйте по отрасли",
"clickToExplore": "Нажмите для изучения",
"searchPlaceholder": "Поиск промптов...",
"teachers": "Учителей",
"developers": "Разработчиков",
"marketers": "Маркетологов",
"designers": "Дизайнеров",
"writers": "Писателей",
"analysts": "Аналитиков",
"entrepreneurs": "Предпринимателей",
"researchers": "Исследователей",
"students": "Студентов",
"consultants": "Консультантов",
"engineers": "Инженеров",
"creators": "Создателей",
"lawyers": "Юристов",
"doctors": "Врачей",
"nurses": "Медсестёр",
"accountants": "Бухгалтеров",
"salespeople": "Продавцов",
"recruiters": "Рекрутеров",
"managers": "Менеджеров",
"executives": "Руководителей",
"freelancers": "Фрилансеров",
"photographers": "Фотографов",
"musicians": "Музыкантов",
"artists": "Художников",
"architects": "Архитекторов",
"scientists": "Учёных",
"journalists": "Журналистов",
"editors": "Редакторов",
"translators": "Переводчиков",
"coaches": "Коучей",
"therapists": "Терапевтов",
"trainers": "Тренеров",
"chefs": "Поваров",
"realtors": "Риелторов",
"investors": "Инвесторов",
"traders": "Трейдеров"
"videoTitle": "GitHub Open Source Friday"
},
"promptBuilder": {
"title": "Агент создания промптов",
@@ -1489,6 +1452,7 @@
"supportNow": "Поддержать сейчас",
"techStackTitle": "Эволюция технологий",
"coreContributorsTitle": "Основные участники",
"securityTitle": "Безопасность",
"designCreditsTitle": "Дизайн",
"ideationTitle": "Идеи",
"communityContributorsTitle": "Участники сообщества",
@@ -2262,5 +2226,12 @@
"submit": "Отправить",
"communityExamples": "Примеры сообщества",
"userExample": "Пример пользователя"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1030,45 +1030,8 @@
}
},
"heroIndustries": {
"prefix": "veya sektöre göre keşfet",
"clickToExplore": "Keşfetmek için tıkla",
"searchPlaceholder": "Prompt ara...",
"teachers": "Öğretmenler",
"developers": "Geliştiriciler",
"marketers": "Pazarlamacılar",
"designers": "Tasarımcılar",
"writers": "Yazarlar",
"analysts": "Analistler",
"entrepreneurs": "Girişimciler",
"researchers": "Araştırmacılar",
"students": "Öğrenciler",
"consultants": "Danışmanlar",
"engineers": "Mühendisler",
"creators": "İçerik Üreticileri",
"lawyers": "Avukatlar",
"doctors": "Doktorlar",
"nurses": "Hemşireler",
"accountants": "Muhasebeciler",
"salespeople": "Satışçılar",
"recruiters": "İK Uzmanları",
"managers": "Yöneticiler",
"executives": "Üst Yöneticiler",
"freelancers": "Serbest Çalışanlar",
"photographers": "Fotoğrafçılar",
"musicians": "Müzisyenler",
"artists": "Sanatçılar",
"architects": "Mimarlar",
"scientists": "Bilim İnsanları",
"journalists": "Gazeteciler",
"editors": "Editörler",
"translators": "Çevirmenler",
"coaches": "Koçlar",
"therapists": "Terapistler",
"trainers": "Eğitmenler",
"chefs": "Şefler",
"realtors": "Emlakçılar",
"investors": "Yatırımcılar",
"traders": "Tüccarlar"
"videoTitle": "GitHub Open Source Friday"
},
"notFound": {
"title": "Sayfa Bulunamadı",
@@ -1489,6 +1452,7 @@
"supportNow": "Şimdi Destekle",
"techStackTitle": "Teknoloji Evrimi",
"coreContributorsTitle": "Çekirdek Katkıda Bulunanlar",
"securityTitle": "Güvenlik",
"designCreditsTitle": "Tasarım",
"ideationTitle": "Fikir",
"communityContributorsTitle": "Topluluk Katkıda Bulunanları",
@@ -2276,5 +2240,12 @@
"submit": "Gönder",
"communityExamples": "Topluluk Örnekleri",
"userExample": "Kullanıcı örneği"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+9 -38
View File
@@ -1030,45 +1030,8 @@
}
},
"heroIndustries": {
"prefix": "或按行业探索",
"clickToExplore": "点击探索",
"searchPlaceholder": "搜索提示词...",
"teachers": "教师",
"developers": "开发者",
"marketers": "营销人员",
"designers": "设计师",
"writers": "作家",
"analysts": "分析师",
"entrepreneurs": "创业者",
"researchers": "研究员",
"students": "学生",
"consultants": "顾问",
"engineers": "工程师",
"creators": "创作者",
"lawyers": "律师",
"doctors": "医生",
"nurses": "护士",
"accountants": "会计",
"salespeople": "销售",
"recruiters": "招聘官",
"managers": "经理",
"executives": "高管",
"freelancers": "自由职业者",
"photographers": "摄影师",
"musicians": "音乐家",
"artists": "艺术家",
"architects": "建筑师",
"scientists": "科学家",
"journalists": "记者",
"editors": "编辑",
"translators": "翻译",
"coaches": "教练",
"therapists": "治疗师",
"trainers": "培训师",
"chefs": "厨师",
"realtors": "房产经纪",
"investors": "投资者",
"traders": "交易员"
"videoTitle": "GitHub Open Source Friday"
},
"notFound": {
"title": "页面未找到",
@@ -1489,6 +1452,7 @@
"supportNow": "立即支持",
"techStackTitle": "技术演进",
"coreContributorsTitle": "核心贡献者",
"securityTitle": "安全",
"designCreditsTitle": "设计",
"ideationTitle": "创意",
"communityContributorsTitle": "社区贡献者",
@@ -2265,5 +2229,12 @@
"submit": "提交",
"communityExamples": "社区示例",
"userExample": "用户示例"
},
"selfHosting": {
"prerequisites": {
"nodeJs": "Node.js 24.x",
"postgresql": "PostgreSQL database",
"npm": "npm"
}
}
}
+4 -5
View File
@@ -82,11 +82,10 @@ export default withSentryConfig(withMDX(withNextIntl(nextConfig)), {
// Upload a larger set of source maps for prettier stack traces (increases build time)
widenClientFileUpload: true,
// Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers.
// This can increase your server load as well as your hosting bill.
// Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client-
// side errors will fail.
tunnelRoute: "/monitoring",
// tunnelRoute removed — was proxying all browser Sentry events through Vercel edge,
// generating unnecessary edge requests ($2.45/M) and function invocations ($0.60/M).
// Estimated savings: $100-400/month. Trade-off: some ad-blockers may block direct Sentry calls.
// See: https://github.com/f/prompts.chat/issues/1085
webpack: {
// Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.)
+1 -1
View File
@@ -2375,7 +2375,7 @@ import type {
## Requirements
- **Node.js** 18+
- **Node.js** 24.x
- **TypeScript** 5+ (optional, for type checking)
---
+1 -1
View File
@@ -2,7 +2,7 @@ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
import { homedir } from 'os';
import { join } from 'path';
const PROMPTS_URL = 'https://prompts.chat/prompts.json';
const PROMPTS_URL = 'https://prompts.chat/prompts.json?full_content=true';
const CACHE_DIR = join(homedir(), '.prompts-chat');
const CACHE_FILE = join(CACHE_DIR, 'prompts.json');
@@ -77,7 +77,7 @@ export function PromptDetail({ prompt, onBack, onCopy }: PromptDetailProps) {
const contentHeight = Math.max(terminalHeight - headerLines - footerLines, 5);
useEffect(() => {
const vars = extractVariables(prompt.content);
const vars = extractVariables(prompt.content ?? '');
setVariables(vars);
const defaults: Record<string, string> = {};
@@ -90,7 +90,7 @@ export function PromptDetail({ prompt, onBack, onCopy }: PromptDetailProps) {
const contentLines = useMemo(() => {
if (!prompt) return [];
// Parse escape sequences like \n
const parsedContent = prompt.content.replace(/\\n/g, '\n');
const parsedContent = (prompt.content ?? '').replace(/\\n/g, '\n');
return wrapText(parsedContent, terminalWidth - 6);
}, [prompt, terminalWidth]);
@@ -200,12 +200,12 @@ export function PromptDetail({ prompt, onBack, onCopy }: PromptDetailProps) {
setCurrentVarIndex(0);
setCurrentInput(variableValues[variables[0].name] || '');
} else {
handleCopy(prompt.content);
handleCopy(prompt.content ?? '');
}
}
if (input === 'C' && prompt) {
handleCopy(prompt.content);
handleCopy(prompt.content ?? '');
}
if (input === 'o' && prompt) {
@@ -31,6 +31,7 @@ export const codePlatforms: Platform[] = [
{ id: "goose", name: "Goose", baseUrl: "goose://recipe", isDeeplink: true },
{ id: "github-copilot", name: "GitHub Copilot Chat", baseUrl: "https://github.com/copilot" },
{ id: "github-copilot-agents", name: "GitHub Copilot Agents", baseUrl: "https://github.com/copilot/agents" },
{ id: "netlify", name: "Netlify", baseUrl: "https://app.netlify.com/run" },
{ id: "bolt", name: "Bolt", baseUrl: "https://bolt.new" },
{ id: "lovable", name: "Lovable", baseUrl: "https://lovable.dev" },
{ id: "v0", name: "v0", baseUrl: "https://v0.dev/chat" },
@@ -103,6 +104,8 @@ export function buildUrl(
return `${baseUrl}/?prompt=${encoded}`;
case "lovable":
return `${baseUrl}/?autosubmit=true#prompt=${encoded}`;
case "netlify":
return `${baseUrl}?prompt=${encoded}&ref=prompts-chat`;
case "mistral":
return `${baseUrl}?q=${encoded}`;
case "perplexity":
+8
View File
@@ -192,6 +192,12 @@ export const codePlatforms: Platform[] = [
baseUrl: "https://github.com/copilot",
supportsQuerystring: true,
},
{
id: "netlify",
name: "Netlify",
baseUrl: "https://app.netlify.com/run",
supportsQuerystring: true,
},
{
id: "bolt",
name: "Bolt",
@@ -278,6 +284,8 @@ export function buildUrl(
return `${baseUrl}/?prompt=${encoded}`;
case "lovable":
return `${baseUrl}/?autosubmit=true#prompt=${encoded}`;
case "netlify":
return `${baseUrl}?prompt=${encoded}&ref=prompts-chat`;
case "mistral":
return `${baseUrl}?q=${encoded}`;
case "perplexity":
@@ -0,0 +1,4 @@
-- Add case-insensitive unique indexes to prevent TOCTOU race conditions
-- These ensure the database enforces uniqueness regardless of casing
CREATE UNIQUE INDEX "users_username_ci_unique" ON "users" (LOWER("username"));
CREATE UNIQUE INDEX "users_email_ci_unique" ON "users" (LOWER("email"));
+2
View File
@@ -139,6 +139,8 @@ model Prompt {
@@index([isPrivate])
@@index([isFeatured])
@@index([isUnlisted])
@@index([slug])
@@index([isPrivate, isUnlisted, deletedAt, createdAt(sort: Desc)])
@@map("prompts")
}
+36 -8
View File
@@ -3,14 +3,15 @@ import bcrypt from "bcryptjs";
const prisma = new PrismaClient();
const PROMPTS_JSON_URL = "https://prompts.chat/prompts.json";
const PROMPTS_JSON_URL = "https://prompts.chat/prompts.json?full_content=true";
interface RemotePrompt {
/** Raw shape returned by the remote API — content may be absent. */
interface RemotePromptRaw {
id: string;
title: string;
slug: string;
description: string | null;
content: string;
content?: string;
type: string;
structuredFormat: string | null;
mediaUrl: string | null;
@@ -52,11 +53,20 @@ interface RemotePrompt {
}>;
}
interface RemotePromptsResponse {
count: number;
prompts: RemotePrompt[];
/** Validated prompt with required content field. */
type RemotePrompt = RemotePromptRaw & { content: string };
/** Type guard that narrows a raw API prompt to a validated RemotePrompt. */
function hasContent(prompt: RemotePromptRaw): prompt is RemotePrompt {
return typeof prompt.content === "string" && prompt.content.length > 0;
}
interface RemotePromptsResponse {
count: number;
prompts: RemotePromptRaw[];
}
/** Fetches all prompts from the remote prompts.chat API with full content. */
async function fetchPrompts(): Promise<RemotePromptsResponse> {
console.log(`📡 Fetching prompts from ${PROMPTS_JSON_URL}...`);
const response = await fetch(PROMPTS_JSON_URL);
@@ -68,12 +78,13 @@ async function fetchPrompts(): Promise<RemotePromptsResponse> {
return data;
}
/** Seeds the database with users, categories, tags, and prompts from prompts.chat. */
async function main() {
console.log("🌱 Seeding database from prompts.chat...");
// Create admin user for assigning prompts
const password = await bcrypt.hash("password123", 12);
const admin = await prisma.user.upsert({
where: { email: "admin@prompts.chat" },
update: {},
@@ -174,7 +185,7 @@ async function main() {
userIdMap.set(username, admin.id);
continue;
}
const user = await prisma.user.upsert({
where: { username },
update: { name: author.name, avatar: author.avatar },
@@ -225,6 +236,13 @@ async function main() {
};
const structuredFormat = remotePrompt.structuredFormat ? formatMap[remotePrompt.structuredFormat] : null;
// Skip prompts without content
if (!hasContent(remotePrompt)) {
console.warn(`⚠ Skipping prompt "${remotePrompt.title}" - no content`);
promptsSkipped++;
continue;
}
// Check if prompt already exists
const existingPrompt = await prisma.prompt.findFirst({
where: { slug: remotePrompt.slug },
@@ -280,6 +298,16 @@ async function main() {
}
console.log(`✅ Created ${promptsCreated} prompts (${promptsSkipped} skipped)`);
// Fail-fast if no prompts were created — likely an upstream API regression
const total = promptsCreated + promptsSkipped;
if (total > 0 && promptsCreated === 0) {
throw new Error(
`Seeding failed: 0 prompts created out of ${total} (${promptsSkipped} skipped). ` +
`This likely indicates an upstream API regression — check that ${PROMPTS_JSON_URL} returns content.`
);
}
console.log("\n🎉 Seeding complete!");
console.log("\n📋 Test credentials (password: password123):");
console.log(" Admin: admin@prompts.chat");
+4 -4
View File
@@ -33,7 +33,7 @@ export default defineConfig({
// Authentication plugins
auth: {
// Available: "credentials" | "google" | "azure" | "github" | "apple" | custom
// Available: "credentials" | "google" | "azure" | "github" | "apple" | "oidc" | "oauth" | custom
// Use `providers` array to enable multiple auth providers
providers: ["github", "google", "apple"],
// Allow public registration (only applies to credentials provider)
@@ -57,11 +57,11 @@ export default defineConfig({
// Enable tags
tags: true,
// Enable AI-powered semantic search (requires OPENAI_API_KEY)
aiSearch: false,
aiSearch: true,
// Enable AI-powered generation features (requires OPENAI_API_KEY)
aiGeneration: false,
aiGeneration: true,
// Enable MCP (Model Context Protocol) features including API key generation
mcp: false,
mcp: true,
// Enable comments on prompts
comments: true,
},
+27543 -1224
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 319 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

+44
View File
@@ -0,0 +1,44 @@
<svg width="240" height="24" viewBox="0 0 240 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.4283 0.610352L26.8565 23.8046H0L13.4283 0.610352Z" fill="#fff"/>
<path d="M236.436 22.7547L235.081 17.1148V23.8045H233.849V15.1372H235.557L236.924 20.7405L238.291 15.1372H240V23.8045H238.767V17.1148L237.412 22.7547H236.436Z" fill="#fff"/>
<path d="M226.237 23.8045L228.776 15.1372H230.436L232.974 23.8045H231.644L231.022 21.5462H228.19L227.568 23.8045H226.237ZM229.606 16.4678L228.52 20.362H230.692L229.606 16.4678Z" fill="#fff"/>
<path d="M219.444 23.8045V15.1372H222.142C223.972 15.1372 225.095 16.126 225.095 17.7252C225.095 18.7628 224.436 19.5197 223.631 19.7761C224.485 19.9348 224.9 20.4109 224.973 21.3386L225.193 23.8045H223.911L223.716 21.5828C223.643 20.716 223.301 20.4231 222.239 20.4231H220.726V23.8045H219.444ZM220.726 19.2267H222.117C223.179 19.2267 223.777 18.7018 223.777 17.7862C223.777 16.8585 223.179 16.3458 222.117 16.3458H220.726V19.2267Z" fill="#fff"/>
<path d="M214.957 23.9999C213.09 23.9999 211.748 22.4251 211.748 19.4831C211.748 16.6876 212.956 14.9419 214.994 14.9419C216.63 14.9419 217.704 16.0772 218.082 17.8107L216.752 17.8961C216.508 16.8341 215.934 16.1504 215.006 16.1504C213.774 16.1504 213.078 17.3468 213.078 19.4831C213.078 21.6072 213.798 22.7913 215.067 22.7913C216.178 22.7913 216.861 21.8758 216.91 20.4963H215.006V19.3854H218.094V23.8045H217.057L217.02 22.6937C216.642 23.4749 215.983 23.9999 214.957 23.9999Z" fill="#fff"/>
<path d="M207.651 23.9999C205.589 23.9999 204.429 22.3763 204.429 19.4831C204.429 16.5655 205.589 14.9419 207.651 14.9419C209.714 14.9419 210.873 16.5655 210.873 19.4831C210.873 22.3763 209.714 23.9999 207.651 23.9999ZM207.651 22.8035C208.872 22.8035 209.543 21.6804 209.543 19.4831C209.543 17.2857 208.872 16.1382 207.651 16.1382C206.431 16.1382 205.76 17.2857 205.76 19.4831C205.76 21.6804 206.431 22.8035 207.651 22.8035Z" fill="#fff"/>
<path d="M197.489 23.8045V15.1372H200.187C202.017 15.1372 203.14 16.126 203.14 17.7252C203.14 18.7628 202.481 19.5197 201.676 19.7761C202.53 19.9348 202.945 20.4109 203.018 21.3386L203.238 23.8045H201.956L201.761 21.5828C201.688 20.716 201.346 20.4231 200.284 20.4231H198.771V23.8045H197.489ZM198.771 19.2267H200.162C201.224 19.2267 201.822 18.7018 201.822 17.7862C201.822 16.8585 201.224 16.3458 200.162 16.3458H198.771V19.2267Z" fill="#fff"/>
<path d="M190.403 23.8045V15.1372H193.088C194.894 15.1372 196.09 16.1626 196.09 17.8351C196.09 19.4953 194.894 20.5207 193.088 20.5207H191.684V23.8045H190.403ZM191.684 19.3122H192.954C194.186 19.3122 194.76 18.7995 194.76 17.8351C194.76 16.8707 194.186 16.3458 192.954 16.3458H191.684V19.3122Z" fill="#fff"/>
<path d="M175.791 23.8045V15.1372H181.112V16.3458H177.073V18.8727H180.966V20.0446H177.073V22.596H181.21V23.8045H175.791Z" fill="#fff"/>
<path d="M168.216 23.8045V15.1372H170.914C172.744 15.1372 173.867 16.126 173.867 17.7252C173.867 18.7628 173.208 19.5197 172.403 19.7761C173.257 19.9348 173.672 20.4109 173.745 21.3386L173.965 23.8045H172.683L172.488 21.5828C172.415 20.716 172.073 20.4231 171.011 20.4231H169.498V23.8045H168.216ZM169.498 19.2267H170.889C171.951 19.2267 172.549 18.7018 172.549 17.7862C172.549 16.8585 171.951 16.3458 170.889 16.3458H169.498V19.2267Z" fill="#fff"/>
<path d="M160.374 23.8045L162.912 15.1372H164.572L167.111 23.8045H165.78L165.158 21.5462H162.326L161.704 23.8045H160.374ZM163.742 16.4678L162.656 20.362H164.828L163.742 16.4678Z" fill="#fff"/>
<path d="M154.032 23.8045L153.104 15.1372H154.386L155.045 22.1565L155.862 16.1138H156.985L157.803 22.1565L158.462 15.1372H159.744L158.816 23.8045H157.144L156.424 18.5309L155.704 23.8045H154.032Z" fill="#fff"/>
<path d="M148.471 23.8045V16.3458H145.932V15.1372H152.279V16.3458H149.74V23.8045H148.471Z" fill="#fff"/>
<path d="M139.322 23.8045V15.1372H144.741V16.3213H140.604V18.9826H144.522V20.1545H140.604V23.8045H139.322Z" fill="#fff"/>
<path d="M134.469 23.9999C132.407 23.9999 131.247 22.3763 131.247 19.4831C131.247 16.5655 132.407 14.9419 134.469 14.9419C136.532 14.9419 137.691 16.5655 137.691 19.4831C137.691 22.3763 136.532 23.9999 134.469 23.9999ZM134.469 22.8035C135.69 22.8035 136.361 21.6804 136.361 19.4831C136.361 17.2857 135.69 16.1382 134.469 16.1382C133.249 16.1382 132.577 17.2857 132.577 19.4831C132.577 21.6804 133.249 22.8035 134.469 22.8035Z" fill="#fff"/>
<path d="M127.261 23.9999C125.381 23.9999 124.161 22.8035 124.014 20.9846L125.332 20.8992C125.503 22.1443 126.211 22.8035 127.31 22.8035C128.371 22.8035 128.969 22.3763 128.969 21.6072C128.969 20.8381 128.554 20.3987 126.736 19.8859C124.954 19.3976 124.209 18.7995 124.209 17.4566C124.209 15.9673 125.308 14.9419 127.126 14.9419C128.933 14.9419 129.97 16.0772 130.141 17.7496L128.823 17.8229C128.689 16.8219 128.127 16.1382 127.09 16.1382C126.138 16.1382 125.528 16.6387 125.528 17.3956C125.528 18.1525 125.955 18.4332 127.493 18.8605C129.567 19.4221 130.288 20.1911 130.288 21.6072C130.288 23.0355 129.079 23.9999 127.261 23.9999Z" fill="#fff"/>
<path d="M109.927 23.8045V15.1372H115.248V16.3458H111.208V18.8727H115.102V20.0446H111.208V22.596H115.346V23.8045H109.927Z" fill="#fff"/>
<path d="M105.232 23.9999C103.145 23.9999 101.974 22.2664 101.974 19.4831C101.974 16.6876 103.145 14.9419 105.232 14.9419C106.807 14.9419 107.942 16.0284 108.296 17.9083L106.953 17.9816C106.709 16.773 106.05 16.1382 105.232 16.1382C103.975 16.1382 103.304 17.3468 103.304 19.4831C103.304 21.6072 103.975 22.8035 105.232 22.8035C106.123 22.8035 106.795 22.1077 107.014 20.7893L108.345 20.8503C108.04 22.8279 106.892 23.9999 105.232 23.9999Z" fill="#fff"/>
<path d="M95.0342 23.8045V15.1372H97.7315C99.5622 15.1372 100.685 16.126 100.685 17.7252C100.685 18.7628 100.026 19.5197 99.2205 19.7761C100.075 19.9348 100.49 20.4109 100.563 21.3386L100.783 23.8045H99.5012L99.3059 21.5828C99.2327 20.716 98.891 20.4231 97.8291 20.4231H96.3157V23.8045H95.0342ZM96.3157 19.2267H97.7071C98.7689 19.2267 99.367 18.7018 99.367 17.7862C99.367 16.8585 98.7689 16.3458 97.7071 16.3458H96.3157V19.2267Z" fill="#fff"/>
<path d="M90.5596 23.9999C88.7166 23.9999 87.606 22.8035 87.606 20.7893V15.1372H88.8875V20.8381C88.8875 22.1077 89.4733 22.8035 90.5596 22.8035C91.6458 22.8035 92.2317 22.1077 92.2317 20.8381V15.1372H93.5132V20.7893C93.5132 22.8035 92.4025 23.9999 90.5596 23.9999Z" fill="#fff"/>
<path d="M83.2417 23.9999C81.179 23.9999 80.0195 22.3763 80.0195 19.4831C80.0195 16.5655 81.179 14.9419 83.2417 14.9419C85.3043 14.9419 86.4638 16.5655 86.4638 19.4831C86.4638 22.3763 85.3043 23.9999 83.2417 23.9999ZM83.2417 22.8035C84.4622 22.8035 85.1334 21.6804 85.1334 19.4831C85.1334 17.2857 84.4622 16.1382 83.2417 16.1382C82.0212 16.1382 81.3499 17.2857 81.3499 19.4831C81.3499 21.6804 82.0212 22.8035 83.2417 22.8035Z" fill="#fff"/>
<path d="M76.0332 23.9999C74.1536 23.9999 72.9331 22.8035 72.7866 20.9846L74.1048 20.8992C74.2756 22.1443 74.9835 22.8035 76.082 22.8035C77.1438 22.8035 77.7419 22.3763 77.7419 21.6072C77.7419 20.8381 77.3269 20.3987 75.5083 19.8859C73.7264 19.3976 72.9819 18.7995 72.9819 17.4566C72.9819 15.9673 74.0804 14.9419 75.8989 14.9419C77.7052 14.9419 78.7427 16.0772 78.9135 17.7496L77.5954 17.8229C77.4611 16.8219 76.8997 16.1382 75.8623 16.1382C74.9103 16.1382 74.3 16.6387 74.3 17.3956C74.3 18.1525 74.7272 18.4332 76.265 18.8605C78.3399 19.4221 79.06 20.1911 79.06 21.6072C79.06 23.0355 77.8517 23.9999 76.0332 23.9999Z" fill="#fff"/>
<path d="M58.4556 23.8045V15.1372H60.0178L62.8616 21.9856V15.1372H64.1187V23.8045H62.5564L59.7127 16.9561V23.8045H58.4556Z" fill="#fff"/>
<path d="M51.3813 23.8045V15.1372H56.7027V16.3458H52.6629V18.8727H56.5563V20.0446H52.6629V22.596H56.8004V23.8045H51.3813Z" fill="#fff"/>
<path d="M44.0386 23.8045V15.1372H46.7237C48.53 15.1372 49.7261 16.1626 49.7261 17.8351C49.7261 19.4953 48.53 20.5207 46.7237 20.5207H45.3201V23.8045H44.0386ZM45.3201 19.3122H46.5894C47.8221 19.3122 48.3958 18.7995 48.3958 17.8351C48.3958 16.8707 47.8221 16.3458 46.5894 16.3458H45.3201V19.3122Z" fill="#fff"/>
<path d="M39.332 23.9999C37.2693 23.9999 36.1099 22.3763 36.1099 19.4831C36.1099 16.5655 37.2693 14.9419 39.332 14.9419C41.3946 14.9419 42.5541 16.5655 42.5541 19.4831C42.5541 22.3763 41.3946 23.9999 39.332 23.9999ZM39.332 22.8035C40.5525 22.8035 41.2238 21.6804 41.2238 19.4831C41.2238 17.2857 40.5525 16.1382 39.332 16.1382C38.1115 16.1382 37.4402 17.2857 37.4402 19.4831C37.4402 21.6804 38.1115 22.8035 39.332 22.8035Z" fill="#fff"/>
<path d="M171.085 9.35094C169.083 9.35094 167.96 7.95929 167.96 5.46895C167.96 2.60019 168.864 0.292969 171.414 0.292969C173.013 0.292969 173.819 1.1597 174.148 2.38045L172.83 2.49032C172.659 1.89215 172.269 1.48931 171.414 1.48931C170.243 1.48931 169.474 2.36825 169.303 4.2482C169.718 3.71107 170.426 3.32043 171.329 3.32043C173.05 3.32043 174.161 4.48015 174.161 6.25024C174.161 8.16681 172.916 9.35094 171.085 9.35094ZM171.085 8.1424C172.147 8.1424 172.83 7.45878 172.83 6.27465C172.83 5.17597 172.196 4.48015 171.183 4.48015C170.096 4.48015 169.315 5.17597 169.315 6.27465C169.315 7.34891 169.999 8.1424 171.085 8.1424Z" fill="#fff" fill-opacity="0.5"/>
<path d="M160.667 9.15562C160.667 7.22684 161.387 6.01829 163.925 4.67547C165.011 4.10171 165.475 3.72328 165.475 2.88096C165.475 2.05085 164.95 1.48931 163.937 1.48931C162.827 1.48931 162.217 2.09968 162.046 3.18615L160.715 3.1007C160.898 1.37944 162.021 0.292969 163.937 0.292969C165.78 0.292969 166.806 1.3184 166.806 2.83213C166.806 4.17496 166.22 4.83416 164.45 5.78635C162.949 6.59205 162.241 7.36112 162.192 7.94708H166.818V9.15562H160.667Z" fill="#fff" fill-opacity="0.5"/>
<path d="M156.424 9.35094C154.508 9.35094 153.348 7.61748 153.348 4.83416C153.348 2.03864 154.508 0.292969 156.424 0.292969C158.34 0.292969 159.499 2.03864 159.499 4.83416C159.499 7.61748 158.34 9.35094 156.424 9.35094ZM154.678 4.83416C154.678 5.55441 154.752 6.1892 154.91 6.68971L157.449 1.98981C157.181 1.66021 156.827 1.48931 156.424 1.48931C155.338 1.48931 154.678 2.72226 154.678 4.83416ZM156.424 8.15461C157.51 8.15461 158.169 6.92165 158.169 4.83416C158.169 4.10171 158.096 3.46692 157.937 2.96641L155.386 7.6541C155.667 7.9837 156.021 8.15461 156.424 8.15461Z" fill="#fff" fill-opacity="0.5"/>
<path d="M146.03 9.15562C146.03 7.22684 146.75 6.01829 149.289 4.67547C150.375 4.10171 150.839 3.72328 150.839 2.88096C150.839 2.05085 150.314 1.48931 149.301 1.48931C148.19 1.48931 147.58 2.09968 147.409 3.18615L146.079 3.1007C146.262 1.37944 147.385 0.292969 149.301 0.292969C151.144 0.292969 152.169 1.3184 152.169 2.83213C152.169 4.17496 151.583 4.83416 149.813 5.78635C148.312 6.59205 147.604 7.36112 147.555 7.94708H152.181V9.15562H146.03Z" fill="#fff" fill-opacity="0.5"/>
<path d="M132.041 10.4985L135.727 0H136.899L133.212 10.4985H132.041Z" fill="#fff" fill-opacity="0.5"/>
<path d="M124.722 10.4985L128.409 0H129.581L125.894 10.4985H124.722Z" fill="#fff" fill-opacity="0.5"/>
<path d="M111.684 9.15582V7.54443H113.344V9.15582H111.684Z" fill="#fff"/>
<path d="M105.232 9.35094C103.145 9.35094 101.974 7.61748 101.974 4.83416C101.974 2.03864 103.145 0.292969 105.232 0.292969C106.807 0.292969 107.942 1.37944 108.296 3.25939L106.953 3.33264C106.709 2.1241 106.05 1.48931 105.232 1.48931C103.975 1.48931 103.304 2.69785 103.304 4.83416C103.304 6.95827 103.975 8.15461 105.232 8.15461C106.123 8.15461 106.795 7.45878 107.014 6.14037L108.345 6.20141C108.04 8.17902 106.892 9.35094 105.232 9.35094Z" fill="#fff"/>
<path d="M95.0464 9.15562V0.488281H96.6086L99.4524 7.3367V0.488281H100.71V9.15562H99.1473L96.3035 2.3072V9.15562H95.0464Z" fill="#fff"/>
<path d="M87.8501 9.15562V7.94707H89.9249V1.69683H87.8501V0.488281H93.2691V1.69683H91.1943V7.94707H93.2691V9.15562H87.8501Z" fill="#fff"/>
<path d="M73.4575 9.15562V0.488281H74.739V7.94707H78.8765V9.15562H73.4575Z" fill="#fff"/>
<path d="M66.0171 9.15562V0.488281H71.3385V1.69683H67.2986V4.22378H71.192V5.3957H67.2986V7.94707H71.4361V9.15562H66.0171Z" fill="#fff"/>
<path d="M61.3232 9.35094C59.2361 9.35094 58.0645 7.61748 58.0645 4.83416C58.0645 2.03864 59.2361 0.292969 61.3232 0.292969C62.8976 0.292969 64.0327 1.37944 64.3866 3.25939L63.0441 3.33264C62.8 2.1241 62.1409 1.48931 61.3232 1.48931C60.0661 1.48931 59.3948 2.69785 59.3948 4.83416C59.3948 6.95827 60.0661 8.15461 61.3232 8.15461C62.2142 8.15461 62.8854 7.45878 63.1051 6.14037L64.4355 6.20141C64.1303 8.17902 62.9831 9.35094 61.3232 9.35094Z" fill="#fff"/>
<path d="M51.125 9.15562V0.488281H53.8223C55.6531 0.488281 56.7759 1.47709 56.7759 3.07627C56.7759 4.11391 56.1168 4.87078 55.3113 5.12714C56.1657 5.28583 56.5806 5.76193 56.6539 6.6897L56.8736 9.15562H55.592L55.3968 6.93385C55.3235 6.06711 54.9818 5.77413 53.9199 5.77413H52.4065V9.15562H51.125ZM52.4065 4.5778H53.7979C54.8597 4.5778 55.4578 4.05288 55.4578 3.13731C55.4578 2.20954 54.8597 1.69683 53.7979 1.69683H52.4065V4.5778Z" fill="#fff"/>
<path d="M44.063 9.15562V0.488281H49.3844V1.69683H45.3445V4.22378H49.2379V5.3957H45.3445V7.94707H49.482V9.15562H44.063Z" fill="#fff"/>
<path d="M38.5753 9.15562L36 0.488281H37.3548L39.332 7.44656L41.3092 0.488281H42.6639L40.0887 9.15562H38.5753Z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

+44
View File
@@ -0,0 +1,44 @@
<svg width="240" height="24" viewBox="0 0 240 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13.4283 0.610352L26.8565 23.8046H0L13.4283 0.610352Z" fill="#000"/>
<path d="M236.436 22.7547L235.081 17.1148V23.8045H233.849V15.1372H235.557L236.924 20.7405L238.291 15.1372H240V23.8045H238.767V17.1148L237.412 22.7547H236.436Z" fill="#000"/>
<path d="M226.237 23.8045L228.776 15.1372H230.436L232.974 23.8045H231.644L231.022 21.5462H228.19L227.568 23.8045H226.237ZM229.606 16.4678L228.52 20.362H230.692L229.606 16.4678Z" fill="#000"/>
<path d="M219.444 23.8045V15.1372H222.142C223.972 15.1372 225.095 16.126 225.095 17.7252C225.095 18.7628 224.436 19.5197 223.631 19.7761C224.485 19.9348 224.9 20.4109 224.973 21.3386L225.193 23.8045H223.911L223.716 21.5828C223.643 20.716 223.301 20.4231 222.239 20.4231H220.726V23.8045H219.444ZM220.726 19.2267H222.117C223.179 19.2267 223.777 18.7018 223.777 17.7862C223.777 16.8585 223.179 16.3458 222.117 16.3458H220.726V19.2267Z" fill="#000"/>
<path d="M214.957 23.9999C213.09 23.9999 211.748 22.4251 211.748 19.4831C211.748 16.6876 212.956 14.9419 214.994 14.9419C216.63 14.9419 217.704 16.0772 218.082 17.8107L216.752 17.8961C216.508 16.8341 215.934 16.1504 215.006 16.1504C213.774 16.1504 213.078 17.3468 213.078 19.4831C213.078 21.6072 213.798 22.7913 215.067 22.7913C216.178 22.7913 216.861 21.8758 216.91 20.4963H215.006V19.3854H218.094V23.8045H217.057L217.02 22.6937C216.642 23.4749 215.983 23.9999 214.957 23.9999Z" fill="#000"/>
<path d="M207.651 23.9999C205.589 23.9999 204.429 22.3763 204.429 19.4831C204.429 16.5655 205.589 14.9419 207.651 14.9419C209.714 14.9419 210.873 16.5655 210.873 19.4831C210.873 22.3763 209.714 23.9999 207.651 23.9999ZM207.651 22.8035C208.872 22.8035 209.543 21.6804 209.543 19.4831C209.543 17.2857 208.872 16.1382 207.651 16.1382C206.431 16.1382 205.76 17.2857 205.76 19.4831C205.76 21.6804 206.431 22.8035 207.651 22.8035Z" fill="#000"/>
<path d="M197.489 23.8045V15.1372H200.187C202.017 15.1372 203.14 16.126 203.14 17.7252C203.14 18.7628 202.481 19.5197 201.676 19.7761C202.53 19.9348 202.945 20.4109 203.018 21.3386L203.238 23.8045H201.956L201.761 21.5828C201.688 20.716 201.346 20.4231 200.284 20.4231H198.771V23.8045H197.489ZM198.771 19.2267H200.162C201.224 19.2267 201.822 18.7018 201.822 17.7862C201.822 16.8585 201.224 16.3458 200.162 16.3458H198.771V19.2267Z" fill="#000"/>
<path d="M190.403 23.8045V15.1372H193.088C194.894 15.1372 196.09 16.1626 196.09 17.8351C196.09 19.4953 194.894 20.5207 193.088 20.5207H191.684V23.8045H190.403ZM191.684 19.3122H192.954C194.186 19.3122 194.76 18.7995 194.76 17.8351C194.76 16.8707 194.186 16.3458 192.954 16.3458H191.684V19.3122Z" fill="#000"/>
<path d="M175.791 23.8045V15.1372H181.112V16.3458H177.073V18.8727H180.966V20.0446H177.073V22.596H181.21V23.8045H175.791Z" fill="#000"/>
<path d="M168.216 23.8045V15.1372H170.914C172.744 15.1372 173.867 16.126 173.867 17.7252C173.867 18.7628 173.208 19.5197 172.403 19.7761C173.257 19.9348 173.672 20.4109 173.745 21.3386L173.965 23.8045H172.683L172.488 21.5828C172.415 20.716 172.073 20.4231 171.011 20.4231H169.498V23.8045H168.216ZM169.498 19.2267H170.889C171.951 19.2267 172.549 18.7018 172.549 17.7862C172.549 16.8585 171.951 16.3458 170.889 16.3458H169.498V19.2267Z" fill="#000"/>
<path d="M160.374 23.8045L162.912 15.1372H164.572L167.111 23.8045H165.78L165.158 21.5462H162.326L161.704 23.8045H160.374ZM163.742 16.4678L162.656 20.362H164.828L163.742 16.4678Z" fill="#000"/>
<path d="M154.032 23.8045L153.104 15.1372H154.386L155.045 22.1565L155.862 16.1138H156.985L157.803 22.1565L158.462 15.1372H159.744L158.816 23.8045H157.144L156.424 18.5309L155.704 23.8045H154.032Z" fill="#000"/>
<path d="M148.471 23.8045V16.3458H145.932V15.1372H152.279V16.3458H149.74V23.8045H148.471Z" fill="#000"/>
<path d="M139.322 23.8045V15.1372H144.741V16.3213H140.604V18.9826H144.522V20.1545H140.604V23.8045H139.322Z" fill="#000"/>
<path d="M134.469 23.9999C132.407 23.9999 131.247 22.3763 131.247 19.4831C131.247 16.5655 132.407 14.9419 134.469 14.9419C136.532 14.9419 137.691 16.5655 137.691 19.4831C137.691 22.3763 136.532 23.9999 134.469 23.9999ZM134.469 22.8035C135.69 22.8035 136.361 21.6804 136.361 19.4831C136.361 17.2857 135.69 16.1382 134.469 16.1382C133.249 16.1382 132.577 17.2857 132.577 19.4831C132.577 21.6804 133.249 22.8035 134.469 22.8035Z" fill="#000"/>
<path d="M127.261 23.9999C125.381 23.9999 124.161 22.8035 124.014 20.9846L125.332 20.8992C125.503 22.1443 126.211 22.8035 127.31 22.8035C128.371 22.8035 128.969 22.3763 128.969 21.6072C128.969 20.8381 128.554 20.3987 126.736 19.8859C124.954 19.3976 124.209 18.7995 124.209 17.4566C124.209 15.9673 125.308 14.9419 127.126 14.9419C128.933 14.9419 129.97 16.0772 130.141 17.7496L128.823 17.8229C128.689 16.8219 128.127 16.1382 127.09 16.1382C126.138 16.1382 125.528 16.6387 125.528 17.3956C125.528 18.1525 125.955 18.4332 127.493 18.8605C129.567 19.4221 130.288 20.1911 130.288 21.6072C130.288 23.0355 129.079 23.9999 127.261 23.9999Z" fill="#000"/>
<path d="M109.927 23.8045V15.1372H115.248V16.3458H111.208V18.8727H115.102V20.0446H111.208V22.596H115.346V23.8045H109.927Z" fill="#000"/>
<path d="M105.232 23.9999C103.145 23.9999 101.974 22.2664 101.974 19.4831C101.974 16.6876 103.145 14.9419 105.232 14.9419C106.807 14.9419 107.942 16.0284 108.296 17.9083L106.953 17.9816C106.709 16.773 106.05 16.1382 105.232 16.1382C103.975 16.1382 103.304 17.3468 103.304 19.4831C103.304 21.6072 103.975 22.8035 105.232 22.8035C106.123 22.8035 106.795 22.1077 107.014 20.7893L108.345 20.8503C108.04 22.8279 106.892 23.9999 105.232 23.9999Z" fill="#000"/>
<path d="M95.0342 23.8045V15.1372H97.7315C99.5622 15.1372 100.685 16.126 100.685 17.7252C100.685 18.7628 100.026 19.5197 99.2205 19.7761C100.075 19.9348 100.49 20.4109 100.563 21.3386L100.783 23.8045H99.5012L99.3059 21.5828C99.2327 20.716 98.891 20.4231 97.8291 20.4231H96.3157V23.8045H95.0342ZM96.3157 19.2267H97.7071C98.7689 19.2267 99.367 18.7018 99.367 17.7862C99.367 16.8585 98.7689 16.3458 97.7071 16.3458H96.3157V19.2267Z" fill="#000"/>
<path d="M90.5596 23.9999C88.7166 23.9999 87.606 22.8035 87.606 20.7893V15.1372H88.8875V20.8381C88.8875 22.1077 89.4733 22.8035 90.5596 22.8035C91.6458 22.8035 92.2317 22.1077 92.2317 20.8381V15.1372H93.5132V20.7893C93.5132 22.8035 92.4025 23.9999 90.5596 23.9999Z" fill="#000"/>
<path d="M83.2417 23.9999C81.179 23.9999 80.0195 22.3763 80.0195 19.4831C80.0195 16.5655 81.179 14.9419 83.2417 14.9419C85.3043 14.9419 86.4638 16.5655 86.4638 19.4831C86.4638 22.3763 85.3043 23.9999 83.2417 23.9999ZM83.2417 22.8035C84.4622 22.8035 85.1334 21.6804 85.1334 19.4831C85.1334 17.2857 84.4622 16.1382 83.2417 16.1382C82.0212 16.1382 81.3499 17.2857 81.3499 19.4831C81.3499 21.6804 82.0212 22.8035 83.2417 22.8035Z" fill="#000"/>
<path d="M76.0332 23.9999C74.1536 23.9999 72.9331 22.8035 72.7866 20.9846L74.1048 20.8992C74.2756 22.1443 74.9835 22.8035 76.082 22.8035C77.1438 22.8035 77.7419 22.3763 77.7419 21.6072C77.7419 20.8381 77.3269 20.3987 75.5083 19.8859C73.7264 19.3976 72.9819 18.7995 72.9819 17.4566C72.9819 15.9673 74.0804 14.9419 75.8989 14.9419C77.7052 14.9419 78.7427 16.0772 78.9135 17.7496L77.5954 17.8229C77.4611 16.8219 76.8997 16.1382 75.8623 16.1382C74.9103 16.1382 74.3 16.6387 74.3 17.3956C74.3 18.1525 74.7272 18.4332 76.265 18.8605C78.3399 19.4221 79.06 20.1911 79.06 21.6072C79.06 23.0355 77.8517 23.9999 76.0332 23.9999Z" fill="#000"/>
<path d="M58.4556 23.8045V15.1372H60.0178L62.8616 21.9856V15.1372H64.1187V23.8045H62.5564L59.7127 16.9561V23.8045H58.4556Z" fill="#000"/>
<path d="M51.3813 23.8045V15.1372H56.7027V16.3458H52.6629V18.8727H56.5563V20.0446H52.6629V22.596H56.8004V23.8045H51.3813Z" fill="#000"/>
<path d="M44.0386 23.8045V15.1372H46.7237C48.53 15.1372 49.7261 16.1626 49.7261 17.8351C49.7261 19.4953 48.53 20.5207 46.7237 20.5207H45.3201V23.8045H44.0386ZM45.3201 19.3122H46.5894C47.8221 19.3122 48.3958 18.7995 48.3958 17.8351C48.3958 16.8707 47.8221 16.3458 46.5894 16.3458H45.3201V19.3122Z" fill="#000"/>
<path d="M39.332 23.9999C37.2693 23.9999 36.1099 22.3763 36.1099 19.4831C36.1099 16.5655 37.2693 14.9419 39.332 14.9419C41.3946 14.9419 42.5541 16.5655 42.5541 19.4831C42.5541 22.3763 41.3946 23.9999 39.332 23.9999ZM39.332 22.8035C40.5525 22.8035 41.2238 21.6804 41.2238 19.4831C41.2238 17.2857 40.5525 16.1382 39.332 16.1382C38.1115 16.1382 37.4402 17.2857 37.4402 19.4831C37.4402 21.6804 38.1115 22.8035 39.332 22.8035Z" fill="#000"/>
<path d="M171.085 9.35094C169.083 9.35094 167.96 7.95929 167.96 5.46895C167.96 2.60019 168.864 0.292969 171.414 0.292969C173.013 0.292969 173.819 1.1597 174.148 2.38045L172.83 2.49032C172.659 1.89215 172.269 1.48931 171.414 1.48931C170.243 1.48931 169.474 2.36825 169.303 4.2482C169.718 3.71107 170.426 3.32043 171.329 3.32043C173.05 3.32043 174.161 4.48015 174.161 6.25024C174.161 8.16681 172.916 9.35094 171.085 9.35094ZM171.085 8.1424C172.147 8.1424 172.83 7.45878 172.83 6.27465C172.83 5.17597 172.196 4.48015 171.183 4.48015C170.096 4.48015 169.315 5.17597 169.315 6.27465C169.315 7.34891 169.999 8.1424 171.085 8.1424Z" fill="#000" fill-opacity="0.5"/>
<path d="M160.667 9.15562C160.667 7.22684 161.387 6.01829 163.925 4.67547C165.011 4.10171 165.475 3.72328 165.475 2.88096C165.475 2.05085 164.95 1.48931 163.937 1.48931C162.827 1.48931 162.217 2.09968 162.046 3.18615L160.715 3.1007C160.898 1.37944 162.021 0.292969 163.937 0.292969C165.78 0.292969 166.806 1.3184 166.806 2.83213C166.806 4.17496 166.22 4.83416 164.45 5.78635C162.949 6.59205 162.241 7.36112 162.192 7.94708H166.818V9.15562H160.667Z" fill="#000" fill-opacity="0.5"/>
<path d="M156.424 9.35094C154.508 9.35094 153.348 7.61748 153.348 4.83416C153.348 2.03864 154.508 0.292969 156.424 0.292969C158.34 0.292969 159.499 2.03864 159.499 4.83416C159.499 7.61748 158.34 9.35094 156.424 9.35094ZM154.678 4.83416C154.678 5.55441 154.752 6.1892 154.91 6.68971L157.449 1.98981C157.181 1.66021 156.827 1.48931 156.424 1.48931C155.338 1.48931 154.678 2.72226 154.678 4.83416ZM156.424 8.15461C157.51 8.15461 158.169 6.92165 158.169 4.83416C158.169 4.10171 158.096 3.46692 157.937 2.96641L155.386 7.6541C155.667 7.9837 156.021 8.15461 156.424 8.15461Z" fill="#000" fill-opacity="0.5"/>
<path d="M146.03 9.15562C146.03 7.22684 146.75 6.01829 149.289 4.67547C150.375 4.10171 150.839 3.72328 150.839 2.88096C150.839 2.05085 150.314 1.48931 149.301 1.48931C148.19 1.48931 147.58 2.09968 147.409 3.18615L146.079 3.1007C146.262 1.37944 147.385 0.292969 149.301 0.292969C151.144 0.292969 152.169 1.3184 152.169 2.83213C152.169 4.17496 151.583 4.83416 149.813 5.78635C148.312 6.59205 147.604 7.36112 147.555 7.94708H152.181V9.15562H146.03Z" fill="#000" fill-opacity="0.5"/>
<path d="M132.041 10.4985L135.727 0H136.899L133.212 10.4985H132.041Z" fill="#000" fill-opacity="0.5"/>
<path d="M124.722 10.4985L128.409 0H129.581L125.894 10.4985H124.722Z" fill="#000" fill-opacity="0.5"/>
<path d="M111.684 9.15582V7.54443H113.344V9.15582H111.684Z" fill="#000"/>
<path d="M105.232 9.35094C103.145 9.35094 101.974 7.61748 101.974 4.83416C101.974 2.03864 103.145 0.292969 105.232 0.292969C106.807 0.292969 107.942 1.37944 108.296 3.25939L106.953 3.33264C106.709 2.1241 106.05 1.48931 105.232 1.48931C103.975 1.48931 103.304 2.69785 103.304 4.83416C103.304 6.95827 103.975 8.15461 105.232 8.15461C106.123 8.15461 106.795 7.45878 107.014 6.14037L108.345 6.20141C108.04 8.17902 106.892 9.35094 105.232 9.35094Z" fill="#000"/>
<path d="M95.0464 9.15562V0.488281H96.6086L99.4524 7.3367V0.488281H100.71V9.15562H99.1473L96.3035 2.3072V9.15562H95.0464Z" fill="#000"/>
<path d="M87.8501 9.15562V7.94707H89.9249V1.69683H87.8501V0.488281H93.2691V1.69683H91.1943V7.94707H93.2691V9.15562H87.8501Z" fill="#000"/>
<path d="M73.4575 9.15562V0.488281H74.739V7.94707H78.8765V9.15562H73.4575Z" fill="#000"/>
<path d="M66.0171 9.15562V0.488281H71.3385V1.69683H67.2986V4.22378H71.192V5.3957H67.2986V7.94707H71.4361V9.15562H66.0171Z" fill="#000"/>
<path d="M61.3232 9.35094C59.2361 9.35094 58.0645 7.61748 58.0645 4.83416C58.0645 2.03864 59.2361 0.292969 61.3232 0.292969C62.8976 0.292969 64.0327 1.37944 64.3866 3.25939L63.0441 3.33264C62.8 2.1241 62.1409 1.48931 61.3232 1.48931C60.0661 1.48931 59.3948 2.69785 59.3948 4.83416C59.3948 6.95827 60.0661 8.15461 61.3232 8.15461C62.2142 8.15461 62.8854 7.45878 63.1051 6.14037L64.4355 6.20141C64.1303 8.17902 62.9831 9.35094 61.3232 9.35094Z" fill="#000"/>
<path d="M51.125 9.15562V0.488281H53.8223C55.6531 0.488281 56.7759 1.47709 56.7759 3.07627C56.7759 4.11391 56.1168 4.87078 55.3113 5.12714C56.1657 5.28583 56.5806 5.76193 56.6539 6.6897L56.8736 9.15562H55.592L55.3968 6.93385C55.3235 6.06711 54.9818 5.77413 53.9199 5.77413H52.4065V9.15562H51.125ZM52.4065 4.5778H53.7979C54.8597 4.5778 55.4578 4.05288 55.4578 3.13731C55.4578 2.20954 54.8597 1.69683 53.7979 1.69683H52.4065V4.5778Z" fill="#000"/>
<path d="M44.063 9.15562V0.488281H49.3844V1.69683H45.3445V4.22378H49.2379V5.3957H45.3445V7.94707H49.482V9.15562H44.063Z" fill="#000"/>
<path d="M38.5753 9.15562L36 0.488281H37.3548L39.332 7.44656L41.3092 0.488281H42.6639L40.0887 9.15562H38.5753Z" fill="#000"/>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB

+218 -307
View File
@@ -39,377 +39,288 @@ python3 << 'PYTHON_SCRIPT'
import csv
import subprocess
import os
import io
import sys
import re
# Increase CSV field size limit to handle large prompt content
csv.field_size_limit(sys.maxsize)
project_dir = os.environ.get('PROJECT_DIR', '.')
csv_file = os.path.join(project_dir, 'prompts.csv')
remote_csv = os.path.join(project_dir, 'prompts.csv.remote')
prompts_md_path = os.path.join(project_dir, 'PROMPTS.md')
# Read existing local prompts (by act title as key)
local_prompts = {}
fieldnames = None
skipped_local = 0
with open(csv_file, 'r', newline='', encoding='utf-8') as f:
# Normalize CRLF to LF
content = f.read().replace('\r\n', '\n').replace('\r', '\n')
reader = csv.DictReader(io.StringIO(content))
fieldnames = reader.fieldnames
for row in reader:
try:
act = row.get('act', '').strip()
if act:
local_prompts[act] = row
except csv.Error as e:
skipped_local += 1
print(f"Skipping local row due to CSV error: {e}")
# --- CSV I/O (ordered, roundtrip-safe) ---
print(f"Found {len(local_prompts)} existing local prompts" + (f" (skipped {skipped_local})" if skipped_local else ""))
def read_csv(path):
"""Read CSV into an ordered list of rows and an act->index map."""
rows = []
index = {}
skipped = 0
with open(path, 'r', newline='', encoding='utf-8') as f:
reader = csv.DictReader(f)
fieldnames = list(reader.fieldnames) if reader.fieldnames else []
while True:
try:
row = next(reader)
act = (row.get('act') or '').strip()
if act:
index[act] = len(rows)
rows.append(row)
except csv.Error as e:
skipped += 1
print(f"Skipping row due to CSV error: {e}")
except StopIteration:
break
return rows, index, fieldnames, skipped
# Read remote prompts (normalize CRLF to LF)
remote_prompts = []
skipped_remote = 0
with open(remote_csv, 'r', newline='', encoding='utf-8') as f:
content = f.read().replace('\r\n', '\n').replace('\r', '\n')
reader = csv.DictReader(io.StringIO(content))
remote_fieldnames = reader.fieldnames
while True:
try:
row = next(reader)
remote_prompts.append(row)
except csv.Error as e:
skipped_remote += 1
print(f"Skipping remote row due to CSV error: {e}")
except StopIteration:
break
def write_csv(rows, fieldnames, path):
"""Write CSV deterministically — unchanged rows produce identical bytes."""
with open(path, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for row in rows:
writer.writerow(row)
print(f"Found {len(remote_prompts)} remote prompts" + (f" (skipped {skipped_remote})" if skipped_remote else ""))
def rebuild_index(rows):
"""Rebuild the act->index map after mutations."""
return {(r.get('act') or '').strip(): i for i, r in enumerate(rows)}
# Use remote fieldnames if local is empty
if not fieldnames:
fieldnames = remote_fieldnames
def normalize(s):
"""Normalize a string for comparison only."""
return (s or '').replace('\r\n', '\n').replace('\r', '\n').strip()
# Build set of remote prompt acts for quick lookup
remote_acts = set()
for row in remote_prompts:
act = row.get('act', '').strip()
if act:
remote_acts.add(act)
# --- Contributor helpers ---
# Find new, updated, and deleted prompts
new_prompts = []
updated_prompts = []
deleted_prompts = []
# Check for new and updated
for row in remote_prompts:
act = row.get('act', '').strip()
if not act:
continue
if act not in local_prompts:
new_prompts.append(row)
else:
local_row = local_prompts[act]
# Check if content OR contributors changed
content_changed = row.get('prompt', '').strip() != local_row.get('prompt', '').strip()
contributors_changed = row.get('contributor', '').strip() != local_row.get('contributor', '').strip()
if content_changed or contributors_changed:
updated_prompts.append((row, local_row))
# Check for deleted (in local but not in remote)
for act, local_row in local_prompts.items():
if act not in remote_acts:
deleted_prompts.append(local_row)
print(f"Found {len(new_prompts)} new prompts to add")
print(f"Found {len(updated_prompts)} updated prompts to modify")
print(f"Found {len(deleted_prompts)} prompts to remove (unlisted/deleted)")
# Helper function to parse contributors (supports "user1,user2,user3" format)
def parse_contributors(contributor_field):
"""Parse contributor field, returns (primary_author, co_authors_list)"""
if not contributor_field:
def parse_contributors(field):
if not field:
return 'anonymous', []
# Split by comma and clean up
contributors = [c.strip() for c in contributor_field.split(',') if c.strip()]
if not contributors:
parts = [c.strip() for c in field.split(',') if c.strip()]
if not parts:
return 'anonymous', []
primary = contributors[0]
co_authors = contributors[1:] if len(contributors) > 1 else []
return primary, co_authors
return parts[0], parts[1:]
def build_commit_message(action, act, co_authors):
"""Build commit message with optional co-author trailers"""
def make_email(name):
"""Build an email — don't double-suffix if the contributor is already an email."""
if '@' in name:
return name
return f'{name}@users.noreply.github.com'
def build_commit_msg(action, act, co_authors):
msg = f'{action} prompt: {act}'
if co_authors:
msg += '\n\n'
for co_author in co_authors:
co_email = f"{co_author}@users.noreply.github.com"
msg += f'Co-authored-by: {co_author} <{co_email}>\n'
for ca in co_authors:
msg += f'Co-authored-by: {ca} <{make_email(ca)}>\n'
return msg
def git_commit(author_name, author_email, message):
"""Stage CSV + PROMPTS.md and commit if there are real changes. Returns True if committed."""
subprocess.run(['git', 'add', csv_file, prompts_md_path], check=True)
if subprocess.run(['git', 'diff', '--cached', '--quiet'], capture_output=True).returncode == 0:
return False
env = os.environ.copy()
env['GIT_AUTHOR_NAME'] = author_name
env['GIT_AUTHOR_EMAIL'] = author_email
env['GIT_COMMITTER_NAME'] = author_name
env['GIT_COMMITTER_EMAIL'] = author_email
subprocess.run([
'git', 'commit', '-m', message,
f'--author={author_name} <{author_email}>'
], env=env, check=True)
return True
# --- PROMPTS.md helpers ---
EMAIL_RE = re.compile(r'^[^@\s]+@[^@\s]+\.[^@\s]+$')
GITHUB_USERNAME_RE = re.compile(r'^[A-Za-z0-9](?:[A-Za-z0-9]|-(?=[A-Za-z0-9])){0,38}$')
def format_contributor_links(contributor_field):
"""Format contributors as GitHub profile links"""
if not contributor_field:
return '@anonymous'
contributors = [c.strip() for c in contributor_field.split(',') if c.strip()]
if not contributors:
return '@anonymous'
return ', '.join([f'[@{c}](https://github.com/{c})' for c in contributors])
links = []
for contributor in contributors:
normalized = contributor.lstrip('@')
if EMAIL_RE.match(normalized):
links.append('@anonymous')
elif GITHUB_USERNAME_RE.match(normalized):
links.append(f'[@{normalized}](https://github.com/{normalized})')
elif normalized:
links.append(f'@{normalized}')
return ', '.join(links) if links else '@anonymous'
def generate_prompt_block(row):
"""Generate a single prompt's <details> block"""
act = row.get('act', 'Untitled')
prompt = row.get('prompt', '')
contributor = row.get('contributor', '')
prompt_type = row.get('type', 'TEXT').upper()
# Determine code block language based on type
if prompt_type == 'TEXT':
lang = 'md'
elif prompt_type == 'JSON':
lang = 'json'
elif prompt_type == 'YAML':
lang = 'yaml'
else:
lang = 'md'
contributor_links = format_contributor_links(contributor)
block = f'<details>\n'
block += f'<summary><strong>{act}</strong></summary>\n\n'
block += f'## {act}\n\n'
block += f'Contributed by {contributor_links}\n\n'
block += f'```{lang}\n'
block += f'{prompt}\n'
block += f'```\n\n'
block += f'</details>\n\n'
return block
prompt_type = (row.get('type') or 'TEXT').upper()
def init_prompts_md(prompts_md_path):
"""Initialize PROMPTS.md with header if it doesn't exist"""
lang = {'TEXT': 'md', 'JSON': 'json', 'YAML': 'yaml'}.get(prompt_type, 'md')
contributor_links = format_contributor_links(contributor)
return (
f'<details>\n'
f'<summary><strong>{act}</strong></summary>\n\n'
f'## {act}\n\n'
f'Contributed by {contributor_links}\n\n'
f'```{lang}\n'
f'{prompt}\n'
f'```\n\n'
f'</details>\n\n'
)
def init_prompts_md():
if not os.path.exists(prompts_md_path):
with open(prompts_md_path, 'w', encoding='utf-8') as f:
f.write('# prompts.chat\n\n')
f.write('> A curated list of prompts for ChatGPT and other AI models.\n\n')
f.write('---\n\n')
def append_prompt_to_md(row, prompts_md_path):
"""Append a new prompt block to PROMPTS.md"""
init_prompts_md(prompts_md_path)
block = generate_prompt_block(row)
def append_prompt_to_md(row):
init_prompts_md()
with open(prompts_md_path, 'a', encoding='utf-8') as f:
f.write(block)
f.write(generate_prompt_block(row))
def update_prompt_in_md(row, prompts_md_path):
"""Update an existing prompt's block in PROMPTS.md"""
def update_prompt_in_md(row):
act = row.get('act', '')
if not os.path.exists(prompts_md_path):
append_prompt_to_md(row, prompts_md_path)
append_prompt_to_md(row)
return
with open(prompts_md_path, 'r', encoding='utf-8') as f:
content = f.read()
# Find and replace the specific prompt block using regex
import re
# Pattern to match the entire <details> block for this prompt
pattern = rf'<details>\n<summary><strong>{re.escape(act)}</strong></summary>.*?</details>\n\n'
new_block = generate_prompt_block(row)
new_content, count = re.subn(pattern, new_block, content, flags=re.DOTALL)
new_content, count = re.subn(pattern, generate_prompt_block(row), content, flags=re.DOTALL)
if count > 0:
with open(prompts_md_path, 'w', encoding='utf-8') as f:
f.write(new_content)
else:
# Prompt not found, append it
append_prompt_to_md(row, prompts_md_path)
append_prompt_to_md(row)
def remove_prompt_from_md(act, prompts_md_path):
"""Remove a prompt's block from PROMPTS.md"""
def remove_prompt_from_md(act):
if not os.path.exists(prompts_md_path):
return
with open(prompts_md_path, 'r', encoding='utf-8') as f:
content = f.read()
import re
pattern = rf'<details>\n<summary><strong>{re.escape(act)}</strong></summary>.*?</details>\n\n'
new_content = re.sub(pattern, '', content, flags=re.DOTALL)
with open(prompts_md_path, 'w', encoding='utf-8') as f:
f.write(new_content)
prompts_md_path = os.path.join(project_dir, 'PROMPTS.md')
# --- Main ---
local_rows, local_index, fieldnames, skipped_l = read_csv(csv_file)
remote_rows, remote_index, remote_fieldnames, skipped_r = read_csv(remote_csv)
if not fieldnames:
fieldnames = remote_fieldnames
print(f"Local: {len(local_rows)} prompts" + (f" (skipped {skipped_l})" if skipped_l else ""))
print(f"Remote: {len(remote_rows)} prompts" + (f" (skipped {skipped_r})" if skipped_r else ""))
# Compute diffs
remote_acts = set(remote_index.keys())
new_prompts = []
updated_prompts = []
deleted_prompts = []
for row in remote_rows:
act = (row.get('act') or '').strip()
if not act:
continue
if act not in local_index:
new_prompts.append(row)
else:
local_row = local_rows[local_index[act]]
if (normalize(row.get('prompt')) != normalize(local_row.get('prompt')) or
normalize(row.get('contributor')) != normalize(local_row.get('contributor'))):
updated_prompts.append(row)
for act in list(local_index):
if act not in remote_acts:
deleted_prompts.append(local_rows[local_index[act]])
print(f"\nNew: {len(new_prompts)}, Updated: {len(updated_prompts)}, Deleted: {len(deleted_prompts)}")
if not new_prompts and not updated_prompts and not deleted_prompts:
print("\nNo CSV changes detected. Already up to date!")
else:
# Process updates one at a time (apply and commit each update separately)
if updated_prompts:
print("\nApplying updates to existing prompts...")
for i, (remote_row, local_row) in enumerate(updated_prompts, 1):
act = remote_row.get('act', '').strip()
contributor_field = remote_row.get('contributor', '').strip()
# Update this specific prompt in local_prompts
local_prompts[act] = remote_row
# Rewrite the CSV with this update applied
with open(csv_file, 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
# Write in order of remote (to maintain order)
for row in remote_prompts:
row_act = row.get('act', '').strip()
if row_act in local_prompts:
writer.writerow(local_prompts[row_act])
# Update only this prompt's block in PROMPTS.md
update_prompt_in_md(remote_row, prompts_md_path)
primary_author, co_authors = parse_contributors(contributor_field)
email = f"{primary_author}@users.noreply.github.com"
subprocess.run(['git', 'add', csv_file, prompts_md_path], check=True)
# Check if there are actual changes to commit
diff_result = subprocess.run(['git', 'diff', '--cached', '--quiet'], capture_output=True)
if diff_result.returncode == 0:
# No changes staged, skip this commit
print(f"[UPDATE {i}/{len(updated_prompts)}] {act} - no changes, skipping")
continue
env = os.environ.copy()
env['GIT_AUTHOR_NAME'] = primary_author
env['GIT_AUTHOR_EMAIL'] = email
env['GIT_COMMITTER_NAME'] = primary_author
env['GIT_COMMITTER_EMAIL'] = email
commit_msg = build_commit_message('Update', act, co_authors)
subprocess.run([
'git', 'commit',
'-m', commit_msg,
f'--author={primary_author} <{email}>'
], env=env, check=True)
co_authors_str = f" (+ {', '.join(co_authors)})" if co_authors else ""
print(f"[UPDATE {i}/{len(updated_prompts)}] {primary_author}{co_authors_str}: {act}")
# Process new prompts
if new_prompts:
print("\nCreating commits for new prompts...")
for i, row in enumerate(new_prompts, 1):
contributor_field = row.get('contributor', '').strip()
act = row.get('act', 'Unknown')
primary_author, co_authors = parse_contributors(contributor_field)
email = f"{primary_author}@users.noreply.github.com"
# Append this row to the CSV
with open(csv_file, 'a', newline='') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writerow(row)
# Track in local_prompts
local_prompts[act] = row
# Append only this prompt's block to PROMPTS.md
append_prompt_to_md(row, prompts_md_path)
# Stage and commit
subprocess.run(['git', 'add', csv_file, prompts_md_path], check=True)
# Check if there are actual changes to commit
diff_result = subprocess.run(['git', 'diff', '--cached', '--quiet'], capture_output=True)
if diff_result.returncode == 0:
print(f"[NEW {i}/{len(new_prompts)}] {act} - no changes, skipping")
continue
env = os.environ.copy()
env['GIT_AUTHOR_NAME'] = primary_author
env['GIT_AUTHOR_EMAIL'] = email
env['GIT_COMMITTER_NAME'] = primary_author
env['GIT_COMMITTER_EMAIL'] = email
commit_msg = build_commit_message('Add', act, co_authors)
subprocess.run([
'git', 'commit',
'-m', commit_msg,
f'--author={primary_author} <{email}>'
], env=env, check=True)
co_authors_str = f" (+ {', '.join(co_authors)})" if co_authors else ""
print(f"[NEW {i}/{len(new_prompts)}] {primary_author}{co_authors_str}: {act}")
# Process deleted prompts (remove from CSV, commit with original author)
if deleted_prompts:
print("\nRemoving unlisted/deleted prompts...")
for i, row in enumerate(deleted_prompts, 1):
contributor_field = row.get('contributor', '').strip()
act = row.get('act', 'Unknown')
primary_author, co_authors = parse_contributors(contributor_field)
email = f"{primary_author}@users.noreply.github.com"
# Remove this prompt from local_prompts
if act in local_prompts:
del local_prompts[act]
# Rewrite CSV without the deleted prompt
with open(csv_file, 'w', newline='') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
for remaining_act, remaining_row in local_prompts.items():
writer.writerow(remaining_row)
# Remove only this prompt's block from PROMPTS.md
remove_prompt_from_md(act, prompts_md_path)
# Stage and commit
subprocess.run(['git', 'add', csv_file, prompts_md_path], check=True)
# Check if there are actual changes to commit
diff_result = subprocess.run(['git', 'diff', '--cached', '--quiet'], capture_output=True)
if diff_result.returncode == 0:
print(f"[REMOVE {i}/{len(deleted_prompts)}] {act} - no changes, skipping")
continue
env = os.environ.copy()
env['GIT_AUTHOR_NAME'] = primary_author
env['GIT_AUTHOR_EMAIL'] = email
env['GIT_COMMITTER_NAME'] = primary_author
env['GIT_COMMITTER_EMAIL'] = email
commit_msg = build_commit_message('Remove', act, co_authors)
subprocess.run([
'git', 'commit',
'-m', commit_msg,
f'--author={primary_author} <{email}>'
], env=env, check=True)
co_authors_str = f" (+ {', '.join(co_authors)})" if co_authors else ""
print(f"[REMOVE {i}/{len(deleted_prompts)}] {primary_author}{co_authors_str}: {act}")
print(f"\nDone! Created {len(new_prompts)} new, {len(updated_prompts)} update, {len(deleted_prompts)} remove commits.")
print("Already up to date!")
sys.exit(0)
counts = {'add': 0, 'update': 0, 'remove': 0}
# 1) Deletes — remove one row at a time, keeping other rows untouched
if deleted_prompts:
print("\nRemoving unlisted/deleted prompts...")
for i, row in enumerate(deleted_prompts, 1):
act = (row.get('act') or '').strip()
contributor = (row.get('contributor') or '').strip()
primary, coauthors = parse_contributors(contributor)
email = make_email(primary)
if act in local_index:
local_rows.pop(local_index[act])
local_index = rebuild_index(local_rows)
remove_prompt_from_md(act)
write_csv(local_rows, fieldnames, csv_file)
msg = build_commit_msg('Remove', act, coauthors)
if git_commit(primary, email, msg):
ca = f" (+ {', '.join(coauthors)})" if coauthors else ""
print(f" [{i}/{len(deleted_prompts)}] {primary}{ca}: {act}")
counts['remove'] += 1
else:
print(f" [{i}/{len(deleted_prompts)}] {act} — no changes, skipping")
# 2) Updates — replace only the specific row in-place
if updated_prompts:
print("\nUpdating existing prompts...")
for i, row in enumerate(updated_prompts, 1):
act = (row.get('act') or '').strip()
contributor = (row.get('contributor') or '').strip()
primary, coauthors = parse_contributors(contributor)
email = make_email(primary)
if act in local_index:
local_rows[local_index[act]] = row
update_prompt_in_md(row)
write_csv(local_rows, fieldnames, csv_file)
msg = build_commit_msg('Update', act, coauthors)
if git_commit(primary, email, msg):
ca = f" (+ {', '.join(coauthors)})" if coauthors else ""
print(f" [{i}/{len(updated_prompts)}] {primary}{ca}: {act}")
counts['update'] += 1
else:
print(f" [{i}/{len(updated_prompts)}] {act} — no changes, skipping")
# 3) New prompts — append one at a time
if new_prompts:
print("\nAdding new prompts...")
for i, row in enumerate(new_prompts, 1):
act = (row.get('act') or '').strip()
contributor = (row.get('contributor') or '').strip()
primary, coauthors = parse_contributors(contributor)
email = make_email(primary)
local_rows.append(row)
local_index[act] = len(local_rows) - 1
append_prompt_to_md(row)
write_csv(local_rows, fieldnames, csv_file)
msg = build_commit_msg('Add', act, coauthors)
if git_commit(primary, email, msg):
ca = f" (+ {', '.join(coauthors)})" if coauthors else ""
print(f" [{i}/{len(new_prompts)}] {primary}{ca}: {act}")
counts['add'] += 1
else:
print(f" [{i}/{len(new_prompts)}] {act} — no changes, skipping")
print(f"\nDone! {counts['add']} added, {counts['update']} updated, {counts['remove']} removed.")
PYTHON_SCRIPT
PYTHON_EXIT=$?
+1 -1
View File
@@ -12,7 +12,7 @@ Sentry.init({
enabled: process.env.NODE_ENV === "production",
// Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
tracesSampleRate: 1,
tracesSampleRate: 0.1,
// Enable logs to be sent to Sentry
enableLogs: true,
+1 -1
View File
@@ -11,7 +11,7 @@ Sentry.init({
enabled: process.env.NODE_ENV === "production",
// Define how likely traces are sampled. Adjust this value in production, or use tracesSampler for greater control.
tracesSampleRate: 1,
tracesSampleRate: 0.1,
// Enable logs to be sent to Sentry
enableLogs: true,
+187
View File
@@ -0,0 +1,187 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import type { NextApiRequest, NextApiResponse } from "next";
// Mock all heavy dependencies before importing handler
vi.mock("@/lib/db", () => ({
db: {
user: { findUnique: vi.fn() },
prompt: { findMany: vi.fn(), findFirst: vi.fn(), create: vi.fn() },
tag: { findUnique: vi.fn(), create: vi.fn() },
$queryRaw: vi.fn(),
},
}));
vi.mock("@/lib/rate-limit", () => ({
mcpGeneralLimiter: { check: vi.fn().mockReturnValue({ allowed: true }) },
mcpToolCallLimiter: { check: vi.fn().mockReturnValue({ allowed: true }) },
mcpWriteToolLimiter: { check: vi.fn().mockReturnValue({ allowed: true }) },
mcpAiToolLimiter: { check: vi.fn().mockReturnValue({ allowed: true }) },
}));
vi.mock("@/../prompts.config", () => ({
default: {
features: { mcp: true },
},
}));
vi.mock("@/lib/api-key", () => ({
isValidApiKeyFormat: vi.fn().mockReturnValue(false),
}));
vi.mock("@/lib/skill-files", () => ({
parseSkillFiles: vi.fn(),
serializeSkillFiles: vi.fn(),
sanitizeFilename: vi.fn(),
DEFAULT_SKILL_FILE: "main.md",
}));
function createMockReq(method: string, overrides: Partial<NextApiRequest> = {}): NextApiRequest {
return {
method,
headers: {},
url: "/api/mcp",
socket: { remoteAddress: "127.0.0.1" },
...overrides,
} as unknown as NextApiRequest;
}
function createMockRes(): NextApiResponse & {
_status: number;
_json: unknown;
_headers: Record<string, string>;
_ended: boolean;
} {
const res = {
_status: 200,
_json: null,
_headers: {} as Record<string, string>,
_ended: false,
status(code: number) {
res._status = code;
return res;
},
json(data: unknown) {
res._json = data;
return res;
},
end() {
res._ended = true;
return res;
},
setHeader(key: string, value: string) {
res._headers[key] = value;
return res;
},
getHeader(key: string) {
return res._headers[key];
},
headersSent: false,
on: vi.fn(),
};
return res as unknown as NextApiResponse & typeof res;
}
describe("MCP API handler - HTTP method routing", () => {
let handler: (req: NextApiRequest, res: NextApiResponse) => Promise<void>;
beforeEach(async () => {
vi.clearAllMocks();
// Dynamic import to pick up mocks
const mod = await import("@/pages/api/mcp");
handler = mod.default;
});
describe("GET requests", () => {
it("should return 405 Method Not Allowed per MCP Streamable HTTP spec", async () => {
const req = createMockReq("GET");
const res = createMockRes();
await handler(req, res);
expect(res._status).toBe(405);
});
it("should return JSON-RPC error body", async () => {
const req = createMockReq("GET");
const res = createMockRes();
await handler(req, res);
expect(res._json).toEqual({
jsonrpc: "2.0",
error: expect.objectContaining({
code: -32000,
message: expect.stringContaining("Method not allowed"),
}),
id: null,
});
});
it("should set Cache-Control: no-store to prevent caching stale 405s", async () => {
const req = createMockReq("GET");
const res = createMockRes();
await handler(req, res);
expect(res._headers["Cache-Control"]).toBe("no-store");
});
});
describe("DELETE requests", () => {
it("should return 204 No Content", async () => {
const req = createMockReq("DELETE");
const res = createMockRes();
await handler(req, res);
expect(res._status).toBe(204);
expect(res._ended).toBe(true);
});
});
describe("unsupported methods", () => {
it("should return 405 for PUT", async () => {
const req = createMockReq("PUT");
const res = createMockRes();
await handler(req, res);
expect(res._status).toBe(405);
});
it("should return 405 for PATCH", async () => {
const req = createMockReq("PATCH");
const res = createMockRes();
await handler(req, res);
expect(res._status).toBe(405);
});
});
describe("MCP disabled", () => {
it("should return 404 when MCP feature is disabled", async () => {
// Re-mock config with mcp disabled
vi.doMock("@/../prompts.config", () => ({
default: { features: { mcp: false } },
}));
// Re-import to get new mock
vi.resetModules();
const mod = await import("@/pages/api/mcp");
const disabledHandler = mod.default;
const req = createMockReq("GET");
const res = createMockRes();
await disabledHandler(req, res);
expect(res._status).toBe(404);
// Restore original mock
vi.doMock("@/../prompts.config", () => ({
default: { features: { mcp: true } },
}));
});
});
});
+120 -17
View File
@@ -1,4 +1,5 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { Prisma } from "@prisma/client";
import { POST } from "@/app/api/auth/register/route";
import { db } from "@/lib/db";
import { getConfig } from "@/lib/config";
@@ -158,14 +159,15 @@ describe("POST /api/auth/register", () => {
});
describe("duplicate checks", () => {
it("should return 400 when email already exists", async () => {
// Mock: email check finds existing user
vi.mocked(db.user.findUnique).mockImplementation(async (args) => {
if (args?.where?.email) {
return { id: "1", email: "test@example.com" } as never;
}
return null;
});
it("should return 409 when email already exists", async () => {
// Mock: create throws P2002 unique violation on email
vi.mocked(db.user.create).mockRejectedValue(
new Prisma.PrismaClientKnownRequestError("Unique constraint failed", {
code: "P2002",
meta: { target: ["email"] },
clientVersion: "5.0.0",
})
);
const request = createRequest({
name: "Test User",
@@ -177,14 +179,43 @@ describe("POST /api/auth/register", () => {
const response = await POST(request);
const data = await response.json();
expect(response.status).toBe(400);
expect(response.status).toBe(409);
expect(data.error).toBe("email_taken");
});
it("should return 400 when username already exists", async () => {
// Mock: email check passes, username check (case-insensitive via findFirst) finds existing user
vi.mocked(db.user.findUnique).mockResolvedValue(null);
vi.mocked(db.user.findFirst).mockResolvedValue({ id: "1", username: "testuser" } as never);
it("should return 409 for case-insensitive email collision", async () => {
// Mock: create throws P2002 unique violation on CI email index
vi.mocked(db.user.create).mockRejectedValue(
new Prisma.PrismaClientKnownRequestError("Unique constraint failed", {
code: "P2002",
meta: { target: ["users_email_ci_unique"] },
clientVersion: "5.0.0",
})
);
const request = createRequest({
name: "Test User",
username: "testuser",
email: "Test@Example.COM",
password: "password123",
});
const response = await POST(request);
const data = await response.json();
expect(response.status).toBe(409);
expect(data.error).toBe("email_taken");
});
it("should return 409 when username already exists", async () => {
// Mock: create throws P2002 unique violation on username
vi.mocked(db.user.create).mockRejectedValue(
new Prisma.PrismaClientKnownRequestError("Unique constraint failed", {
code: "P2002",
meta: { target: ["username"] },
clientVersion: "5.0.0",
})
);
const request = createRequest({
name: "Test User",
@@ -196,15 +227,52 @@ describe("POST /api/auth/register", () => {
const response = await POST(request);
const data = await response.json();
expect(response.status).toBe(409);
expect(data.error).toBe("username_taken");
});
it("should return 400 for uppercase username", async () => {
const request = createRequest({
name: "Test User",
username: "TestUser",
email: "test@example.com",
password: "password123",
});
const response = await POST(request);
const data = await response.json();
expect(response.status).toBe(400);
expect(data.error).toBe("validation_error");
});
it("should return 409 for case-insensitive username collision", async () => {
// Mock: create throws P2002 unique violation on CI username index
vi.mocked(db.user.create).mockRejectedValue(
new Prisma.PrismaClientKnownRequestError("Unique constraint failed", {
code: "P2002",
meta: { target: ["users_username_ci_unique"] },
clientVersion: "5.0.0",
})
);
const request = createRequest({
name: "Test User",
username: "testuser",
email: "test@example.com",
password: "password123",
});
const response = await POST(request);
const data = await response.json();
expect(response.status).toBe(409);
expect(data.error).toBe("username_taken");
});
});
describe("successful registration", () => {
it("should create user and return user data", async () => {
vi.mocked(db.user.findUnique).mockResolvedValue(null);
vi.mocked(db.user.findFirst).mockResolvedValue(null);
vi.mocked(db.user.create).mockResolvedValue({
id: "user-123",
name: "Test User",
@@ -238,9 +306,44 @@ describe("POST /api/auth/register", () => {
expect(data.password).toBeUndefined(); // Password should not be returned
});
it("should lowercase and trim email and username before saving", async () => {
vi.mocked(db.user.create).mockResolvedValue({
id: "user-123",
name: "Test User",
username: "testuser",
email: "test@example.com",
password: "hashed_password",
emailVerified: null,
image: null,
role: "USER",
bio: null,
credits: 0,
createdAt: new Date(),
updatedAt: new Date(),
});
const request = createRequest({
name: " Test User ",
username: " testuser ",
email: " Test@Example.COM ",
password: "password123",
});
const response = await POST(request);
expect(response.status).toBe(200);
expect(db.user.create).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({
name: "Test User",
username: "testuser",
email: "test@example.com",
}),
})
);
});
it("should accept valid username with underscores", async () => {
vi.mocked(db.user.findUnique).mockResolvedValue(null);
vi.mocked(db.user.findFirst).mockResolvedValue(null);
vi.mocked(db.user.create).mockResolvedValue({
id: "user-123",
name: "Test User",
+36 -7
View File
@@ -1,4 +1,5 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { Prisma } from "@prisma/client";
import { GET, PATCH } from "@/app/api/user/profile/route";
import { db } from "@/lib/db";
import { auth } from "@/lib/auth";
@@ -8,6 +9,7 @@ vi.mock("@/lib/db", () => ({
db: {
user: {
findUnique: vi.fn(),
findFirst: vi.fn(),
update: vi.fn(),
},
},
@@ -160,9 +162,15 @@ describe("PATCH /api/user/profile", () => {
expect(data.error).toBe("validation_error");
});
it("should return 400 if username is taken", async () => {
it("should return 409 if username is taken", async () => {
vi.mocked(auth).mockResolvedValue({ user: { id: "user1", username: "olduser" } } as never);
vi.mocked(db.user.findUnique).mockResolvedValue({ id: "other-user" } as never);
vi.mocked(db.user.update).mockRejectedValue(
new Prisma.PrismaClientKnownRequestError("Unique constraint failed", {
code: "P2002",
meta: { target: ["username"] },
clientVersion: "5.0.0",
})
);
const request = new Request("http://localhost:3000/api/user/profile", {
method: "PATCH",
@@ -172,7 +180,29 @@ describe("PATCH /api/user/profile", () => {
const response = await PATCH(request);
const data = await response.json();
expect(response.status).toBe(400);
expect(response.status).toBe(409);
expect(data.error).toBe("username_taken");
});
it("should return 409 for case-insensitive username collision", async () => {
vi.mocked(auth).mockResolvedValue({ user: { id: "user1", username: "olduser" } } as never);
vi.mocked(db.user.update).mockRejectedValue(
new Prisma.PrismaClientKnownRequestError("Unique constraint failed", {
code: "P2002",
meta: { target: ["users_username_ci_unique"] },
clientVersion: "5.0.0",
})
);
const request = new Request("http://localhost:3000/api/user/profile", {
method: "PATCH",
body: JSON.stringify({ name: "Test", username: "takenuser" }),
});
const response = await PATCH(request);
const data = await response.json();
expect(response.status).toBe(409);
expect(data.error).toBe("username_taken");
});
@@ -196,13 +226,12 @@ describe("PATCH /api/user/profile", () => {
expect(response.status).toBe(200);
expect(data.name).toBe("Updated Name");
// Should NOT check for existing username when keeping the same one
expect(db.user.findUnique).not.toHaveBeenCalled();
// No pre-check needed — uniqueness enforced at DB level
expect(db.user.update).toHaveBeenCalled();
});
it("should update profile successfully", async () => {
vi.mocked(auth).mockResolvedValue({ user: { id: "user1", username: "olduser" } } as never);
vi.mocked(db.user.findUnique).mockResolvedValue(null); // Username not taken
vi.mocked(db.user.update).mockResolvedValue({
id: "user1",
name: "New Name",
@@ -318,7 +347,7 @@ describe("PATCH /api/user/profile", () => {
it("should accept valid username with underscores", async () => {
vi.mocked(auth).mockResolvedValue({ user: { id: "user1", username: "old" } } as never);
vi.mocked(db.user.findUnique).mockResolvedValue(null);
vi.mocked(db.user.findFirst).mockResolvedValue(null);
vi.mocked(db.user.update).mockResolvedValue({
id: "user1",
name: "Test",
+16
View File
@@ -29,6 +29,10 @@ describe("GET /api/prompts/[id]/versions", () => {
});
it("should return empty array for prompt with no versions", async () => {
vi.mocked(db.prompt.findUnique).mockResolvedValue({
isPrivate: false,
authorId: "user1",
} as never);
vi.mocked(db.promptVersion.findMany).mockResolvedValue([]);
const request = new Request("http://localhost:3000/api/prompts/123/versions");
@@ -42,6 +46,10 @@ describe("GET /api/prompts/[id]/versions", () => {
});
it("should return versions ordered by version desc", async () => {
vi.mocked(db.prompt.findUnique).mockResolvedValue({
isPrivate: false,
authorId: "user1",
} as never);
vi.mocked(db.promptVersion.findMany).mockResolvedValue([
{
id: "v3",
@@ -83,6 +91,10 @@ describe("GET /api/prompts/[id]/versions", () => {
});
it("should include author info in response", async () => {
vi.mocked(db.prompt.findUnique).mockResolvedValue({
isPrivate: false,
authorId: "user1",
} as never);
vi.mocked(db.promptVersion.findMany).mockResolvedValue([
{
id: "v1",
@@ -106,6 +118,10 @@ describe("GET /api/prompts/[id]/versions", () => {
});
it("should call findMany with correct parameters", async () => {
vi.mocked(db.prompt.findUnique).mockResolvedValue({
isPrivate: false,
authorId: "user1",
} as never);
vi.mocked(db.promptVersion.findMany).mockResolvedValue([]);
const request = new Request("http://localhost:3000/api/prompts/123/versions");
@@ -0,0 +1,141 @@
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { getProviderMetadata, getConfiguredProviderIds } from "@/lib/auth/provider-metadata";
type ConfigParam = Parameters<typeof getConfiguredProviderIds>[0];
describe("Provider Metadata", () => {
const originalEnv = process.env;
beforeEach(() => {
process.env = { ...originalEnv };
});
afterEach(() => {
process.env = originalEnv;
});
describe("getProviderMetadata", () => {
it("should return empty maps when no generic providers are requested", () => {
const result = getProviderMetadata(["github", "google"]);
expect(result.displayNames).toEqual({});
expect(result.logos).toEqual({});
});
it("should read OIDC display name and logo from env", () => {
process.env.AUTH_OIDC_NAME = "Corporate SSO";
process.env.AUTH_OIDC_LOGO = "https://example.com/logo.svg";
const result = getProviderMetadata(["github", "oidc"]);
expect(result.displayNames).toEqual({ oidc: "Corporate SSO" });
expect(result.logos).toEqual({ oidc: "https://example.com/logo.svg" });
});
it("should read OAuth display name and logo from env", () => {
process.env.AUTH_OAUTH_NAME = "Legacy IdP";
process.env.AUTH_OAUTH_LOGO = "https://idp.example.com/icon.png";
const result = getProviderMetadata(["oauth"]);
expect(result.displayNames).toEqual({ oauth: "Legacy IdP" });
expect(result.logos).toEqual({ oauth: "https://idp.example.com/icon.png" });
});
it("should return both OIDC and OAuth metadata when both are configured", () => {
process.env.AUTH_OIDC_NAME = "OIDC Provider";
process.env.AUTH_OIDC_LOGO = "https://oidc.example.com/logo.svg";
process.env.AUTH_OAUTH_NAME = "OAuth Provider";
process.env.AUTH_OAUTH_LOGO = "https://oauth.example.com/logo.svg";
const result = getProviderMetadata(["oidc", "oauth"]);
expect(result.displayNames).toEqual({
oidc: "OIDC Provider",
oauth: "OAuth Provider",
});
expect(result.logos).toEqual({
oidc: "https://oidc.example.com/logo.svg",
oauth: "https://oauth.example.com/logo.svg",
});
});
it("should omit name when env var is not set", () => {
process.env.AUTH_OIDC_LOGO = "https://example.com/logo.svg";
// AUTH_OIDC_NAME not set
const result = getProviderMetadata(["oidc"]);
expect(result.displayNames).toEqual({});
expect(result.logos).toEqual({ oidc: "https://example.com/logo.svg" });
});
it("should omit logo when env var is not set", () => {
process.env.AUTH_OIDC_NAME = "My Provider";
// AUTH_OIDC_LOGO not set
const result = getProviderMetadata(["oidc"]);
expect(result.displayNames).toEqual({ oidc: "My Provider" });
expect(result.logos).toEqual({});
});
it("should reject logo URLs with javascript: protocol", () => {
process.env.AUTH_OIDC_NAME = "Evil Provider";
process.env.AUTH_OIDC_LOGO = "javascript:alert('xss')";
const result = getProviderMetadata(["oidc"]);
expect(result.displayNames).toEqual({ oidc: "Evil Provider" });
expect(result.logos).toEqual({});
});
it("should reject logo URLs with data: protocol", () => {
process.env.AUTH_OIDC_LOGO = "data:image/svg+xml,<svg></svg>";
const result = getProviderMetadata(["oidc"]);
expect(result.logos).toEqual({});
});
it("should accept http:// logo URLs", () => {
process.env.AUTH_OIDC_LOGO = "http://internal.corp.com/logo.png";
const result = getProviderMetadata(["oidc"]);
expect(result.logos).toEqual({ oidc: "http://internal.corp.com/logo.png" });
});
it("should reject malformed URLs", () => {
process.env.AUTH_OIDC_LOGO = "not-a-url";
const result = getProviderMetadata(["oidc"]);
expect(result.logos).toEqual({});
});
});
describe("getConfiguredProviderIds", () => {
it("should return providers array when configured", () => {
const config = {
auth: { providers: ["github", "google", "oidc"], allowRegistration: false },
} as unknown as ConfigParam;
expect(getConfiguredProviderIds(config)).toEqual(["github", "google", "oidc"]);
});
it("should fallback to deprecated singular provider string if present", () => {
const config = {
auth: { provider: "github", allowRegistration: false },
} as unknown as ConfigParam;
expect(getConfiguredProviderIds(config)).toEqual(["github"]);
});
it("should default to credentials when providers array is empty", () => {
const config = {
auth: { providers: [], allowRegistration: false },
} as unknown as ConfigParam;
expect(getConfiguredProviderIds(config)).toEqual(["credentials"]);
});
it("should default to credentials when providers is not set", () => {
const config = {
auth: { allowRegistration: false },
} as unknown as ConfigParam;
expect(getConfiguredProviderIds(config)).toEqual(["credentials"]);
});
});
});
@@ -0,0 +1,132 @@
/* eslint-disable @typescript-eslint/no-explicit-any -- tests inspect the dynamic NextAuth provider object */
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { oauthPlugin } from "@/lib/plugins/auth/oauth";
describe("OAuth 2.0 Auth Plugin", () => {
const originalEnv = process.env;
beforeEach(() => {
process.env = { ...originalEnv };
process.env.AUTH_OAUTH_ID = "test-client-id";
process.env.AUTH_OAUTH_SECRET = "test-client-secret";
process.env.AUTH_OAUTH_ISSUER = "https://sso.test.com";
process.env.AUTH_OAUTH_NAME = "Test OAuth";
});
afterEach(() => {
process.env = originalEnv;
});
it("should have correct plugin id and name", () => {
expect(oauthPlugin.id).toBe("oauth");
expect(oauthPlugin.name).toBe("Generic OAuth 2.0");
});
it("should have PKCE enabled by default", () => {
const provider: any = oauthPlugin.getProvider();
expect(provider.checks).toBeUndefined(); // Enabled by default
});
it("should allow disabling PKCE explicitly", () => {
process.env.AUTH_OAUTH_ENABLE_PKCE = "false";
const provider: any = oauthPlugin.getProvider();
expect(provider.checks).toEqual(["state"]);
});
it("should configure standard OAuth provider dynamically from env", () => {
process.env.AUTH_OAUTH_ID = "test-client-id";
process.env.AUTH_OAUTH_SECRET = "test-client-secret";
process.env.AUTH_OAUTH_ISSUER = "https://sso.test.com";
const provider: any = oauthPlugin.getProvider();
expect(provider.id).toBe("oauth");
expect(provider.type).toBe("oauth");
expect(provider.clientId).toBe("test-client-id");
expect(provider.clientSecret).toBe("test-client-secret");
expect(provider.issuer).toBe("https://sso.test.com");
// Check fallback URLs derived from issuer
expect(provider.authorization.url).toBe("https://sso.test.com/authorize");
expect(provider.token).toBe("https://sso.test.com/token");
expect(provider.userinfo).toBe("https://sso.test.com/userinfo");
// Check default scope (should NOT include openid for relaxed OAuth)
expect(provider.authorization.params.scope).toBe("email profile");
});
it("should use explicit URL overrides when provided", () => {
process.env.AUTH_OAUTH_ID = "test-client-id";
process.env.AUTH_OAUTH_SECRET = "test-client-secret";
process.env.AUTH_OAUTH_ISSUER = "https://sso.test.com";
process.env.AUTH_OAUTH_AUTHORIZATION_URL = "https://custom.test.com/auth";
process.env.AUTH_OAUTH_TOKEN_URL = "https://custom.test.com/token";
process.env.AUTH_OAUTH_USERINFO_URL = "https://custom.test.com/me";
const provider: any = oauthPlugin.getProvider();
expect(provider.authorization.url).toBe("https://custom.test.com/auth");
expect(provider.token).toBe("https://custom.test.com/token");
expect(provider.userinfo).toBe("https://custom.test.com/me");
});
it("should handle wellknown discovery correctly", () => {
process.env.AUTH_OAUTH_ID = "test-client-id";
process.env.AUTH_OAUTH_SECRET = "test-client-secret";
process.env.AUTH_OAUTH_ISSUER = "https://sso.test.com";
process.env.AUTH_OAUTH_WELLKNOWN = "https://sso.test.com/.well-known";
const provider: any = oauthPlugin.getProvider();
expect(provider.wellKnown).toBe("https://sso.test.com/.well-known");
expect(provider.authorization.url).toBeUndefined(); // Let wellKnown handle it
expect(provider.token).toBeUndefined();
expect(provider.userinfo).toBeUndefined();
});
it("should handle custom style logo", () => {
process.env.AUTH_OAUTH_LOGO = "https://logo.com/image.png";
const provider: any = oauthPlugin.getProvider();
expect(provider.style?.logo).toBe("https://logo.com/image.png");
});
it("should process user profile mappings correctly", () => {
const provider: any = oauthPlugin.getProvider();
const mockProfile = {
sub: "12345",
name: "Test User",
email: "test@example.com",
picture: "https://avatar.com/me.png",
preferred_username: "testuser"
};
const parsedProfile = provider.profile(mockProfile);
expect(parsedProfile.id).toBe("12345");
expect(parsedProfile.name).toBe("Test User");
expect(parsedProfile.email).toBe("test@example.com");
expect(parsedProfile.image).toBe("https://avatar.com/me.png");
expect(parsedProfile.username).toBe("testuser");
});
it("should fallback correctly if standard profile fields are missing", () => {
const provider: any = oauthPlugin.getProvider();
const weirdProfile = {
id: 999, // Testing numeric ID coercion
email: "weird@example.com",
avatar_url: "https://avatar.com/me2.png"
};
const parsedProfile = provider.profile(weirdProfile);
expect(parsedProfile.id).toBe("999");
expect(parsedProfile.name).toBe("weird@example.com"); // Fallback to email
expect(parsedProfile.email).toBe("weird@example.com");
expect(parsedProfile.image).toBe("https://avatar.com/me2.png");
expect(parsedProfile.username).toBe("weird"); // Fallback to email prefix
});
});
@@ -0,0 +1,96 @@
/* eslint-disable @typescript-eslint/no-explicit-any -- tests inspect the dynamic NextAuth provider object */
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { oidcPlugin } from "@/lib/plugins/auth/oidc";
describe("OpenID Connect Auth Plugin", () => {
const originalEnv = process.env;
beforeEach(() => {
process.env = { ...originalEnv };
process.env.AUTH_OIDC_ID = "test-client-id";
process.env.AUTH_OIDC_SECRET = "test-client-secret";
process.env.AUTH_OIDC_ISSUER = "https://sso.test.com";
process.env.AUTH_OIDC_NAME = "Test OIDC";
});
afterEach(() => {
process.env = originalEnv;
});
it("should have correct plugin id and name", () => {
expect(oidcPlugin.id).toBe("oidc");
expect(oidcPlugin.name).toBe("Generic OIDC");
});
it("should configure standard OIDC provider dynamically from env", () => {
process.env.AUTH_OIDC_ID = "test-client-id";
process.env.AUTH_OIDC_SECRET = "test-client-secret";
process.env.AUTH_OIDC_ISSUER = "https://sso.test.com";
const provider: any = oidcPlugin.getProvider();
expect(provider.id).toBe("oidc");
expect(provider.type).toBe("oidc");
expect(provider.clientId).toBe("test-client-id");
expect(provider.clientSecret).toBe("test-client-secret");
expect(provider.issuer).toBe("https://sso.test.com");
expect(provider.wellKnown).toBe("https://sso.test.com/.well-known/openid-configuration");
});
it("should support well-known discovery override", () => {
process.env.AUTH_OIDC_ISSUER = "https://sso.test.com";
process.env.AUTH_OIDC_WELLKNOWN = "https://sso.test.com/custom-well-known";
const provider: any = oidcPlugin.getProvider();
expect(provider.wellKnown).toBe("https://sso.test.com/custom-well-known");
});
it("should have PKCE enabled by default", () => {
delete process.env.AUTH_OIDC_ENABLE_PKCE;
const provider: any = oidcPlugin.getProvider();
expect(provider.checks).toBeUndefined(); // Enabled by default
});
it("should apply PKCE bypass if explicitly disabled", () => {
process.env.AUTH_OIDC_ENABLE_PKCE = "false";
const provider: any = oidcPlugin.getProvider();
expect(provider.checks).toEqual(["state"]);
});
it("should keep PKCE enabled if explicitly turned on", () => {
process.env.AUTH_OIDC_ENABLE_PKCE = "true";
const provider: any = oidcPlugin.getProvider();
expect(provider.checks).toBeUndefined(); // Auth.js will handle PKCE natively
});
it("should handle custom style logo", () => {
process.env.AUTH_OIDC_LOGO = "https://logo.com/image.png";
const provider: any = oidcPlugin.getProvider();
expect(provider.style?.logo).toBe("https://logo.com/image.png");
});
it("should fall back to standard UserInfo fields correctly", () => {
process.env.AUTH_OIDC_ID = "test-client-id";
process.env.AUTH_OIDC_SECRET = "test-client-secret";
process.env.AUTH_OIDC_ISSUER = "https://sso.test.com";
const provider: any = oidcPlugin.getProvider();
const mockProfile = {
sub: "12345",
name: "Test User",
email: "test@example.com",
picture: "https://avatar.com/me.png",
preferred_username: "testuser"
};
const parsedProfile: any = provider.profile(mockProfile);
expect(parsedProfile.id).toBe("12345");
expect(parsedProfile.name).toBe("Test User");
expect(parsedProfile.email).toBe("test@example.com");
expect(parsedProfile.image).toBe("https://avatar.com/me.png");
expect(parsedProfile.username).toBe("testuser");
});
});
+108
View File
@@ -0,0 +1,108 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { canViewPrompt, checkPromptAccess } from "@/lib/prompt-access";
import { auth } from "@/lib/auth";
import type { Session } from "next-auth";
vi.mock("@/lib/auth", () => ({
auth: vi.fn(),
}));
describe("canViewPrompt", () => {
it("should return false for null prompt", () => {
expect(canViewPrompt(null, null)).toBe(false);
});
it("should return true for public prompt with no session", () => {
expect(
canViewPrompt({ isPrivate: false, authorId: "user1" }, null)
).toBe(true);
});
it("should return true for public prompt with any session", () => {
const session = { user: { id: "other" } } as Session;
expect(
canViewPrompt({ isPrivate: false, authorId: "user1" }, session)
).toBe(true);
});
it("should return false for private prompt with no session", () => {
expect(
canViewPrompt({ isPrivate: true, authorId: "user1" }, null)
).toBe(false);
});
it("should return false for private prompt when user is not owner", () => {
const session = { user: { id: "other", role: "USER" } } as Session;
expect(
canViewPrompt({ isPrivate: true, authorId: "user1" }, session)
).toBe(false);
});
it("should return true for private prompt when user is the owner", () => {
const session = { user: { id: "user1", role: "USER" } } as Session;
expect(
canViewPrompt({ isPrivate: true, authorId: "user1" }, session)
).toBe(true);
});
it("should return true for private prompt when user is admin", () => {
const session = { user: { id: "admin1", role: "ADMIN" } } as Session;
expect(
canViewPrompt({ isPrivate: true, authorId: "user1" }, session)
).toBe(true);
});
it("should return false for private prompt with session missing user", () => {
const session = {} as Session;
expect(
canViewPrompt({ isPrivate: true, authorId: "user1" }, session)
).toBe(false);
});
});
describe("checkPromptAccess", () => {
beforeEach(() => {
vi.clearAllMocks();
});
it("should return 404 for null prompt", async () => {
const result = await checkPromptAccess(null);
expect(result).not.toBeNull();
expect(result!.status).toBe(404);
const data = await result!.json();
expect(data.error).toBe("not_found");
});
it("should return null for public prompt (no auth call)", async () => {
const result = await checkPromptAccess({ isPrivate: false, authorId: "user1" });
expect(result).toBeNull();
expect(auth).not.toHaveBeenCalled();
});
it("should return 404 for private prompt with no session", async () => {
vi.mocked(auth).mockResolvedValue(null);
const result = await checkPromptAccess({ isPrivate: true, authorId: "user1" });
expect(result).not.toBeNull();
expect(result!.status).toBe(404);
expect(auth).toHaveBeenCalledOnce();
});
it("should return 404 for private prompt when user is not owner", async () => {
vi.mocked(auth).mockResolvedValue({ user: { id: "other", role: "USER" } } as never);
const result = await checkPromptAccess({ isPrivate: true, authorId: "user1" });
expect(result).not.toBeNull();
expect(result!.status).toBe(404);
});
it("should return null for private prompt when user is the owner", async () => {
vi.mocked(auth).mockResolvedValue({ user: { id: "user1", role: "USER" } } as never);
const result = await checkPromptAccess({ isPrivate: true, authorId: "user1" });
expect(result).toBeNull();
});
it("should return null for private prompt when user is admin", async () => {
vi.mocked(auth).mockResolvedValue({ user: { id: "admin1", role: "ADMIN" } } as never);
const result = await checkPromptAccess({ isPrivate: true, authorId: "user1" });
expect(result).toBeNull();
});
});
+4 -13
View File
@@ -2,6 +2,7 @@ import { Metadata } from "next";
import Link from "next/link";
import { getTranslations } from "next-intl/server";
import { getConfig } from "@/lib/config";
import { getConfiguredProviderIds, getProviderMetadata } from "@/lib/auth/provider-metadata";
import { AuthContent } from "@/components/auth/auth-content";
export const metadata: Metadata = {
@@ -9,24 +10,14 @@ export const metadata: Metadata = {
description: "Login to your account",
};
// Helper to get providers from config (supports both old `provider` and new `providers` array)
function getProviders(config: Awaited<ReturnType<typeof getConfig>>): string[] {
if (config.auth.providers && config.auth.providers.length > 0) {
return config.auth.providers;
}
if (config.auth.provider) {
return [config.auth.provider];
}
return ["credentials"];
}
export default async function LoginPage() {
const t = await getTranslations("auth");
const config = await getConfig();
const providers = getProviders(config);
const providers = getConfiguredProviderIds(config);
const hasCredentials = providers.includes("credentials");
const hasOnlyCredentials = providers.length === 1 && hasCredentials;
const useCloneBranding = config.homepage?.useCloneBranding ?? false;
const { displayNames, logos } = getProviderMetadata(providers);
return (
<div className="container flex min-h-[calc(100vh-6rem)] flex-col items-center justify-center py-8">
@@ -38,7 +29,7 @@ export default async function LoginPage() {
</p>
</div>
<div className="border rounded-lg p-4">
<AuthContent providers={providers} mode="login" useCloneBranding={useCloneBranding} />
<AuthContent providers={providers} mode="login" useCloneBranding={useCloneBranding} providerDisplayNames={displayNames} providerLogos={logos} />
</div>
{hasCredentials && (
<p className="text-center text-xs text-muted-foreground">
+5 -13
View File
@@ -3,6 +3,7 @@ import Link from "next/link";
import { redirect } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { getConfig } from "@/lib/config";
import { getConfiguredProviderIds, getProviderMetadata } from "@/lib/auth/provider-metadata";
import { AuthContent } from "@/components/auth/auth-content";
export const metadata: Metadata = {
@@ -10,21 +11,10 @@ export const metadata: Metadata = {
description: "Create a new account",
};
// Helper to get providers from config (supports both old `provider` and new `providers` array)
function getProviders(config: Awaited<ReturnType<typeof getConfig>>): string[] {
if (config.auth.providers && config.auth.providers.length > 0) {
return config.auth.providers;
}
if (config.auth.provider) {
return [config.auth.provider];
}
return ["credentials"];
}
export default async function RegisterPage() {
const t = await getTranslations("auth");
const config = await getConfig();
const providers = getProviders(config);
const providers = getConfiguredProviderIds(config);
const hasCredentials = providers.includes("credentials");
// Block registration if disabled or credentials not enabled
@@ -32,6 +22,8 @@ export default async function RegisterPage() {
redirect("/login");
}
const { displayNames, logos } = getProviderMetadata(providers);
return (
<div className="container flex min-h-[calc(100vh-6rem)] flex-col items-center justify-center py-8">
<div className="w-full max-w-sm space-y-4">
@@ -40,7 +32,7 @@ export default async function RegisterPage() {
<p className="text-xs text-muted-foreground">{t("registerDescription")}</p>
</div>
<div className="border rounded-lg p-4">
<AuthContent providers={providers} mode="register" />
<AuthContent providers={providers} mode="register" providerDisplayNames={displayNames} providerLogos={logos} />
</div>
<p className="text-center text-xs text-muted-foreground">
{t("hasAccount")}{" "}
+2
View File
@@ -8,6 +8,7 @@ export const size = {
height: 630,
};
export const contentType = "image/png";
export const revalidate = 3600;
const radiusMap: Record<string, number> = {
none: 0,
@@ -49,6 +50,7 @@ export default async function OGImage({ params }: { params: Promise<{ username:
const user = await db.user.findFirst({
where: { username: { equals: username, mode: "insensitive" } },
orderBy: { createdAt: "asc" },
select: {
id: true,
name: true,
+2
View File
@@ -38,6 +38,7 @@ export async function generateMetadata({ params }: UserProfilePageProps): Promis
const user = await db.user.findFirst({
where: { username: { equals: username, mode: "insensitive" } },
orderBy: { createdAt: "asc" },
select: { name: true, username: true },
});
@@ -72,6 +73,7 @@ export default async function UserProfilePage({ params, searchParams }: UserProf
const user = await db.user.findFirst({
where: { username: { equals: username, mode: "insensitive" } },
orderBy: { createdAt: "asc" },
select: {
id: true,
name: true,
+61
View File
@@ -124,6 +124,11 @@ const coreContributors = [
role: "Chrome Extension Maintainer",
x: "fatihsolhann",
},
{
username: "JohnPhamous",
role: "Performance (Vercel)",
x: "JohnPhamous",
},
{
username: "claude-opus-4.5",
displayName: "Claude Opus 4.5",
@@ -169,6 +174,15 @@ const designCredits = [
},
];
const securityCredits = [
{
username: "mdisec",
displayName: "Mehmet Ince",
role: "Security Fixes",
x: "mdisec",
},
];
const ideationCredits = [
{
username: "semihkislar",
@@ -566,6 +580,53 @@ export default async function AboutPage() {
</div>
</section>
{/* Security */}
<section className="mb-10">
<h2 className="text-lg font-semibold mb-4">{t("securityTitle")}</h2>
<div className="grid gap-3 sm:grid-cols-2">
{securityCredits.map((contributor) => (
<div
key={contributor.username}
className="flex items-center gap-3 p-3 border rounded-lg"
>
<Image
src={`https://github.com/${contributor.username}.png`}
alt=""
width={40}
height={40}
className="rounded-full shrink-0"
/>
<div className="flex-1 min-w-0">
<div className="font-medium text-sm">
{contributor.displayName ?? `@${contributor.username}`}
</div>
<div className="text-xs text-muted-foreground">{contributor.role}</div>
</div>
<div className="flex items-center gap-2">
<Link
href={`https://github.com/${contributor.username}`}
target="_blank"
rel="noopener noreferrer"
className="p-1.5 rounded-md hover:bg-muted transition-colors"
title="GitHub"
>
<BrandIcon name="github" />
</Link>
<Link
href={`https://x.com/${contributor.x}`}
target="_blank"
rel="noopener noreferrer"
className="p-1.5 rounded-md hover:bg-muted transition-colors"
title="X"
>
<BrandIcon name="x" />
</Link>
</div>
</div>
))}
</div>
</section>
{/* Ideation */}
<section className="mb-10">
<h2 className="text-lg font-semibold mb-4">{t("ideationTitle")}</h2>
-17
View File
@@ -1,17 +0,0 @@
import { NextResponse } from "next/server";
export async function GET() {
const domain = process.env.EZOIC_SITE_DOMAIN;
if (!domain) {
return new NextResponse("# ads.txt not configured\n", {
status: 200,
headers: { "Content-Type": "text/plain" },
});
}
return NextResponse.redirect(
`https://srv.adstxtmanager.com/19390/${domain}`,
301
);
}
+38 -42
View File
@@ -2,12 +2,16 @@ import { NextResponse } from "next/server";
import bcrypt from "bcryptjs";
import { z } from "zod";
import { db } from "@/lib/db";
import { isUniqueConstraintViolation } from "@/lib/db-errors";
import { getConfig } from "@/lib/config";
// Trim before validation to prevent unicode/whitespace tricks that bypass uniqueness checks (e.g. "admin@x.com\u200B" vs "admin@x.com") on certain DBMS
const trimmed = z.preprocess((v) => (typeof v === "string" ? v.trim() : v), z.string());
const registerSchema = z.object({
name: z.string().min(2),
username: z.string().min(1).regex(/^[a-zA-Z0-9_]+$/),
email: z.string().email(),
name: trimmed.pipe(z.string().min(2)),
username: trimmed.pipe(z.string().min(1).max(30).regex(/^[a-z0-9_]+$/)),
email: trimmed.pipe(z.string().email()).transform((v) => v.toLowerCase()),
password: z.string().min(6),
});
@@ -34,49 +38,41 @@ export async function POST(request: Request) {
const { name, username, email, password } = parsed.data;
// Check if email already exists
const existingEmail = await db.user.findUnique({
where: { email },
});
if (existingEmail) {
return NextResponse.json(
{ error: "email_taken", message: "Email is already taken" },
{ status: 400 }
);
}
// Check if username already exists (case-insensitive)
const existingUsername = await db.user.findFirst({
where: { username: { equals: username, mode: "insensitive" } },
});
if (existingUsername) {
return NextResponse.json(
{ error: "username_taken", message: "Username is already taken" },
{ status: 400 }
);
}
// Hash password
const hashedPassword = await bcrypt.hash(password, 12);
// Create user
const user = await db.user.create({
data: {
name,
username,
email,
password: hashedPassword,
},
});
// Atomic create — DB unique constraints enforce email and CI username uniqueness
try {
const user = await db.user.create({
data: {
name,
username,
email,
password: hashedPassword,
},
});
return NextResponse.json({
id: user.id,
name: user.name,
username: user.username,
email: user.email,
});
return NextResponse.json({
id: user.id,
name: user.name,
username: user.username,
email: user.email,
});
} catch (error) {
if (isUniqueConstraintViolation(error, "email")) {
return NextResponse.json(
{ error: "email_taken", message: "Email is already taken" },
{ status: 409 }
);
}
if (isUniqueConstraintViolation(error, "username")) {
return NextResponse.json(
{ error: "username_taken", message: "Username is already taken" },
{ status: 409 }
);
}
throw error;
}
} catch (error) {
console.error("Registration error:", error);
return NextResponse.json(
@@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";
import { checkPromptAccess } from "@/lib/prompt-access";
const updateChangeRequestSchema = z.object({
status: z.enum(["APPROVED", "REJECTED", "PENDING"]),
@@ -196,7 +197,8 @@ export async function GET(
select: {
id: true,
title: true,
content: true,
isPrivate: true,
authorId: true,
},
},
},
@@ -209,6 +211,9 @@ export async function GET(
);
}
const denied = await checkPromptAccess(changeRequest.prompt);
if (denied) return denied;
return NextResponse.json(changeRequest);
} catch (error) {
console.error("Get change request error:", error);
@@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";
import { checkPromptAccess } from "@/lib/prompt-access";
const createChangeRequestSchema = z.object({
proposedContent: z.string().min(1),
@@ -94,6 +95,14 @@ export async function GET(
try {
const { id: promptId } = await params;
const prompt = await db.prompt.findUnique({
where: { id: promptId },
select: { isPrivate: true, authorId: true },
});
const denied = await checkPromptAccess(prompt);
if (denied) return denied;
const changeRequests = await db.changeRequest.findMany({
where: { promptId },
orderBy: { createdAt: "desc" },
+4 -4
View File
@@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";
import { z } from "zod";
import { checkPromptAccess } from "@/lib/prompt-access";
const addExampleSchema = z.object({
mediaUrl: z.string().url(),
@@ -16,12 +17,11 @@ export async function GET(
const prompt = await db.prompt.findUnique({
where: { id: promptId },
select: { id: true, type: true },
select: { id: true, type: true, isPrivate: true, authorId: true },
});
if (!prompt) {
return NextResponse.json({ error: "Prompt not found" }, { status: 404 });
}
const denied = await checkPromptAccess(prompt);
if (denied || !prompt) return denied!;
// Only allow examples for IMAGE and VIDEO prompts
if (prompt.type !== "IMAGE" && prompt.type !== "VIDEO") {
+12 -3
View File
@@ -1,6 +1,6 @@
import { NextRequest } from "next/server";
import { db } from "@/lib/db";
import { parseSkillFiles } from "@/lib/skill-files";
import { parseSkillFiles, sanitizeFilename } from "@/lib/skill-files";
import JSZip from "jszip";
/**
@@ -53,9 +53,18 @@ export async function GET(
// Create a zip file
const zip = new JSZip();
// Add each file to the zip
// Add each file to the zip (sanitize filenames to prevent Zip Slip)
for (const file of files) {
zip.file(file.filename, file.content);
const candidate = file.filename
.replace(/\\/g, "/")
.split("/")
.filter((segment) => segment && segment !== "." && segment !== "..")
.join("/");
const safeName = sanitizeFilename(candidate);
if (!safeName) {
continue;
}
zip.file(safeName, file.content);
}
// Generate the zip content as blob for Response compatibility
@@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
import { z } from "zod";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";
import { checkPromptAccess } from "@/lib/prompt-access";
const createVersionSchema = z.object({
content: z.string().min(1, "Content is required"),
@@ -116,6 +117,14 @@ export async function GET(
try {
const { id: promptId } = await params;
const prompt = await db.prompt.findUnique({
where: { id: promptId },
select: { isPrivate: true, authorId: true },
});
const denied = await checkPromptAccess(prompt);
if (denied) return denied;
const versions = await db.promptVersion.findMany({
where: { promptId },
orderBy: { version: "desc" },
+12 -6
View File
@@ -1,6 +1,7 @@
import { NextRequest, NextResponse } from "next/server";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";
import { checkPromptAccess } from "@/lib/prompt-access";
// POST - Upvote a prompt
export async function POST(
@@ -21,14 +22,11 @@ export async function POST(
// Check if prompt exists
const prompt = await db.prompt.findUnique({
where: { id: promptId },
select: { isPrivate: true, authorId: true },
});
if (!prompt) {
return NextResponse.json(
{ error: "not_found", message: "Prompt not found" },
{ status: 404 }
);
}
const denied = await checkPromptAccess(prompt);
if (denied) return denied;
// Check if already voted
const existing = await db.promptVote.findUnique({
@@ -86,6 +84,14 @@ export async function DELETE(
const { id: promptId } = await params;
const prompt = await db.prompt.findUnique({
where: { id: promptId },
select: { isPrivate: true, authorId: true },
});
const denied = await checkPromptAccess(prompt);
if (denied) return denied;
// Delete vote
await db.promptVote.deleteMany({
where: {
+31 -36
View File
@@ -3,6 +3,7 @@ import { z } from "zod";
import { Prisma } from "@prisma/client";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";
import { isUniqueConstraintViolation } from "@/lib/db-errors";
const customLinkSchema = z.object({
type: z.enum(["website", "github", "twitter", "linkedin", "instagram", "youtube", "twitch", "discord", "mastodon", "bluesky", "sponsor"]),
@@ -10,13 +11,12 @@ const customLinkSchema = z.object({
label: z.string().max(30).optional(),
});
// Trim before validation to prevent unicode/whitespace tricks that bypass uniqueness checks (e.g. "admin\u200B@x.com" vs "admin@x.com")
const trimmed = z.preprocess((v) => (typeof v === "string" ? v.trim() : v), z.string());
const updateProfileSchema = z.object({
name: z.string().min(1).max(100),
username: z
.string()
.min(1)
.max(30)
.regex(/^[a-zA-Z0-9_]+$/),
name: trimmed.pipe(z.string().min(1).max(100)),
username: trimmed.pipe(z.string().min(1).max(30).regex(/^[a-z0-9_]+$/)),
avatar: z.string().url().optional().or(z.literal("")),
bio: z.string().max(250).optional().or(z.literal("")),
customLinks: z.array(customLinkSchema).max(5).optional(),
@@ -44,43 +44,38 @@ export async function PATCH(request: NextRequest) {
const { name, username, avatar, bio, customLinks } = parsed.data;
// Check if username is taken by another user
if (username !== session.user.username) {
const existingUser = await db.user.findUnique({
where: { username },
select: { id: true },
// Atomic update — DB-level CI unique index prevents collisions
try {
const user = await db.user.update({
where: { id: session.user.id },
data: {
name,
username,
avatar: avatar || null,
bio: bio || null,
customLinks: customLinks && customLinks.length > 0 ? customLinks : Prisma.DbNull,
},
select: {
id: true,
name: true,
username: true,
email: true,
avatar: true,
bio: true,
customLinks: true,
},
});
if (existingUser && existingUser.id !== session.user.id) {
return NextResponse.json(user);
} catch (error) {
if (isUniqueConstraintViolation(error, "username")) {
return NextResponse.json(
{ error: "username_taken", message: "This username is already taken" },
{ status: 400 }
{ status: 409 }
);
}
throw error;
}
// Update user
const user = await db.user.update({
where: { id: session.user.id },
data: {
name,
username,
avatar: avatar || null,
bio: bio || null,
customLinks: customLinks && customLinks.length > 0 ? customLinks : Prisma.DbNull,
},
select: {
id: true,
name: true,
username: true,
email: true,
avatar: true,
bio: true,
customLinks: true,
},
});
return NextResponse.json(user);
} catch (error) {
console.error("Update profile error:", error);
return NextResponse.json(
+1 -1
View File
@@ -130,7 +130,7 @@ export default async function BookHomePage() {
{/* JSON-LD structured data */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd).replace(/</g, '\\u003c') }}
/>
<div className="max-w-2xl">
{/* Continue Reading Button */}
+7 -4
View File
@@ -1,5 +1,6 @@
import Link from "next/link";
import Image from "next/image";
import { getTranslations } from "next-intl/server";
import { Server, Database, Key, Palette, Globe, Settings, Cpu } from "lucide-react";
import DeepWikiIcon from "@/../public/deepwiki.svg";
import Context7Icon from "@/../public/context7.svg";
@@ -17,7 +18,9 @@ export const metadata = {
description: "Deploy your own prompts.chat instance with customizable branding, themes, and authentication",
};
export default function SelfHostingPage() {
export default async function SelfHostingPage() {
const t = await getTranslations("selfHosting");
return (
<div className="container max-w-4xl py-10">
<h1 className="text-2xl font-bold mb-2">Self-Hosting Guide</h1>
@@ -110,9 +113,9 @@ export default function SelfHostingPage() {
Prerequisites
</h3>
<ul className="list-disc list-inside text-muted-foreground space-y-1">
<li>Node.js 18+</li>
<li>PostgreSQL database</li>
<li>npm or yarn</li>
<li>{t("prerequisites.nodeJs")}</li>
<li>{t("prerequisites.postgresql")}</li>
<li>{t("prerequisites.npm")}</li>
</ul>
</div>
-70
View File
@@ -802,73 +802,3 @@
padding: 0;
}
/* Ezoic privacy policy container styling */
#ezoic-privacy-policy-container {
margin-top: 1rem;
color: var(--muted-foreground);
}
#ezoic-privacy-policy-container h2,
#ezoic-privacy-policy-container h3,
#ezoic-privacy-policy-container h4 {
font-size: 1rem;
font-weight: 600;
margin-top: 1rem;
margin-bottom: 0.5rem;
color: var(--foreground);
}
#ezoic-privacy-policy-container p {
margin-top: 0.75rem;
margin-bottom: 0.75rem;
line-height: 1.7;
color: var(--muted-foreground);
}
#ezoic-privacy-policy-container a {
color: var(--primary);
text-decoration: underline;
text-underline-offset: 2px;
}
#ezoic-privacy-policy-container a:hover {
opacity: 0.8;
}
#ezoic-privacy-policy-container ul,
#ezoic-privacy-policy-container ol {
margin-top: 0.75rem;
margin-bottom: 0.75rem;
padding-left: 1.5rem;
color: var(--muted-foreground);
}
#ezoic-privacy-policy-container li {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}
#ezoic-privacy-policy-container table {
width: 100%;
border-collapse: collapse;
margin: 1rem 0;
font-size: 0.875rem;
}
#ezoic-privacy-policy-container th,
#ezoic-privacy-policy-container td {
border: 1px solid var(--border);
padding: 0.5rem 0.75rem;
text-align: left;
}
#ezoic-privacy-policy-container th {
background: var(--muted);
font-weight: 600;
}
/* Ezoic ad content: center and constrain injected ad creatives */
.ezoic-ad-content * {
margin-left: auto !important;
margin-right: auto !important;
}
+4 -3
View File
@@ -7,9 +7,9 @@ import { Header } from "@/components/layout/header";
import { Footer } from "@/components/layout/footer";
import { CookieConsentBanner } from "@/components/layout/cookie-consent";
import { Analytics } from "@/components/layout/analytics";
import { EzoicAds } from "@/components/layout/ezoic-ads";
import { WebsiteStructuredData } from "@/components/seo/structured-data";
import { AppBanner } from "@/components/layout/app-banner";
import { AnnouncementBanner } from "@/components/layout/announcement-banner";
import { LocaleDetector } from "@/components/providers/locale-detector";
import { getConfig } from "@/lib/config";
import { isRtlLocale } from "@/lib/i18n/config";
@@ -153,6 +153,7 @@ export default async function RootLayout({
const pathname = headersList.get("x-pathname") || headersList.get("x-invoke-path") || "";
const isEmbedRoute = pathname.startsWith("/embed");
const isKidsRoute = pathname.startsWith("/kids");
const isPresentationRoute = pathname.startsWith("/presentation");
const locale = await getLocale();
const messages = await getMessages();
@@ -190,14 +191,14 @@ export default async function RootLayout({
{process.env.GOOGLE_ANALYTICS_ID && (
<Analytics gaId={process.env.GOOGLE_ANALYTICS_ID} />
)}
{process.env.EZOIC_ENABLED === "true" && <EzoicAds />}
<Providers locale={locale} messages={messages} theme={config.theme} branding={{ ...config.branding, useCloneBranding: config.homepage?.useCloneBranding }}>
{isEmbedRoute || isKidsRoute ? (
{isEmbedRoute || isKidsRoute || isPresentationRoute ? (
children
) : (
<>
<LocaleDetector />
<div className="relative min-h-screen flex flex-col">
<AnnouncementBanner />
<Header authProvider={config.auth.provider} allowRegistration={config.auth.allowRegistration} />
<main className="flex-1">{children}</main>
<Footer />
+20 -2
View File
@@ -72,7 +72,7 @@ export default async function HomePage() {
/>
</div>
) : (
<div className="absolute top-0 end-0 bottom-0 w-1/3 2xl:w-1/2 hidden md:block pointer-events-none">
<div className="absolute top-0 end-0 bottom-0 w-2/5 xl:w-[45%] 2xl:w-1/2 hidden md:block pointer-events-none overflow-hidden">
{/* Video background */}
<div className="absolute inset-0">
<div className="absolute inset-0 bg-gradient-to-r rtl:bg-gradient-to-l from-background via-background/80 to-transparent z-10" />
@@ -126,7 +126,7 @@ export default async function HomePage() {
)}
<div className="container relative z-20">
<div className="max-w-2xl">
<div className="max-w-2xl lg:max-w-xl xl:max-w-2xl">
{useCloneBranding ? (
<>
<h1 className="text-2xl font-bold tracking-tight sm:text-3xl md:text-4xl lg:text-5xl !text-2xl sm:!text-3xl md:!text-4xl lg:!text-5xl text-primary">
@@ -313,6 +313,24 @@ export default async function HomePage() {
/>
</BuiltWithLink>
<span>by Cognition</span>
<span className="mx-0.5">·</span>
<span>hosted on</span>
<Link href="https://vercel.com/oss" target="_blank" rel="noopener noreferrer" className="inline-flex items-center opacity-60 hover:opacity-100 transition-opacity">
<Image
src="/sponsors/vercel-oss.svg"
alt="Vercel OSS Program"
width={240}
height={24}
className="h-4.5 w-auto dark:hidden"
/>
<Image
src="/sponsors/vercel-oss-dark.svg"
alt="Vercel OSS Program"
width={240}
height={24}
className="h-4.5 w-auto hidden dark:block"
/>
</Link>
</span>
</div>
)}
+141
View File
@@ -0,0 +1,141 @@
"use client";
import { useCallback, useEffect, useRef, useState } from "react";
import { ChevronLeft, ChevronRight, RadioTower, WifiOff } from "lucide-react";
type DeckState = {
currentSlide: number;
totalSlides: number;
notes: string[];
};
export default function PresenterNotesPage() {
const channelRef = useRef<BroadcastChannel | null>(null);
const [state, setState] = useState<DeckState | null>(null);
const [connected, setConnected] = useState(false);
const send = useCallback((message: Record<string, unknown>) => {
channelRef.current?.postMessage(message);
}, []);
useEffect(() => {
if (typeof window === "undefined" || typeof BroadcastChannel === "undefined") return;
const channel = new BroadcastChannel("prompts-presentation");
channelRef.current = channel;
channel.onmessage = (event) => {
const data = event.data;
if (data?.type === "state") {
setConnected(true);
setState({
currentSlide: data.currentSlide ?? 0,
totalSlides: data.totalSlides ?? 0,
notes: Array.isArray(data.notes) ? data.notes : [],
});
}
};
channel.postMessage({ type: "request" });
const retry = setInterval(() => {
if (!channelRef.current) return;
channelRef.current.postMessage({ type: "request" });
}, 1000);
return () => {
clearInterval(retry);
channel.close();
channelRef.current = null;
};
}, []);
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "ArrowRight" || event.key === " " || event.key === "PageDown") {
event.preventDefault();
send({ type: "next" });
} else if (event.key === "ArrowLeft" || event.key === "PageUp") {
event.preventDefault();
send({ type: "prev" });
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [send]);
const current = state?.currentSlide ?? 0;
const total = state?.totalSlides ?? 0;
const notes = state?.notes ?? [];
const currentNote = notes[current];
const nextNote = notes[current + 1];
const atStart = current <= 0;
const atEnd = total > 0 && current >= total - 1;
return (
<div className="flex h-[100dvh] w-screen flex-col bg-zinc-950 text-zinc-100">
<header className="flex items-center justify-between border-b border-white/10 px-6 py-4">
<div className="flex items-center gap-3">
<span className="text-sm font-bold uppercase tracking-[0.28em] text-primary">Presenter notes</span>
<span
className={`inline-flex items-center gap-1.5 rounded-full px-3 py-1 text-xs font-semibold ${
connected ? "bg-emerald-500/15 text-emerald-300" : "bg-amber-500/15 text-amber-300"
}`}
>
{connected ? <RadioTower className="h-3.5 w-3.5" /> : <WifiOff className="h-3.5 w-3.5" />}
{connected ? "Synced" : "Waiting for deck…"}
</span>
</div>
<div className="rounded-full border border-white/15 px-4 py-1.5 text-sm font-semibold text-zinc-300">
{total > 0 ? `Slide ${current + 1} / ${total}` : "—"}
</div>
</header>
<main className="flex flex-1 flex-col gap-6 overflow-hidden p-6 sm:p-8">
<section className="flex min-h-0 flex-1 flex-col rounded-3xl border border-white/10 bg-white/[0.03] p-6 sm:p-8">
<div className="mb-4 text-xs font-bold uppercase tracking-[0.24em] text-primary">Now</div>
<div className="min-h-0 flex-1 overflow-y-auto pr-2">
{connected ? (
<p className="text-2xl font-medium leading-relaxed text-zinc-100 sm:text-3xl">
{currentNote || "No note for this slide."}
</p>
) : (
<p className="text-xl text-zinc-400">
Open the presentation in another window and this view will sync automatically.
</p>
)}
</div>
</section>
<section className="rounded-3xl border border-white/10 bg-white/[0.02] p-5 sm:p-6">
<div className="mb-2 text-xs font-bold uppercase tracking-[0.24em] text-zinc-500">Next</div>
<p className="line-clamp-3 text-base leading-relaxed text-zinc-400 sm:text-lg">
{atEnd ? "End of deck." : nextNote || "—"}
</p>
</section>
</main>
<footer className="flex items-center justify-center gap-5 border-t border-white/10 px-6 py-5">
<button
onClick={() => send({ type: "prev" })}
disabled={atStart}
className="inline-flex h-12 w-12 items-center justify-center rounded-full border border-white/15 bg-white/5 text-zinc-200 transition hover:bg-white/10 disabled:cursor-not-allowed disabled:opacity-30"
aria-label="Previous slide"
>
<ChevronLeft className="h-6 w-6" />
</button>
<span className="min-w-[5rem] text-center text-sm font-medium text-zinc-400">
{total > 0 ? `${current + 1} / ${total}` : "—"}
</span>
<button
onClick={() => send({ type: "next" })}
disabled={atEnd}
className="inline-flex h-12 w-12 items-center justify-center rounded-full border border-white/15 bg-white/5 text-zinc-200 transition hover:bg-white/10 disabled:cursor-not-allowed disabled:opacity-30"
aria-label="Next slide"
>
<ChevronRight className="h-6 w-6" />
</button>
</footer>
</div>
);
}
+405 -209
View File
@@ -1,233 +1,429 @@
import { SlideDeck, SlideTitle, SlideContent, SlideHighlight } from "@/components/presentation/SlideDeck";
import { MoveRight, Star, GitMerge, FileCode2, Sparkles, MessageSquare, Globe, Users, Code, Zap, Lightbulb } from "lucide-react";
import Link from "next/link";
import { Button } from "@/components/ui/button";
import {
ArrowRight,
Bot,
BookOpen,
Boxes,
Code2,
GitBranch,
Gamepad2,
Globe,
Layers3,
Lock,
MessageSquareText,
Network,
PackageCheck,
Rocket,
Search,
Share2,
ShieldCheck,
Sparkles,
Star,
Workflow,
} from "lucide-react";
import type { LucideIcon } from "lucide-react";
import Image from "next/image";
import type { ReactNode } from "react";
import { SlideContent, SlideDeck, SlideHighlight, SlideTitle } from "@/components/presentation/SlideDeck";
export const metadata = {
title: "Why prompts.chat? | Presentation",
description: "Discover why prompts are more important than ever in the agentic era.",
title: "prompts.chat: An Open Prompt Ecosystem for the Age of Agents | Microsoft Build",
description:
"15-minute lightning talk at Microsoft Build: how prompts.chat grew from a GitHub repo into an open prompt ecosystem — platform, book, and game — for the age of agents.",
};
const speakerNotes = [
"Okay, hi everyone. So I want to start with a mistake that, honestly, a lot of people make. They think that when AI models get smarter, prompts will not matter anymore — like, prompting is just a temporary trick and the next model will make it useless. But actually, for me, it's the opposite. Even the best models give you better answers when you give them better prompts. And in the age of agents, prompts are kind of like atoms — every agent is basically made of them. So no, prompts are not going away. They actually matter more than before. So in the next fifteen minutes, I want to show you why, and the open ecosystem I'm building around them: prompts.chat.",
"But first, a quick hello. I'm Fatih. I'm a developer advocate on the WordPress team at Automattic. I also created the Awesome ChatGPT Prompts project, and I'm a GitHub Star. Okay, that's enough about me — let's actually talk about prompts.",
"So, this whole thing actually started as a tiny GitHub repo. Just a simple list of prompts you could copy and paste. And one detail people are always surprised by — this is not new at all. I created it almost four years ago, literally about one week after OpenAI announced ChatGPT. The book came later. Honestly, back then I didn't expect much. But it kind of exploded — it became one of the most starred AI projects on GitHub, used by tens of millions of people. And that told me something: a good prompt is actually worth sharing.",
"But here's the problem, right? Most prompts just get lost. They're hidden in screenshots, random gists, old chat history. No version, no owner, no review. That great prompt you wrote last week? It's probably gone the second you closed the tab. And okay, that's annoying for us as people — but honestly, it completely falls apart once agents are involved.",
"So why does it fall apart for agents? Well, when an agent acts for you, the prompt is not just a casual message anymore. It's actually the plan. It's the contract. It's basically the source code for how that agent behaves. Look at this one — a role, a goal, the sources it can use, the limits, and when to stop. You really want to save and improve something like this, right? Not lose it somewhere in a chat.",
"So this is exactly what prompts.chat does. It treats prompts as real, shareable things. You can discover good ones, fork them, keep versions, reuse them. And it's open source, so you can even host it yourself — your team actually owns its own prompt library.",
"Now, why does being open matter so much, especially for agents? I'd say three reasons. First, you can actually read what the agent was told to do. Second, the same prompt works across different models and tools. And third, open prompts plug right into agents, editors, an MCP layer. So basically, a world full of agents needs an open world of prompts.",
"Okay, now two things people don't really expect. The first one is a book. It's called The Interactive Book of Prompting. It's free, and it's not some boring PDF — it's actually interactive, with live demos you can try right there on the page, from the basics all the way to agents.",
"And the second one is a game. So, this is Promi — a little robot — on an adventure through Prompt Land. It's a fun way for kids to learn how to talk to AI. Because, honestly, this skill shouldn't only be for engineers, right? It kind of belongs to everyone, including the next generation.",
"So if you put it all together, you actually get one open loop. The repo where it all began, the platform to discover and reuse, the book to learn, the game to bring in new people, and an API and MCP layer that feeds everything back to both humans and agents. So good prompts come in, the community makes them better, and they go back out.",
"Okay, so here's the big picture. As agents start doing real work, the prompt is how we steer them — it's becoming the interface to these systems. Now, around those prompts you need some tooling — a way to manage them, version them, test them, serve them. And a lot of people now call this the \"harness\". So, just to be clear, the harness is not the prompt itself — it's actually the tooling that keeps your prompts accurate and well-tuned. And honestly, the same model can give you very different results depending on how good that harness is. So let's keep this whole thing open, shared, and easy to improve — together.",
"And that's pretty much it. So, come build this open prompt ecosystem with us. Check out prompts.chat, read the book, play the game with your kids, and take a look at the project on GitHub. Thank you so much — and I think we have a moment for maybe one question.",
];
type CardProps = {
icon: LucideIcon;
title: string;
children: ReactNode;
accent?: string;
};
function PixelEdge() {
return (
<div
className="pointer-events-none absolute inset-x-0 top-0 h-1.5"
style={{
backgroundImage:
"repeating-linear-gradient(90deg, #F25022 0 7px, #FFB900 7px 14px, #7FBA00 14px 21px, #00A4EF 21px 28px)",
}}
aria-hidden
/>
);
}
function Card({ icon: Icon, title, children, accent = "text-primary" }: CardProps) {
return (
<div className="relative border border-white/12 bg-white/[0.03] p-6 pt-7 shadow-sm backdrop-blur transition-transform duration-300 hover:-translate-y-1">
<PixelEdge />
<div className={`mb-4 flex h-12 w-12 items-center justify-center bg-primary/10 ${accent}`}>
<Icon className="h-6 w-6" />
</div>
<h3 className="mb-2 text-2xl font-bold text-foreground">{title}</h3>
<p className="text-lg leading-relaxed text-muted-foreground">{children}</p>
</div>
);
}
function Pill({ children }: { children: ReactNode }) {
return (
<span className="inline-flex items-center rounded-none border border-primary/40 bg-primary/10 px-4 py-2 font-mono text-sm font-semibold uppercase tracking-[0.18em] text-primary">
{children}
</span>
);
}
function CodePanel({ children, title = "prompt.md" }: { children: ReactNode; title?: string }) {
return (
<div className="overflow-hidden rounded-none border border-border bg-zinc-950 text-zinc-100 shadow-2xl">
<div className="flex items-center justify-between border-b border-white/10 bg-white/5 px-5 py-3">
<div className="flex gap-2">
<span className="h-3 w-3 rounded-none bg-red-400" />
<span className="h-3 w-3 rounded-none bg-yellow-400" />
<span className="h-3 w-3 rounded-none bg-green-400" />
</div>
<span className="font-mono text-xs text-zinc-400">{title}</span>
</div>
<pre className="whitespace-pre-wrap p-6 font-mono text-sm leading-relaxed md:text-base">{children}</pre>
</div>
);
}
function FlowStep({ icon: Icon, title, text }: { icon: LucideIcon; title: string; text: string }) {
return (
<div className="relative border border-white/12 bg-white/[0.03] p-5 pt-6 shadow-sm">
<PixelEdge />
<div className="mb-4 flex h-12 w-12 items-center justify-center bg-primary/10 text-primary">
<Icon className="h-6 w-6" />
</div>
<h3 className="text-2xl font-bold">{title}</h3>
<p className="mt-2 text-lg leading-relaxed text-muted-foreground">{text}</p>
</div>
);
}
export default function PresentationPage() {
return (
<SlideDeck>
{/* 1. Title Slide */}
<div className="flex flex-col items-center justify-center text-center h-full">
<div className="w-24 h-24 bg-primary/10 rounded-3xl flex items-center justify-center mb-8 rotate-12 transition-transform hover:rotate-0 duration-500">
<Sparkles className="w-12 h-12 text-primary" />
<SlideDeck notes={speakerNotes}>
<div className="flex min-h-[70vh] flex-col items-center justify-center text-center">
<Image
src="/presentation/build-logo.png"
alt="Microsoft Build"
width={720}
height={405}
priority
unoptimized
className="mb-10 h-auto w-[20rem] md:w-[24rem]"
/>
<div className="mb-7 flex items-center justify-center">
<Image
src="/logo-dark.svg"
alt="prompts.chat logo"
width={112}
height={112}
unoptimized
className="h-24 w-24 object-contain"
/>
</div>
<SlideTitle className="mb-6">Why prompts.chat?</SlideTitle>
<SlideContent className="max-w-3xl mb-12">Discover why prompts are more important than ever in the agentic era.</SlideContent>
<p className="text-sm text-muted-foreground animate-pulse mt-8">
Use arrow keys <MoveRight className="inline w-4 h-4 mx-1" /> or swipe to navigate
<SlideTitle className="max-w-5xl">prompts.chat</SlideTitle>
<SlideContent className="mx-auto max-w-4xl">
Building an <SlideHighlight>Open Prompt Ecosystem</SlideHighlight> for the Age of Agents
</SlideContent>
<p className="mx-auto mt-6 max-w-3xl text-lg font-medium text-muted-foreground/80 md:text-xl">
Smarter models don&apos;t make prompts obsolete — prompts are the{" "}
<SlideHighlight>atoms of every agent</SlideHighlight>.
</p>
</div>
{/* 2. The Genesis */}
<div className="flex flex-col justify-center h-full">
<Star className="w-12 h-12 text-yellow-500 mb-6" />
<SlideTitle>The History of prompts.chat</SlideTitle>
<SlideContent>
From a simple repository to a full-fledged platform. We started as Awesome ChatGPT Prompts, and evolved to support the entire AI community with typed prompts, workflows, and skills.
</SlideContent>
<div className="mt-12 p-6 bg-muted/50 rounded-2xl border border-border max-w-2xl">
<p className="text-lg text-foreground font-mono">
Awesome ChatGPT Prompts → <SlideHighlight>prompts.chat</SlideHighlight>
<div className="grid min-h-[70vh] items-center gap-8 lg:grid-cols-[1fr_0.95fr]">
<div className="relative order-2 lg:order-1">
<div className="absolute -left-8 top-10 h-72 w-72 rounded-none bg-primary/20 blur-3xl" />
<div className="relative mx-auto w-full max-w-[34rem]">
<div className="absolute -inset-4 -rotate-3 rounded-none bg-gradient-to-br from-primary/30 via-primary/10 to-transparent" />
<div className="relative overflow-hidden rounded-none border border-border bg-background shadow-2xl">
<Image
src="https://github.com/f.png"
alt="Fatih Kadir Akın profile photo"
width={900}
height={900}
priority
unoptimized
className="aspect-square w-full object-cover"
/>
<div className="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/80 via-black/45 to-transparent p-8 text-white">
<h2 className="mt-2 text-5xl font-black tracking-tight">Fatih Kadir Akın</h2>
<p className="mt-3 max-w-md text-lg font-semibold leading-snug text-white/85">
Developer Advocate, WordPress @ Automattic
<br /> Creator of prompts.chat
<br /> GitHub Star
</p>
</div>
</div>
</div>
</div>
<div className="order-1 lg:order-2">
<SlideTitle className="mb-5">Hi, I&apos;m Fatih.</SlideTitle>
<SlideContent className="max-w-2xl">
I build tools that make developers&apos; lives easier — one of them is{" "}
<SlideHighlight>prompts.chat</SlideHighlight>.
</SlideContent>
<div className="mt-10 flex flex-wrap items-center gap-5">
<div className="flex items-center gap-3 rounded-none border border-border/70 bg-background/75 px-5 py-4 shadow-sm backdrop-blur">
<Image
src="https://cdn.simpleicons.org/automattic/FFFFFF"
alt="Automattic"
width={40}
height={40}
unoptimized
className="h-10 w-10"
/>
<span className="text-xl font-bold text-foreground">Automattic</span>
</div>
<div className="flex items-center gap-3 rounded-none border border-border/70 bg-background/75 px-5 py-4 shadow-sm backdrop-blur">
<Star className="h-9 w-9 text-yellow-500" />
<span className="text-xl font-bold text-foreground">GitHub Star</span>
</div>
</div>
</div>
</div>
<div className="grid min-h-[70vh] items-center gap-10 lg:grid-cols-2">
<div>
<SlideTitle>It started as a GitHub repo</SlideTitle>
<SlideContent>
<SlideHighlight>Awesome ChatGPT Prompts</SlideHighlight> — a simple list of copy-paste prompts that grew
into one of the most-starred AI repositories in the world.
</SlideContent>
<p className="mt-6 max-w-2xl text-lg font-medium text-muted-foreground/80 md:text-xl">
And it&apos;s not new — the repo (and later the book) are almost{" "}
<SlideHighlight>four years old</SlideHighlight>, born just a week after OpenAI announced ChatGPT.
</p>
</div>
</div>
{/* 3. The Paradigm Shift */}
<div className="flex flex-col justify-center h-full">
<Zap className="w-12 h-12 text-blue-500 mb-6" />
<SlideTitle>The Agentic Era</SlideTitle>
<SlideContent>
Why are prompts still important? Because agents need instructions. As AI becomes more autonomous, the quality of instructions determines the quality of the outcome.
</SlideContent>
</div>
{/* 4. The Core Question */}
<div className="flex flex-col items-center justify-center text-center h-full">
<Lightbulb className="w-16 h-16 text-yellow-400 mb-8" />
<SlideTitle className="text-5xl md:text-6xl">Wait, isn't AI getting smarter?</SlideTitle>
<SlideContent className="max-w-4xl mt-8">
Yes, but <SlideHighlight>smart AI still needs direction.</SlideHighlight>
<br /><br />
A genius without instructions is just a very capable idle machine.
</SlideContent>
</div>
{/* 5. The Agentic Need */}
<div className="flex flex-col justify-center h-full">
<SlideTitle>The Agentic Need</SlideTitle>
<SlideContent>
Agents require precise instructions, constraints, and goal definitions.
<ul className="mt-8 space-y-6 list-disc list-inside ml-4 text-foreground/80 text-2xl md:text-3xl">
<li>What tools can they use?</li>
<li>What are their boundaries?</li>
<li>How should they format the output?</li>
<li>What tone should they adopt?</li>
</ul>
</SlideContent>
</div>
{/* 6. The SLM Revolution */}
<div className="flex flex-col justify-center h-full">
<Globe className="w-12 h-12 text-green-500 mb-6" />
<SlideTitle>Crucial for SLMs</SlideTitle>
<SlideContent>
Small Language Models (SLMs) are the future of edge computing. They require precise, well-crafted prompts to perform tasks accurately without the massive parameter count of frontier models.
</SlideContent>
</div>
{/* 7. SLM Constraints */}
<div className="flex flex-col justify-center h-full">
<SlideTitle>SLM Constraints</SlideTitle>
<SlideContent>
Smaller models lack the vast "common sense" of 1T+ parameter models.
<br /><br />
They require <SlideHighlight>highly optimized, battle-tested prompts</SlideHighlight> to punch above their weight class and run efficiently on local devices.
</SlideContent>
</div>
{/* 8. The New Primitive */}
<div className="flex flex-col justify-center h-full">
<FileCode2 className="w-12 h-12 text-purple-500 mb-6" />
<SlideTitle>Prompts are New Code Snippets</SlideTitle>
<SlideContent>
Just as developers copy/paste code snippets from StackOverflow, AI practitioners now share prompt templates. Prompts are the new primitive of programming.
</SlideContent>
<div className="mt-12 flex items-center gap-4 text-xl md:text-2xl font-mono text-muted-foreground bg-muted p-6 rounded-xl border max-w-fit">
<span>const codeSnippet = "..."</span>
<MoveRight className="w-6 h-6 text-primary mx-2" />
<span className="text-primary">const promptTemplate = "..."</span>
<div className="grid gap-4">
<Card icon={Star} title="Hundreds of thousands of stars" accent="text-yellow-500">
One of GitHub&apos;s most popular AI projects.
</Card>
<Card icon={Globe} title="Tens of millions of developers">
People copied these prompts into every AI tool imaginable.
</Card>
<Card icon={MessageSquareText} title="A new kind of artifact">
The prompt itself became something worth sharing.
</Card>
</div>
</div>
{/* 9. Open Source AI */}
<div className="flex flex-col justify-center h-full">
<Users className="w-12 h-12 text-indigo-500 mb-6" />
<SlideTitle>Community Sharing</SlideTitle>
<SlideContent>
Nobody learns in isolation. By sharing prompts, we accelerate the collective understanding of how to communicate with AI. It's the open-source movement for human-AI interaction.
</SlideContent>
</div>
{/* 10. Collective Intelligence */}
<div className="flex flex-col items-center justify-center text-center h-full">
<SlideTitle className="text-5xl md:text-6xl">Collective Intelligence</SlideTitle>
<SlideContent className="max-w-4xl mt-8">
We are building the <SlideHighlight>largest open repository</SlideHighlight> of human-AI interaction patterns.
<br /><br />
Tested, versioned, and peer-reviewed.
</SlideContent>
</div>
{/* 11. Feature - Typed Prompts */}
<div className="flex flex-col justify-center h-full">
<Code className="w-12 h-12 text-red-500 mb-6" />
<SlideTitle>Feature: Typed Prompts</SlideTitle>
<SlideContent>
Natural language is ambiguous. <SlideHighlight>Typed Prompts</SlideHighlight> bring structure.
<br /><br />
Define inputs, outputs, and variables systematically so prompts can be executed predictably via APIs.
</SlideContent>
</div>
{/* 12. Feature - Workflows */}
<div className="flex flex-col justify-center h-full">
<div className="flex gap-2 mb-6">
<div className="w-8 h-8 rounded bg-primary"></div>
<MoveRight className="w-8 h-8 text-muted-foreground" />
<div className="w-8 h-8 rounded bg-primary/70"></div>
<MoveRight className="w-8 h-8 text-muted-foreground" />
<div className="w-8 h-8 rounded bg-primary/40"></div>
<div className="flex min-h-[70vh] flex-col justify-center">
<SlideTitle>But prompts get lost</SlideTitle>
<div className="grid gap-6 md:grid-cols-3">
<Card icon={Share2} title="Scattered" accent="text-orange-500">
Trapped in screenshots, gists, and DMs.
</Card>
<Card icon={GitBranch} title="Unversioned" accent="text-sky-500">
No history, no review, no ownership.
</Card>
<Card icon={Lock} title="Locked in chats" accent="text-red-500">
The good ones disappear when the tab closes.
</Card>
</div>
<SlideTitle>Feature: Workflows</SlideTitle>
<SlideContent>
Some tasks are too complex for a single prompt.
<br /><br />
Chain multiple prompts together to create <SlideHighlight>Workflows</SlideHighlight> — dividing and conquering complex agentic tasks.
<SlideContent className="mt-10 max-w-4xl">
Annoying for humans — and <SlideHighlight>broken for agents</SlideHighlight>.
</SlideContent>
</div>
{/* 13. Feature - Agent Skills */}
<div className="flex flex-col justify-center h-full">
<SlideTitle>Feature: Agent Skills</SlideTitle>
<SlideContent>
Equip coding assistants (like Claude, Cursor, Windsurf) with specialized, multi-file capabilities.
<br /><br />
Give your AI the context and rules it needs to build within your specific tech stack.
</SlideContent>
</div>
{/* 14. Feature - Change Requests */}
<div className="flex flex-col justify-center h-full">
<GitMerge className="w-12 h-12 text-orange-500 mb-6" />
<SlideTitle>Feature: Change Requests</SlideTitle>
<SlideContent>
Prompts evolve. We've introduced <SlideHighlight>Pull Requests for Prompts.</SlideHighlight>
<br /><br />
Collaborate, suggest improvements, and refine instructions together as a community.
</SlideContent>
</div>
{/* 15. For Developers */}
<div className="flex flex-col justify-center h-full">
<SlideTitle>For Developers</SlideTitle>
<SlideContent>
prompts.chat isn't just for end-users. With features like Agent Skills, Typed Prompts, and API integrations, it's a vital tool for developers building the next generation of AI apps.
</SlideContent>
</div>
{/* 16. For Everyone */}
<div className="flex flex-col justify-center h-full">
<MessageSquare className="w-12 h-12 text-pink-500 mb-6" />
<SlideTitle>For Everyone</SlideTitle>
<SlideContent>
Discover, collect, and learn from <SlideHighlight>Promptmasters</SlideHighlight>.
<br /><br />
A beautifully designed, accessible platform to find exactly what you need to make AI work for you.
</SlideContent>
</div>
{/* 17. Self-Hosted */}
<div className="flex flex-col justify-center h-full">
<Globe className="w-12 h-12 text-teal-500 mb-6" />
<SlideTitle>Fully Self-Hosted</SlideTitle>
<SlideContent>
Your data, your platform.
<br /><br />
prompts.chat is <SlideHighlight>100% open-source</SlideHighlight> and deployable to any server or cloud provider. Own your organization's prompt library securely.
</SlideContent>
</div>
{/* 18. The Vision */}
<div className="flex flex-col items-center justify-center text-center h-full">
<SlideTitle className="text-5xl md:text-6xl">The Vision</SlideTitle>
<SlideContent className="max-w-4xl mt-8">
To create the <SlideHighlight>standard protocol</SlideHighlight> for human-AI interaction.
<br /><br />
Where every great instruction is shared, improved, and accessible to all.
</SlideContent>
</div>
{/* 19. Call to Action */}
<div className="flex flex-col items-center justify-center text-center h-full">
<div className="w-24 h-24 bg-primary/10 rounded-full flex items-center justify-center mb-8">
<Users className="w-12 h-12 text-primary" />
<div className="grid min-h-[70vh] items-center gap-8 lg:grid-cols-2">
<div>
<SlideTitle>In the age of agents, a prompt is a spec</SlideTitle>
<SlideContent>
When an agent acts on your behalf, the prompt stops being a casual message. It becomes the{" "}
<SlideHighlight>contract</SlideHighlight> — the source code of behavior.
</SlideContent>
</div>
<SlideTitle>Join the Community</SlideTitle>
<SlideContent className="max-w-2xl mb-12">
Start exploring, sharing, and building the future of AI interaction today.
<CodePanel title="agent-instructions.md">
{`Role: Release notes agent for our repo.
Goal: Summarize merged PRs since the last tag.
Sources: GitHub API, CHANGELOG.md.
Limits: No breaking-change claims without a label.
Stop: When the draft is posted for review.
Output: Markdown, grouped by feature / fix / chore.`}
</CodePanel>
</div>
<div className="grid min-h-[70vh] items-center gap-10 lg:grid-cols-[1.05fr_0.95fr]">
<div>
<SlideTitle>prompts.chat: an open prompt ecosystem</SlideTitle>
<SlideContent>
Prompts as <SlideHighlight>first-class assets</SlideHighlight> — discoverable, forkable, versioned, and
reusable. Open source and self-hostable.
</SlideContent>
</div>
<div className="grid gap-4 sm:grid-cols-2">
<Card icon={Search} title="Discover">
Find a proven prompt instead of starting from scratch.
</Card>
<Card icon={GitBranch} title="Fork">
Branch it, tweak it, make it yours.
</Card>
<Card icon={Layers3} title="Version">
Prompts mature through review and feedback.
</Card>
<Card icon={PackageCheck} title="Reuse">
Carry quality across teams, tools, and agents.
</Card>
</div>
</div>
<div className="flex min-h-[70vh] flex-col justify-center">
<SlideTitle>Why open matters for agents</SlideTitle>
<div className="grid gap-6 md:grid-cols-3">
<Card icon={ShieldCheck} title="Inspectable" accent="text-emerald-500">
You can read exactly what the agent was told to do.
</Card>
<Card icon={Globe} title="Portable" accent="text-sky-500">
The same instruction travels across models and tools.
</Card>
<Card icon={Bot} title="Composable" accent="text-purple-500">
Open prompts plug into agents, IDEs, and an MCP layer.
</Card>
</div>
<SlideContent className="mt-10">
An ecosystem of agents needs an <SlideHighlight>open</SlideHighlight> ecosystem of prompts.
</SlideContent>
<div className="flex flex-col sm:flex-row gap-4">
<Link href="/discover">
<Button size="lg" className="text-lg px-8 py-6 rounded-xl">Explore Prompts</Button>
</Link>
<Link href="https://github.com/fka/awesome-chatgpt-prompts" target="_blank">
<Button size="lg" variant="outline" className="text-lg px-8 py-6 rounded-xl">Star on GitHub</Button>
</Link>
</div>
<div className="grid min-h-[70vh] items-center gap-10 lg:grid-cols-2">
<div>
<SlideTitle>Learn it: The Interactive Book of Prompting</SlideTitle>
<SlideContent>
A <SlideHighlight>free, interactive</SlideHighlight> prompt-engineering guide — with live, hands-on demos
instead of a static PDF.
</SlideContent>
<div className="mt-7 space-y-3">
<div className="flex items-center gap-3 text-lg text-muted-foreground">
<BookOpen className="h-5 w-5 flex-none text-primary" />
Hands-on chapters, from fundamentals to agents.
</div>
<div className="flex items-center gap-3 text-lg text-muted-foreground">
<Code2 className="h-5 w-5 flex-none text-primary" />
Runnable demos you can try right on the page.
</div>
</div>
<div className="mt-8 flex flex-wrap gap-3">
<Pill>prompts.chat/book</Pill>
<Pill>Open &amp; community-driven</Pill>
</div>
</div>
<div className="relative mx-auto w-full max-w-[34rem]">
<div className="absolute -inset-4 -rotate-2 rounded-none bg-gradient-to-br from-primary/30 via-primary/10 to-transparent" />
<div className="relative overflow-hidden rounded-none border border-border bg-background shadow-2xl">
<Image
src="/book-cover-photo.jpg"
alt="The Interactive Book of Prompting cover"
width={1200}
height={630}
unoptimized
className="h-auto w-full object-cover"
/>
</div>
</div>
</div>
<div className="grid min-h-[70vh] items-center gap-10 lg:grid-cols-2">
<div>
<SlideTitle>Play it: Promi in Prompt Land</SlideTitle>
<SlideContent>
A <SlideHighlight>game-based</SlideHighlight> way for kids to learn how to talk to AI — because this
literacy belongs to everyone.
</SlideContent>
<div className="mt-7 space-y-3">
<div className="flex items-center gap-3 text-lg text-muted-foreground">
<Gamepad2 className="h-5 w-5 flex-none text-green-500" />
Join Promi the robot on an adventure through Prompt Land.
</div>
<div className="flex items-center gap-3 text-lg text-muted-foreground">
<Sparkles className="h-5 w-5 flex-none text-amber-500" />
Kids practice asking AI for what they actually want.
</div>
</div>
<div className="mt-8 flex flex-wrap gap-3">
<Pill>prompts.chat/kids</Pill>
<Pill>For the next generation</Pill>
</div>
</div>
<div className="relative mx-auto w-full max-w-[19rem]">
<div className="absolute -inset-4 rotate-2 rounded-none bg-gradient-to-br from-primary/30 via-primary/10 to-transparent" />
<div className="relative overflow-hidden rounded-none border border-border bg-background shadow-2xl">
<Image
src="/presentation/kids-screenshot.png"
alt="Promi in Prompt Land — the kids game"
width={800}
height={2026}
unoptimized
className="h-auto w-full object-cover"
/>
</div>
</div>
</div>
<div className="flex min-h-[70vh] flex-col justify-center">
<SlideTitle>One open loop</SlideTitle>
<div className="grid gap-5 md:grid-cols-5">
<FlowStep icon={Star} title="Repo" text="Where it all began." />
<FlowStep icon={Boxes} title="Platform" text="Discover, fork, version, reuse." />
<FlowStep icon={BookOpen} title="Book" text="Learn the craft." />
<FlowStep icon={Gamepad2} title="Game" text="Onboard the next generation." />
<FlowStep icon={Network} title="API / MCP" text="Feed humans and agents." />
</div>
<SlideContent className="mt-10 max-w-4xl">
Prompts flow in, get refined by the community, and flow back out to{" "}
<SlideHighlight>humans and agents</SlideHighlight>.
</SlideContent>
</div>
<div className="flex min-h-[70vh] flex-col items-center justify-center text-center">
<div className="mb-8 flex h-24 w-24 items-center justify-center rounded-none bg-primary/10 text-primary">
<Workflow className="h-12 w-12" />
</div>
<SlideTitle className="max-w-5xl">Prompts are the new interface</SlideTitle>
<SlideContent className="mx-auto max-w-4xl">
As agents take action, the prompt is how we steer them — and the tooling that manages those prompts is what
people now call the <SlideHighlight>&ldquo;harness&rdquo;</SlideHighlight>.
</SlideContent>
<p className="mx-auto mt-6 max-w-3xl text-lg font-medium text-muted-foreground/80 md:text-xl">
The harness isn&apos;t the prompt — it&apos;s what keeps your prompts accurate and well-tuned. So let&apos;s
keep it <SlideHighlight>open, shared, and improvable</SlideHighlight>.
</p>
</div>
<div className="flex min-h-[70vh] flex-col items-center justify-center text-center">
<div className="mb-8 flex h-24 w-24 items-center justify-center rounded-none bg-primary/10 text-primary">
<Rocket className="h-12 w-12" />
</div>
<SlideTitle>Thank you</SlideTitle>
<SlideContent className="mx-auto max-w-4xl">
Come build the open prompt ecosystem with us.
</SlideContent>
<div className="mt-10 flex flex-wrap justify-center gap-3">
<Pill>prompts.chat</Pill>
<Pill>/book</Pill>
<Pill>/kids</Pill>
<Pill>github.com/f/prompts.chat</Pill>
</div>
<div className="mt-8 flex items-center gap-2 text-lg font-semibold text-muted-foreground">
Questions <ArrowRight className="h-5 w-5" />
</div>
</div>
</SlideDeck>
-21
View File
@@ -97,27 +97,6 @@ export default function PrivacyPage() {
</p>
</section>
{process.env.EZOIC_ENABLED === "true" && (
<section className="space-y-3">
<h2 className="text-lg font-semibold">Advertising & Ezoic</h2>
<p className="text-muted-foreground">
We use Ezoic to provide personalized ads and analytics on this site. Ezoic and its partners
may collect and use data about your visit to this and other websites to provide relevant
advertisements. For full details on how Ezoic and its partners use your information, including
a list of known cookies used on this site, please see the{" "}
<a
href="http://g.ezoic.net/privacy/prompts.chat"
target="_blank"
rel="noopener noreferrer"
className="underline hover:text-foreground"
>
Ezoic privacy disclosures
</a>.
</p>
<span id="ezoic-privacy-policy-embed"></span>
</section>
)}
<section className="space-y-3">
<h2 className="text-lg font-semibold">Your Rights & CC0 License</h2>
<p className="text-muted-foreground">
+2
View File
@@ -23,6 +23,8 @@ function getUserIdentifier(user: { email: string; username: string; githubUserna
return user.githubUsername || (isUnclaimedAccount ? user.username : user.email);
}
export const revalidate = 3600;
export async function GET() {
try {
const prompts = await db.prompt.findMany({
+210 -121
View File
@@ -1,5 +1,6 @@
import { NextResponse } from "next/server";
import { NextRequest, NextResponse } from "next/server";
import { db } from "@/lib/db";
import crypto from "crypto";
function getUserIdentifier(user: {
username: string;
@@ -8,139 +9,227 @@ function getUserIdentifier(user: {
return user.githubUsername || user.username;
}
export async function GET() {
const CONTENT_PREVIEW_LENGTH = 500;
const DEFAULT_LIMIT = 50;
const MAX_LIMIT = 100;
export const dynamic = "force-dynamic";
export const revalidate = 3600;
function generateETag(count: number, latestUpdatedAt: Date | null): string {
const raw = `${count}-${latestUpdatedAt?.toISOString() ?? "none"}`;
const hash = crypto.createHash("md5").update(raw).digest("hex");
return `"${hash}"`;
}
export async function GET(request: NextRequest) {
try {
const prompts = await db.prompt.findMany({
where: {
isPrivate: false,
isUnlisted: false,
deletedAt: null,
const searchParams = request.nextUrl.searchParams;
const fullContent = searchParams.get("full_content") === "true";
const pageParam = searchParams.get("page");
const limitParam = searchParams.get("limit");
const isPaginated = pageParam !== null || limitParam !== null;
const page = Math.max(1, parseInt(pageParam ?? "1", 10) || 1);
const limit = Math.min(
MAX_LIMIT,
Math.max(1, parseInt(limitParam ?? String(DEFAULT_LIMIT), 10) || DEFAULT_LIMIT)
);
const whereClause = {
isPrivate: false,
isUnlisted: false,
deletedAt: null,
};
// Fetch total count and latest updatedAt for ETag generation
const [totalCount, latestPrompt] = await Promise.all([
db.prompt.count({ where: whereClause }),
db.prompt.findFirst({
where: whereClause,
orderBy: { updatedAt: "desc" },
select: { updatedAt: true },
}),
]);
// Generate and check ETag for conditional requests
const etag = generateETag(totalCount, latestPrompt?.updatedAt ?? null);
const ifNoneMatch = request.headers.get("If-None-Match");
if (ifNoneMatch && ifNoneMatch === etag) {
return new NextResponse(null, {
status: 304,
headers: {
ETag: etag,
"Cache-Control":
"public, max-age=3600, s-maxage=3600, stale-while-revalidate=86400",
},
});
}
const selectClause = {
id: true,
title: true,
slug: true,
description: true,
content: true,
type: true,
mediaUrl: true,
viewCount: true,
createdAt: true,
updatedAt: true,
structuredFormat: true,
isFeatured: true,
featuredAt: true,
requiresMediaUpload: true,
requiredMediaType: true,
requiredMediaCount: true,
category: {
select: {
id: true,
name: true,
slug: true,
icon: true,
},
},
select: {
id: true,
title: true,
slug: true,
description: true,
content: true,
type: true,
mediaUrl: true,
viewCount: true,
createdAt: true,
updatedAt: true,
structuredFormat: true,
isFeatured: true,
featuredAt: true,
requiresMediaUpload: true,
requiredMediaType: true,
requiredMediaCount: true,
category: {
select: {
id: true,
name: true,
slug: true,
icon: true,
},
author: {
select: {
username: true,
name: true,
avatar: true,
githubUsername: true,
verified: true,
},
author: {
select: {
username: true,
name: true,
avatar: true,
githubUsername: true,
verified: true,
},
},
contributors: {
select: {
username: true,
name: true,
avatar: true,
githubUsername: true,
verified: true,
},
contributors: {
select: {
username: true,
name: true,
avatar: true,
githubUsername: true,
verified: true,
},
},
tags: {
select: {
tag: {
select: {
id: true,
name: true,
slug: true,
color: true,
},
},
tags: {
select: {
tag: {
select: {
id: true,
name: true,
slug: true,
color: true,
},
},
},
_count: {
select: {
votes: true,
comments: true,
},
},
_count: {
select: {
votes: true,
comments: true,
},
},
orderBy: { createdAt: "desc" },
} as const;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const queryOptions: any = {
where: whereClause,
select: selectClause,
orderBy: { createdAt: "desc" as const },
};
if (isPaginated) {
queryOptions.skip = (page - 1) * limit;
queryOptions.take = limit;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const prompts: any[] = await db.prompt.findMany(queryOptions);
const includeFullContent = fullContent;
const formattedPrompts = prompts.map((prompt) => {
const content = prompt.content ?? "";
const contentPreview =
content.length > CONTENT_PREVIEW_LENGTH
? content.slice(0, CONTENT_PREVIEW_LENGTH) + "..."
: content;
return {
id: prompt.id,
title: prompt.title,
slug: prompt.slug,
description: prompt.description,
...(includeFullContent
? { content, contentPreview }
: { contentPreview }),
type: prompt.type,
structuredFormat: prompt.structuredFormat,
mediaUrl: prompt.mediaUrl,
viewCount: prompt.viewCount,
voteCount: prompt._count.votes,
commentCount: prompt._count.comments,
isFeatured: prompt.isFeatured,
featuredAt: prompt.featuredAt,
requiresMediaUpload: prompt.requiresMediaUpload,
requiredMediaType: prompt.requiredMediaType,
requiredMediaCount: prompt.requiredMediaCount,
createdAt: prompt.createdAt,
updatedAt: prompt.updatedAt,
category: prompt.category
? {
id: prompt.category.id,
name: prompt.category.name,
slug: prompt.category.slug,
icon: prompt.category.icon,
}
: null,
author: {
username: prompt.author.username,
name: prompt.author.name,
avatar: prompt.author.avatar,
identifier: getUserIdentifier(prompt.author),
verified: prompt.author.verified,
},
contributors: prompt.contributors.map((c: { username: string; name: string | null; avatar: string | null; githubUsername: string | null; verified: boolean }) => ({
username: c.username,
name: c.name,
avatar: c.avatar,
identifier: getUserIdentifier(c),
verified: c.verified,
})),
tags: prompt.tags.map((pt: { tag: { id: string; name: string; slug: string; color: string | null } }) => ({
id: pt.tag.id,
name: pt.tag.name,
slug: pt.tag.slug,
color: pt.tag.color,
})),
};
});
const formattedPrompts = prompts.map((prompt) => ({
id: prompt.id,
title: prompt.title,
slug: prompt.slug,
description: prompt.description,
content: prompt.content,
type: prompt.type,
structuredFormat: prompt.structuredFormat,
mediaUrl: prompt.mediaUrl,
viewCount: prompt.viewCount,
voteCount: prompt._count.votes,
commentCount: prompt._count.comments,
isFeatured: prompt.isFeatured,
featuredAt: prompt.featuredAt,
requiresMediaUpload: prompt.requiresMediaUpload,
requiredMediaType: prompt.requiredMediaType,
requiredMediaCount: prompt.requiredMediaCount,
createdAt: prompt.createdAt,
updatedAt: prompt.updatedAt,
category: prompt.category
? {
id: prompt.category.id,
name: prompt.category.name,
slug: prompt.category.slug,
icon: prompt.category.icon,
}
: null,
author: {
username: prompt.author.username,
name: prompt.author.name,
avatar: prompt.author.avatar,
identifier: getUserIdentifier(prompt.author),
verified: prompt.author.verified,
},
contributors: prompt.contributors.map((c) => ({
username: c.username,
name: c.name,
avatar: c.avatar,
identifier: getUserIdentifier(c),
verified: c.verified,
})),
tags: prompt.tags.map((pt) => ({
id: pt.tag.id,
name: pt.tag.name,
slug: pt.tag.slug,
color: pt.tag.color,
})),
}));
const totalPages = isPaginated ? Math.ceil(totalCount / limit) : 1;
return NextResponse.json(
{
count: formattedPrompts.length,
prompts: formattedPrompts,
const responseBody = isPaginated
? {
count: totalCount,
page,
limit,
totalPages,
hasMore: page < totalPages,
prompts: formattedPrompts,
}
: {
count: formattedPrompts.length,
prompts: formattedPrompts,
};
return NextResponse.json(responseBody, {
headers: {
"Cache-Control":
"public, max-age=3600, s-maxage=3600, stale-while-revalidate=86400",
ETag: etag,
},
{
headers: {
"Cache-Control": "public, max-age=3600",
},
}
);
});
} catch (error) {
console.error("prompts.json error:", error);
return NextResponse.json(
+1
View File
@@ -8,6 +8,7 @@ export const size = {
height: 630,
};
export const contentType = "image/png";
export const revalidate = 3600;
const typeLabels: Record<string, string> = {
TEXT: "Text Prompt",
+10 -2
View File
@@ -8,6 +8,7 @@ import { AnimatedDate } from "@/components/ui/animated-date";
import { ShareDropdown } from "@/components/prompts/share-dropdown";
import { auth } from "@/lib/auth";
import { db } from "@/lib/db";
import { canViewPrompt } from "@/lib/prompt-access";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
@@ -61,13 +62,20 @@ export async function generateMetadata({ params }: PromptPageProps): Promise<Met
const id = extractPromptId(idParam);
const prompt = await db.prompt.findUnique({
where: { id },
select: { title: true, description: true },
select: { title: true, description: true, isPrivate: true, authorId: true },
});
if (!prompt) {
return { title: "Prompt Not Found" };
}
if (prompt.isPrivate) {
const session = await auth();
if (!canViewPrompt(prompt, session)) {
return { title: "Prompt Not Found" };
}
}
return {
title: prompt.title,
description: prompt.description || `View the prompt: ${prompt.title}`,
@@ -223,7 +231,7 @@ export default async function PromptPage({ params }: PromptPageProps) {
}
// Check if user can view private prompt
if (prompt.isPrivate && prompt.authorId !== session?.user?.id) {
if (!canViewPrompt(prompt, session)) {
notFound();
}
+2
View File
@@ -16,6 +16,8 @@ import { isAISearchEnabled, semanticSearch } from "@/lib/ai/embeddings";
import { isAIGenerationEnabled } from "@/lib/ai/generation";
import config from "@/../prompts.config";
export const revalidate = 60;
export const metadata: Metadata = {
title: "Prompts",
description: "Browse and discover AI prompts",
-81
View File
@@ -1,81 +0,0 @@
"use client";
import { useEffect, useRef, useState } from "react";
import { useTranslations } from "next-intl";
import { runEzoic } from "@/lib/ezoic";
interface EzoicPlaceholderProps {
id: number;
}
export function EzoicPlaceholder({ id }: EzoicPlaceholderProps) {
const t = useTranslations("common");
const [isRendered, setIsRendered] = useState(false);
const [hasAdContent, setHasAdContent] = useState(true);
const placeholderRef = useRef<HTMLDivElement>(null);
useEffect(() => {
// Render the placeholder div first, then tell Ezoic to fill it.
// This ensures the DOM element exists before showAds is called.
setIsRendered(true);
// Use requestAnimationFrame to guarantee the placeholder div
// is in the DOM before Ezoic tries to find it.
const rafId = requestAnimationFrame(() => {
runEzoic(() => {
window.ezstandalone?.showAds(id);
});
});
// Observe the placeholder for ad content injection by Ezoic.
// If nothing is injected after a timeout, hide the container
// to avoid showing an empty white card.
const el = document.getElementById(`ezoic-pub-ad-placeholder-${id}`);
let observer: MutationObserver | undefined;
let timeoutId: ReturnType<typeof setTimeout> | undefined;
if (el) {
let filled = false;
observer = new MutationObserver(() => {
if (el.childNodes.length > 0 || el.innerHTML.trim().length > 0) {
filled = true;
setHasAdContent(true);
}
});
observer.observe(el, { childList: true, subtree: true });
// If Ezoic doesn't fill the placeholder within 5s, hide it
timeoutId = setTimeout(() => {
if (!filled && el.childNodes.length === 0) {
setHasAdContent(false);
}
}, 5000);
}
return () => {
cancelAnimationFrame(rafId);
observer?.disconnect();
if (timeoutId) clearTimeout(timeoutId);
runEzoic(() => {
window.ezstandalone?.destroyPlaceholders(id);
});
};
}, [id]);
if (!hasAdContent) return null;
return (
<div className="ezoic-ad-container group border rounded-[var(--radius)] overflow-hidden hover:border-foreground/20 transition-colors flex flex-col">
<div className="px-3 py-1.5 border-b bg-muted/50">
<span className="text-[10px] font-medium uppercase tracking-wider text-muted-foreground">
{t("ad")}
</span>
</div>
<div className="ezoic-ad-content overflow-hidden flex items-center justify-center">
{isRendered && <div id={`ezoic-pub-ad-placeholder-${id}`} ref={placeholderRef} />}
</div>
</div>
);
}
+5 -2
View File
@@ -9,6 +9,8 @@ interface AuthContentProps {
providers: string[];
mode: "login" | "register";
useCloneBranding?: boolean;
providerDisplayNames?: Record<string, string>;
providerLogos?: Record<string, string>;
}
const providerNames: Record<string, string> = {
@@ -19,7 +21,7 @@ const providerNames: Record<string, string> = {
credentials: "Email",
};
export function AuthContent({ providers, mode, useCloneBranding = false }: AuthContentProps) {
export function AuthContent({ providers, mode, useCloneBranding = false, providerDisplayNames, providerLogos }: AuthContentProps) {
const t = useTranslations("auth");
const hasCredentials = providers.includes("credentials");
const oauthProviders = providers.filter((p) => p !== "credentials");
@@ -34,7 +36,8 @@ export function AuthContent({ providers, mode, useCloneBranding = false }: AuthC
<OAuthButton
key={provider}
provider={provider}
providerName={providerNames[provider] || provider}
providerName={providerDisplayNames?.[provider] || providerNames[provider] || provider}
iconUrl={providerLogos?.[provider]}
/>
))}
{hasGitHub && !useCloneBranding && (
+11 -2
View File
@@ -10,6 +10,7 @@ import { analyticsAuth } from "@/lib/analytics";
interface OAuthButtonProps {
provider: string;
providerName: string;
iconUrl?: string;
}
const providerIcons: Record<string, React.ReactNode> = {
@@ -38,9 +39,10 @@ const providerIcons: Record<string, React.ReactNode> = {
),
};
export function OAuthButton({ provider, providerName }: OAuthButtonProps) {
export function OAuthButton({ provider, providerName, iconUrl }: OAuthButtonProps) {
const t = useTranslations("auth");
const [isLoading, setIsLoading] = useState(false);
const [imgError, setImgError] = useState(false);
const handleSignIn = async () => {
setIsLoading(true);
@@ -63,8 +65,15 @@ export function OAuthButton({ provider, providerName }: OAuthButtonProps) {
>
{isLoading ? (
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
) : (
) : iconUrl && !imgError ? (
/* eslint-disable-next-line @next/next/no-img-element */
<img src={iconUrl} alt={providerName} className="mr-2 h-4 w-4 object-contain" onError={() => setImgError(true)} />
) : providerIcons[provider] ? (
<span className="mr-2">{providerIcons[provider]}</span>
) : (
<span className="mr-2 flex h-4 w-4 items-center justify-center rounded bg-primary/10 text-[10px] font-bold text-primary">
{providerName.charAt(0).toUpperCase()}
</span>
)}
{t("signInWith", { provider: providerName })}
</Button>
+1 -1
View File
@@ -22,7 +22,7 @@ import { analyticsAuth } from "@/lib/analytics";
const registerSchema = z.object({
name: z.string().min(2, "Name must be at least 2 characters"),
username: z.string().min(1, "Username is required").regex(/^[a-zA-Z0-9_]+$/, "Username can only contain letters, numbers, and underscores"),
username: z.string().min(1, "Username is required").max(30, "Username must be at most 30 characters").regex(/^[a-z0-9_]+$/, "Username can only contain lowercase letters, numbers, and underscores"),
email: z.string().email("Invalid email address"),
password: z.string().min(6, "Password must be at least 6 characters"),
confirmPassword: z.string(),
@@ -0,0 +1,118 @@
"use client";
import { useEffect, useState } from "react";
import Link from "next/link";
import { useSearchParams } from "next/navigation";
import { Sparkles, X } from "lucide-react";
import { useBranding } from "@/components/providers/branding-provider";
export interface AnnouncementBannerConfig {
// Unique id used for the localStorage dismissal key. Bump this to re-show
// the banner after editing the message for a new announcement.
id: string;
// Optional href; if provided the banner becomes a link.
href?: string;
// Whether the link should open in a new tab. Defaults to true for external links.
external?: boolean;
// Main message; rendered on small+ screens.
message: React.ReactNode;
// Shorter message rendered on mobile (falls back to `message`).
messageShort?: React.ReactNode;
// Optional call-to-action label rendered after the message (e.g. "View session →").
cta?: string;
}
// Edit this to change/disable the active announcement.
// Set to `null` to hide the banner entirely.
export const ACTIVE_ANNOUNCEMENT: AnnouncementBannerConfig | null = {
id: "ms-build-2026",
href: "https://build.microsoft.com/en-US/sessions/LTG468",
external: true,
message: (
<>
<span className="font-semibold">Fatih Kadir Akın</span> is speaking about
prompts.chat at <span className="font-semibold">Microsoft Build 2026</span>
{" · June 2–3, San Francisco"}
</>
),
messageShort: (
<>
<span className="font-semibold">prompts.chat</span> at Microsoft Build 2026
</>
),
cta: "View session →",
};
export function AnnouncementBanner({
announcement = ACTIVE_ANNOUNCEMENT,
}: {
announcement?: AnnouncementBannerConfig | null;
}) {
const branding = useBranding();
const searchParams = useSearchParams();
const [isVisible, setIsVisible] = useState(false);
const storageKey = announcement
? `announcement-banner-dismissed:${announcement.id}`
: null;
const hideViaQuery = searchParams?.has("no-announcement");
useEffect(() => {
if (!storageKey) return;
const dismissed = localStorage.getItem(storageKey);
if (!dismissed) setIsVisible(true);
}, [storageKey]);
if (!announcement || !isVisible || branding.useCloneBranding || hideViaQuery) {
return null;
}
const handleDismiss = () => {
if (storageKey) localStorage.setItem(storageKey, "true");
setIsVisible(false);
};
const content = (
<>
<Sparkles className="h-3.5 w-3.5 shrink-0" aria-hidden="true" />
<span className="truncate">
<span className="hidden sm:inline">{announcement.message}</span>
<span className="sm:hidden">
{announcement.messageShort ?? announcement.message}
</span>
{announcement.cta && (
<span className="ml-1 underline-offset-2 hover:underline">
{announcement.cta}
</span>
)}
</span>
</>
);
return (
<div className="bg-gradient-to-r from-primary/90 to-primary text-primary-foreground">
<div className="container flex items-center justify-between gap-3 py-1.5 text-xs sm:text-sm">
{announcement.href ? (
<Link
href={announcement.href}
target={announcement.external ? "_blank" : undefined}
rel={announcement.external ? "noopener noreferrer" : undefined}
className="flex min-w-0 flex-1 items-center gap-2 hover:underline"
>
{content}
</Link>
) : (
<div className="flex min-w-0 flex-1 items-center gap-2">{content}</div>
)}
<button
type="button"
onClick={handleDismiss}
className="-mr-1 flex h-6 w-6 shrink-0 items-center justify-center rounded-md text-primary-foreground/80 hover:bg-primary-foreground/20 hover:text-primary-foreground"
aria-label="Dismiss announcement"
>
<X className="h-3.5 w-3.5" />
</button>
</div>
</div>
);
}

Some files were not shown because too many files have changed in this diff Show More