From 4c96c4ac2b312f7a29285ad7e87461bfdd6ba08a Mon Sep 17 00:00:00 2001
From: ShadowDara <128976697+ShadowDara@users.noreply.github.com>
Date: Wed, 9 Sep 2026 20:59:59 +0200
Subject: [PATCH 01/76] Create AGENTS.md
---
finder-template-generator-ssg/AGENTS.md | 409 ++++++++++++++++++++++++
1 file changed, 409 insertions(+)
create mode 100644 finder-template-generator-ssg/AGENTS.md
diff --git a/finder-template-generator-ssg/AGENTS.md b/finder-template-generator-ssg/AGENTS.md
new file mode 100644
index 00000000..86bcbb41
--- /dev/null
+++ b/finder-template-generator-ssg/AGENTS.md
@@ -0,0 +1,409 @@
+# AGENTS — Pages SSG Plugin + JSX Runtime
+
+Dieses Dokument beschreibt den eigenen Vite-Plugin-Stack in diesem Projekt: das Seiten-Plugin, die JSX-Runtime und den Ablauf, wie aus `.tsx`/`.jsx`-Dateien statische Seiten entstehen.
+
+Ziel:
+
+- versteht, wie Seiten in `pages/` automatisch erkannt werden
+- erklärt, wie die JSX-Runtime HTML erzeugt
+- zeigt, was man damit praktisch bauen kann
+- macht die Verbindung zwischen Page-Route, `window.PAGE_ID` und dem Render-Export klar
+
+---
+
+## 1) Überblick
+
+Das Projekt hat ein eigenes SSG-/Pages-Plugin in:
+
+- `pages-ssg-plugin.ts`
+- `src/jsx-runtime.ts`
+- `src/main.ts`
+
+Das Plugin scannt Dateien im `pages/`-Ordner, baut daraus eine virtuelle `virtual:pages`-Map und erzeugt dabei per Route eine eigene HTML-Datei.
+
+Wichtig:
+
+- Jede Seite ist normalerweise eine Datei unter `pages/`
+- Jede Seite exportiert eine Standardfunktion wie `default function render(el) { ... }`
+- Diese Funktion bekommt ein `HTMLDivElement` und schreibt dort den gerenderten Inhalt hinein
+- Die erzeugten Inhalte sind keine React-Komponenten, sondern HTML-Strings, die von der eigenen JSX-Runtime gebaut werden
+
+---
+
+## 2) Wie das Plugin funktioniert
+
+### 2.1 Seiten entdecken
+
+Im Plugin `pages-ssg-plugin.ts` läuft die Logik grob so:
+
+1. `scanPages()` liest alle Dateien im `pages/`-Verzeichnis
+2. `scanDocs()` liest Markdown-Dateien aus `docs/`
+3. `preparePages()` sammelt alle Seiten zu einer Liste
+4. `createVirtualModule()` erzeugt eine virtuelle Module-Datei mit einer Map wie:
+
+```ts
+export const pages = {
+ home: { id: "home", type: "component", load: () => import("/pages/home.tsx"), styles: [...] },
+ viewer: { id: "viewer", type: "component", load: () => import("/pages/viewer.tsx"), styles: [...] },
+};
+```
+
+Das ist wichtig, weil `src/main.ts` nicht manuell jede Seite importiert, sondern genau diese virtuelle Map verwendet.
+
+### 2.2 Route + PAGE_ID
+
+Die generierte HTML-Seite setzt in der Vorlage ein globales Fenster-Flag:
+
+```html
+
+```
+
+Dann startet `src/main.ts`:
+
+```ts
+const id = window.PAGE_ID;
+const page = pages[id];
+```
+
+Wenn die Seite gefunden wird, lädt sie dynamisch:
+
+```ts
+const module = await page.load();
+await module.default(app, page.data);
+```
+
+Das heißt: die HTML-Seite selbst ist nur das Shell-HTML; die eigentliche Seite kommt aus der Page-Datei.
+
+---
+
+## 3) Wie JSX-Seiten funktionieren
+
+### 3.1 Die JSX-Factory
+
+Die eigentliche JSX-Erzeugung geschieht in `src/jsx-runtime.ts`:
+
+```ts
+export function jsx(tag, props, ...children) { ... }
+export function Fragment(props) { ... }
+export function raw(value) { ... }
+```
+
+Die zentrale Idee ist: Statt React zu verwenden, erzeugt die Funktion direkt ein HTML-Fragment als String.
+
+Beispiel:
+
+```tsx
+return (
+ BeschreibungFinder
+
+ Finder
+
+My Product
+
+ About
+
+ Trag deine App, das Release-Archiv und die enthaltenen Binaries ein. + Daraus entsteht ein einzelnes Bash-Skript für Linux und macOS, das + herunterlädt, entpackt, in den PATH einträgt und optional zwischen + Installationsarten wählen lässt. Alles läuft nur in diesem Browser, es + wird nichts hochgeladen. +
+Wie deine App heißt und wo sie herkommt.
++ Platzhalter {"{appName}"} {"{version}"} {"{os}"} {"{arch}"} werden + beim Installieren aufgelöst, z.B. zu "mytool-darwin-arm64". +
++ Pfad, wie die Datei im entpackten Archiv heißt. OS leer lassen = auf + beiden Systemen installieren. +
+ + +Optionale Umgebungsvariablen für die Shell-RC-Datei.
+ + ++ Optional. Ohne Eintrag gibt es genau eine Installation mit allen + Binaries. Mit Einträgen erscheint ein Auswahlmenü (oder --type + <id>). +
+ + +{tool.description}
+ + + ))} ++ Exportiert alle Felder als Base64-kodierten JSON-String (UTF-8 sicher) + oder lädt sie daraus wieder zurück. +
+ +The whole finder CHANGELOG
SHA256SUMS to SHA256SUMS.txt--json to commandCUSTOM_TEMPLATESSearch on all Drives on Windows from 0.3.3, it~/.finder/templates/ or ./.finder/templates/ without recompiling the program.json5 files are automatically detected and loaded on startupparser.go: Dedicated argument parsing logichandlers.go: Isolated command handlerscommands.go: Clean routing (reduced from 300+ to 60 lines)h, -h, --help in addition to helpls in addition to list--file in addition to -f--config in addition to -c.IsHelp(), .IsList(), .IsCheck(), .IsFileLoad(), .IsDirectLoad(), .IsTemplateSearch().GetFileArg(), .GetDirectLoadArg(), .GetTemplateName()--verbose flag for extended outputtemplateloader.go)LoadUserTemplates(): Discovers user templates from filesystemJSONtemplateLoaderWithUserTemplates(): Intelligent loading with user overrideLoadAllWithUserTemplates(): Combined built-in + custom template discoveryHandleCommand()) unchangedThis version brings the biggest improvement since 0.2.0:
Template System & CLI Foundations
More Templates Better Console Output Help Message
Programm Init
the start
',styles:[f]},configeditor:{id:"configeditor",type:"component",load:()=>i(()=>import("./configeditor.js"),__vite__mapDeps([2,3]),import.meta.url),data:null,styles:[E]},creator:{id:"creator",type:"component",load:()=>i(()=>import("./creator.js"),__vite__mapDeps([4,5]),import.meta.url),data:null,styles:[]},"docs/config":{id:"docs/config",type:"markdown",html:'Port for the findergen server to view and create templates.
When set to true, the results of will be saved as a cache and can then be used afterwards
When set to true, the cache data of finder will be saved in a Git DB. Git is required for this.
Finder instances which will run at the same time when creating cache for all templates
',styles:[f]},"docs/index":{id:"docs/index",type:"markdown",html:'soon
',styles:[f]},home:{id:"home",type:"component",load:()=>i(()=>import("./home.js"),__vite__mapDeps([6,7]),import.meta.url),data:null,styles:[]},index:{id:"index",type:"component",load:()=>i(()=>import("./index.js"),[],import.meta.url),data:`# AGENTS — Finder Template Authoring Guide
+const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./cacheviewer.js","./cacheviewer.css","./configeditor.js","./configeditor.css","./creator.js","./creator.css","./home.js","./home.css","./about.js","./mcappheader.js","./mcappheader.css","./index2.js","./info.js","./worlds.js","./regexcreator.js","./regexcreator.css","./samfile.js","./jquery.module.js","./samfile.css","./index3.js","./index.css","./installscript.js","./installscript.css","./markdowneditor.js","./markdowneditor.css","./tellraw.js","./tellraw.css","./viewer.js","./viewer.css"])))=>i.map(i=>d[i]);
+const T="modulepreload",E=function(e,s){return new URL(e,s).href},y={},i=function(s,n,o){let h=Promise.resolve();if(n&&n.length>0){let d=function(l){return Promise.all(l.map(u=>Promise.resolve(u).then(m=>({status:"fulfilled",value:m}),m=>({status:"rejected",reason:m}))))};const r=document.getElementsByTagName("link"),a=document.querySelector("meta[property=csp-nonce]"),c=(a==null?void 0:a.nonce)||(a==null?void 0:a.getAttribute("nonce"));h=d(n.map(l=>{if(l=E(l,o),l in y)return;y[l]=!0;const u=l.endsWith(".css"),m=u?'[rel="stylesheet"]':"";if(!!o)for(let g=r.length-1;g>=0;g--){const j=r[g];if(j.href===l&&(!u||j.rel==="stylesheet"))return}else if(document.querySelector(`link[href="${l}"]${m}`))return;const p=document.createElement("link");if(p.rel=u?"stylesheet":T,u||(p.as="script"),p.crossOrigin="",p.href=l,c&&p.setAttribute("nonce",c),document.head.appendChild(p),u)return new Promise((g,j)=>{p.addEventListener("load",g),p.addEventListener("error",()=>j(new Error(`Unable to preload CSS for ${l}`)))})}))}function q(d){const r=new Event("vite:preloadError",{cancelable:!0});if(r.payload=d,window.dispatchEvent(r),!r.defaultPrevented)throw d}return h.then(d=>{for(const r of d||[])r.status==="rejected"&&q(r.reason);return s().catch(q)})},f=""+new URL("markdownrootstyle.css",import.meta.url).href,S=""+new URL("markdownstyle.css",import.meta.url).href,w={cacheviewer:{id:"cacheviewer",type:"component",load:()=>i(()=>import("./cacheviewer.js"),__vite__mapDeps([0,1]),import.meta.url),data:null,styles:[]},changelog:{id:"changelog",type:"markdown",html:'CHANGELOG
The whole finder CHANGELOG
Newest prob 0.3.17
- added regex support
- added mcapp minecraft world dashboard
- fixed buildcheck workflow
0.3.16 - 08.09.2026
- added cache creation
- added config editor
- added cache viewer
- Moved every site on the finder website to TSX instead
- add code to the ssg plugin which runs on build time - 07.09.2026
- the search function should return an array of
- added size plugin for the frontend
- added syntax highliting for the markdown codeblocks
- updated some templates
- renamed checksums file in the release from
SHA256SUMS to SHA256SUMS.txt - added some helpfule vite plugins
- added file content checksum check
- fixed that to old template warning because it showed up the finder and the template where in the same version
- added SHA512 checksums
0.3.15 - 02.09.2025
- added new Templates
- added a HTML Server with go backend to create and view all templates
- added json output support to finder, just add
--json to command - added tags and min version to a lot of the templates
- the Templates are now saved as minified json
0.3.14 - 25.06.2026
0.3.13 - 22.06.2026
0.3.12 - 22.06.2026
0.3.11 - 10.04.2026
0.3.10 - 10.04.2026
0.3.9 - 09.04.2026
- fixed Binary Search
0.3.8 - 27.02.2026
- added Checksums
0.3.7 - 24.02.2026
- only for releasing
0.3.6 - 24.02.2026
- added Size option to the Templates
- updated README File
- updates
CUSTOM_TEMPLATES - added a new entry to the Template: min finder version which should
- added Version package
0.3.5 - 18.02.2026
- made a Folder public for public finder modules
- added Template for
- flax
- added Time which the searching took
- resturctured the argparser
- added version Command
- added Argparser package
- removed loading templates directly from the Console or via a custom filepath!
- json output is broken in this Release, but will we fixed in future Releases
- formatted the tag Search output correctly
0.3.4 - 16.02.2026
- changed Go Version to 1.18
- fixed
Search on all Drives on Windows from 0.3.3, it - added Async Search
- made color package public
0.3.3 - 15.02.2026
- added JSON Shema
- added File Options
- Search on all Drives on Windows
- added Tag Search
0.3.2 - 15.02.2026
- little Fixes
0.3.1 - 15.02.2026
✨ Features
Runtime Custom Template System
- Custom Templates without Recompilation: Users can now create templates in
~/.finder/templates/ or ./.finder/templates/ without recompiling the program - Automatic Template Discovery: New
.json5 files are automatically detected and loaded on startup - User Templates Override: User-defined templates can override built-in templates with the same name
- Precedence System: User templates take precedence over built-in templates
CLI Reorganization & Modernization
- Modular CLI Architecture: Complete restructuring from monolithic design
parser.go: Dedicated argument parsing logichandlers.go: Isolated command handlerscommands.go: Clean routing (reduced from 300+ to 60 lines)
- Command Aliases: New shorter forms for common commands
h, -h, --help in addition to helpls in addition to list--file in addition to -f--config in addition to -c
- CLIOptions Struct: Structured argument representation with predicates
.IsHelp(), .IsList(), .IsCheck(), .IsFileLoad(), .IsDirectLoad(), .IsTemplateSearch().GetFileArg(), .GetDirectLoadArg(), .GetTemplateName()
- Verbose Mode: New
--verbose flag for extended output
Enhanced Help System
- Better Help Structure: Organized into COMMANDS, FILE & CONFIG OPERATIONS, GLOBAL FLAGS
- Table Layout: Improved readability with consistent formatting
- Custom Templates Info: Documentation for user template setup
- Detailed Descriptions: Each command with clear explanation
Enhanced List & Check Commands
- Separated Display: Built-in and custom templates are listed separately
- Template Sources: Source attribute shows whether template is built-in or custom
- Helpful Hints: Paths for custom template setup are displayed
- Improved Validation: Check command validates with source information
🧪 Testing
- 40+ new unit tests for CLI parser logic
- Parser Tests: Comprehensive coverage for command recognition, flag parsing, argument extraction
- Integration Tests: End-to-end tests for command execution
- Routing Tests: Tests for handler mapping
- Error Handling Tests: Validation of error handling and user feedback
📖 Documentation
- ARCHITECTURE.md: Detailed technical documentation of the new CLI structure
- REORGANIZATION.md: Comprehensive before/after comparison and explanation
- QUICKSTART.md: Practical guide for adding new commands
- CUSTOM_TEMPLATES.md: User guide for custom template creation
- Inline Code Comments: Improved code documentation
🔧 Infrastructure
- Enhanced Template Loader (
templateloader.go)LoadUserTemplates(): Discovers user templates from filesystemJSONtemplateLoaderWithUserTemplates(): Intelligent loading with user overrideLoadAllWithUserTemplates(): Combined built-in + custom template discovery
- Template Override Mechanism: User templates can replace built-in templates
- Graceful Error Handling: Missing user template directories are not fatal
🎯 Quality Improvements
- Clean Code Structure: Single Responsibility Principle consistently applied
- Better Testability: Each module can be tested in isolation
- Extensibility: New commands can be added in 5 simple steps
- Backward Compatibility: External API (
HandleCommand()) unchanged
👥 User Experience
- Better Error Messages: Context-sensitive error messages with suggestions
- Helpful Hints: Tips for common tasks (e.g., where to place templates)
- Flexible Command Syntax: Multiple synonyms for each command
- Consistent Output Formatting: Unified design across all commands
📊 Performance
- No Recompilation Required: Custom templates are loaded at runtime
- Efficient Template Discovery: Fast filesystem traversal
- Minimal Overhead: Template loading has negligible performance impact
🐛 Bug Fixes & Improvements
- Improved error handling in template loading
- Better handling of missing or malformed user templates
- Consistent error messages across all commands
- Fixed edge cases in CLI argument parsing
📝 Breaking Changes
- No Breaking Changes: All existing commands work unchanged
- Internal structure completely refactored, but public API remains stable
🙏 Highlights
This version brings the biggest improvement since 0.2.0:
- Users can now create their own templates
- Codebase is more maintainable and extensible
- Test coverage drastically improved
0.3.0 - 23.01.2026
Template System & CLI Foundations
0.2.0 - 23.01.2026
More Templates Better Console Output Help Message
0.1.0 - 17.11.2025
Programm Init
0.0.0 - 30.11.2025
the start
',styles:[f]},configeditor:{id:"configeditor",type:"component",load:()=>i(()=>import("./configeditor.js"),__vite__mapDeps([2,3]),import.meta.url),data:null,styles:[S]},creator:{id:"creator",type:"component",load:()=>i(()=>import("./creator.js"),__vite__mapDeps([4,5]),import.meta.url),data:null,styles:[]},"docs/config":{id:"docs/config",type:"markdown",html:'Config fields
Port
Port for the findergen server to view and create templates.
Cache
When set to true, the results of will be saved as a cache and can then be used afterwards
Create Cache Database
When set to true, the cache data of finder will be saved in a Git DB. Git is required for this.
Finder Instances
Finder instances which will run at the same time when creating cache for all templates
',styles:[f]},"docs/index":{id:"docs/index",type:"markdown",html:'Finder Docs
soon
',styles:[f]},home:{id:"home",type:"component",load:()=>i(()=>import("./home.js"),__vite__mapDeps([6,7]),import.meta.url),data:null,styles:[]},index:{id:"index",type:"component",load:()=>i(()=>import("./index.js"),[],import.meta.url),data:`# AGENTS — Finder Template Authoring Guide
This document is for AI assistants such as ChatGPT, Claude, Copilot,
and similar tools that need to create valid Finder templates.
@@ -639,4 +639,4 @@ docs in the root files.
// You dont have to use it obviously
"create_cache_db": false
}
For more and detailed Information and more config values check out the config editor here
Mistakes
I thing i would change is to use raw JSON for the templates instead of JSON with comments, which i called JSON5 back then, but it is no real JSON5.
Development
Run tests:
go test ./...
Generate coverage report:
go test -coverprofile=coverage ./...
-go tool cover -html=coverage
Build:
go build ./cmd/finder
Check the available Templates
go run ./cmd/finder check
Contributing
- Found a missing or inaccurate template? Please open an issue.
- Add new templates via PR. Keep them in JSON5 and provide a short
Roadmap / Ideas
- use temporary Template via the Command Line
- Caching/Indexing for faster searches
- Web UI for template management
- Template schema and validation
License
See LICENSE.
Project: https://github.com/shadowdara/finder
Extra Info
The Project fs-tools was more or less the prototype for finder.
Info Video
(a Youtube Video)
`,styles:[f]},regexcreator:{id:"regexcreator",type:"component",load:()=>i(()=>import("./regexcreator.js"),__vite__mapDeps([14,15]),import.meta.url),data:null,styles:[]},samfile:{id:"samfile",type:"component",load:()=>i(()=>import("./samfile.js"),__vite__mapDeps([16,17,18]),import.meta.url),data:null,styles:[]},"tools/markdowneditor":{id:"tools/markdowneditor",type:"component",load:()=>i(()=>import("./markdowneditor.js"),__vite__mapDeps([19,20]),import.meta.url),data:null,styles:[]},"tools/minecraft/tellraw":{id:"tools/minecraft/tellraw",type:"component",load:()=>i(()=>import("./tellraw.js"),__vite__mapDeps([21,17,22]),import.meta.url),data:null,styles:[]},viewer:{id:"viewer",type:"component",load:()=>i(()=>import("./viewer.js"),__vite__mapDeps([23,24]),import.meta.url),data:null,styles:[]}},v=Symbol("html");function t(e,s,...n){if(typeof e=="function")return e({...s??{},children:n});const o=new Set(["disabled","checked","selected","readonly","required","multiple","hidden","autofocus","open"]),h=Object.entries(s??{}).filter(([a])=>a!=="children"&&a!=="key").map(([a,c])=>{if(c==null)return"";const l=a==="className"?"class":a;return typeof c=="boolean"&&o.has(l)?c?` ${l}`:"":typeof c=="boolean"?` ${l}="${c}"`:c===!1?"":` ${l}="${C(String(c))}"`}).join(""),q=n.flat(1/0).filter(a=>a!=null&&a!==!1).map(a=>k(a)?a.value:_(String(a))).join(""),r=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]).has(e)?`<${e}${h}>`:`<${e}${h}>${q}${e}>`;return b(r)}function I(e){const s=(e.children??[]).flat(1/0).filter(n=>n!=null&&n!==!1).map(n=>k(n)?n.value:_(String(n))).join("");return b(s)}function b(e){return{[v]:!0,value:e,toString(){return e}}}function k(e){return typeof e=="object"&&e!==null&&v in e}function C(e){return e.replace(/&/g,"&").replace(/"/g,""").replace(//g,">")}function _(e){return e.replace(/&/g,"&").replace(//g,">")}function H(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function x(e){return b(e)}function A(e){for(const s of e){const n=new URL(s,import.meta.url).href;if(document.head.querySelector(`link[data-page-style="${CSS.escape(n)}"]`))continue;const o=document.createElement("link");o.rel="stylesheet",o.href=n,o.dataset.pageStyle=n,document.head.appendChild(o)}}function L(e){e.innerHTML=t("main",null,t("h1",null,"404"),t("p",null,"No page id was provided."),t("a",{href:"/"},"Go home"))}function O(e,s){const n=Object.keys(s).filter(o=>o!=="__404__").map(o=>t("li",null,t("a",{href:o==="index"?"/":`/${o}`},o))).join("");e.innerHTML=t("main",null,t("h1",null,"404"),t("p",null,"Page not found."),t("h2",null,"Available pages"),t("ul",null,x(n)),t("a",{href:"/"},"Go home"))}function R(e,s){e.innerHTML=t("main",null,t("h1",null,"404"),t("p",null,"Page ",s," not found."),t("a",{href:"/"},"Go home"))}function P(e,s,n){console.error(`[pages] Failed to load page "${s}"`,n),e.innerHTML=t("main",null,t("h1",null,"Failed to load page"),t("p",null,'Could not load "$',s,'".'),t("a",{href:"/"},"Go home"),t("pre",null,`[pages] Failed to load page "${s}"`),t("pre",null,n))}function F(e,s){s.type==="markdown"&&(e.innerHTML=t(I,null,t("a",{href:"../"},"Home"),t("article",{class:"markdown"},x(s.html??""))))}async function D(){const e=document.getElementById("app");if(e==null)throw new Error("Missing #app element");const s=window.PAGE_ID;if(!s){L(e);return}if(s==="__404__"){O(e,w);return}const n=w[s];if(!n){console.error(`[pages] Unknown page id: ${s}`),R(e,s);return}try{if(A(n.styles),n.type==="markdown"){F(e,n);return}await(await n.load()).default(e,n.data)}catch(o){P(e,s,o)}}D();export{I as F,H as e,t as j,x as r};
+go tool cover -html=coverageBuild:
go build ./cmd/finderCheck the available Templates
go run ./cmd/finder checkSee LICENSE.
Project: https://github.com/shadowdara/finder
The Project fs-tools was more or less the prototype for finder.
(a Youtube Video)
`,styles:[f]},regexcreator:{id:"regexcreator",type:"component",load:()=>i(()=>import("./regexcreator.js"),__vite__mapDeps([14,15]),import.meta.url),data:null,styles:[]},samfile:{id:"samfile",type:"component",load:()=>i(()=>import("./samfile.js"),__vite__mapDeps([16,17,18]),import.meta.url),data:null,styles:[]},"tools/index":{id:"tools/index",type:"component",load:()=>i(()=>import("./index3.js"),__vite__mapDeps([19,20]),import.meta.url),data:null,styles:[]},"tools/installscript":{id:"tools/installscript",type:"component",load:()=>i(()=>import("./installscript.js"),__vite__mapDeps([21,22]),import.meta.url),data:null,styles:[]},"tools/markdowneditor":{id:"tools/markdowneditor",type:"component",load:()=>i(()=>import("./markdowneditor.js"),__vite__mapDeps([23,24]),import.meta.url),data:null,styles:[]},"tools/minecraft/tellraw":{id:"tools/minecraft/tellraw",type:"component",load:()=>i(()=>import("./tellraw.js"),__vite__mapDeps([25,17,26]),import.meta.url),data:null,styles:[]},viewer:{id:"viewer",type:"component",load:()=>i(()=>import("./viewer.js"),__vite__mapDeps([27,28]),import.meta.url),data:null,styles:[]}},v=Symbol("html");function t(e,s,...n){if(typeof e=="function")return e({...s??{},children:n});const o=new Set(["disabled","checked","selected","readonly","required","multiple","hidden","autofocus","open"]),h=Object.entries(s??{}).filter(([a])=>a!=="children"&&a!=="key").map(([a,c])=>{if(c==null)return"";const l=a==="className"?"class":a;return typeof c=="boolean"&&o.has(l)?c?` ${l}`:"":typeof c=="boolean"?` ${l}="${c}"`:c===!1?"":` ${l}="${A(String(c))}"`}).join(""),q=n.flat(1/0).filter(a=>a!=null&&a!==!1).map(a=>k(a)?a.value:_(String(a))).join(""),r=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]).has(e)?`<${e}${h}>`:`<${e}${h}>${q}${e}>`;return b(r)}function I(e){const s=(e.children??[]).flat(1/0).filter(n=>n!=null&&n!==!1).map(n=>k(n)?n.value:_(String(n))).join("");return b(s)}function b(e){return{[v]:!0,value:e,toString(){return e}}}function k(e){return typeof e=="object"&&e!==null&&v in e}function A(e){return e.replace(/&/g,"&").replace(/"/g,""").replace(//g,">")}function _(e){return e.replace(/&/g,"&").replace(//g,">")}function H(e){return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function x(e){return b(e)}function C(e){for(const s of e){const n=new URL(s,import.meta.url).href;if(document.head.querySelector(`link[data-page-style="${CSS.escape(n)}"]`))continue;const o=document.createElement("link");o.rel="stylesheet",o.href=n,o.dataset.pageStyle=n,document.head.appendChild(o)}}function L(e){e.innerHTML=t("main",null,t("h1",null,"404"),t("p",null,"No page id was provided."),t("a",{href:"/"},"Go home"))}function O(e,s){const n=Object.keys(s).filter(o=>o!=="__404__").map(o=>t("li",null,t("a",{href:o==="index"?"/":`/${o}`},o))).join("");e.innerHTML=t("main",null,t("h1",null,"404"),t("p",null,"Page not found."),t("h2",null,"Available pages"),t("ul",null,x(n)),t("a",{href:"/"},"Go home"))}function R(e,s){e.innerHTML=t("main",null,t("h1",null,"404"),t("p",null,"Page ",s," not found."),t("a",{href:"/"},"Go home"))}function P(e,s,n){console.error(`[pages] Failed to load page "${s}"`,n),e.innerHTML=t("main",null,t("h1",null,"Failed to load page"),t("p",null,'Could not load "$',s,'".'),t("a",{href:"/"},"Go home"),t("pre",null,`[pages] Failed to load page "${s}"`),t("pre",null,n))}function D(e,s){s.type==="markdown"&&(e.innerHTML=t(I,null,t("a",{href:"../"},"Home"),t("article",{class:"markdown"},x(s.html??""))))}async function F(){const e=document.getElementById("app");if(e==null)throw new Error("Missing #app element");const s=window.PAGE_ID;if(!s){L(e);return}if(s==="__404__"){O(e,w);return}const n=w[s];if(!n){console.error(`[pages] Unknown page id: ${s}`),R(e,s);return}try{if(C(n.styles),n.type==="markdown"){D(e,n);return}await(await n.load()).default(e,n.data)}catch(o){P(e,s,o)}}F();export{I as F,H as e,t as j,x as r}; diff --git a/cmd/findergen/frontend/assets/tellraw.js b/cmd/findergen/frontend/assets/tellraw.js index 0d58a421..322b8270 100644 --- a/cmd/findergen/frontend/assets/tellraw.js +++ b/cmd/findergen/frontend/assets/tellraw.js @@ -1,3 +1,3 @@ var d=Object.defineProperty;var m=(e,t,i)=>t in e?d(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i;var a=(e,t,i)=>m(e,typeof t!="symbol"?t+"":t,i);import{j as r}from"./main_entry.js";import{j as p}from"./jquery.module.js";class o extends Error{constructor(i,s){super(`${i} at position ${s}`);a(this,"position");this.position=s,this.name="SnbtParseError"}}function w(e){const t=new k(e),i=t.parseValue();if(t.skipWhitespace(),!t.eof)throw new o("Unexpected trailing data",t.position);return i}class k{constructor(t){a(this,"input");a(this,"position",0);this.input=t}get eof(){return this.position>=this.input.length}peek(){return this.input[this.position]??""}skipWhitespace(){for(;!this.eof&&/\s/.test(this.peek());)this.position++}parseValue(){this.skipWhitespace();const t=this.peek();return t==="{"?this.parseObject():t==="["?this.parseArray():t==="'"||t==='"'?this.parseString():this.parsePrimitive()}parseObject(){this.expect("{");const t={};if(this.skipWhitespace(),this.peek()==="}")return this.position++,t;for(;;){this.skipWhitespace();const i=this.parseKey();if(this.skipWhitespace(),this.expect(":"),t[i]=this.parseValue(),this.skipWhitespace(),this.peek()==="}")return this.position++,t;this.expect(",")}}parseArray(){this.expect("[");const t=[];if(this.skipWhitespace(),this.peek()==="]")return this.position++,t;for(;;){if(t.push(this.parseValue()),this.skipWhitespace(),this.peek()==="]")return this.position++,t;this.expect(",")}}parseKey(){this.skipWhitespace();const t=this.peek();if(t==="'"||t==='"')return this.parseString();const i=this.position;for(;!this.eof;){const s=this.peek();if(s===":"||/\s/.test(s))break;this.position++}if(this.position===i)throw new o("Expected object key",this.position);return this.input.slice(i,this.position)}parseString(){const t=this.peek();this.position++;let i="";for(;!this.eof;){const s=this.peek();if(this.position++,s===t)return i;if(s==="\\"){if(this.eof)throw new o("Unterminated escape sequence",this.position);const n=this.peek();switch(this.position++,n){case"n":i+=` `;break;case"r":i+="\r";break;case"t":i+=" ";break;case"\\":i+="\\";break;case"'":i+="'";break;case'"':i+='"';break;default:i+=n}}else i+=s}throw new o("Unterminated string",this.position)}parsePrimitive(){const t=this.position;for(;!this.eof;){const s=this.peek();if(s===","||s==="}"||s==="]"||/\s/.test(s))break;this.position++}const i=this.input.slice(t,this.position);if(i==="true")return!0;if(i==="false")return!1;if(i==="null")return null;if(/^[+-]?(?:\d+\.?\d*|\.\d+)(?:[eE][+-]?\d+)?[bBsSlLfFdD]?$/.test(i)){const s=Number(i.replace(/[bBsSlLfFdD]$/,""));if(Number.isFinite(s))return s}return i}expect(t){if(this.skipWhitespace(),this.peek()!==t)throw new o(`Expected '${t}', got '${this.peek()}'`,this.position);this.position++}}function b(e){const t=e.match(/^\s*\/?tellraw\s+([^\s]+)\s+([\s\S]+)$/i);if(!t)throw new Error(`Invalid tellraw command: -${e}`);const i=t[1],s=t[2].trim();try{return{command:"tellraw",target:i,data:JSON.parse(s),format:"json",raw:e.trim()}}catch{return{command:"tellraw",target:i,data:w(s),format:"snbt",raw:e.trim()}}}const y=/^[A-Za-z0-9_+.-]+$/;function g(e,t={}){const{format:i="snbt",pretty:s=!1,quoteKeys:n=!1,leadingSlash:c=!1}=t,l=c?"/tellraw":"tellraw",f=i==="json"?JSON.stringify(e.data,null,s?2:0):h(e.data,{quoteKeys:n});return`${l} ${e.target} ${f}`}function h(e,t={}){if(e===null)return"null";if(typeof e=="string")return u(e);if(typeof e=="number"){if(!Number.isFinite(e))throw new Error("Cannot stringify NaN or Infinity as SNBT");return String(e)}return typeof e=="boolean"?e?"true":"false":Array.isArray(e)?`[${e.map(s=>h(s,t)).join(",")}]`:`{${Object.entries(e).map(([s,n])=>`${t.quoteKeys||!y.test(s)?u(s):s}:${h(n,t)}`).join(",")}}`}function u(e){return`'${e.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}'`}function S(e){if(!e.trim())return"";try{const t=b(e);return g(t,{format:"snbt"})}catch(t){return`Error: ${t instanceof Error?t.message:String(t)}`}}function E(e){e.innerHTML=r("main",null,r("p",null,"Tellraw Converter from JSON to SNBT to Update it for newer Minecraft Versions"),r("section",{class:"text-editor"},r("div",{class:"text-panel"},r("label",{for:"input"},"Input"),r("textarea",{id:"input",placeholder:"tellraw @a {text:'Hello',bold:true}"})),r("div",{class:"text-arrow"},"→"),r("div",{class:"text-panel"},r("label",{for:"output"},"Output"),r("textarea",{id:"output",readOnly:!0,placeholder:"SNBT Output..."}))),r("p",null,"More Minecraft Tools are"," ",r("a",{href:"https://shadowdara.github.io/mctools"},"here"),"!")),p("#input").on("input",function(){const t=p(this).val();p("#output").val(S(t))})}export{E as default}; +${e}`);const i=t[1],s=t[2].trim();try{return{command:"tellraw",target:i,data:JSON.parse(s),format:"json",raw:e.trim()}}catch{return{command:"tellraw",target:i,data:w(s),format:"snbt",raw:e.trim()}}}const y=/^[A-Za-z0-9_+.-]+$/;function g(e,t={}){const{format:i="snbt",pretty:s=!1,quoteKeys:n=!1,leadingSlash:c=!1}=t,l=c?"/tellraw":"tellraw",f=i==="json"?JSON.stringify(e.data,null,s?2:0):h(e.data,{quoteKeys:n});return`${l} ${e.target} ${f}`}function h(e,t={}){if(e===null)return"null";if(typeof e=="string")return u(e);if(typeof e=="number"){if(!Number.isFinite(e))throw new Error("Cannot stringify NaN or Infinity as SNBT");return String(e)}return typeof e=="boolean"?e?"true":"false":Array.isArray(e)?`[${e.map(s=>h(s,t)).join(",")}]`:`{${Object.entries(e).map(([s,n])=>`${t.quoteKeys||!y.test(s)?u(s):s}:${h(n,t)}`).join(",")}}`}function u(e){return`'${e.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}'`}function S(e){if(!e.trim())return"";try{const t=b(e);return g(t,{format:"snbt"})}catch(t){return`Error: ${t instanceof Error?t.message:String(t)}`}}function E(e){e.innerHTML=r("main",null,r("p",null,r("a",{href:"../../../"},"HOME")," - Tellraw Converter from JSON to SNBT to Update it for newer Minecraft Versions"),r("section",{class:"text-editor"},r("div",{class:"text-panel"},r("label",{for:"input"},"Input"),r("textarea",{id:"input",placeholder:"tellraw @a {text:'Hello',bold:true}"})),r("div",{class:"text-arrow"},"→"),r("div",{class:"text-panel"},r("label",{for:"output"},"Output"),r("textarea",{id:"output",readOnly:!0,placeholder:"SNBT Output..."}))),r("p",null,"More Minecraft Tools are"," ",r("a",{href:"https://shadowdara.github.io/mctools"},"here"),"!")),p("#input").on("input",function(){const t=p(this).val();p("#output").val(S(t))})}export{E as default}; diff --git a/cmd/findergen/frontend/install.sh b/cmd/findergen/frontend/install.sh index 69e88ea6..61504b95 100644 --- a/cmd/findergen/frontend/install.sh +++ b/cmd/findergen/frontend/install.sh @@ -91,3 +91,5 @@ if [[ ":$PATH:" != *":$INSTALL_DIR:"* ]]; then echo "export PATH=\"\$PATH:$INSTALL_DIR\"" >> "$HOME/.bashrc" export PATH="$PATH:$INSTALL_DIR" fi + +source ~/.bashrc diff --git a/cmd/findergen/frontend/tools/index.html b/cmd/findergen/frontend/tools/index.html new file mode 100644 index 00000000..6a72cb00 --- /dev/null +++ b/cmd/findergen/frontend/tools/index.html @@ -0,0 +1 @@ +- Tellraw Converter from JSON to SNBT to Update it for newer Minecraft - Versions + HOME - Tellraw Converter from JSON to SNBT to + Update it for newer Minecraft Versions
@@ -595,6 +633,93 @@ export default function buildPage(app: HTMLElement): void {
+ So führst du das generierte Skript aus und was es dabei tut. +
+ ++ Nach dem Generieren kannst du das Skript direkt im Terminal + ausführen. Am einfachsten mit: +
+sh install.sh
+ + Oder erst ausführbar machen und dann starten (Linux/macOS): +
+chmod +x install.sh
+./install.sh
+
+ Das Skript lädt das passende Archiv für dein System (Linux/macOS und
+ Architektur) herunter, entpackt es und installiert die Binaries nach{" "}
+ $HOME/.local/<app>/bin. Anschließend trägt es diesen
+ Ordner in den PATH deiner Shell-RC ein (z.B.{" "}
+ ~/.bashrc oder ~/.zshrc).
+
+ Damit der PATH-Update wirkt, starte eine neue Shell oder lade deine + Konfiguration neu: +
+source ~/.bashrc
+ Danach sollte der Befehl direkt verfügbar sein:
+<app> --help
+
+ + Wenn du mehrere Installationsoptionen (Install Options) eingetragen + hast, fragt das Skript interaktiv nach, welche Variante installiert + werden soll. Für eine automatisierte Installation kannst du den Typ + direkt angeben: +
+sh install.sh -t minimal
+ Alle verfügbaren Typen anzeigen:
+sh install.sh --list
+
+ + Ist "Neueste Version verwenden (latest)" aktiviert, ermittelt das + Skript beim Ausführen die aktuellste Version automatisch von der + GitHub-API. Alternativ kannst du das auch manuell erzwingen: +
+sh install.sh --latest
+
+ Standard ist $HOME/.local/<app>. Mit --prefix kannst du ein anderes Ziel wählen:
sh install.sh --prefix /opt/mein-app
+
+ + In Skripten oder CI-Umgebungen (ohne TTY) werden Animationen + automatisch deaktiviert. Du kannst sie aber auch explizit abschalten: +
+sh install.sh --no-animation
+
+ + Wenn du das Skript irgendwo gehostet hast, kann man es direkt von + dort ausführen, ohne es erst herunterzuladen: +
+curl -fsSL https://example.com/install.sh | sh
+ + Achtung: Bei dieser Variante läuft das Skript ohne TTY, also + automatisch nicht-interaktiv (es wird der erste Installationstyp + verwendet). +
+ +
+ Das generierte Skript enthält am Ende einen Kommentar-Block mit der
+ Konfiguration als Base64 (Markierung #$$$). Fügst du
+ diesen Block (oder nur den Base64-String) oben im Feld "Konfiguration
+ speichern / laden" ein und klickst auf "Importieren", werden alle
+ Felder wiederhergestellt – so kannst du das Setup später erneut
+ anpassen oder auf einem anderen Rechner weiterverwenden.
+
Zwei Wortlisten werden zu einem Muster verrechnet: alles aus der
- ersten Liste passt, alles aus der zweiten nicht.
+ ersten Liste passt, alles aus der zweiten nicht. Für Datei-Endungen
+ einfach den Modus endet mit wählen und z. B.{" "}
+ .jpg und .jpeg eingeben.