diff --git a/.gitignore b/.gitignore
index f4649a2..ba8194a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,43 +1,6 @@
-# Wails 自动生成的绑定代码
-frontend/
-web/src/wailsjs/
-
-# 构建产物
-build/bin/
-build/*.log
-web/dist/
-
-# 临时文件
-*.tmp
-
-# 依赖目录
-web/node_modules/
-web/bun.lock
-
-# Go 相关
-*.exe
-*.exe~
-*.dll
-*.so
-*.dylib
-*.test
-*.out
-go.work
-
-# IDE
-.idea/
-.vscode/
-.claude/
-*.swp
-*.swo
-*~
-
-# 系统文件
-.DS_Store
-Thumbs.db
-
-# 日志文件
-*.log
-
-# 其他
-docs/
\ No newline at end of file
+.task
+bin
+frontend/dist
+frontend/node_modules
+build/linux/appimage/build
+build/windows/nsis/MicrosoftEdgeWebview2Setup.exe
\ No newline at end of file
diff --git a/README.md b/README.md
index c7d3e09..ad12c3f 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,59 @@
-# U-Desk v0.3.4
+# Welcome to Your New Wails3 Project!
-## 功能
-- **文件管理** — 本地文件浏览、编辑(CodeMirror 语法高亮+搜索)、预览(图片/视频/PDF/HTML/Markdown/Excel/Word/CSV)
-- **数据库客户端** — 多数据库连接管理、SQL 执行、查询历史、表结构管理
-- **Markdown 编辑器** — 独立编辑页面、实时预览、PDF 导出
-- **版本更新** — 自动检查更新、下载安装、changelog 渲染
-- **系统信息** — CPU/内存/磁盘硬件信息查询
+Congratulations on generating your Wails3 application! This README will guide you through the next steps to get your project up and running.
-## 技术栈
-- **后端**: Go + Wails v2 (桌面应用框架)
-- **前端**: Vue 3 + Arco Design + CodeMirror 6 + Pinia
-- **存储**: SQLite (GORM)
-- **本地文件服务器**: `localhost:8073`(CSS/JS 路径转换、HTML 预览)
+## Getting Started
-## 开发
-```bash
-wails dev
-```
+1. Navigate to your project directory in the terminal.
-## 更新
-- ✅ 文件服务器安全重构+编辑器增强+搜索排序+更新面板渲染
+2. To run your application in development mode, use the following command:
+
+ ```
+ wails3 dev
+ ```
+
+ This will start your application and enable hot-reloading for both frontend and backend changes.
+
+3. To build your application for production, use:
+
+ ```
+ wails3 build
+ ```
+
+ This will create a production-ready executable in the `build` directory.
+
+## Exploring Wails3 Features
+
+Now that you have your project set up, it's time to explore the features that Wails3 offers:
+
+1. **Check out the examples**: The best way to learn is by example. Visit the `examples` directory in the `v3/examples` directory to see various sample applications.
+
+2. **Run an example**: To run any of the examples, navigate to the example's directory and use:
+
+ ```
+ go run .
+ ```
+
+ Note: Some examples may be under development during the alpha phase.
+
+3. **Explore the documentation**: Visit the [Wails3 documentation](https://v3.wails.io/) for in-depth guides and API references.
+
+4. **Join the community**: Have questions or want to share your progress? Join the [Wails Discord](https://discord.gg/JDdSxwjhGf) or visit the [Wails discussions on GitHub](https://github.com/wailsapp/wails/discussions).
+
+## Project Structure
+
+Take a moment to familiarize yourself with your project structure:
+
+- `frontend/`: Contains your frontend code (HTML, CSS, JavaScript/TypeScript)
+- `main.go`: The entry point of your Go backend
+- `app.go`: Define your application structure and methods here
+- `wails.json`: Configuration file for your Wails project
+
+## Next Steps
+
+1. Modify the frontend in the `frontend/` directory to create your desired UI.
+2. Add backend functionality in `main.go`.
+3. Use `wails3 dev` to see your changes in real-time.
+4. When ready, build your application with `wails3 build`.
+
+Happy coding with Wails3! If you encounter any issues or have questions, don't hesitate to consult the documentation or reach out to the Wails community.
diff --git a/Taskfile.yml b/Taskfile.yml
new file mode 100644
index 0000000..f29c0b7
--- /dev/null
+++ b/Taskfile.yml
@@ -0,0 +1,60 @@
+version: '3'
+
+includes:
+ common: ./build/Taskfile.yml
+ windows: ./build/windows/Taskfile.yml
+ darwin: ./build/darwin/Taskfile.yml
+ linux: ./build/linux/Taskfile.yml
+ ios: ./build/ios/Taskfile.yml
+ android: ./build/android/Taskfile.yml
+
+vars:
+ APP_NAME: "u-desk"
+ BIN_DIR: "bin"
+ VITE_PORT: '{{.WAILS_VITE_PORT | default 9245}}'
+
+tasks:
+ build:
+ summary: Builds the application
+ cmds:
+ - task: "{{OS}}:build"
+
+ package:
+ summary: Packages a production build of the application
+ cmds:
+ - task: "{{OS}}:package"
+
+ run:
+ summary: Runs the application
+ cmds:
+ - task: "{{OS}}:run"
+
+ dev:
+ summary: Runs the application in development mode
+ cmds:
+ - wails3 dev
+
+ setup:docker:
+ summary: Builds Docker image for cross-compilation (~800MB download)
+ cmds:
+ - task: common:setup:docker
+
+ build:server:
+ summary: Builds the application in server mode (no GUI, HTTP server only)
+ cmds:
+ - task: common:build:server
+
+ run:server:
+ summary: Runs the application in server mode
+ cmds:
+ - task: common:run:server
+
+ build:docker:
+ summary: Builds a Docker image for server mode deployment
+ cmds:
+ - task: common:build:docker
+
+ run:docker:
+ summary: Builds and runs the Docker image
+ cmds:
+ - task: common:run:docker
diff --git a/app.go b/app.go
index 9c11869..1a75c8f 100644
--- a/app.go
+++ b/app.go
@@ -10,6 +10,7 @@ import (
"path/filepath"
stdruntime "runtime"
"strings"
+ "sync"
"time"
"golang.org/x/sys/windows/registry"
@@ -20,17 +21,21 @@ import (
"u-desk/internal/storage"
"u-desk/internal/system"
- "github.com/wailsapp/wails/v2/pkg/runtime"
+ "github.com/wailsapp/wails/v3/pkg/application"
+ "github.com/wailsapp/wails/v3/pkg/w32"
)
// App 应用结构体
type App struct {
- ctx context.Context
- updateAPI *api.UpdateAPI
- configAPI *api.ConfigAPI
- pdfAPI *api.PdfAPI
- filesystem *filesystem.FileSystemService
- isAlwaysOnTop bool
+ ctx context.Context
+ mainWindow *application.WebviewWindow
+ updateAPI *api.UpdateAPI
+ updateTicker *time.Ticker
+ configAPI *api.ConfigAPI
+ pdfAPI *api.PdfAPI
+ filesystem *filesystem.FileSystemService
+ isAlwaysOnTop bool
+ mu sync.Mutex
}
// App 方法命名约定:
@@ -42,21 +47,24 @@ func NewApp() *App {
return &App{}
}
-// Startup 应用启动时调用
-func (a *App) Startup(ctx context.Context) {
+// SetMainWindow 设置主窗口引用(由 main.go 在创建窗口后调用)
+func (a *App) SetMainWindow(w *application.WebviewWindow) {
+ a.mainWindow = w
+}
+
+// ServiceStartup Wails v3 服务启动生命周期(替代 v2 的 Startup)
+func (a *App) ServiceStartup(ctx context.Context, _ application.ServiceOptions) error {
a.ctx = ctx
// 1. 核心初始化:SQLite(必须同步,很快)
- sqliteDB, err := storage.InitFast()
- if err != nil {
- panic(fmt.Sprintf("SQLite 初始化失败,应用无法启动: %v", err))
+ if _, err := storage.InitFast(); err != nil {
+ return fmt.Errorf("SQLite 初始化失败,应用无法启动: %w", err)
}
- _ = sqliteDB // 全局 DB 已由 InitFast() 设置
// 2. 初始化配置服务
configService, err := api.NewConfigAPI()
if err != nil {
- panic(fmt.Sprintf("配置服务初始化失败: %v", err))
+ return fmt.Errorf("配置服务初始化失败: %w", err)
}
a.configAPI = configService
@@ -68,7 +76,6 @@ func (a *App) Startup(ctx context.Context) {
pdfAPI, err := api.NewPdfAPI()
if err != nil {
fmt.Printf("[启动] PDF导出API初始化失败: %v\n", err)
- // PDF导出失败不应影响应用启动,所以只警告不panic
} else {
a.pdfAPI = pdfAPI
fmt.Println("[启动] PDF导出模块初始化完成")
@@ -84,18 +91,27 @@ func (a *App) Startup(ctx context.Context) {
// 4. 根据配置初始化模块(条件初始化)
if err := a.initModulesByConfig(visibleTabs); err != nil {
- panic(fmt.Sprintf("模块初始化失败: %v", err))
+ return fmt.Errorf("模块初始化失败: %w", err)
}
// 5. 异步初始化:UpdateAPI(涉及网络请求,完全异步)
go func() {
if updateAPI, err := api.NewUpdateAPI("https://c.1216.top/last-version.json"); err == nil {
+ a.mu.Lock()
a.updateAPI = updateAPI
+ a.mu.Unlock()
+
a.updateAPI.SetContext(ctx)
+ a.updateAPI.SetEventEmitter(func(name string, data ...any) {
+ if a.mainWindow != nil {
+ a.mainWindow.EmitEvent(name, data...)
+ }
+ })
a.startAutoUpdateCheck()
}
}()
+ return nil
}
// getVisibleTabs 获取配置中的可见 Tabs
@@ -106,20 +122,17 @@ func (a *App) getVisibleTabs() []string {
return common.DefaultVisibleTabs
}
- // 快速检查成功标识
success, ok := config["success"].(bool)
if !ok || !success {
fmt.Printf("[启动] 配置读取失败,使用默认配置\n")
return common.DefaultVisibleTabs
}
- // 提取 data
data, ok := config["data"].(map[string]interface{})
if !ok {
return common.DefaultVisibleTabs
}
- // 提取 visibleTabs
visibleTabsInterface, ok := data["visibleTabs"].([]interface{})
if !ok {
return common.DefaultVisibleTabs
@@ -136,11 +149,9 @@ func (a *App) getVisibleTabs() []string {
// initModulesByConfig 根据配置初始化模块
func (a *App) initModulesByConfig(visibleTabs []string) error {
- // 检查是否启用文件系统模块
if common.Contains(visibleTabs, common.TabFileSystem) {
fmt.Println("[启动] 初始化文件系统模块...")
- // 初始化文件系统服务
fsConfig := filesystem.DefaultConfig()
var err error
a.filesystem, err = filesystem.NewFileSystemService(fsConfig)
@@ -148,7 +159,6 @@ func (a *App) initModulesByConfig(visibleTabs []string) error {
return fmt.Errorf("文件系统服务初始化失败: %w", err)
}
- // 异步启动文件服务器
go a.startFileServer()
fmt.Println("[启动] 文件系统模块初始化完成")
@@ -161,22 +171,22 @@ func (a *App) initModulesByConfig(visibleTabs []string) error {
// startFileServer 启动文件服务器
func (a *App) startFileServer() {
- // 启动独立的本地文件服务器(使用 filesystem 包中的实现)
if _, err := filesystem.StartLocalFileServer(); err != nil {
fmt.Printf("[文件服务器] 启动失败: %v\n", err)
return
}
-
fmt.Println("[文件服务器] 启动在 http://localhost:8073")
}
-// Shutdown 应用关闭时调用
-func (a *App) Shutdown(ctx context.Context) {
- // 创建带超时的上下文(5秒超时)
- shutdownCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
+// ServiceShutdown Wails v3 服务关闭生命周期(替代 v2 的 Shutdown)
+func (a *App) ServiceShutdown() error {
+ if a.updateTicker != nil {
+ a.updateTicker.Stop()
+ }
+
+ shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
- // 1. 关闭文件系统服务(优雅关闭,释放资源)
if a.filesystem != nil {
fmt.Println("[文件系统服务] 正在关闭...")
if err := a.filesystem.Close(shutdownCtx); err != nil {
@@ -186,13 +196,13 @@ func (a *App) Shutdown(ctx context.Context) {
}
}
- // 2. 停止文件服务器(使用全局服务器的关闭方法)
fmt.Println("[文件服务器] 正在关闭...")
if err := filesystem.ShutdownLocalFileServer(); err != nil {
fmt.Printf("[文件服务器] 关闭失败: %v\n", err)
} else {
fmt.Println("[文件服务器] 已关闭")
}
+ return nil
}
// GetSystemInfo 获取系统信息
@@ -307,7 +317,6 @@ func (a *App) ExtractFileFromZip(zipPath, filePath string) (string, error) {
}
// ExtractFileFromZipToTemp 从 zip 文件中提取单个文件到临时目录
-// 返回临时文件的完整路径,适用于图片等二进制文件
func (a *App) ExtractFileFromZipToTemp(zipPath, filePath string) (string, error) {
return a.filesystem.ExtractFileFromZipToTemp(zipPath, filePath)
}
@@ -327,10 +336,8 @@ func (a *App) ResolveShortcut(lnkPath string) (map[string]interface{}, error) {
}, err
}
- // 获取目标文件信息
fileInfo, err := a.filesystem.GetFileInfo(targetPath)
if err != nil {
- // 目标文件不存在或无法访问
return map[string]interface{}{
"success": true,
"targetPath": targetPath,
@@ -339,7 +346,6 @@ func (a *App) ResolveShortcut(lnkPath string) (map[string]interface{}, error) {
}, nil
}
- // 返回完整的目标信息
return map[string]interface{}{
"success": true,
"targetPath": targetPath,
@@ -350,11 +356,10 @@ func (a *App) ResolveShortcut(lnkPath string) (map[string]interface{}, error) {
}
// getWindowsSpecialFolder 从注册表读取 Windows 特殊文件夹的真实路径
-// 用户可通过系统设置修改下载/桌面/文档等目录位置,注册表记录实际路径
func getWindowsSpecialFolder(guid string, fallbackName string) string {
key, err := registry.OpenKey(registry.CURRENT_USER,
`Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders`,
- registry.READ)
+ registry.READ)
if err != nil {
return ""
}
@@ -365,9 +370,7 @@ func getWindowsSpecialFolder(guid string, fallbackName string) string {
return ""
}
- // 展开 %USERPROFILE% 等环境变量
path := os.ExpandEnv(val)
- // 验证路径存在
if _, err := os.Stat(path); err != nil {
return ""
}
@@ -385,7 +388,6 @@ func (a *App) GetCommonPaths() (map[string]string, error) {
"home": homeDir,
}
- // Windows: 从注册表读取特殊文件夹真实路径(用户可能已修改位置)
folderGUIDs := map[string]string{
"desktop": "{B4BFCC3A-DB2C-424C-B029-7FE99A87C641}",
"documents": "{D20B4C7F-5EA7-424C-B25E-039F6F1FCC8A}",
@@ -395,12 +397,10 @@ func (a *App) GetCommonPaths() (map[string]string, error) {
if p := getWindowsSpecialFolder(guid, name); p != "" {
paths[name] = p
} else {
- // folderGUIDs 的 key 均为 ASCII,无需 Unicode 处理
paths[name] = filepath.Join(homeDir, strings.ToUpper(name[:1])+name[1:])
}
}
- // Windows: 动态添加所有盘符
if stdruntime.GOOS == "windows" {
for _, drive := range "ABCDEFGHIJKLMNOPQRSTUVWXYZ" {
path := string(drive) + ":\\"
@@ -416,16 +416,15 @@ func (a *App) GetCommonPaths() (map[string]string, error) {
// Reload 重新加载窗口(用于菜单项)
func (a *App) Reload() {
- if a.ctx != nil {
- runtime.WindowReload(a.ctx)
+ if a.mainWindow != nil {
+ a.mainWindow.Reload()
}
}
// ClearCache 清理本地缓存(用于菜单项)
func (a *App) ClearCache() {
- if a.ctx != nil {
- // 发送事件到前端,让前端清理 localStorage
- runtime.EventsEmit(a.ctx, "clear-cache")
+ if a.mainWindow != nil {
+ a.mainWindow.EmitEvent("clear-cache")
}
}
@@ -433,58 +432,72 @@ func (a *App) ClearCache() {
// WindowMinimize 最小化窗口
func (a *App) WindowMinimize() {
- if a.ctx != nil {
- runtime.WindowMinimise(a.ctx)
+ if a.mainWindow != nil {
+ a.mainWindow.Minimise()
}
}
// WindowMaximize 最大化/还原窗口
func (a *App) WindowMaximize() {
- if a.ctx != nil {
- if runtime.WindowIsMaximised(a.ctx) {
- runtime.WindowUnmaximise(a.ctx)
- } else {
- runtime.WindowMaximise(a.ctx)
- }
+ if a.mainWindow == nil {
+ return
+ }
+ if a.mainWindow.IsMaximised() {
+ a.mainWindow.UnMaximise()
+ } else {
+ a.mainWindow.Maximise()
}
}
// WindowClose 关闭窗口
func (a *App) WindowClose() {
- if a.ctx != nil {
- runtime.Quit(a.ctx)
- }
+ application.Get().Quit()
}
// WindowIsMaximized 检查窗口是否最大化
func (a *App) WindowIsMaximized() bool {
- if a.ctx != nil {
- return runtime.WindowIsMaximised(a.ctx)
+ if a.mainWindow != nil {
+ return a.mainWindow.IsMaximised()
}
return false
}
// WindowToggleAlwaysOnTop 切换窗口置顶
func (a *App) WindowToggleAlwaysOnTop() bool {
- if a.ctx == nil {
+ if a.mainWindow == nil {
return false
}
a.isAlwaysOnTop = !a.isAlwaysOnTop
- runtime.WindowSetAlwaysOnTop(a.ctx, a.isAlwaysOnTop)
+ a.mainWindow.SetAlwaysOnTop(a.isAlwaysOnTop)
return a.isAlwaysOnTop
}
+// SetWindowTitleBarColor 设置原生标题栏颜色 + 主题模式(0x00BBGGRR 格式)
+func (a *App) SetWindowTitleBarColor(color uint32, isDark bool) {
+ if a.mainWindow == nil || stdruntime.GOOS != "windows" {
+ return
+ }
+ hwnd := uintptr(a.mainWindow.NativeWindow())
+ if hwnd == 0 {
+ return
+ }
+ w32.SetTheme(hwnd, isDark)
+ w32.SetTitleBarColour(hwnd, color)
+}
+
// ========== 版本更新管理接口 ==========
-// requireUpdateAPI 检查 updateAPI 是否已初始化,未初始化返回统一错误
+// requireUpdateAPI 检查 updateAPI 是否已初始化
func (a *App) requireUpdateAPI() (*api.UpdateAPI, error) {
+ a.mu.Lock()
+ defer a.mu.Unlock()
if a.updateAPI == nil {
return nil, fmt.Errorf("更新功能正在初始化中")
}
return a.updateAPI, nil
}
-// CheckUpdate 检查更新(UpdateAPI 可能尚未初始化完成)
+// CheckUpdate 检查更新
func (a *App) CheckUpdate() (map[string]interface{}, error) {
api, err := a.requireUpdateAPI()
if err != nil {
@@ -586,13 +599,11 @@ func (a *App) startAutoUpdateCheck() {
interval = 5
}
- // 立即检查一次
go a.checkUpdate()
- // 启动定时器
- ticker := time.NewTicker(time.Duration(interval) * time.Minute)
+ a.updateTicker = time.NewTicker(time.Duration(interval) * time.Minute)
go func() {
- for range ticker.C {
+ for range a.updateTicker.C {
a.checkUpdate()
}
}()
@@ -606,11 +617,15 @@ func (a *App) checkUpdate() {
}
}()
- if a.updateAPI == nil {
+ a.mu.Lock()
+ api := a.updateAPI
+ a.mu.Unlock()
+
+ if api == nil {
return
}
- result, err := a.updateAPI.CheckUpdate()
+ result, err := api.CheckUpdate()
if err != nil {
return
}
@@ -626,8 +641,8 @@ func (a *App) checkUpdate() {
}
hasUpdate, ok := data["has_update"].(bool)
- if ok && hasUpdate && a.ctx != nil {
- runtime.EventsEmit(a.ctx, "update-available", data)
+ if ok && hasUpdate && a.mainWindow != nil {
+ a.mainWindow.EmitEvent("update-available", data)
}
}
@@ -645,7 +660,7 @@ func (a *App) GetFileServerURL() string {
return "http://localhost:8073"
}
-// DetectFileTypeByContent 通过文件内容检测文件类型(用于小文件)
+// DetectFileTypeByContent 通过文件内容检测文件类型
func (a *App) DetectFileTypeByContent(path string) (map[string]interface{}, error) {
return filesystem.DetectFileTypeByContentSimple(path)
}
@@ -695,7 +710,6 @@ func (a *App) SaveAppConfig(req SaveAppConfigRequest) (map[string]interface{}, e
return nil, fmt.Errorf("配置服务正在初始化中")
}
- // 保存前检查是否有新启用的模块,需要动态初始化
oldConfig, _ := a.configAPI.GetAppConfig()
var oldVisibleTabs []string
if success, ok := oldConfig["success"].(bool); ok && success {
@@ -717,7 +731,6 @@ func (a *App) SaveAppConfig(req SaveAppConfigRequest) (map[string]interface{}, e
return result, err
}
- // 保存成功后,检查是否有新启用的模块需要初始化
if success, ok := result["success"].(bool); ok && success {
a.handleNewlyEnabledModules(oldVisibleTabs, req.VisibleTabs)
}
@@ -762,7 +775,6 @@ func (a *App) initFilesystemModule() {
return
}
- // 启动文件服务器
go a.startFileServer()
fmt.Println("[模块] 文件系统模块初始化完成")
@@ -810,4 +822,3 @@ func (a *App) SelectPDFSaveDirectory() (string, error) {
return a.pdfAPI.SelectDirectory()
}
-
diff --git a/build/Taskfile.yml b/build/Taskfile.yml
new file mode 100644
index 0000000..8be49b8
--- /dev/null
+++ b/build/Taskfile.yml
@@ -0,0 +1,253 @@
+version: '3'
+
+tasks:
+ go:mod:tidy:
+ summary: Runs `go mod tidy`
+ internal: true
+ cmds:
+ - go mod tidy
+
+ install:frontend:deps:
+ summary: Install frontend dependencies
+ dir: frontend
+ sources:
+ - package.json
+ - package-lock.json
+ generates:
+ - node_modules
+ preconditions:
+ - sh: npm version
+ msg: "Looks like npm isn't installed. Npm is part of the Node installer: https://nodejs.org/en/download/"
+ cmds:
+ - npm install
+
+ build:frontend:
+ label: build:frontend (DEV={{.DEV}})
+ summary: Build the frontend project
+ dir: frontend
+ sources:
+ - "**/*"
+ - exclude: node_modules/**/*
+ generates:
+ - dist/**/*
+ deps:
+ - task: install:frontend:deps
+ - task: generate:bindings
+ vars:
+ BUILD_FLAGS:
+ ref: .BUILD_FLAGS
+ cmds:
+ - npm run {{.BUILD_COMMAND}} -q
+ env:
+ PRODUCTION: '{{if eq .DEV "true"}}false{{else}}true{{end}}'
+ vars:
+ BUILD_COMMAND: '{{if eq .DEV "true"}}build:dev{{else}}build{{end}}'
+
+
+ frontend:vendor:puppertino:
+ summary: Fetches Puppertino CSS into frontend/public for consistent mobile styling
+ sources:
+ - frontend/public/puppertino/puppertino.css
+ generates:
+ - frontend/public/puppertino/puppertino.css
+ cmds:
+ - |
+ set -euo pipefail
+ mkdir -p frontend/public/puppertino
+ # If bundled Puppertino exists, prefer it. Otherwise, try to fetch, but don't fail build on error.
+ if [ ! -f frontend/public/puppertino/puppertino.css ]; then
+ echo "No bundled Puppertino found. Attempting to fetch from GitHub..."
+ if curl -fsSL https://raw.githubusercontent.com/codedgar/Puppertino/main/dist/css/full.css -o frontend/public/puppertino/puppertino.css; then
+ curl -fsSL https://raw.githubusercontent.com/codedgar/Puppertino/main/LICENSE -o frontend/public/puppertino/LICENSE || true
+ echo "Puppertino CSS downloaded to frontend/public/puppertino/puppertino.css"
+ else
+ echo "Warning: Could not fetch Puppertino CSS. Proceeding without download since template may bundle it."
+ fi
+ else
+ echo "Using bundled Puppertino at frontend/public/puppertino/puppertino.css"
+ fi
+ # Ensure index.html includes Puppertino CSS and button classes
+ INDEX_HTML=frontend/index.html
+ if [ -f "$INDEX_HTML" ]; then
+ if ! grep -q 'href="/puppertino/puppertino.css"' "$INDEX_HTML"; then
+ # Insert Puppertino link tag after style.css link
+ awk '
+ /href="\/style.css"\/?/ && !x { print; print " "; x=1; next }1
+ ' "$INDEX_HTML" > "$INDEX_HTML.tmp" && mv "$INDEX_HTML.tmp" "$INDEX_HTML"
+ fi
+ # Replace default .btn with Puppertino primary button classes if present
+ sed -E -i'' 's/class=\"btn\"/class=\"p-btn p-prim-col\"/g' "$INDEX_HTML" || true
+ fi
+
+
+ generate:bindings:
+ label: generate:bindings (BUILD_FLAGS={{.BUILD_FLAGS}})
+ summary: Generates bindings for the frontend
+ deps:
+ - task: go:mod:tidy
+ sources:
+ - "**/*.[jt]s"
+ - exclude: frontend/**/*
+ - frontend/bindings/**/* # Rerun when switching between dev/production mode causes changes in output
+ - "**/*.go"
+ - go.mod
+ - go.sum
+ generates:
+ - frontend/bindings/**/*
+ cmds:
+ - wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=true -ts
+
+ generate:icons:
+ summary: Generates Windows `.ico` and Mac `.icns` from an image; on macOS, `-iconcomposerinput appicon.icon -macassetdir darwin` also produces `Assets.car` from a `.icon` file (skipped on other platforms).
+ dir: build
+ sources:
+ - "appicon.png"
+ - "appicon.icon"
+ generates:
+ - "darwin/icons.icns"
+ - "windows/icon.ico"
+ cmds:
+ - wails3 generate icons -input appicon.png -macfilename darwin/icons.icns -windowsfilename windows/icon.ico -iconcomposerinput appicon.icon -macassetdir darwin
+
+ dev:frontend:
+ summary: Runs the frontend in development mode
+ dir: frontend
+ deps:
+ - task: install:frontend:deps
+ cmds:
+ - npm run dev -- --port {{.VITE_PORT}} --strictPort
+
+ update:build-assets:
+ summary: Updates the build assets
+ dir: build
+ cmds:
+ - wails3 update build-assets -name "{{.APP_NAME}}" -binaryname "{{.APP_NAME}}" -config config.yml -dir .
+
+ build:server:
+ summary: Builds the application in server mode (no GUI, HTTP server only)
+ desc: |
+ Builds the application with the server build tag enabled.
+ Server mode runs as a pure HTTP server without native GUI dependencies.
+ Usage: task build:server
+ deps:
+ - task: build:frontend
+ vars:
+ BUILD_FLAGS:
+ ref: .BUILD_FLAGS
+ cmds:
+ - go build -tags server {{.BUILD_FLAGS}} -o {{.BIN_DIR}}/{{.APP_NAME}}-server{{exeExt}}
+ vars:
+ BUILD_FLAGS: "{{.BUILD_FLAGS}}"
+
+ run:server:
+ summary: Builds and runs the application in server mode
+ deps:
+ - task: build:server
+ cmds:
+ - ./{{.BIN_DIR}}/{{.APP_NAME}}-server{{exeExt}}
+
+ build:docker:
+ summary: Builds a Docker image for server mode deployment
+ desc: |
+ Creates a minimal Docker image containing the server mode binary.
+ The image is based on distroless for security and small size.
+ Usage: task build:docker [TAG=myapp:latest]
+ cmds:
+ - docker build -t {{.TAG | default (printf "%s:latest" .APP_NAME)}} -f build/docker/Dockerfile.server .
+ vars:
+ TAG: "{{.TAG}}"
+ preconditions:
+ - sh: docker info > /dev/null 2>&1
+ msg: "Docker is required. Please install Docker first."
+ - sh: test -f build/docker/Dockerfile.server
+ msg: "Dockerfile.server not found. Run 'wails3 update build-assets' to generate it."
+
+ run:docker:
+ summary: Builds and runs the Docker image
+ desc: |
+ Builds the Docker image and runs it, exposing port 8080.
+ Usage: task run:docker [TAG=myapp:latest] [PORT=8080]
+ Note: The internal container port is always 8080. The PORT variable
+ only changes the host port mapping. Ensure your app uses port 8080
+ or modify the Dockerfile to match your ServerOptions.Port setting.
+ deps:
+ - task: build:docker
+ vars:
+ TAG:
+ ref: .TAG
+ cmds:
+ - docker run --rm -p {{.PORT | default "8080"}}:8080 {{.TAG | default (printf "%s:latest" .APP_NAME)}}
+ vars:
+ TAG: "{{.TAG}}"
+ PORT: "{{.PORT}}"
+
+ setup:docker:
+ summary: Builds Docker image for cross-compilation (~800MB download)
+ desc: |
+ Builds the Docker image needed for cross-compiling to any platform.
+ Run this once to enable cross-platform builds from any OS.
+ cmds:
+ - docker build -t wails-cross -f build/docker/Dockerfile.cross build/docker/
+ preconditions:
+ - sh: docker info > /dev/null 2>&1
+ msg: "Docker is required. Please install Docker first."
+
+ ios:device:list:
+ summary: Lists connected iOS devices (UDIDs)
+ cmds:
+ - xcrun xcdevice list
+
+ ios:run:device:
+ summary: Build, install, and launch on a physical iPhone using Apple tools (xcodebuild/devicectl)
+ vars:
+ PROJECT: '{{.PROJECT}}' # e.g., build/ios/xcode/.xcodeproj
+ SCHEME: '{{.SCHEME}}' # e.g., ios.dev
+ CONFIG: '{{.CONFIG | default "Debug"}}'
+ DERIVED: '{{.DERIVED | default "build/ios/DerivedData"}}'
+ UDID: '{{.UDID}}' # from `task ios:device:list`
+ BUNDLE_ID: '{{.BUNDLE_ID}}' # e.g., com.yourco.wails.ios.dev
+ TEAM_ID: '{{.TEAM_ID}}' # optional, if your project is not already set up for signing
+ preconditions:
+ - sh: xcrun -f xcodebuild
+ msg: "xcodebuild not found. Please install Xcode."
+ - sh: xcrun -f devicectl
+ msg: "devicectl not found. Please update to Xcode 15+ (which includes devicectl)."
+ - sh: test -n '{{.PROJECT}}'
+ msg: "Set PROJECT to your .xcodeproj path (e.g., PROJECT=build/ios/xcode/App.xcodeproj)."
+ - sh: test -n '{{.SCHEME}}'
+ msg: "Set SCHEME to your app scheme (e.g., SCHEME=ios.dev)."
+ - sh: test -n '{{.UDID}}'
+ msg: "Set UDID to your device UDID (see: task ios:device:list)."
+ - sh: test -n '{{.BUNDLE_ID}}'
+ msg: "Set BUNDLE_ID to your app's bundle identifier (e.g., com.yourco.wails.ios.dev)."
+ cmds:
+ - |
+ set -euo pipefail
+ echo "Building for device: UDID={{.UDID}} SCHEME={{.SCHEME}} PROJECT={{.PROJECT}}"
+ XCB_ARGS=(
+ -project "{{.PROJECT}}"
+ -scheme "{{.SCHEME}}"
+ -configuration "{{.CONFIG}}"
+ -destination "id={{.UDID}}"
+ -derivedDataPath "{{.DERIVED}}"
+ -allowProvisioningUpdates
+ -allowProvisioningDeviceRegistration
+ )
+ # Optionally inject signing identifiers if provided
+ if [ -n '{{.TEAM_ID}}' ]; then XCB_ARGS+=(DEVELOPMENT_TEAM={{.TEAM_ID}}); fi
+ if [ -n '{{.BUNDLE_ID}}' ]; then XCB_ARGS+=(PRODUCT_BUNDLE_IDENTIFIER={{.BUNDLE_ID}}); fi
+ xcodebuild "${XCB_ARGS[@]}" build | xcpretty || true
+ # If xcpretty isn't installed, run without it
+ if [ "${PIPESTATUS[0]}" -ne 0 ]; then
+ xcodebuild "${XCB_ARGS[@]}" build
+ fi
+ # Find built .app
+ APP_PATH=$(find "{{.DERIVED}}/Build/Products" -type d -name "*.app" -maxdepth 3 | head -n 1)
+ if [ -z "$APP_PATH" ]; then
+ echo "Could not locate built .app under {{.DERIVED}}/Build/Products" >&2
+ exit 1
+ fi
+ echo "Installing: $APP_PATH"
+ xcrun devicectl device install app --device "{{.UDID}}" "$APP_PATH"
+ echo "Launching: {{.BUNDLE_ID}}"
+ xcrun devicectl device process launch --device "{{.UDID}}" --stderr console --stdout console "{{.BUNDLE_ID}}"
diff --git a/build/android/Taskfile.yml b/build/android/Taskfile.yml
new file mode 100644
index 0000000..aca62e4
--- /dev/null
+++ b/build/android/Taskfile.yml
@@ -0,0 +1,237 @@
+version: '3'
+
+includes:
+ common: ../Taskfile.yml
+
+vars:
+ APP_ID: '{{.APP_ID | default "com.wails.app"}}'
+ MIN_SDK: '21'
+ TARGET_SDK: '34'
+ NDK_VERSION: 'r26d'
+
+tasks:
+ install:deps:
+ summary: Check and install Android development dependencies
+ cmds:
+ - go run build/android/scripts/deps/install_deps.go
+ env:
+ TASK_FORCE_YES: '{{if .YES}}true{{else}}false{{end}}'
+ prompt: This will check and install Android development dependencies. Continue?
+
+ build:
+ summary: Creates a build of the application for Android
+ deps:
+ - task: common:go:mod:tidy
+ - task: generate:android:bindings
+ vars:
+ BUILD_FLAGS:
+ ref: .BUILD_FLAGS
+ - task: common:build:frontend
+ vars:
+ BUILD_FLAGS:
+ ref: .BUILD_FLAGS
+ PRODUCTION:
+ ref: .PRODUCTION
+ - task: common:generate:icons
+ cmds:
+ - echo "Building Android app {{.APP_NAME}}..."
+ - task: compile:go:shared
+ vars:
+ ARCH: '{{.ARCH | default "arm64"}}'
+ vars:
+ BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production,android -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-tags android,debug -buildvcs=false -gcflags=all="-l"{{end}}'
+ env:
+ PRODUCTION: '{{.PRODUCTION | default "false"}}'
+
+ compile:go:shared:
+ summary: Compile Go code to shared library (.so)
+ cmds:
+ - |
+ NDK_ROOT="${ANDROID_NDK_HOME:-$ANDROID_HOME/ndk/{{.NDK_VERSION}}}"
+ if [ ! -d "$NDK_ROOT" ]; then
+ echo "Error: Android NDK not found at $NDK_ROOT"
+ echo "Please set ANDROID_NDK_HOME or install NDK {{.NDK_VERSION}} via Android Studio"
+ exit 1
+ fi
+
+ # Determine toolchain based on host OS
+ case "$(uname -s)" in
+ Darwin) HOST_TAG="darwin-x86_64" ;;
+ Linux) HOST_TAG="linux-x86_64" ;;
+ *) echo "Unsupported host OS"; exit 1 ;;
+ esac
+
+ TOOLCHAIN="$NDK_ROOT/toolchains/llvm/prebuilt/$HOST_TAG"
+
+ # Set compiler based on architecture
+ case "{{.ARCH}}" in
+ arm64)
+ export CC="$TOOLCHAIN/bin/aarch64-linux-android{{.MIN_SDK}}-clang"
+ export CXX="$TOOLCHAIN/bin/aarch64-linux-android{{.MIN_SDK}}-clang++"
+ export GOARCH=arm64
+ JNI_DIR="arm64-v8a"
+ ;;
+ amd64|x86_64)
+ export CC="$TOOLCHAIN/bin/x86_64-linux-android{{.MIN_SDK}}-clang"
+ export CXX="$TOOLCHAIN/bin/x86_64-linux-android{{.MIN_SDK}}-clang++"
+ export GOARCH=amd64
+ JNI_DIR="x86_64"
+ ;;
+ *)
+ echo "Unsupported architecture: {{.ARCH}}"
+ exit 1
+ ;;
+ esac
+
+ export CGO_ENABLED=1
+ export GOOS=android
+
+ mkdir -p {{.BIN_DIR}}
+ mkdir -p build/android/app/src/main/jniLibs/$JNI_DIR
+
+ go build -buildmode=c-shared {{.BUILD_FLAGS}} \
+ -o build/android/app/src/main/jniLibs/$JNI_DIR/libwails.so
+ vars:
+ BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production,android -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-tags android,debug -buildvcs=false -gcflags=all="-l"{{end}}'
+
+ compile:go:all-archs:
+ summary: Compile Go code for all Android architectures (fat APK)
+ cmds:
+ - task: compile:go:shared
+ vars:
+ ARCH: arm64
+ - task: compile:go:shared
+ vars:
+ ARCH: amd64
+
+ package:
+ summary: Packages a production build of the application into an APK
+ deps:
+ - task: build
+ vars:
+ PRODUCTION: "true"
+ cmds:
+ - task: assemble:apk
+
+ package:fat:
+ summary: Packages a production build for all architectures (fat APK)
+ cmds:
+ - task: compile:go:all-archs
+ - task: assemble:apk
+
+ assemble:apk:
+ summary: Assembles the APK using Gradle
+ cmds:
+ - |
+ cd build/android
+ ./gradlew assembleDebug
+ cp app/build/outputs/apk/debug/app-debug.apk "../../{{.BIN_DIR}}/{{.APP_NAME}}.apk"
+ echo "APK created: {{.BIN_DIR}}/{{.APP_NAME}}.apk"
+
+ assemble:apk:release:
+ summary: Assembles a release APK using Gradle
+ cmds:
+ - |
+ cd build/android
+ ./gradlew assembleRelease
+ cp app/build/outputs/apk/release/app-release-unsigned.apk "../../{{.BIN_DIR}}/{{.APP_NAME}}-release.apk"
+ echo "Release APK created: {{.BIN_DIR}}/{{.APP_NAME}}-release.apk"
+
+ generate:android:bindings:
+ internal: true
+ summary: Generates bindings for Android
+ sources:
+ - "**/*.go"
+ - go.mod
+ - go.sum
+ generates:
+ - frontend/bindings/**/*
+ cmds:
+ - wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=true
+ env:
+ GOOS: android
+ CGO_ENABLED: 1
+ GOARCH: '{{.ARCH | default "arm64"}}'
+
+ ensure-emulator:
+ internal: true
+ summary: Ensure Android Emulator is running
+ silent: true
+ cmds:
+ - |
+ # Check if an emulator is already running
+ if adb devices | grep -q "emulator"; then
+ echo "Emulator already running"
+ exit 0
+ fi
+
+ # Get first available AVD
+ AVD_NAME=$(emulator -list-avds | head -1)
+ if [ -z "$AVD_NAME" ]; then
+ echo "No Android Virtual Devices found."
+ echo "Create one using: Android Studio > Tools > Device Manager"
+ exit 1
+ fi
+
+ echo "Starting emulator: $AVD_NAME"
+ emulator -avd "$AVD_NAME" -no-snapshot-load &
+
+ # Wait for emulator to boot (max 60 seconds)
+ echo "Waiting for emulator to boot..."
+ adb wait-for-device
+
+ for i in {1..60}; do
+ BOOT_COMPLETED=$(adb shell getprop sys.boot_completed 2>/dev/null | tr -d '\r')
+ if [ "$BOOT_COMPLETED" = "1" ]; then
+ echo "Emulator booted successfully"
+ exit 0
+ fi
+ sleep 1
+ done
+
+ echo "Emulator boot timeout"
+ exit 1
+ preconditions:
+ - sh: command -v adb
+ msg: "adb not found. Please install Android SDK and add platform-tools to PATH"
+ - sh: command -v emulator
+ msg: "emulator not found. Please install Android SDK and add emulator to PATH"
+
+ deploy-emulator:
+ summary: Deploy to Android Emulator
+ deps: [package]
+ cmds:
+ - adb uninstall {{.APP_ID}} 2>/dev/null || true
+ - adb install "{{.BIN_DIR}}/{{.APP_NAME}}.apk"
+ - adb shell am start -n {{.APP_ID}}/.MainActivity
+
+ run:
+ summary: Run the application in Android Emulator
+ deps:
+ - task: ensure-emulator
+ - task: build
+ vars:
+ ARCH: x86_64
+ cmds:
+ - task: assemble:apk
+ - adb uninstall {{.APP_ID}} 2>/dev/null || true
+ - adb install "{{.BIN_DIR}}/{{.APP_NAME}}.apk"
+ - adb shell am start -n {{.APP_ID}}/.MainActivity
+
+ logs:
+ summary: Stream Android logcat filtered to this app
+ cmds:
+ - adb logcat -v time | grep -E "(Wails|{{.APP_NAME}})"
+
+ logs:all:
+ summary: Stream all Android logcat (verbose)
+ cmds:
+ - adb logcat -v time
+
+ clean:
+ summary: Clean build artifacts
+ cmds:
+ - rm -rf {{.BIN_DIR}}
+ - rm -rf build/android/app/build
+ - rm -rf build/android/app/src/main/jniLibs/*/libwails.so
+ - rm -rf build/android/.gradle
diff --git a/build/android/app/build.gradle b/build/android/app/build.gradle
new file mode 100644
index 0000000..78fdbf7
--- /dev/null
+++ b/build/android/app/build.gradle
@@ -0,0 +1,63 @@
+plugins {
+ id 'com.android.application'
+}
+
+android {
+ namespace 'com.wails.app'
+ compileSdk 34
+
+ buildFeatures {
+ buildConfig = true
+ }
+
+ defaultConfig {
+ applicationId "com.wails.app"
+ minSdk 21
+ targetSdk 34
+ versionCode 1
+ versionName "1.0"
+
+ // Configure supported ABIs
+ ndk {
+ abiFilters 'arm64-v8a', 'x86_64'
+ }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ debug {
+ debuggable true
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_11
+ targetCompatibility JavaVersion.VERSION_11
+ }
+
+ // Source sets configuration
+ sourceSets {
+ main {
+ // JNI libraries are in jniLibs folder
+ jniLibs.srcDirs = ['src/main/jniLibs']
+ // Assets for the WebView
+ assets.srcDirs = ['src/main/assets']
+ }
+ }
+
+ // Packaging options
+ packagingOptions {
+ // Don't strip Go symbols in debug builds
+ doNotStrip '*/arm64-v8a/libwails.so'
+ doNotStrip '*/x86_64/libwails.so'
+ }
+}
+
+dependencies {
+ implementation 'androidx.appcompat:appcompat:1.6.1'
+ implementation 'androidx.webkit:webkit:1.9.0'
+ implementation 'com.google.android.material:material:1.11.0'
+}
diff --git a/build/android/app/proguard-rules.pro b/build/android/app/proguard-rules.pro
new file mode 100644
index 0000000..8b88c3d
--- /dev/null
+++ b/build/android/app/proguard-rules.pro
@@ -0,0 +1,12 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+
+# Keep native methods
+-keepclasseswithmembernames class * {
+ native ;
+}
+
+# Keep Wails bridge classes
+-keep class com.wails.app.WailsBridge { *; }
+-keep class com.wails.app.WailsJSBridge { *; }
diff --git a/build/android/app/src/main/AndroidManifest.xml b/build/android/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..6c7982a
--- /dev/null
+++ b/build/android/app/src/main/AndroidManifest.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/android/app/src/main/java/com/wails/app/MainActivity.java b/build/android/app/src/main/java/com/wails/app/MainActivity.java
new file mode 100644
index 0000000..3067fee
--- /dev/null
+++ b/build/android/app/src/main/java/com/wails/app/MainActivity.java
@@ -0,0 +1,198 @@
+package com.wails.app;
+
+import android.annotation.SuppressLint;
+import android.os.Bundle;
+import android.util.Log;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebResourceResponse;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.webkit.WebViewAssetLoader;
+import com.wails.app.BuildConfig;
+
+/**
+ * MainActivity hosts the WebView and manages the Wails application lifecycle.
+ * It uses WebViewAssetLoader to serve assets from the Go library without
+ * requiring a network server.
+ */
+public class MainActivity extends AppCompatActivity {
+ private static final String TAG = "WailsActivity";
+ private static final String WAILS_SCHEME = "https";
+ private static final String WAILS_HOST = "wails.localhost";
+
+ private WebView webView;
+ private WailsBridge bridge;
+ private WebViewAssetLoader assetLoader;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ // Initialize the native Go library
+ bridge = new WailsBridge(this);
+ bridge.initialize();
+
+ // Set up WebView
+ setupWebView();
+
+ // Load the application
+ loadApplication();
+ }
+
+ @SuppressLint("SetJavaScriptEnabled")
+ private void setupWebView() {
+ webView = findViewById(R.id.webview);
+
+ // Configure WebView settings
+ WebSettings settings = webView.getSettings();
+ settings.setJavaScriptEnabled(true);
+ settings.setDomStorageEnabled(true);
+ settings.setDatabaseEnabled(true);
+ settings.setAllowFileAccess(false);
+ settings.setAllowContentAccess(false);
+ settings.setMediaPlaybackRequiresUserGesture(false);
+ settings.setMixedContentMode(WebSettings.MIXED_CONTENT_NEVER_ALLOW);
+
+ // Enable debugging in debug builds
+ if (BuildConfig.DEBUG) {
+ WebView.setWebContentsDebuggingEnabled(true);
+ }
+
+ // Set up asset loader for serving local assets
+ assetLoader = new WebViewAssetLoader.Builder()
+ .setDomain(WAILS_HOST)
+ .addPathHandler("/", new WailsPathHandler(bridge))
+ .build();
+
+ // Set up WebView client to intercept requests
+ webView.setWebViewClient(new WebViewClient() {
+ @Nullable
+ @Override
+ public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
+ String url = request.getUrl().toString();
+ Log.d(TAG, "Intercepting request: " + url);
+
+ // Handle wails.localhost requests
+ if (request.getUrl().getHost() != null &&
+ request.getUrl().getHost().equals(WAILS_HOST)) {
+
+ // For wails API calls (runtime, capabilities, etc.), we need to pass the full URL
+ // including query string because WebViewAssetLoader.PathHandler strips query params
+ String path = request.getUrl().getPath();
+ if (path != null && path.startsWith("/wails/")) {
+ // Get full path with query string for runtime calls
+ String fullPath = path;
+ String query = request.getUrl().getQuery();
+ if (query != null && !query.isEmpty()) {
+ fullPath = path + "?" + query;
+ }
+ Log.d(TAG, "Wails API call detected, full path: " + fullPath);
+
+ // Call bridge directly with full path
+ byte[] data = bridge.serveAsset(fullPath, request.getMethod(), "{}");
+ if (data != null && data.length > 0) {
+ java.io.InputStream inputStream = new java.io.ByteArrayInputStream(data);
+ java.util.Map headers = new java.util.HashMap<>();
+ headers.put("Access-Control-Allow-Origin", "*");
+ headers.put("Cache-Control", "no-cache");
+ headers.put("Content-Type", "application/json");
+
+ return new WebResourceResponse(
+ "application/json",
+ "UTF-8",
+ 200,
+ "OK",
+ headers,
+ inputStream
+ );
+ }
+ // Return error response if data is null
+ return new WebResourceResponse(
+ "application/json",
+ "UTF-8",
+ 500,
+ "Internal Error",
+ new java.util.HashMap<>(),
+ new java.io.ByteArrayInputStream("{}".getBytes())
+ );
+ }
+
+ // For regular assets, use the asset loader
+ return assetLoader.shouldInterceptRequest(request.getUrl());
+ }
+
+ return super.shouldInterceptRequest(view, request);
+ }
+
+ @Override
+ public void onPageFinished(WebView view, String url) {
+ super.onPageFinished(view, url);
+ Log.d(TAG, "Page loaded: " + url);
+ // Inject Wails runtime
+ bridge.injectRuntime(webView, url);
+ }
+ });
+
+ // Add JavaScript interface for Go communication
+ webView.addJavascriptInterface(new WailsJSBridge(bridge, webView), "wails");
+ }
+
+ private void loadApplication() {
+ // Load the main page from the asset server
+ String url = WAILS_SCHEME + "://" + WAILS_HOST + "/";
+ Log.d(TAG, "Loading URL: " + url);
+ webView.loadUrl(url);
+ }
+
+ /**
+ * Execute JavaScript in the WebView from the Go side
+ */
+ public void executeJavaScript(final String js) {
+ runOnUiThread(() -> {
+ if (webView != null) {
+ webView.evaluateJavascript(js, null);
+ }
+ });
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (bridge != null) {
+ bridge.onResume();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (bridge != null) {
+ bridge.onPause();
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (bridge != null) {
+ bridge.shutdown();
+ }
+ if (webView != null) {
+ webView.destroy();
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (webView != null && webView.canGoBack()) {
+ webView.goBack();
+ } else {
+ super.onBackPressed();
+ }
+ }
+}
diff --git a/build/android/app/src/main/java/com/wails/app/WailsBridge.java b/build/android/app/src/main/java/com/wails/app/WailsBridge.java
new file mode 100644
index 0000000..3dab652
--- /dev/null
+++ b/build/android/app/src/main/java/com/wails/app/WailsBridge.java
@@ -0,0 +1,214 @@
+package com.wails.app;
+
+import android.content.Context;
+import android.util.Log;
+import android.webkit.WebView;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * WailsBridge manages the connection between the Java/Android side and the Go native library.
+ * It handles:
+ * - Loading and initializing the native Go library
+ * - Serving asset requests from Go
+ * - Passing messages between JavaScript and Go
+ * - Managing callbacks for async operations
+ */
+public class WailsBridge {
+ private static final String TAG = "WailsBridge";
+
+ static {
+ // Load the native Go library
+ System.loadLibrary("wails");
+ }
+
+ private final Context context;
+ private final AtomicInteger callbackIdGenerator = new AtomicInteger(0);
+ private final ConcurrentHashMap pendingAssetCallbacks = new ConcurrentHashMap<>();
+ private final ConcurrentHashMap pendingMessageCallbacks = new ConcurrentHashMap<>();
+ private WebView webView;
+ private volatile boolean initialized = false;
+
+ // Native methods - implemented in Go
+ private static native void nativeInit(WailsBridge bridge);
+ private static native void nativeShutdown();
+ private static native void nativeOnResume();
+ private static native void nativeOnPause();
+ private static native void nativeOnPageFinished(String url);
+ private static native byte[] nativeServeAsset(String path, String method, String headers);
+ private static native String nativeHandleMessage(String message);
+ private static native String nativeGetAssetMimeType(String path);
+
+ public WailsBridge(Context context) {
+ this.context = context;
+ }
+
+ /**
+ * Initialize the native Go library
+ */
+ public void initialize() {
+ if (initialized) {
+ return;
+ }
+
+ Log.i(TAG, "Initializing Wails bridge...");
+ try {
+ nativeInit(this);
+ initialized = true;
+ Log.i(TAG, "Wails bridge initialized successfully");
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to initialize Wails bridge", e);
+ }
+ }
+
+ /**
+ * Shutdown the native Go library
+ */
+ public void shutdown() {
+ if (!initialized) {
+ return;
+ }
+
+ Log.i(TAG, "Shutting down Wails bridge...");
+ try {
+ nativeShutdown();
+ initialized = false;
+ } catch (Exception e) {
+ Log.e(TAG, "Error during shutdown", e);
+ }
+ }
+
+ /**
+ * Called when the activity resumes
+ */
+ public void onResume() {
+ if (initialized) {
+ nativeOnResume();
+ }
+ }
+
+ /**
+ * Called when the activity pauses
+ */
+ public void onPause() {
+ if (initialized) {
+ nativeOnPause();
+ }
+ }
+
+ /**
+ * Serve an asset from the Go asset server
+ * @param path The URL path requested
+ * @param method The HTTP method
+ * @param headers The request headers as JSON
+ * @return The asset data, or null if not found
+ */
+ public byte[] serveAsset(String path, String method, String headers) {
+ if (!initialized) {
+ Log.w(TAG, "Bridge not initialized, cannot serve asset: " + path);
+ return null;
+ }
+
+ Log.d(TAG, "Serving asset: " + path);
+ try {
+ return nativeServeAsset(path, method, headers);
+ } catch (Exception e) {
+ Log.e(TAG, "Error serving asset: " + path, e);
+ return null;
+ }
+ }
+
+ /**
+ * Get the MIME type for an asset
+ * @param path The asset path
+ * @return The MIME type string
+ */
+ public String getAssetMimeType(String path) {
+ if (!initialized) {
+ return "application/octet-stream";
+ }
+
+ try {
+ String mimeType = nativeGetAssetMimeType(path);
+ return mimeType != null ? mimeType : "application/octet-stream";
+ } catch (Exception e) {
+ Log.e(TAG, "Error getting MIME type for: " + path, e);
+ return "application/octet-stream";
+ }
+ }
+
+ /**
+ * Handle a message from JavaScript
+ * @param message The message from JavaScript (JSON)
+ * @return The response to send back to JavaScript (JSON)
+ */
+ public String handleMessage(String message) {
+ if (!initialized) {
+ Log.w(TAG, "Bridge not initialized, cannot handle message");
+ return "{\"error\":\"Bridge not initialized\"}";
+ }
+
+ Log.d(TAG, "Handling message from JS: " + message);
+ try {
+ return nativeHandleMessage(message);
+ } catch (Exception e) {
+ Log.e(TAG, "Error handling message", e);
+ return "{\"error\":\"" + e.getMessage() + "\"}";
+ }
+ }
+
+ /**
+ * Inject the Wails runtime JavaScript into the WebView.
+ * Called when the page finishes loading.
+ * @param webView The WebView to inject into
+ * @param url The URL that finished loading
+ */
+ public void injectRuntime(WebView webView, String url) {
+ this.webView = webView;
+ // Notify Go side that page has finished loading so it can inject the runtime
+ Log.d(TAG, "Page finished loading: " + url + ", notifying Go side");
+ if (initialized) {
+ nativeOnPageFinished(url);
+ }
+ }
+
+ /**
+ * Execute JavaScript in the WebView (called from Go side)
+ * @param js The JavaScript code to execute
+ */
+ public void executeJavaScript(String js) {
+ if (webView != null) {
+ webView.post(() -> webView.evaluateJavascript(js, null));
+ }
+ }
+
+ /**
+ * Called from Go when an event needs to be emitted to JavaScript
+ * @param eventName The event name
+ * @param eventData The event data (JSON)
+ */
+ public void emitEvent(String eventName, String eventData) {
+ String js = String.format("window.wails && window.wails._emit('%s', %s);",
+ escapeJsString(eventName), eventData);
+ executeJavaScript(js);
+ }
+
+ private String escapeJsString(String str) {
+ return str.replace("\\", "\\\\")
+ .replace("'", "\\'")
+ .replace("\n", "\\n")
+ .replace("\r", "\\r");
+ }
+
+ // Callback interfaces
+ public interface AssetCallback {
+ void onAssetReady(byte[] data, String mimeType);
+ void onAssetError(String error);
+ }
+
+ public interface MessageCallback {
+ void onResponse(String response);
+ void onError(String error);
+ }
+}
diff --git a/build/android/app/src/main/java/com/wails/app/WailsJSBridge.java b/build/android/app/src/main/java/com/wails/app/WailsJSBridge.java
new file mode 100644
index 0000000..98ae5b2
--- /dev/null
+++ b/build/android/app/src/main/java/com/wails/app/WailsJSBridge.java
@@ -0,0 +1,142 @@
+package com.wails.app;
+
+import android.util.Log;
+import android.webkit.JavascriptInterface;
+import android.webkit.WebView;
+import com.wails.app.BuildConfig;
+
+/**
+ * WailsJSBridge provides the JavaScript interface that allows the web frontend
+ * to communicate with the Go backend. This is exposed to JavaScript as the
+ * `window.wails` object.
+ *
+ * Similar to iOS's WKScriptMessageHandler but using Android's addJavascriptInterface.
+ */
+public class WailsJSBridge {
+ private static final String TAG = "WailsJSBridge";
+
+ private final WailsBridge bridge;
+ private final WebView webView;
+
+ public WailsJSBridge(WailsBridge bridge, WebView webView) {
+ this.bridge = bridge;
+ this.webView = webView;
+ }
+
+ /**
+ * Send a message to Go and return the response synchronously.
+ * Called from JavaScript: wails.invoke(message)
+ *
+ * @param message The message to send (JSON string)
+ * @return The response from Go (JSON string)
+ */
+ @JavascriptInterface
+ public String invoke(String message) {
+ Log.d(TAG, "Invoke called: " + message);
+ return bridge.handleMessage(message);
+ }
+
+ /**
+ * Send a message to Go asynchronously.
+ * The response will be sent back via a callback.
+ * Called from JavaScript: wails.invokeAsync(callbackId, message)
+ *
+ * @param callbackId The callback ID to use for the response
+ * @param message The message to send (JSON string)
+ */
+ @JavascriptInterface
+ public void invokeAsync(final String callbackId, final String message) {
+ Log.d(TAG, "InvokeAsync called: " + message);
+
+ // Handle in background thread to not block JavaScript
+ new Thread(() -> {
+ try {
+ String response = bridge.handleMessage(message);
+ sendCallback(callbackId, response, null);
+ } catch (Exception e) {
+ Log.e(TAG, "Error in async invoke", e);
+ sendCallback(callbackId, null, e.getMessage());
+ }
+ }).start();
+ }
+
+ /**
+ * Log a message from JavaScript to Android's logcat
+ * Called from JavaScript: wails.log(level, message)
+ *
+ * @param level The log level (debug, info, warn, error)
+ * @param message The message to log
+ */
+ @JavascriptInterface
+ public void log(String level, String message) {
+ switch (level.toLowerCase()) {
+ case "debug":
+ Log.d(TAG + "/JS", message);
+ break;
+ case "info":
+ Log.i(TAG + "/JS", message);
+ break;
+ case "warn":
+ Log.w(TAG + "/JS", message);
+ break;
+ case "error":
+ Log.e(TAG + "/JS", message);
+ break;
+ default:
+ Log.v(TAG + "/JS", message);
+ break;
+ }
+ }
+
+ /**
+ * Get the platform name
+ * Called from JavaScript: wails.platform()
+ *
+ * @return "android"
+ */
+ @JavascriptInterface
+ public String platform() {
+ return "android";
+ }
+
+ /**
+ * Check if we're running in debug mode
+ * Called from JavaScript: wails.isDebug()
+ *
+ * @return true if debug build, false otherwise
+ */
+ @JavascriptInterface
+ public boolean isDebug() {
+ return BuildConfig.DEBUG;
+ }
+
+ /**
+ * Send a callback response to JavaScript
+ */
+ private void sendCallback(String callbackId, String result, String error) {
+ final String js;
+ if (error != null) {
+ js = String.format(
+ "window.wails && window.wails._callback('%s', null, '%s');",
+ escapeJsString(callbackId),
+ escapeJsString(error)
+ );
+ } else {
+ js = String.format(
+ "window.wails && window.wails._callback('%s', %s, null);",
+ escapeJsString(callbackId),
+ result != null ? result : "null"
+ );
+ }
+
+ webView.post(() -> webView.evaluateJavascript(js, null));
+ }
+
+ private String escapeJsString(String str) {
+ if (str == null) return "";
+ return str.replace("\\", "\\\\")
+ .replace("'", "\\'")
+ .replace("\n", "\\n")
+ .replace("\r", "\\r");
+ }
+}
diff --git a/build/android/app/src/main/java/com/wails/app/WailsPathHandler.java b/build/android/app/src/main/java/com/wails/app/WailsPathHandler.java
new file mode 100644
index 0000000..326fa9b
--- /dev/null
+++ b/build/android/app/src/main/java/com/wails/app/WailsPathHandler.java
@@ -0,0 +1,118 @@
+package com.wails.app;
+
+import android.net.Uri;
+import android.util.Log;
+import android.webkit.WebResourceResponse;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.webkit.WebViewAssetLoader;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * WailsPathHandler implements WebViewAssetLoader.PathHandler to serve assets
+ * from the Go asset server. This allows the WebView to load assets without
+ * using a network server, similar to iOS's WKURLSchemeHandler.
+ */
+public class WailsPathHandler implements WebViewAssetLoader.PathHandler {
+ private static final String TAG = "WailsPathHandler";
+
+ private final WailsBridge bridge;
+
+ public WailsPathHandler(WailsBridge bridge) {
+ this.bridge = bridge;
+ }
+
+ @Nullable
+ @Override
+ public WebResourceResponse handle(@NonNull String path) {
+ Log.d(TAG, "Handling path: " + path);
+
+ // Normalize path
+ if (path.isEmpty() || path.equals("/")) {
+ path = "/index.html";
+ }
+
+ // Get asset from Go
+ byte[] data = bridge.serveAsset(path, "GET", "{}");
+
+ if (data == null || data.length == 0) {
+ Log.w(TAG, "Asset not found: " + path);
+ return null; // Return null to let WebView handle 404
+ }
+
+ // Determine MIME type
+ String mimeType = bridge.getAssetMimeType(path);
+ Log.d(TAG, "Serving " + path + " with type " + mimeType + " (" + data.length + " bytes)");
+
+ // Create response
+ InputStream inputStream = new ByteArrayInputStream(data);
+ Map headers = new HashMap<>();
+ headers.put("Access-Control-Allow-Origin", "*");
+ headers.put("Cache-Control", "no-cache");
+
+ return new WebResourceResponse(
+ mimeType,
+ "UTF-8",
+ 200,
+ "OK",
+ headers,
+ inputStream
+ );
+ }
+
+ /**
+ * Determine MIME type from file extension
+ */
+ private String getMimeType(String path) {
+ String lowerPath = path.toLowerCase();
+
+ if (lowerPath.endsWith(".html") || lowerPath.endsWith(".htm")) {
+ return "text/html";
+ } else if (lowerPath.endsWith(".js") || lowerPath.endsWith(".mjs")) {
+ return "application/javascript";
+ } else if (lowerPath.endsWith(".css")) {
+ return "text/css";
+ } else if (lowerPath.endsWith(".json")) {
+ return "application/json";
+ } else if (lowerPath.endsWith(".png")) {
+ return "image/png";
+ } else if (lowerPath.endsWith(".jpg") || lowerPath.endsWith(".jpeg")) {
+ return "image/jpeg";
+ } else if (lowerPath.endsWith(".gif")) {
+ return "image/gif";
+ } else if (lowerPath.endsWith(".svg")) {
+ return "image/svg+xml";
+ } else if (lowerPath.endsWith(".ico")) {
+ return "image/x-icon";
+ } else if (lowerPath.endsWith(".woff")) {
+ return "font/woff";
+ } else if (lowerPath.endsWith(".woff2")) {
+ return "font/woff2";
+ } else if (lowerPath.endsWith(".ttf")) {
+ return "font/ttf";
+ } else if (lowerPath.endsWith(".eot")) {
+ return "application/vnd.ms-fontobject";
+ } else if (lowerPath.endsWith(".xml")) {
+ return "application/xml";
+ } else if (lowerPath.endsWith(".txt")) {
+ return "text/plain";
+ } else if (lowerPath.endsWith(".wasm")) {
+ return "application/wasm";
+ } else if (lowerPath.endsWith(".mp3")) {
+ return "audio/mpeg";
+ } else if (lowerPath.endsWith(".mp4")) {
+ return "video/mp4";
+ } else if (lowerPath.endsWith(".webm")) {
+ return "video/webm";
+ } else if (lowerPath.endsWith(".webp")) {
+ return "image/webp";
+ }
+
+ return "application/octet-stream";
+ }
+}
diff --git a/build/android/app/src/main/res/layout/activity_main.xml b/build/android/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..f278384
--- /dev/null
+++ b/build/android/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
diff --git a/build/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/build/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..9409abe
Binary files /dev/null and b/build/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/build/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/build/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..9409abe
Binary files /dev/null and b/build/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/build/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/build/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..5b6acc0
Binary files /dev/null and b/build/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/build/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/build/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..5b6acc0
Binary files /dev/null and b/build/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/build/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/build/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..1c2c664
Binary files /dev/null and b/build/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/build/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/build/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..1c2c664
Binary files /dev/null and b/build/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/build/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/build/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..be557d8
Binary files /dev/null and b/build/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/build/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/build/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..be557d8
Binary files /dev/null and b/build/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/build/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/build/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..4507f32
Binary files /dev/null and b/build/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/build/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/build/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..4507f32
Binary files /dev/null and b/build/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/build/android/app/src/main/res/values/colors.xml b/build/android/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..dd33f3b
--- /dev/null
+++ b/build/android/app/src/main/res/values/colors.xml
@@ -0,0 +1,8 @@
+
+
+ #3574D4
+ #2C5FB8
+ #1B2636
+ #FFFFFFFF
+ #FF000000
+
diff --git a/build/android/app/src/main/res/values/strings.xml b/build/android/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..3ed9e47
--- /dev/null
+++ b/build/android/app/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Wails App
+
diff --git a/build/android/app/src/main/res/values/themes.xml b/build/android/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..be8a282
--- /dev/null
+++ b/build/android/app/src/main/res/values/themes.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/build/android/build.gradle b/build/android/build.gradle
new file mode 100644
index 0000000..d7fbab3
--- /dev/null
+++ b/build/android/build.gradle
@@ -0,0 +1,4 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ id 'com.android.application' version '8.7.3' apply false
+}
diff --git a/build/android/gradle.properties b/build/android/gradle.properties
new file mode 100644
index 0000000..b9d4426
--- /dev/null
+++ b/build/android/gradle.properties
@@ -0,0 +1,26 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. For more details, visit
+# https://developer.android.com/build/optimize-your-build#parallel
+# org.gradle.parallel=true
+
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
diff --git a/build/android/gradle/wrapper/gradle-wrapper.jar b/build/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..f8e1ee3
Binary files /dev/null and b/build/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/build/android/gradle/wrapper/gradle-wrapper.properties b/build/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..23449a2
--- /dev/null
+++ b/build/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/build/android/gradlew b/build/android/gradlew
new file mode 100644
index 0000000..adff685
--- /dev/null
+++ b/build/android/gradlew
@@ -0,0 +1,248 @@
+#!/bin/sh
+
+#
+# Copyright © 2015 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/build/android/gradlew.bat b/build/android/gradlew.bat
new file mode 100644
index 0000000..c4bdd3a
--- /dev/null
+++ b/build/android/gradlew.bat
@@ -0,0 +1,93 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/build/android/main_android.go b/build/android/main_android.go
new file mode 100644
index 0000000..70a7164
--- /dev/null
+++ b/build/android/main_android.go
@@ -0,0 +1,11 @@
+//go:build android
+
+package main
+
+import "github.com/wailsapp/wails/v3/pkg/application"
+
+func init() {
+ // Register main function to be called when the Android app initializes
+ // This is necessary because in c-shared build mode, main() is not automatically called
+ application.RegisterAndroidMain(main)
+}
diff --git a/build/android/scripts/deps/install_deps.go b/build/android/scripts/deps/install_deps.go
new file mode 100644
index 0000000..d9dfedf
--- /dev/null
+++ b/build/android/scripts/deps/install_deps.go
@@ -0,0 +1,151 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+)
+
+func main() {
+ fmt.Println("Checking Android development dependencies...")
+ fmt.Println()
+
+ errors := []string{}
+
+ // Check Go
+ if !checkCommand("go", "version") {
+ errors = append(errors, "Go is not installed. Install from https://go.dev/dl/")
+ } else {
+ fmt.Println("✓ Go is installed")
+ }
+
+ // Check ANDROID_HOME
+ androidHome := os.Getenv("ANDROID_HOME")
+ if androidHome == "" {
+ androidHome = os.Getenv("ANDROID_SDK_ROOT")
+ }
+ if androidHome == "" {
+ // Try common default locations
+ home, _ := os.UserHomeDir()
+ possiblePaths := []string{
+ filepath.Join(home, "Android", "Sdk"),
+ filepath.Join(home, "Library", "Android", "sdk"),
+ "/usr/local/share/android-sdk",
+ }
+ for _, p := range possiblePaths {
+ if _, err := os.Stat(p); err == nil {
+ androidHome = p
+ break
+ }
+ }
+ }
+
+ if androidHome == "" {
+ errors = append(errors, "ANDROID_HOME not set. Install Android Studio and set ANDROID_HOME environment variable")
+ } else {
+ fmt.Printf("✓ ANDROID_HOME: %s\n", androidHome)
+ }
+
+ // Check adb
+ if !checkCommand("adb", "version") {
+ if androidHome != "" {
+ platformTools := filepath.Join(androidHome, "platform-tools")
+ errors = append(errors, fmt.Sprintf("adb not found. Add %s to PATH", platformTools))
+ } else {
+ errors = append(errors, "adb not found. Install Android SDK Platform-Tools")
+ }
+ } else {
+ fmt.Println("✓ adb is installed")
+ }
+
+ // Check emulator
+ if !checkCommand("emulator", "-list-avds") {
+ if androidHome != "" {
+ emulatorPath := filepath.Join(androidHome, "emulator")
+ errors = append(errors, fmt.Sprintf("emulator not found. Add %s to PATH", emulatorPath))
+ } else {
+ errors = append(errors, "emulator not found. Install Android Emulator via SDK Manager")
+ }
+ } else {
+ fmt.Println("✓ Android Emulator is installed")
+ }
+
+ // Check NDK
+ ndkHome := os.Getenv("ANDROID_NDK_HOME")
+ if ndkHome == "" && androidHome != "" {
+ // Look for NDK in default location
+ ndkDir := filepath.Join(androidHome, "ndk")
+ if entries, err := os.ReadDir(ndkDir); err == nil {
+ for _, entry := range entries {
+ if entry.IsDir() {
+ ndkHome = filepath.Join(ndkDir, entry.Name())
+ break
+ }
+ }
+ }
+ }
+
+ if ndkHome == "" {
+ errors = append(errors, "Android NDK not found. Install NDK via Android Studio > SDK Manager > SDK Tools > NDK (Side by side)")
+ } else {
+ fmt.Printf("✓ Android NDK: %s\n", ndkHome)
+ }
+
+ // Check Java
+ if !checkCommand("java", "-version") {
+ errors = append(errors, "Java not found. Install JDK 11+ (OpenJDK recommended)")
+ } else {
+ fmt.Println("✓ Java is installed")
+ }
+
+ // Check for AVD (Android Virtual Device)
+ if checkCommand("emulator", "-list-avds") {
+ cmd := exec.Command("emulator", "-list-avds")
+ output, err := cmd.Output()
+ if err == nil && len(strings.TrimSpace(string(output))) > 0 {
+ avds := strings.Split(strings.TrimSpace(string(output)), "\n")
+ fmt.Printf("✓ Found %d Android Virtual Device(s)\n", len(avds))
+ } else {
+ fmt.Println("⚠ No Android Virtual Devices found. Create one via Android Studio > Tools > Device Manager")
+ }
+ }
+
+ fmt.Println()
+
+ if len(errors) > 0 {
+ fmt.Println("❌ Missing dependencies:")
+ for _, err := range errors {
+ fmt.Printf(" - %s\n", err)
+ }
+ fmt.Println()
+ fmt.Println("Setup instructions:")
+ fmt.Println("1. Install Android Studio: https://developer.android.com/studio")
+ fmt.Println("2. Open SDK Manager and install:")
+ fmt.Println(" - Android SDK Platform (API 34)")
+ fmt.Println(" - Android SDK Build-Tools")
+ fmt.Println(" - Android SDK Platform-Tools")
+ fmt.Println(" - Android Emulator")
+ fmt.Println(" - NDK (Side by side)")
+ fmt.Println("3. Set environment variables:")
+ if runtime.GOOS == "darwin" {
+ fmt.Println(" export ANDROID_HOME=$HOME/Library/Android/sdk")
+ } else {
+ fmt.Println(" export ANDROID_HOME=$HOME/Android/Sdk")
+ }
+ fmt.Println(" export PATH=$PATH:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator")
+ fmt.Println("4. Create an AVD via Android Studio > Tools > Device Manager")
+ os.Exit(1)
+ }
+
+ fmt.Println("✓ All Android development dependencies are installed!")
+}
+
+func checkCommand(name string, args ...string) bool {
+ cmd := exec.Command(name, args...)
+ cmd.Stdout = nil
+ cmd.Stderr = nil
+ return cmd.Run() == nil
+}
diff --git a/build/android/settings.gradle b/build/android/settings.gradle
new file mode 100644
index 0000000..a3f3ec3
--- /dev/null
+++ b/build/android/settings.gradle
@@ -0,0 +1,18 @@
+pluginManagement {
+ repositories {
+ google()
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "WailsApp"
+include ':app'
diff --git a/build/appicon.icon/Assets/wails_icon_vector.svg b/build/appicon.icon/Assets/wails_icon_vector.svg
new file mode 100644
index 0000000..b099222
--- /dev/null
+++ b/build/appicon.icon/Assets/wails_icon_vector.svg
@@ -0,0 +1,9 @@
+
+
+
diff --git a/build/appicon.icon/icon.json b/build/appicon.icon/icon.json
new file mode 100644
index 0000000..ecf1849
--- /dev/null
+++ b/build/appicon.icon/icon.json
@@ -0,0 +1,51 @@
+{
+ "fill" : {
+ "automatic-gradient" : "extended-gray:1.00000,1.00000"
+ },
+ "groups" : [
+ {
+ "layers" : [
+ {
+ "fill-specializations" : [
+ {
+ "appearance" : "dark",
+ "value" : {
+ "solid" : "srgb:0.92143,0.92145,0.92144,1.00000"
+ }
+ },
+ {
+ "appearance" : "tinted",
+ "value" : {
+ "solid" : "srgb:0.83742,0.83744,0.83743,1.00000"
+ }
+ }
+ ],
+ "image-name" : "wails_icon_vector.svg",
+ "name" : "wails_icon_vector",
+ "position" : {
+ "scale" : 1.25,
+ "translation-in-points" : [
+ 36.890625,
+ 4.96875
+ ]
+ }
+ }
+ ],
+ "shadow" : {
+ "kind" : "neutral",
+ "opacity" : 0.5
+ },
+ "specular" : true,
+ "translucency" : {
+ "enabled" : true,
+ "value" : 0.5
+ }
+ }
+ ],
+ "supported-platforms" : {
+ "circles" : [
+ "watchOS"
+ ],
+ "squares" : "shared"
+ }
+}
\ No newline at end of file
diff --git a/build/config.yml b/build/config.yml
new file mode 100644
index 0000000..8046733
--- /dev/null
+++ b/build/config.yml
@@ -0,0 +1,80 @@
+# This file contains the configuration for this project.
+# When you update `info` or `fileAssociations`, run `wails3 task common:update:build-assets` to update the assets.
+# Note that this will overwrite any changes you have made to the assets.
+version: '3'
+
+# This information is used to generate the build assets.
+info:
+ companyName: "My Company" # The name of the company
+ productName: "My Product" # The name of the application
+ productIdentifier: "com.mycompany.myproduct" # The unique product identifier
+ description: "A program that does X" # The application description
+ copyright: "(c) 2025, My Company" # Copyright text
+ comments: "Some Product Comments" # Comments
+ version: "0.0.1" # The application version
+ # cfBundleIconName: "appicon" # The macOS icon name in Assets.car icon bundles (optional)
+ # # Should match the name of your .icon file without the extension
+ # # If not set and Assets.car exists, defaults to "appicon"
+
+# iOS build configuration (uncomment to customise iOS project generation)
+# Note: Keys under `ios` OVERRIDE values under `info` when set.
+# ios:
+# # The iOS bundle identifier used in the generated Xcode project (CFBundleIdentifier)
+# bundleID: "com.mycompany.myproduct"
+# # The display name shown under the app icon (CFBundleDisplayName/CFBundleName)
+# displayName: "My Product"
+# # The app version to embed in Info.plist (CFBundleShortVersionString/CFBundleVersion)
+# version: "0.0.1"
+# # The company/organisation name for templates and project settings
+# company: "My Company"
+# # Additional comments to embed in Info.plist metadata
+# comments: "Some Product Comments"
+
+# Dev mode configuration
+dev_mode:
+ root_path: .
+ log_level: warn
+ debounce: 1000
+ ignore:
+ dir:
+ - .git
+ - node_modules
+ - frontend
+ - bin
+ file:
+ - .DS_Store
+ - .gitignore
+ - .gitkeep
+ watched_extension:
+ - "*.go"
+ - "*.js" # Watch for changes to JS/TS files included using the //wails:include directive.
+ - "*.ts" # The frontend directory will be excluded entirely by the setting above.
+ git_ignore: true
+ executes:
+ - cmd: wails3 task common:install:frontend:deps
+ type: once
+ - cmd: wails3 task common:dev:frontend
+ type: background
+ - cmd: wails3 task build
+ type: blocking
+ - cmd: wails3 task run
+ type: primary
+
+# File Associations
+# More information at: https://v3.wails.io/noit/done/yet
+fileAssociations:
+# - ext: wails
+# name: Wails
+# description: Wails Application File
+# iconName: wailsFileIcon
+# role: Editor
+# - ext: jpg
+# name: JPEG
+# description: Image File
+# iconName: jpegFileIcon
+# role: Editor
+# mimeType: image/jpeg # (optional)
+
+# Other data
+other:
+ - name: My Other Data
\ No newline at end of file
diff --git a/build/darwin/Assets.car b/build/darwin/Assets.car
new file mode 100644
index 0000000..4def9c3
Binary files /dev/null and b/build/darwin/Assets.car differ
diff --git a/build/darwin/Info.dev.plist b/build/darwin/Info.dev.plist
new file mode 100644
index 0000000..73a9d73
--- /dev/null
+++ b/build/darwin/Info.dev.plist
@@ -0,0 +1,34 @@
+
+
+
+ CFBundlePackageType
+ APPL
+ CFBundleName
+ U-Desk
+ CFBundleExecutable
+ u-desk.exe
+ CFBundleIdentifier
+ com.example.udesk
+ CFBundleVersion
+ 0.1.0
+ CFBundleGetInfoString
+ This is a comment
+ CFBundleShortVersionString
+ 0.1.0
+ CFBundleIconFile
+ icons
+ CFBundleIconName
+ appicon
+ LSMinimumSystemVersion
+ 10.15.0
+ NSHighResolutionCapable
+ true
+ NSHumanReadableCopyright
+ © 2026, My Company
+ NSAppTransportSecurity
+
+ NSAllowsLocalNetworking
+
+
+
+
\ No newline at end of file
diff --git a/build/darwin/Info.plist b/build/darwin/Info.plist
new file mode 100644
index 0000000..a0d931e
--- /dev/null
+++ b/build/darwin/Info.plist
@@ -0,0 +1,29 @@
+
+
+
+ CFBundlePackageType
+ APPL
+ CFBundleName
+ U-Desk
+ CFBundleExecutable
+ u-desk.exe
+ CFBundleIdentifier
+ com.example.udesk
+ CFBundleVersion
+ 0.1.0
+ CFBundleGetInfoString
+ This is a comment
+ CFBundleShortVersionString
+ 0.1.0
+ CFBundleIconFile
+ icons
+ CFBundleIconName
+ appicon
+ LSMinimumSystemVersion
+ 10.15.0
+ NSHighResolutionCapable
+ true
+ NSHumanReadableCopyright
+ © 2026, My Company
+
+
\ No newline at end of file
diff --git a/build/darwin/Taskfile.yml b/build/darwin/Taskfile.yml
new file mode 100644
index 0000000..470b7d8
--- /dev/null
+++ b/build/darwin/Taskfile.yml
@@ -0,0 +1,208 @@
+version: '3'
+
+includes:
+ common: ../Taskfile.yml
+
+vars:
+ # Signing configuration - edit these values for your project
+ # SIGN_IDENTITY: "Developer ID Application: Your Company (TEAMID)"
+ # KEYCHAIN_PROFILE: "my-notarize-profile"
+ # ENTITLEMENTS: "build/darwin/entitlements.plist"
+
+ # Docker image for cross-compilation (used when building on non-macOS)
+ CROSS_IMAGE: wails-cross
+
+tasks:
+ build:
+ summary: Builds the application
+ cmds:
+ - task: '{{if eq OS "darwin"}}build:native{{else}}build:docker{{end}}'
+ vars:
+ ARCH: '{{.ARCH}}'
+ DEV: '{{.DEV}}'
+ OUTPUT: '{{.OUTPUT}}'
+ EXTRA_TAGS: '{{.EXTRA_TAGS}}'
+ vars:
+ DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}'
+ OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}'
+
+ build:native:
+ summary: Builds the application natively on macOS
+ internal: true
+ deps:
+ - task: common:go:mod:tidy
+ - task: common:build:frontend
+ vars:
+ BUILD_FLAGS:
+ ref: .BUILD_FLAGS
+ DEV:
+ ref: .DEV
+ - task: common:generate:icons
+ cmds:
+ - go build {{.BUILD_FLAGS}} -o "{{.OUTPUT}}"
+ vars:
+ BUILD_FLAGS: '{{if eq .DEV "true"}}{{if .EXTRA_TAGS}}-tags {{.EXTRA_TAGS}} {{end}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production{{if .EXTRA_TAGS}},{{.EXTRA_TAGS}}{{end}} -trimpath -buildvcs=false -ldflags="-w -s"{{end}}'
+ DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}'
+ OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}'
+ env:
+ GOOS: darwin
+ CGO_ENABLED: 1
+ GOARCH: '{{.ARCH | default ARCH}}'
+ CGO_CFLAGS: "-mmacosx-version-min=10.15"
+ CGO_LDFLAGS: "-mmacosx-version-min=10.15"
+ MACOSX_DEPLOYMENT_TARGET: "10.15"
+
+ build:docker:
+ summary: Cross-compiles for macOS using Docker (for Linux/Windows hosts)
+ internal: true
+ deps:
+ - task: common:build:frontend
+ - task: common:generate:icons
+ preconditions:
+ - sh: docker info > /dev/null 2>&1
+ msg: "Docker is required for cross-compilation. Please install Docker."
+ - sh: docker image inspect {{.CROSS_IMAGE}} > /dev/null 2>&1
+ msg: |
+ Docker image '{{.CROSS_IMAGE}}' not found.
+ Build it first: wails3 task setup:docker
+ cmds:
+ - docker run --rm -v "{{.ROOT_DIR}}:/app" {{.GO_CACHE_MOUNT}} {{.REPLACE_MOUNTS}} -e APP_NAME="{{.APP_NAME}}" {{if .EXTRA_TAGS}}-e EXTRA_TAGS="{{.EXTRA_TAGS}}"{{end}} {{.CROSS_IMAGE}} darwin {{.DOCKER_ARCH}}
+ - docker run --rm -v "{{.ROOT_DIR}}:/app" alpine chown -R $(id -u):$(id -g) /app/bin
+ - mkdir -p {{.BIN_DIR}}
+ - mv "bin/{{.APP_NAME}}-darwin-{{.DOCKER_ARCH}}" "{{.OUTPUT}}"
+ vars:
+ DOCKER_ARCH: '{{if eq .ARCH "arm64"}}arm64{{else if eq .ARCH "amd64"}}amd64{{else}}arm64{{end}}'
+ DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}'
+ OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}'
+ # Mount Go module cache for faster builds
+ GO_CACHE_MOUNT:
+ sh: 'echo "-v ${GOPATH:-$HOME/go}/pkg/mod:/go/pkg/mod"'
+ # Extract replace directives from go.mod and create -v mounts for each
+ # Handles both relative (=> ../) and absolute (=> /) paths
+ REPLACE_MOUNTS:
+ sh: |
+ grep -E '^replace .* => ' go.mod 2>/dev/null | while read -r line; do
+ path=$(echo "$line" | sed -E 's/^replace .* => //' | tr -d '\r')
+ # Convert relative paths to absolute
+ if [ "${path#/}" = "$path" ]; then
+ path="$(cd "$(dirname "$path")" 2>/dev/null && pwd)/$(basename "$path")"
+ fi
+ # Only mount if directory exists
+ if [ -d "$path" ]; then
+ echo "-v $path:$path:ro"
+ fi
+ done | tr '\n' ' '
+
+ build:universal:
+ summary: Builds darwin universal binary (arm64 + amd64)
+ deps:
+ - task: build
+ vars:
+ ARCH: amd64
+ OUTPUT: "{{.BIN_DIR}}/{{.APP_NAME}}-amd64"
+ - task: build
+ vars:
+ ARCH: arm64
+ OUTPUT: "{{.BIN_DIR}}/{{.APP_NAME}}-arm64"
+ cmds:
+ - task: '{{if eq OS "darwin"}}build:universal:lipo:native{{else}}build:universal:lipo:go{{end}}'
+
+ build:universal:lipo:native:
+ summary: Creates universal binary using native lipo (macOS)
+ internal: true
+ cmds:
+ - lipo -create -output "{{.BIN_DIR}}/{{.APP_NAME}}" "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" "{{.BIN_DIR}}/{{.APP_NAME}}-arm64"
+ - rm "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" "{{.BIN_DIR}}/{{.APP_NAME}}-arm64"
+
+ build:universal:lipo:go:
+ summary: Creates universal binary using wails3 tool lipo (Linux/Windows)
+ internal: true
+ cmds:
+ - wails3 tool lipo -output "{{.BIN_DIR}}/{{.APP_NAME}}" -input "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" -input "{{.BIN_DIR}}/{{.APP_NAME}}-arm64"
+ - rm -f "{{.BIN_DIR}}/{{.APP_NAME}}-amd64" "{{.BIN_DIR}}/{{.APP_NAME}}-arm64"
+
+ package:
+ summary: Packages the application into a `.app` bundle
+ deps:
+ - task: build
+ cmds:
+ - task: create:app:bundle
+
+ package:universal:
+ summary: Packages darwin universal binary (arm64 + amd64)
+ deps:
+ - task: build:universal
+ cmds:
+ - task: create:app:bundle
+
+
+ create:app:bundle:
+ summary: Creates an `.app` bundle
+ cmds:
+ - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/MacOS"
+ - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Resources"
+ - cp build/darwin/icons.icns "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Resources"
+ - |
+ if [ -f build/darwin/Assets.car ]; then
+ cp build/darwin/Assets.car "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/Resources"
+ fi
+ - cp "{{.BIN_DIR}}/{{.APP_NAME}}" "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents/MacOS"
+ - cp build/darwin/Info.plist "{{.BIN_DIR}}/{{.APP_NAME}}.app/Contents"
+ - task: '{{if eq OS "darwin"}}codesign:adhoc{{else}}codesign:skip{{end}}'
+
+ codesign:adhoc:
+ summary: Ad-hoc signs the app bundle (macOS only)
+ internal: true
+ cmds:
+ - codesign --force --deep --sign - "{{.BIN_DIR}}/{{.APP_NAME}}.app"
+
+ codesign:skip:
+ summary: Skips codesigning when cross-compiling
+ internal: true
+ cmds:
+ - 'echo "Skipping codesign (not available on {{OS}}). Sign the .app on macOS before distribution."'
+
+ run:
+ cmds:
+ - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/MacOS"
+ - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Resources"
+ - cp build/darwin/icons.icns "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Resources"
+ - |
+ if [ -f build/darwin/Assets.car ]; then
+ cp build/darwin/Assets.car "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Resources"
+ fi
+ - cp "{{.BIN_DIR}}/{{.APP_NAME}}" "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/MacOS"
+ - cp "build/darwin/Info.dev.plist" "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/Info.plist"
+ - codesign --force --deep --sign - "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app"
+ - '"{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Contents/MacOS/{{.APP_NAME}}"'
+
+ sign:
+ summary: Signs the application bundle with Developer ID
+ desc: |
+ Signs the .app bundle for distribution.
+ Configure SIGN_IDENTITY in the vars section at the top of this file.
+ deps:
+ - task: package
+ cmds:
+ - wails3 tool sign --input "{{.BIN_DIR}}/{{.APP_NAME}}.app" --identity "{{.SIGN_IDENTITY}}" {{if .ENTITLEMENTS}}--entitlements {{.ENTITLEMENTS}}{{end}}
+ preconditions:
+ - sh: '[ -n "{{.SIGN_IDENTITY}}" ]'
+ msg: "SIGN_IDENTITY is required. Set it in the vars section at the top of build/darwin/Taskfile.yml"
+
+ sign:notarize:
+ summary: Signs and notarizes the application bundle
+ desc: |
+ Signs the .app bundle and submits it for notarization.
+ Configure SIGN_IDENTITY and KEYCHAIN_PROFILE in the vars section at the top of this file.
+
+ Setup (one-time):
+ wails3 signing credentials --apple-id "you@email.com" --team-id "TEAMID" --password "app-specific-password" --profile "my-profile"
+ deps:
+ - task: package
+ cmds:
+ - wails3 tool sign --input "{{.BIN_DIR}}/{{.APP_NAME}}.app" --identity "{{.SIGN_IDENTITY}}" {{if .ENTITLEMENTS}}--entitlements {{.ENTITLEMENTS}}{{end}} --notarize --keychain-profile {{.KEYCHAIN_PROFILE}}
+ preconditions:
+ - sh: '[ -n "{{.SIGN_IDENTITY}}" ]'
+ msg: "SIGN_IDENTITY is required. Set it in the vars section at the top of build/darwin/Taskfile.yml"
+ - sh: '[ -n "{{.KEYCHAIN_PROFILE}}" ]'
+ msg: "KEYCHAIN_PROFILE is required. Set it in the vars section at the top of build/darwin/Taskfile.yml"
diff --git a/build/darwin/icons.icns b/build/darwin/icons.icns
new file mode 100644
index 0000000..ff13376
Binary files /dev/null and b/build/darwin/icons.icns differ
diff --git a/build/docker/Dockerfile.cross b/build/docker/Dockerfile.cross
new file mode 100644
index 0000000..a3c01f2
--- /dev/null
+++ b/build/docker/Dockerfile.cross
@@ -0,0 +1,203 @@
+# Cross-compile Wails v3 apps to any platform
+#
+# Darwin: Zig + macOS SDK
+# Linux: Native GCC when host matches target, Zig for cross-arch
+# Windows: Zig + bundled mingw
+#
+# Usage:
+# docker build -t wails-cross -f Dockerfile.cross .
+# docker run --rm -v $(pwd):/app wails-cross darwin arm64
+# docker run --rm -v $(pwd):/app wails-cross darwin amd64
+# docker run --rm -v $(pwd):/app wails-cross linux amd64
+# docker run --rm -v $(pwd):/app wails-cross linux arm64
+# docker run --rm -v $(pwd):/app wails-cross windows amd64
+# docker run --rm -v $(pwd):/app wails-cross windows arm64
+
+FROM golang:1.25-bookworm
+
+ARG TARGETARCH
+
+# Install base tools, GCC, and GTK/WebKit dev packages
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ curl xz-utils nodejs npm pkg-config gcc libc6-dev \
+ libgtk-3-dev libwebkit2gtk-4.1-dev \
+ libgtk-4-dev libwebkitgtk-6.0-dev \
+ && rm -rf /var/lib/apt/lists/*
+
+# Install Zig - automatically selects correct binary for host architecture
+ARG ZIG_VERSION=0.14.0
+RUN ZIG_ARCH=$(case "${TARGETARCH}" in arm64) echo "aarch64" ;; *) echo "x86_64" ;; esac) && \
+ curl -L "https://ziglang.org/download/${ZIG_VERSION}/zig-linux-${ZIG_ARCH}-${ZIG_VERSION}.tar.xz" \
+ | tar -xJ -C /opt \
+ && ln -s /opt/zig-linux-${ZIG_ARCH}-${ZIG_VERSION}/zig /usr/local/bin/zig
+
+# Download macOS SDK (required for darwin targets)
+ARG MACOS_SDK_VERSION=14.5
+RUN curl -L "https://github.com/joseluisq/macosx-sdks/releases/download/${MACOS_SDK_VERSION}/MacOSX${MACOS_SDK_VERSION}.sdk.tar.xz" \
+ | tar -xJ -C /opt \
+ && mv /opt/MacOSX${MACOS_SDK_VERSION}.sdk /opt/macos-sdk
+
+ENV MACOS_SDK_PATH=/opt/macos-sdk
+
+# Create Zig CC wrappers for cross-compilation targets
+# Darwin and Windows use Zig; Linux uses native GCC (run with --platform for cross-arch)
+
+# Darwin arm64
+COPY <<'ZIGWRAP' /usr/local/bin/zcc-darwin-arm64
+#!/bin/sh
+ARGS=""
+SKIP_NEXT=0
+for arg in "$@"; do
+ if [ $SKIP_NEXT -eq 1 ]; then
+ SKIP_NEXT=0
+ continue
+ fi
+ case "$arg" in
+ -target) SKIP_NEXT=1 ;;
+ -mmacosx-version-min=*) ;;
+ *) ARGS="$ARGS $arg" ;;
+ esac
+done
+exec zig cc -fno-sanitize=all -target aarch64-macos-none -isysroot /opt/macos-sdk -I/opt/macos-sdk/usr/include -L/opt/macos-sdk/usr/lib -F/opt/macos-sdk/System/Library/Frameworks -w $ARGS
+ZIGWRAP
+RUN chmod +x /usr/local/bin/zcc-darwin-arm64
+
+# Darwin amd64
+COPY <<'ZIGWRAP' /usr/local/bin/zcc-darwin-amd64
+#!/bin/sh
+ARGS=""
+SKIP_NEXT=0
+for arg in "$@"; do
+ if [ $SKIP_NEXT -eq 1 ]; then
+ SKIP_NEXT=0
+ continue
+ fi
+ case "$arg" in
+ -target) SKIP_NEXT=1 ;;
+ -mmacosx-version-min=*) ;;
+ *) ARGS="$ARGS $arg" ;;
+ esac
+done
+exec zig cc -fno-sanitize=all -target x86_64-macos-none -isysroot /opt/macos-sdk -I/opt/macos-sdk/usr/include -L/opt/macos-sdk/usr/lib -F/opt/macos-sdk/System/Library/Frameworks -w $ARGS
+ZIGWRAP
+RUN chmod +x /usr/local/bin/zcc-darwin-amd64
+
+# Windows amd64 - uses Zig's bundled mingw
+COPY <<'ZIGWRAP' /usr/local/bin/zcc-windows-amd64
+#!/bin/sh
+ARGS=""
+SKIP_NEXT=0
+for arg in "$@"; do
+ if [ $SKIP_NEXT -eq 1 ]; then
+ SKIP_NEXT=0
+ continue
+ fi
+ case "$arg" in
+ -target) SKIP_NEXT=1 ;;
+ -Wl,*) ;;
+ *) ARGS="$ARGS $arg" ;;
+ esac
+done
+exec zig cc -target x86_64-windows-gnu $ARGS
+ZIGWRAP
+RUN chmod +x /usr/local/bin/zcc-windows-amd64
+
+# Windows arm64 - uses Zig's bundled mingw
+COPY <<'ZIGWRAP' /usr/local/bin/zcc-windows-arm64
+#!/bin/sh
+ARGS=""
+SKIP_NEXT=0
+for arg in "$@"; do
+ if [ $SKIP_NEXT -eq 1 ]; then
+ SKIP_NEXT=0
+ continue
+ fi
+ case "$arg" in
+ -target) SKIP_NEXT=1 ;;
+ -Wl,*) ;;
+ *) ARGS="$ARGS $arg" ;;
+ esac
+done
+exec zig cc -target aarch64-windows-gnu $ARGS
+ZIGWRAP
+RUN chmod +x /usr/local/bin/zcc-windows-arm64
+
+# Build script
+COPY <<'SCRIPT' /usr/local/bin/build.sh
+#!/bin/sh
+set -e
+
+OS=${1:-darwin}
+ARCH=${2:-arm64}
+
+case "${OS}-${ARCH}" in
+ darwin-arm64|darwin-aarch64)
+ export CC=zcc-darwin-arm64
+ export GOARCH=arm64
+ export GOOS=darwin
+ ;;
+ darwin-amd64|darwin-x86_64)
+ export CC=zcc-darwin-amd64
+ export GOARCH=amd64
+ export GOOS=darwin
+ ;;
+ linux-arm64|linux-aarch64)
+ export CC=gcc
+ export GOARCH=arm64
+ export GOOS=linux
+ ;;
+ linux-amd64|linux-x86_64)
+ export CC=gcc
+ export GOARCH=amd64
+ export GOOS=linux
+ ;;
+ windows-arm64|windows-aarch64)
+ export CC=zcc-windows-arm64
+ export GOARCH=arm64
+ export GOOS=windows
+ ;;
+ windows-amd64|windows-x86_64)
+ export CC=zcc-windows-amd64
+ export GOARCH=amd64
+ export GOOS=windows
+ ;;
+ *)
+ echo "Usage: "
+ echo " os: darwin, linux, windows"
+ echo " arch: amd64, arm64"
+ exit 1
+ ;;
+esac
+
+export CGO_ENABLED=1
+export CGO_CFLAGS="-w"
+
+# Build frontend if exists and not already built (host may have built it)
+if [ -d "frontend" ] && [ -f "frontend/package.json" ] && [ ! -d "frontend/dist" ]; then
+ (cd frontend && npm install --silent && npm run build --silent)
+fi
+
+# Build
+APP=${APP_NAME:-$(basename $(pwd))}
+mkdir -p bin
+
+EXT=""
+LDFLAGS="-s -w"
+if [ "$GOOS" = "windows" ]; then
+ EXT=".exe"
+ LDFLAGS="-s -w -H windowsgui"
+fi
+
+TAGS="production"
+if [ -n "$EXTRA_TAGS" ]; then
+ TAGS="${TAGS},${EXTRA_TAGS}"
+fi
+
+go build -tags "$TAGS" -trimpath -buildvcs=false -ldflags="$LDFLAGS" -o bin/${APP}-${GOOS}-${GOARCH}${EXT} .
+echo "Built: bin/${APP}-${GOOS}-${GOARCH}${EXT}"
+SCRIPT
+RUN chmod +x /usr/local/bin/build.sh
+
+WORKDIR /app
+ENTRYPOINT ["/usr/local/bin/build.sh"]
+CMD ["darwin", "arm64"]
diff --git a/build/docker/Dockerfile.server b/build/docker/Dockerfile.server
new file mode 100644
index 0000000..58fb64f
--- /dev/null
+++ b/build/docker/Dockerfile.server
@@ -0,0 +1,41 @@
+# Wails Server Mode Dockerfile
+# Multi-stage build for minimal image size
+
+# Build stage
+FROM golang:alpine AS builder
+
+WORKDIR /app
+
+# Install build dependencies
+RUN apk add --no-cache git
+
+# Copy source code
+COPY . .
+
+# Remove local replace directive if present (for production builds)
+RUN sed -i '/^replace/d' go.mod || true
+
+# Download dependencies
+RUN go mod tidy
+
+# Build the server binary
+RUN go build -tags server -ldflags="-s -w" -o server .
+
+# Runtime stage - minimal image
+FROM gcr.io/distroless/static-debian12
+
+# Copy the binary
+COPY --from=builder /app/server /server
+
+# Copy frontend assets
+COPY --from=builder /app/frontend/dist /frontend/dist
+
+# Expose the default port
+EXPOSE 8080
+
+# Bind to all interfaces (required for Docker)
+# Can be overridden at runtime with -e WAILS_SERVER_HOST=...
+ENV WAILS_SERVER_HOST=0.0.0.0
+
+# Run the server
+ENTRYPOINT ["/server"]
diff --git a/build/ios/Assets.xcassets b/build/ios/Assets.xcassets
new file mode 100644
index 0000000..46fbb87
--- /dev/null
+++ b/build/ios/Assets.xcassets
@@ -0,0 +1,116 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ },
+ "images" : [
+ {
+ "filename" : "icon-20@2x.png",
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "20x20"
+ },
+ {
+ "filename" : "icon-20@3x.png",
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "20x20"
+ },
+ {
+ "filename" : "icon-29@2x.png",
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "icon-29@3x.png",
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "icon-40@2x.png",
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "40x40"
+ },
+ {
+ "filename" : "icon-40@3x.png",
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "40x40"
+ },
+ {
+ "filename" : "icon-60@2x.png",
+ "idiom" : "iphone",
+ "scale" : "2x",
+ "size" : "60x60"
+ },
+ {
+ "filename" : "icon-60@3x.png",
+ "idiom" : "iphone",
+ "scale" : "3x",
+ "size" : "60x60"
+ },
+ {
+ "filename" : "icon-20.png",
+ "idiom" : "ipad",
+ "scale" : "1x",
+ "size" : "20x20"
+ },
+ {
+ "filename" : "icon-20@2x.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "20x20"
+ },
+ {
+ "filename" : "icon-29.png",
+ "idiom" : "ipad",
+ "scale" : "1x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "icon-29@2x.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "29x29"
+ },
+ {
+ "filename" : "icon-40.png",
+ "idiom" : "ipad",
+ "scale" : "1x",
+ "size" : "40x40"
+ },
+ {
+ "filename" : "icon-40@2x.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "40x40"
+ },
+ {
+ "filename" : "icon-76.png",
+ "idiom" : "ipad",
+ "scale" : "1x",
+ "size" : "76x76"
+ },
+ {
+ "filename" : "icon-76@2x.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "76x76"
+ },
+ {
+ "filename" : "icon-83.5@2x.png",
+ "idiom" : "ipad",
+ "scale" : "2x",
+ "size" : "83.5x83.5"
+ },
+ {
+ "filename" : "icon-1024.png",
+ "idiom" : "ios-marketing",
+ "scale" : "1x",
+ "size" : "1024x1024"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/build/ios/Info.dev.plist b/build/ios/Info.dev.plist
new file mode 100644
index 0000000..d7ca352
--- /dev/null
+++ b/build/ios/Info.dev.plist
@@ -0,0 +1,62 @@
+
+
+
+
+ CFBundleExecutable
+ u-desk.exe
+ CFBundleIdentifier
+ com.example.udesk.dev
+ CFBundleName
+ U-Desk (Dev)
+ CFBundleDisplayName
+ U-Desk (Dev)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 0.1.0-dev
+ CFBundleVersion
+ 0.1.0
+ LSRequiresIPhoneOS
+
+ MinimumOSVersion
+ 15.0
+ UILaunchStoryboardName
+ LaunchScreen
+ UIRequiredDeviceCapabilities
+
+ armv7
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+ NSAllowsLocalNetworking
+
+
+
+ WailsDevelopmentMode
+
+
+ NSHumanReadableCopyright
+ © 2026, My Company
+
+
+ CFBundleGetInfoString
+ This is a comment
+
+
+
\ No newline at end of file
diff --git a/build/ios/Info.plist b/build/ios/Info.plist
new file mode 100644
index 0000000..746754d
--- /dev/null
+++ b/build/ios/Info.plist
@@ -0,0 +1,59 @@
+
+
+
+
+ CFBundleExecutable
+ u-desk.exe
+ CFBundleIdentifier
+ com.example.udesk
+ CFBundleName
+ U-Desk
+ CFBundleDisplayName
+ U-Desk
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 0.1.0
+ CFBundleVersion
+ 0.1.0
+ LSRequiresIPhoneOS
+
+ MinimumOSVersion
+ 15.0
+ UILaunchStoryboardName
+ LaunchScreen
+ UIRequiredDeviceCapabilities
+
+ armv7
+ arm64
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+ NSAllowsLocalNetworking
+
+
+
+ NSHumanReadableCopyright
+ © 2026, My Company
+
+
+ CFBundleGetInfoString
+ This is a comment
+
+
+
\ No newline at end of file
diff --git a/build/ios/LaunchScreen.storyboard b/build/ios/LaunchScreen.storyboard
new file mode 100644
index 0000000..b343f7a
--- /dev/null
+++ b/build/ios/LaunchScreen.storyboard
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/build/ios/Taskfile.yml b/build/ios/Taskfile.yml
new file mode 100644
index 0000000..8c27f08
--- /dev/null
+++ b/build/ios/Taskfile.yml
@@ -0,0 +1,293 @@
+version: '3'
+
+includes:
+ common: ../Taskfile.yml
+
+vars:
+ BUNDLE_ID: '{{.BUNDLE_ID | default "com.wails.app"}}'
+ # SDK_PATH is computed lazily at task-level to avoid errors on non-macOS systems
+ # Each task that needs it defines SDK_PATH in its own vars section
+
+tasks:
+ install:deps:
+ summary: Check and install iOS development dependencies
+ cmds:
+ - go run build/ios/scripts/deps/install_deps.go
+ env:
+ TASK_FORCE_YES: '{{if .YES}}true{{else}}false{{end}}'
+ prompt: This will check and install iOS development dependencies. Continue?
+
+ # Note: Bindings generation may show CGO warnings for iOS C imports.
+ # These warnings are harmless and don't affect the generated bindings,
+ # as the generator only needs to parse Go types, not C implementations.
+ build:
+ summary: Creates a build of the application for iOS
+ deps:
+ - task: generate:ios:overlay
+ - task: generate:ios:xcode
+ - task: common:go:mod:tidy
+ - task: generate:ios:bindings
+ vars:
+ BUILD_FLAGS:
+ ref: .BUILD_FLAGS
+ - task: common:build:frontend
+ vars:
+ BUILD_FLAGS:
+ ref: .BUILD_FLAGS
+ PRODUCTION:
+ ref: .PRODUCTION
+ - task: common:generate:icons
+ cmds:
+ - echo "Building iOS app {{.APP_NAME}}..."
+ - go build -buildmode=c-archive -overlay build/ios/xcode/overlay.json {{.BUILD_FLAGS}} -o {{.OUTPUT}}.a
+ vars:
+ BUILD_FLAGS: '{{if eq .PRODUCTION "true"}}-tags production,ios -trimpath -buildvcs=false -ldflags="-w -s"{{else}}-tags ios,debug -buildvcs=false -gcflags=all="-l"{{end}}'
+ DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}'
+ OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}'
+ SDK_PATH:
+ sh: xcrun --sdk iphonesimulator --show-sdk-path
+ env:
+ GOOS: ios
+ CGO_ENABLED: 1
+ GOARCH: '{{.ARCH | default "arm64"}}'
+ PRODUCTION: '{{.PRODUCTION | default "false"}}'
+ CGO_CFLAGS: '-isysroot {{.SDK_PATH}} -target arm64-apple-ios15.0-simulator -mios-simulator-version-min=15.0'
+ CGO_LDFLAGS: '-isysroot {{.SDK_PATH}} -target arm64-apple-ios15.0-simulator'
+
+ compile:objc:
+ summary: Compile Objective-C iOS wrapper
+ vars:
+ SDK_PATH:
+ sh: xcrun --sdk iphonesimulator --show-sdk-path
+ cmds:
+ - xcrun -sdk iphonesimulator clang -target arm64-apple-ios15.0-simulator -isysroot {{.SDK_PATH}} -framework Foundation -framework UIKit -framework WebKit -o {{.BIN_DIR}}/{{.APP_NAME}} build/ios/main.m
+ - codesign --force --sign - "{{.BIN_DIR}}/{{.APP_NAME}}"
+
+ package:
+ summary: Packages a production build of the application into a `.app` bundle
+ deps:
+ - task: build
+ vars:
+ PRODUCTION: "true"
+ cmds:
+ - task: create:app:bundle
+
+ create:app:bundle:
+ summary: Creates an iOS `.app` bundle
+ cmds:
+ - rm -rf "{{.BIN_DIR}}/{{.APP_NAME}}.app"
+ - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.app"
+ - cp "{{.BIN_DIR}}/{{.APP_NAME}}" "{{.BIN_DIR}}/{{.APP_NAME}}.app/"
+ - cp build/ios/Info.plist "{{.BIN_DIR}}/{{.APP_NAME}}.app/"
+ - |
+ # Compile asset catalog and embed icons in the app bundle
+ APP_BUNDLE="{{.BIN_DIR}}/{{.APP_NAME}}.app"
+ AC_IN="build/ios/xcode/main/Assets.xcassets"
+ if [ -d "$AC_IN" ]; then
+ TMP_AC=$(mktemp -d)
+ xcrun actool \
+ --compile "$TMP_AC" \
+ --app-icon AppIcon \
+ --platform iphonesimulator \
+ --minimum-deployment-target 15.0 \
+ --product-type com.apple.product-type.application \
+ --target-device iphone \
+ --target-device ipad \
+ --output-partial-info-plist "$APP_BUNDLE/assetcatalog_generated_info.plist" \
+ "$AC_IN"
+ if [ -f "$TMP_AC/Assets.car" ]; then
+ cp -f "$TMP_AC/Assets.car" "$APP_BUNDLE/Assets.car"
+ fi
+ rm -rf "$TMP_AC"
+ if [ -f "$APP_BUNDLE/assetcatalog_generated_info.plist" ]; then
+ /usr/libexec/PlistBuddy -c "Merge $APP_BUNDLE/assetcatalog_generated_info.plist" "$APP_BUNDLE/Info.plist" || true
+ fi
+ fi
+ - codesign --force --sign - "{{.BIN_DIR}}/{{.APP_NAME}}.app"
+
+ deploy-simulator:
+ summary: Deploy to iOS Simulator
+ deps: [package]
+ cmds:
+ - xcrun simctl terminate booted {{.BUNDLE_ID}} 2>/dev/null || true
+ - xcrun simctl uninstall booted {{.BUNDLE_ID}} 2>/dev/null || true
+ - xcrun simctl install booted "{{.BIN_DIR}}/{{.APP_NAME}}.app"
+ - xcrun simctl launch booted {{.BUNDLE_ID}}
+
+ compile:ios:
+ summary: Compile the iOS executable from Go archive and main.m
+ deps:
+ - task: build
+ vars:
+ SDK_PATH:
+ sh: xcrun --sdk iphonesimulator --show-sdk-path
+ cmds:
+ - |
+ MAIN_M=build/ios/xcode/main/main.m
+ if [ ! -f "$MAIN_M" ]; then
+ MAIN_M=build/ios/main.m
+ fi
+ xcrun -sdk iphonesimulator clang \
+ -target arm64-apple-ios15.0-simulator \
+ -isysroot {{.SDK_PATH}} \
+ -framework Foundation -framework UIKit -framework WebKit \
+ -framework Security -framework CoreFoundation \
+ -lresolv \
+ -o "{{.BIN_DIR}}/{{.APP_NAME | lower}}" \
+ "$MAIN_M" "{{.BIN_DIR}}/{{.APP_NAME}}.a"
+
+ generate:ios:bindings:
+ internal: true
+ summary: Generates bindings for iOS with proper CGO flags
+ sources:
+ - "**/*.go"
+ - go.mod
+ - go.sum
+ generates:
+ - frontend/bindings/**/*
+ vars:
+ SDK_PATH:
+ sh: xcrun --sdk iphonesimulator --show-sdk-path
+ cmds:
+ - wails3 generate bindings -f '{{.BUILD_FLAGS}}' -clean=true
+ env:
+ GOOS: ios
+ CGO_ENABLED: 1
+ GOARCH: '{{.ARCH | default "arm64"}}'
+ CGO_CFLAGS: '-isysroot {{.SDK_PATH}} -target arm64-apple-ios15.0-simulator -mios-simulator-version-min=15.0'
+ CGO_LDFLAGS: '-isysroot {{.SDK_PATH}} -target arm64-apple-ios15.0-simulator'
+
+ ensure-simulator:
+ internal: true
+ summary: Ensure iOS Simulator is running and booted
+ silent: true
+ cmds:
+ - |
+ if ! xcrun simctl list devices booted | grep -q "Booted"; then
+ echo "Starting iOS Simulator..."
+ # Get first available iPhone device
+ DEVICE_ID=$(xcrun simctl list devices available | grep "iPhone" | head -1 | grep -o "[A-F0-9-]\{36\}" || true)
+ if [ -z "$DEVICE_ID" ]; then
+ echo "No iPhone simulator found. Creating one..."
+ RUNTIME=$(xcrun simctl list runtimes | grep iOS | tail -1 | awk '{print $NF}')
+ DEVICE_ID=$(xcrun simctl create "iPhone 15 Pro" "iPhone 15 Pro" "$RUNTIME")
+ fi
+ # Boot the device
+ echo "Booting device $DEVICE_ID..."
+ xcrun simctl boot "$DEVICE_ID" 2>/dev/null || true
+ # Open Simulator app
+ open -a Simulator
+ # Wait for boot (max 30 seconds)
+ for i in {1..30}; do
+ if xcrun simctl list devices booted | grep -q "Booted"; then
+ echo "Simulator booted successfully"
+ break
+ fi
+ sleep 1
+ done
+ # Final check
+ if ! xcrun simctl list devices booted | grep -q "Booted"; then
+ echo "Failed to boot simulator after 30 seconds"
+ exit 1
+ fi
+ fi
+ preconditions:
+ - sh: command -v xcrun
+ msg: "xcrun not found. Please run 'wails3 task ios:install:deps' to install iOS development dependencies"
+
+ generate:ios:overlay:
+ internal: true
+ summary: Generate Go build overlay and iOS shim
+ sources:
+ - build/config.yml
+ generates:
+ - build/ios/xcode/overlay.json
+ - build/ios/xcode/gen/main_ios.gen.go
+ cmds:
+ - wails3 ios overlay:gen -out build/ios/xcode/overlay.json -config build/config.yml
+
+ generate:ios:xcode:
+ internal: true
+ summary: Generate iOS Xcode project structure and assets
+ sources:
+ - build/config.yml
+ - build/appicon.png
+ generates:
+ - build/ios/xcode/main/main.m
+ - build/ios/xcode/main/Assets.xcassets/**/*
+ - build/ios/xcode/project.pbxproj
+ cmds:
+ - wails3 ios xcode:gen -outdir build/ios/xcode -config build/config.yml
+
+ run:
+ summary: Run the application in iOS Simulator
+ deps:
+ - task: ensure-simulator
+ - task: compile:ios
+ cmds:
+ - rm -rf "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app"
+ - mkdir -p "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app"
+ - cp "{{.BIN_DIR}}/{{.APP_NAME | lower}}" "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/{{.APP_NAME | lower}}"
+ - cp build/ios/Info.dev.plist "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app/Info.plist"
+ - |
+ # Compile asset catalog and embed icons for dev bundle
+ APP_BUNDLE="{{.BIN_DIR}}/{{.APP_NAME}}.dev.app"
+ AC_IN="build/ios/xcode/main/Assets.xcassets"
+ if [ -d "$AC_IN" ]; then
+ TMP_AC=$(mktemp -d)
+ xcrun actool \
+ --compile "$TMP_AC" \
+ --app-icon AppIcon \
+ --platform iphonesimulator \
+ --minimum-deployment-target 15.0 \
+ --product-type com.apple.product-type.application \
+ --target-device iphone \
+ --target-device ipad \
+ --output-partial-info-plist "$APP_BUNDLE/assetcatalog_generated_info.plist" \
+ "$AC_IN"
+ if [ -f "$TMP_AC/Assets.car" ]; then
+ cp -f "$TMP_AC/Assets.car" "$APP_BUNDLE/Assets.car"
+ fi
+ rm -rf "$TMP_AC"
+ if [ -f "$APP_BUNDLE/assetcatalog_generated_info.plist" ]; then
+ /usr/libexec/PlistBuddy -c "Merge $APP_BUNDLE/assetcatalog_generated_info.plist" "$APP_BUNDLE/Info.plist" || true
+ fi
+ fi
+ - codesign --force --sign - "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app"
+ - xcrun simctl terminate booted "com.wails.{{.APP_NAME | lower}}.dev" 2>/dev/null || true
+ - xcrun simctl uninstall booted "com.wails.{{.APP_NAME | lower}}.dev" 2>/dev/null || true
+ - xcrun simctl install booted "{{.BIN_DIR}}/{{.APP_NAME}}.dev.app"
+ - xcrun simctl launch booted "com.wails.{{.APP_NAME | lower}}.dev"
+
+ xcode:
+ summary: Open the generated Xcode project for this app
+ cmds:
+ - task: generate:ios:xcode
+ - open build/ios/xcode/main.xcodeproj
+
+ logs:
+ summary: Stream iOS Simulator logs filtered to this app
+ cmds:
+ - |
+ xcrun simctl spawn booted log stream \
+ --level debug \
+ --style compact \
+ --predicate 'senderImagePath CONTAINS[c] "{{.APP_NAME | lower}}.app/" OR composedMessage CONTAINS[c] "{{.APP_NAME | lower}}" OR eventMessage CONTAINS[c] "{{.APP_NAME | lower}}" OR process == "{{.APP_NAME | lower}}" OR category CONTAINS[c] "{{.APP_NAME | lower}}"'
+
+ logs:dev:
+ summary: Stream logs for the dev bundle (used by `task ios:run`)
+ cmds:
+ - |
+ xcrun simctl spawn booted log stream \
+ --level debug \
+ --style compact \
+ --predicate 'senderImagePath CONTAINS[c] ".dev.app/" OR subsystem == "com.wails.{{.APP_NAME | lower}}.dev" OR process == "{{.APP_NAME | lower}}"'
+
+ logs:wide:
+ summary: Wide log stream to help discover the exact process/bundle identifiers
+ cmds:
+ - |
+ xcrun simctl spawn booted log stream \
+ --level debug \
+ --style compact \
+ --predicate 'senderImagePath CONTAINS[c] ".app/"'
\ No newline at end of file
diff --git a/build/ios/app_options_default.go b/build/ios/app_options_default.go
new file mode 100644
index 0000000..04e4f1b
--- /dev/null
+++ b/build/ios/app_options_default.go
@@ -0,0 +1,10 @@
+//go:build !ios
+
+package main
+
+import "github.com/wailsapp/wails/v3/pkg/application"
+
+// modifyOptionsForIOS is a no-op on non-iOS platforms
+func modifyOptionsForIOS(opts *application.Options) {
+ // No modifications needed for non-iOS platforms
+}
\ No newline at end of file
diff --git a/build/ios/app_options_ios.go b/build/ios/app_options_ios.go
new file mode 100644
index 0000000..8f6ac31
--- /dev/null
+++ b/build/ios/app_options_ios.go
@@ -0,0 +1,11 @@
+//go:build ios
+
+package main
+
+import "github.com/wailsapp/wails/v3/pkg/application"
+
+// modifyOptionsForIOS adjusts the application options for iOS
+func modifyOptionsForIOS(opts *application.Options) {
+ // Disable signal handlers on iOS to prevent crashes
+ opts.DisableDefaultSignalHandler = true
+}
\ No newline at end of file
diff --git a/build/ios/build.sh b/build/ios/build.sh
new file mode 100644
index 0000000..ef87ddb
--- /dev/null
+++ b/build/ios/build.sh
@@ -0,0 +1,72 @@
+#!/bin/bash
+set -e
+
+# Build configuration
+APP_NAME="u-desk.exe"
+BUNDLE_ID="com.example.udesk"
+VERSION="0.1.0"
+BUILD_NUMBER="0.1.0"
+BUILD_DIR="build/ios"
+TARGET="simulator"
+
+echo "Building iOS app: $APP_NAME"
+echo "Bundle ID: $BUNDLE_ID"
+echo "Version: $VERSION ($BUILD_NUMBER)"
+echo "Target: $TARGET"
+
+# Ensure build directory exists
+mkdir -p "$BUILD_DIR"
+
+# Determine SDK and target architecture
+if [ "$TARGET" = "simulator" ]; then
+ SDK="iphonesimulator"
+ ARCH="arm64-apple-ios15.0-simulator"
+elif [ "$TARGET" = "device" ]; then
+ SDK="iphoneos"
+ ARCH="arm64-apple-ios15.0"
+else
+ echo "Unknown target: $TARGET"
+ exit 1
+fi
+
+# Get SDK path
+SDK_PATH=$(xcrun --sdk $SDK --show-sdk-path)
+
+# Compile the application
+echo "Compiling with SDK: $SDK"
+xcrun -sdk $SDK clang \
+ -target $ARCH \
+ -isysroot "$SDK_PATH" \
+ -framework Foundation \
+ -framework UIKit \
+ -framework WebKit \
+ -framework CoreGraphics \
+ -o "$BUILD_DIR/$APP_NAME" \
+ "$BUILD_DIR/main.m"
+
+# Create app bundle
+echo "Creating app bundle..."
+APP_BUNDLE="$BUILD_DIR/$APP_NAME.app"
+rm -rf "$APP_BUNDLE"
+mkdir -p "$APP_BUNDLE"
+
+# Move executable
+mv "$BUILD_DIR/$APP_NAME" "$APP_BUNDLE/"
+
+# Copy Info.plist
+cp "$BUILD_DIR/Info.plist" "$APP_BUNDLE/"
+
+# Sign the app
+echo "Signing app..."
+codesign --force --sign - "$APP_BUNDLE"
+
+echo "Build complete: $APP_BUNDLE"
+
+# Deploy to simulator if requested
+if [ "$TARGET" = "simulator" ]; then
+ echo "Deploying to simulator..."
+ xcrun simctl terminate booted "$BUNDLE_ID" 2>/dev/null || true
+ xcrun simctl install booted "$APP_BUNDLE"
+ xcrun simctl launch booted "$BUNDLE_ID"
+ echo "App launched on simulator"
+fi
\ No newline at end of file
diff --git a/build/ios/entitlements.plist b/build/ios/entitlements.plist
new file mode 100644
index 0000000..cc5d958
--- /dev/null
+++ b/build/ios/entitlements.plist
@@ -0,0 +1,21 @@
+
+
+
+
+
+ get-task-allow
+
+
+
+ com.apple.security.app-sandbox
+
+
+
+ com.apple.security.network.client
+
+
+
+ com.apple.security.files.user-selected.read-only
+
+
+
\ No newline at end of file
diff --git a/build/ios/icon.png b/build/ios/icon.png
new file mode 100644
index 0000000..be7d591
--- /dev/null
+++ b/build/ios/icon.png
@@ -0,0 +1,3 @@
+# iOS Icon Placeholder
+# This file should be replaced with the actual app icon (1024x1024 PNG)
+# The build process will generate all required icon sizes from this base icon
\ No newline at end of file
diff --git a/build/ios/main.m b/build/ios/main.m
new file mode 100644
index 0000000..366767a
--- /dev/null
+++ b/build/ios/main.m
@@ -0,0 +1,23 @@
+//go:build ios
+// Minimal bootstrap: delegate comes from Go archive (WailsAppDelegate)
+#import
+#include
+
+// External Go initialization function from the c-archive (declare before use)
+extern void WailsIOSMain();
+
+int main(int argc, char * argv[]) {
+ @autoreleasepool {
+ // Disable buffering so stdout/stderr from Go log.Printf flush immediately
+ setvbuf(stdout, NULL, _IONBF, 0);
+ setvbuf(stderr, NULL, _IONBF, 0);
+
+ // Start Go runtime on a background queue to avoid blocking main thread/UI
+ dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
+ WailsIOSMain();
+ });
+
+ // Run UIApplicationMain using WailsAppDelegate provided by the Go archive
+ return UIApplicationMain(argc, argv, nil, @"WailsAppDelegate");
+ }
+}
\ No newline at end of file
diff --git a/build/ios/main_ios.go b/build/ios/main_ios.go
new file mode 100644
index 0000000..b75a403
--- /dev/null
+++ b/build/ios/main_ios.go
@@ -0,0 +1,24 @@
+//go:build ios
+
+package main
+
+import (
+ "C"
+)
+
+// For iOS builds, we need to export a function that can be called from Objective-C
+// This wrapper allows us to keep the original main.go unmodified
+
+//export WailsIOSMain
+func WailsIOSMain() {
+ // DO NOT lock the goroutine to the current OS thread on iOS!
+ // This causes signal handling issues:
+ // "signal 16 received on thread with no signal stack"
+ // "fatal error: non-Go code disabled sigaltstack"
+ // iOS apps run in a sandboxed environment where the Go runtime's
+ // signal handling doesn't work the same way as desktop platforms.
+
+ // Call the actual main function from main.go
+ // This ensures all the user's code is executed
+ main()
+}
\ No newline at end of file
diff --git a/build/ios/project.pbxproj b/build/ios/project.pbxproj
new file mode 100644
index 0000000..00f4908
--- /dev/null
+++ b/build/ios/project.pbxproj
@@ -0,0 +1,222 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {};
+ objectVersion = 56;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ C0DEBEEF0000000000000001 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000002 /* main.m */; };
+ C0DEBEEF00000000000000F1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000101 /* UIKit.framework */; };
+ C0DEBEEF00000000000000F2 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000102 /* Foundation.framework */; };
+ C0DEBEEF00000000000000F3 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000103 /* WebKit.framework */; };
+ C0DEBEEF00000000000000F4 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000104 /* Security.framework */; };
+ C0DEBEEF00000000000000F5 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000105 /* CoreFoundation.framework */; };
+ C0DEBEEF00000000000000F6 /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000106 /* libresolv.tbd */; };
+ C0DEBEEF00000000000000F7 /* U-Desk.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C0DEBEEF0000000000000107 /* U-Desk.a */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ C0DEBEEF0000000000000002 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
+ C0DEBEEF0000000000000003 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ C0DEBEEF0000000000000004 /* U-Desk.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "U-Desk.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ C0DEBEEF0000000000000101 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
+ C0DEBEEF0000000000000102 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+ C0DEBEEF0000000000000103 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
+ C0DEBEEF0000000000000104 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
+ C0DEBEEF0000000000000105 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+ C0DEBEEF0000000000000106 /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.text-based-dylib-definition; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; };
+ C0DEBEEF0000000000000107 /* U-Desk.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "U-Desk.a"; path = ../../../bin/U-Desk.a; sourceTree = SOURCE_ROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXGroup section */
+ C0DEBEEF0000000000000010 = {
+ isa = PBXGroup;
+ children = (
+ C0DEBEEF0000000000000020 /* Products */,
+ C0DEBEEF0000000000000045 /* Frameworks */,
+ C0DEBEEF0000000000000030 /* main */,
+ );
+ sourceTree = "";
+ };
+ C0DEBEEF0000000000000020 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ C0DEBEEF0000000000000004 /* U-Desk.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ C0DEBEEF0000000000000030 /* main */ = {
+ isa = PBXGroup;
+ children = (
+ C0DEBEEF0000000000000002 /* main.m */,
+ C0DEBEEF0000000000000003 /* Info.plist */,
+ );
+ path = main;
+ sourceTree = SOURCE_ROOT;
+ };
+ C0DEBEEF0000000000000045 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ C0DEBEEF0000000000000101 /* UIKit.framework */,
+ C0DEBEEF0000000000000102 /* Foundation.framework */,
+ C0DEBEEF0000000000000103 /* WebKit.framework */,
+ C0DEBEEF0000000000000104 /* Security.framework */,
+ C0DEBEEF0000000000000105 /* CoreFoundation.framework */,
+ C0DEBEEF0000000000000106 /* libresolv.tbd */,
+ C0DEBEEF0000000000000107 /* U-Desk.a */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ C0DEBEEF0000000000000040 /* U-Desk */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C0DEBEEF0000000000000070 /* Build configuration list for PBXNativeTarget "U-Desk" */;
+ buildPhases = (
+ C0DEBEEF0000000000000055 /* Prebuild: Wails Go Archive */,
+ C0DEBEEF0000000000000050 /* Sources */,
+ C0DEBEEF0000000000000056 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "U-Desk";
+ productName = "U-Desk";
+ productReference = C0DEBEEF0000000000000004 /* U-Desk.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ C0DEBEEF0000000000000060 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 1500;
+ ORGANIZATIONNAME = "My Company";
+ TargetAttributes = {
+ C0DEBEEF0000000000000040 = {
+ CreatedOnToolsVersion = 15.0;
+ };
+ };
+ };
+ buildConfigurationList = C0DEBEEF0000000000000080 /* Build configuration list for PBXProject "main" */;
+ compatibilityVersion = "Xcode 15.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = C0DEBEEF0000000000000010;
+ productRefGroup = C0DEBEEF0000000000000020 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ C0DEBEEF0000000000000040 /* U-Desk */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ C0DEBEEF0000000000000056 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C0DEBEEF00000000000000F7 /* U-Desk.a in Frameworks */,
+ C0DEBEEF00000000000000F1 /* UIKit.framework in Frameworks */,
+ C0DEBEEF00000000000000F2 /* Foundation.framework in Frameworks */,
+ C0DEBEEF00000000000000F3 /* WebKit.framework in Frameworks */,
+ C0DEBEEF00000000000000F4 /* Security.framework in Frameworks */,
+ C0DEBEEF00000000000000F5 /* CoreFoundation.framework in Frameworks */,
+ C0DEBEEF00000000000000F6 /* libresolv.tbd in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ C0DEBEEF0000000000000055 /* Prebuild: Wails Go Archive */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ );
+ name = "Prebuild: Wails Go Archive";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "set -e\nAPP_ROOT=\"${PROJECT_DIR}/../../..\"\nSDK_PATH=$(xcrun --sdk iphonesimulator --show-sdk-path)\nexport GOOS=ios\nexport GOARCH=arm64\nexport CGO_ENABLED=1\nexport CGO_CFLAGS=\"-isysroot ${SDK_PATH} -target arm64-apple-ios15.0-simulator -mios-simulator-version-min=15.0\"\nexport CGO_LDFLAGS=\"-isysroot ${SDK_PATH} -target arm64-apple-ios15.0-simulator\"\ncd \"${APP_ROOT}\"\n# Ensure overlay exists\nif [ ! -f build/ios/xcode/overlay.json ]; then\n wails3 ios overlay:gen -out build/ios/xcode/overlay.json -config build/config.yml || true\nfi\n# Build Go c-archive if missing or older than sources\nif [ ! -f bin/U-Desk.a ]; then\n echo \"Building Go c-archive...\"\n go build -buildmode=c-archive -overlay build/ios/xcode/overlay.json -o bin/U-Desk.a\nfi\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ C0DEBEEF0000000000000050 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C0DEBEEF0000000000000001 /* main.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ C0DEBEEF0000000000000090 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INFOPLIST_FILE = main/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.example.udesk";
+ PRODUCT_NAME = "U-Desk";
+ CODE_SIGNING_ALLOWED = NO;
+ SDKROOT = iphonesimulator;
+ };
+ name = Debug;
+ };
+ C0DEBEEF00000000000000A0 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ INFOPLIST_FILE = main/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.0;
+ PRODUCT_BUNDLE_IDENTIFIER = "com.example.udesk";
+ PRODUCT_NAME = "U-Desk";
+ CODE_SIGNING_ALLOWED = NO;
+ SDKROOT = iphonesimulator;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ C0DEBEEF0000000000000070 /* Build configuration list for PBXNativeTarget "U-Desk" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C0DEBEEF0000000000000090 /* Debug */,
+ C0DEBEEF00000000000000A0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Debug;
+ };
+ C0DEBEEF0000000000000080 /* Build configuration list for PBXProject "main" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C0DEBEEF0000000000000090 /* Debug */,
+ C0DEBEEF00000000000000A0 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Debug;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = C0DEBEEF0000000000000060 /* Project object */;
+}
diff --git a/build/ios/scripts/deps/install_deps.go b/build/ios/scripts/deps/install_deps.go
new file mode 100644
index 0000000..88ed47a
--- /dev/null
+++ b/build/ios/scripts/deps/install_deps.go
@@ -0,0 +1,319 @@
+// install_deps.go - iOS development dependency checker
+// This script checks for required iOS development tools.
+// It's designed to be portable across different shells by using Go instead of shell scripts.
+//
+// Usage:
+// go run install_deps.go # Interactive mode
+// TASK_FORCE_YES=true go run install_deps.go # Auto-accept prompts
+// CI=true go run install_deps.go # CI mode (auto-accept)
+
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "os/exec"
+ "strings"
+)
+
+type Dependency struct {
+ Name string
+ CheckFunc func() (bool, string) // Returns (success, details)
+ Required bool
+ InstallCmd []string
+ InstallMsg string
+ SuccessMsg string
+ FailureMsg string
+}
+
+func main() {
+ fmt.Println("Checking iOS development dependencies...")
+ fmt.Println("=" + strings.Repeat("=", 50))
+ fmt.Println()
+
+ hasErrors := false
+ dependencies := []Dependency{
+ {
+ Name: "Xcode",
+ CheckFunc: func() (bool, string) {
+ // Check if xcodebuild exists
+ if !checkCommand([]string{"xcodebuild", "-version"}) {
+ return false, ""
+ }
+ // Get version info
+ out, err := exec.Command("xcodebuild", "-version").Output()
+ if err != nil {
+ return false, ""
+ }
+ lines := strings.Split(string(out), "\n")
+ if len(lines) > 0 {
+ return true, strings.TrimSpace(lines[0])
+ }
+ return true, ""
+ },
+ Required: true,
+ InstallMsg: "Please install Xcode from the Mac App Store:\n https://apps.apple.com/app/xcode/id497799835\n Xcode is REQUIRED for iOS development (includes iOS SDKs, simulators, and frameworks)",
+ SuccessMsg: "✅ Xcode found",
+ FailureMsg: "❌ Xcode not found (REQUIRED)",
+ },
+ {
+ Name: "Xcode Developer Path",
+ CheckFunc: func() (bool, string) {
+ // Check if xcode-select points to a valid Xcode path
+ out, err := exec.Command("xcode-select", "-p").Output()
+ if err != nil {
+ return false, "xcode-select not configured"
+ }
+ path := strings.TrimSpace(string(out))
+
+ // Check if path exists and is in Xcode.app
+ if _, err := os.Stat(path); err != nil {
+ return false, "Invalid Xcode path"
+ }
+
+ // Verify it's pointing to Xcode.app (not just Command Line Tools)
+ if !strings.Contains(path, "Xcode.app") {
+ return false, fmt.Sprintf("Points to %s (should be Xcode.app)", path)
+ }
+
+ return true, path
+ },
+ Required: true,
+ InstallCmd: []string{"sudo", "xcode-select", "-s", "/Applications/Xcode.app/Contents/Developer"},
+ InstallMsg: "Xcode developer path needs to be configured",
+ SuccessMsg: "✅ Xcode developer path configured",
+ FailureMsg: "❌ Xcode developer path not configured correctly",
+ },
+ {
+ Name: "iOS SDK",
+ CheckFunc: func() (bool, string) {
+ // Get the iOS Simulator SDK path
+ cmd := exec.Command("xcrun", "--sdk", "iphonesimulator", "--show-sdk-path")
+ output, err := cmd.Output()
+ if err != nil {
+ return false, "Cannot find iOS SDK"
+ }
+ sdkPath := strings.TrimSpace(string(output))
+
+ // Check if the SDK path exists
+ if _, err := os.Stat(sdkPath); err != nil {
+ return false, "iOS SDK path not found"
+ }
+
+ // Check for UIKit framework (essential for iOS development)
+ uikitPath := fmt.Sprintf("%s/System/Library/Frameworks/UIKit.framework", sdkPath)
+ if _, err := os.Stat(uikitPath); err != nil {
+ return false, "UIKit.framework not found"
+ }
+
+ // Get SDK version
+ versionCmd := exec.Command("xcrun", "--sdk", "iphonesimulator", "--show-sdk-version")
+ versionOut, _ := versionCmd.Output()
+ version := strings.TrimSpace(string(versionOut))
+
+ return true, fmt.Sprintf("iOS %s SDK", version)
+ },
+ Required: true,
+ InstallMsg: "iOS SDK comes with Xcode. Please ensure Xcode is properly installed.",
+ SuccessMsg: "✅ iOS SDK found with UIKit framework",
+ FailureMsg: "❌ iOS SDK not found or incomplete",
+ },
+ {
+ Name: "iOS Simulator Runtime",
+ CheckFunc: func() (bool, string) {
+ if !checkCommand([]string{"xcrun", "simctl", "help"}) {
+ return false, ""
+ }
+ // Check if we can list runtimes
+ out, err := exec.Command("xcrun", "simctl", "list", "runtimes").Output()
+ if err != nil {
+ return false, "Cannot access simulator"
+ }
+ // Count iOS runtimes
+ lines := strings.Split(string(out), "\n")
+ count := 0
+ var versions []string
+ for _, line := range lines {
+ if strings.Contains(line, "iOS") && !strings.Contains(line, "unavailable") {
+ count++
+ // Extract version number
+ if parts := strings.Fields(line); len(parts) > 2 {
+ for _, part := range parts {
+ if strings.HasPrefix(part, "(") && strings.HasSuffix(part, ")") {
+ versions = append(versions, strings.Trim(part, "()"))
+ break
+ }
+ }
+ }
+ }
+ }
+ if count > 0 {
+ return true, fmt.Sprintf("%d runtime(s): %s", count, strings.Join(versions, ", "))
+ }
+ return false, "No iOS runtimes installed"
+ },
+ Required: true,
+ InstallMsg: "iOS Simulator runtimes come with Xcode. You may need to download them:\n Xcode → Settings → Platforms → iOS",
+ SuccessMsg: "✅ iOS Simulator runtime available",
+ FailureMsg: "❌ iOS Simulator runtime not available",
+ },
+ }
+
+ // Check each dependency
+ for _, dep := range dependencies {
+ success, details := dep.CheckFunc()
+ if success {
+ msg := dep.SuccessMsg
+ if details != "" {
+ msg = fmt.Sprintf("%s (%s)", dep.SuccessMsg, details)
+ }
+ fmt.Println(msg)
+ } else {
+ fmt.Println(dep.FailureMsg)
+ if details != "" {
+ fmt.Printf(" Details: %s\n", details)
+ }
+ if dep.Required {
+ hasErrors = true
+ if len(dep.InstallCmd) > 0 {
+ fmt.Println()
+ fmt.Println(" " + dep.InstallMsg)
+ fmt.Printf(" Fix command: %s\n", strings.Join(dep.InstallCmd, " "))
+ if promptUser("Do you want to run this command?") {
+ fmt.Println("Running command...")
+ cmd := exec.Command(dep.InstallCmd[0], dep.InstallCmd[1:]...)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ cmd.Stdin = os.Stdin
+ if err := cmd.Run(); err != nil {
+ fmt.Printf("Command failed: %v\n", err)
+ os.Exit(1)
+ }
+ fmt.Println("✅ Command completed. Please run this check again.")
+ } else {
+ fmt.Printf(" Please run manually: %s\n", strings.Join(dep.InstallCmd, " "))
+ }
+ } else {
+ fmt.Println(" " + dep.InstallMsg)
+ }
+ }
+ }
+ }
+
+ // Check for iPhone simulators
+ fmt.Println()
+ fmt.Println("Checking for iPhone simulator devices...")
+ if !checkCommand([]string{"xcrun", "simctl", "list", "devices"}) {
+ fmt.Println("❌ Cannot check for iPhone simulators")
+ hasErrors = true
+ } else {
+ out, err := exec.Command("xcrun", "simctl", "list", "devices").Output()
+ if err != nil {
+ fmt.Println("❌ Failed to list simulator devices")
+ hasErrors = true
+ } else if !strings.Contains(string(out), "iPhone") {
+ fmt.Println("⚠️ No iPhone simulator devices found")
+ fmt.Println()
+
+ // Get the latest iOS runtime
+ runtimeOut, err := exec.Command("xcrun", "simctl", "list", "runtimes").Output()
+ if err != nil {
+ fmt.Println(" Failed to get iOS runtimes:", err)
+ } else {
+ lines := strings.Split(string(runtimeOut), "\n")
+ var latestRuntime string
+ for _, line := range lines {
+ if strings.Contains(line, "iOS") && !strings.Contains(line, "unavailable") {
+ // Extract runtime identifier
+ parts := strings.Fields(line)
+ if len(parts) > 0 {
+ latestRuntime = parts[len(parts)-1]
+ }
+ }
+ }
+
+ if latestRuntime == "" {
+ fmt.Println(" No iOS runtime found. Please install iOS simulators in Xcode:")
+ fmt.Println(" Xcode → Settings → Platforms → iOS")
+ } else {
+ fmt.Println(" Would you like to create an iPhone 15 Pro simulator?")
+ createCmd := []string{"xcrun", "simctl", "create", "iPhone 15 Pro", "iPhone 15 Pro", latestRuntime}
+ fmt.Printf(" Command: %s\n", strings.Join(createCmd, " "))
+ if promptUser("Create simulator?") {
+ cmd := exec.Command(createCmd[0], createCmd[1:]...)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ if err := cmd.Run(); err != nil {
+ fmt.Printf(" Failed to create simulator: %v\n", err)
+ } else {
+ fmt.Println(" ✅ iPhone 15 Pro simulator created")
+ }
+ } else {
+ fmt.Println(" Skipping simulator creation")
+ fmt.Printf(" Create manually: %s\n", strings.Join(createCmd, " "))
+ }
+ }
+ }
+ } else {
+ // Count iPhone devices
+ count := 0
+ lines := strings.Split(string(out), "\n")
+ for _, line := range lines {
+ if strings.Contains(line, "iPhone") && !strings.Contains(line, "unavailable") {
+ count++
+ }
+ }
+ fmt.Printf("✅ %d iPhone simulator device(s) available\n", count)
+ }
+ }
+
+ // Final summary
+ fmt.Println()
+ fmt.Println("=" + strings.Repeat("=", 50))
+ if hasErrors {
+ fmt.Println("❌ Some required dependencies are missing or misconfigured.")
+ fmt.Println()
+ fmt.Println("Quick setup guide:")
+ fmt.Println("1. Install Xcode from Mac App Store (if not installed)")
+ fmt.Println("2. Open Xcode once and agree to the license")
+ fmt.Println("3. Install additional components when prompted")
+ fmt.Println("4. Run: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer")
+ fmt.Println("5. Download iOS simulators: Xcode → Settings → Platforms → iOS")
+ fmt.Println("6. Run this check again")
+ os.Exit(1)
+ } else {
+ fmt.Println("✅ All required dependencies are installed!")
+ fmt.Println(" You're ready for iOS development with Wails!")
+ }
+}
+
+func checkCommand(args []string) bool {
+ if len(args) == 0 {
+ return false
+ }
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Stdout = nil
+ cmd.Stderr = nil
+ err := cmd.Run()
+ return err == nil
+}
+
+func promptUser(question string) bool {
+ // Check if we're in a non-interactive environment
+ if os.Getenv("CI") != "" || os.Getenv("TASK_FORCE_YES") == "true" {
+ fmt.Printf("%s [y/N]: y (auto-accepted)\n", question)
+ return true
+ }
+
+ reader := bufio.NewReader(os.Stdin)
+ fmt.Printf("%s [y/N]: ", question)
+
+ response, err := reader.ReadString('\n')
+ if err != nil {
+ return false
+ }
+
+ response = strings.ToLower(strings.TrimSpace(response))
+ return response == "y" || response == "yes"
+}
\ No newline at end of file
diff --git a/build/linux/Taskfile.yml b/build/linux/Taskfile.yml
new file mode 100644
index 0000000..a5e583d
--- /dev/null
+++ b/build/linux/Taskfile.yml
@@ -0,0 +1,226 @@
+version: '3'
+
+includes:
+ common: ../Taskfile.yml
+
+vars:
+ # Signing configuration - edit these values for your project
+ # PGP_KEY: "path/to/signing-key.asc"
+ # SIGN_ROLE: "builder" # Options: origin, maint, archive, builder
+ #
+ # Password is stored securely in system keychain. Run: wails3 setup signing
+
+ # Docker image for cross-compilation (used when building on non-Linux or no CC available)
+ CROSS_IMAGE: wails-cross
+
+tasks:
+ build:
+ summary: Builds the application for Linux
+ cmds:
+ # Linux requires CGO - use Docker when:
+ # 1. Cross-compiling from non-Linux, OR
+ # 2. No C compiler is available, OR
+ # 3. Target architecture differs from host architecture (cross-arch compilation)
+ - task: '{{if and (eq OS "linux") (eq .HAS_CC "true") (eq .TARGET_ARCH ARCH)}}build:native{{else}}build:docker{{end}}'
+ vars:
+ ARCH: '{{.ARCH}}'
+ DEV: '{{.DEV}}'
+ OUTPUT: '{{.OUTPUT}}'
+ EXTRA_TAGS: '{{.EXTRA_TAGS}}'
+ vars:
+ DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}'
+ OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}'
+ # Determine target architecture (defaults to host ARCH if not specified)
+ TARGET_ARCH: '{{.ARCH | default ARCH}}'
+ # Check if a C compiler is available (gcc or clang)
+ HAS_CC:
+ sh: '(command -v gcc >/dev/null 2>&1 || command -v clang >/dev/null 2>&1) && echo "true" || echo "false"'
+
+ build:native:
+ summary: Builds the application natively on Linux
+ internal: true
+ deps:
+ - task: common:go:mod:tidy
+ - task: common:build:frontend
+ vars:
+ BUILD_FLAGS:
+ ref: .BUILD_FLAGS
+ DEV:
+ ref: .DEV
+ - task: common:generate:icons
+ - task: generate:dotdesktop
+ cmds:
+ - go build {{.BUILD_FLAGS}} -o {{.OUTPUT}}
+ vars:
+ BUILD_FLAGS: '{{if eq .DEV "true"}}{{if .EXTRA_TAGS}}-tags {{.EXTRA_TAGS}} {{end}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production{{if .EXTRA_TAGS}},{{.EXTRA_TAGS}}{{end}} -trimpath -buildvcs=false -ldflags="-w -s"{{end}}'
+ DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}'
+ OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}'
+ env:
+ GOOS: linux
+ CGO_ENABLED: 1
+ GOARCH: '{{.ARCH | default ARCH}}'
+
+ build:docker:
+ summary: Builds for Linux using Docker (for non-Linux hosts or when no C compiler available)
+ internal: true
+ deps:
+ - task: common:build:frontend
+ - task: common:generate:icons
+ - task: generate:dotdesktop
+ preconditions:
+ - sh: docker info > /dev/null 2>&1
+ msg: "Docker is required for cross-compilation to Linux. Please install Docker."
+ - sh: docker image inspect {{.CROSS_IMAGE}} > /dev/null 2>&1
+ msg: |
+ Docker image '{{.CROSS_IMAGE}}' not found.
+ Build it first: wails3 task setup:docker
+ cmds:
+ - docker run --rm -v "{{.ROOT_DIR}}:/app" {{.GO_CACHE_MOUNT}} {{.REPLACE_MOUNTS}} -e APP_NAME="{{.APP_NAME}}" {{if .EXTRA_TAGS}}-e EXTRA_TAGS="{{.EXTRA_TAGS}}"{{end}} "{{.CROSS_IMAGE}}" linux {{.DOCKER_ARCH}}
+ - docker run --rm -v "{{.ROOT_DIR}}:/app" alpine chown -R $(id -u):$(id -g) /app/bin
+ - mkdir -p {{.BIN_DIR}}
+ - mv "bin/{{.APP_NAME}}-linux-{{.DOCKER_ARCH}}" "{{.OUTPUT}}"
+ vars:
+ DOCKER_ARCH: '{{.ARCH | default "amd64"}}'
+ DEFAULT_OUTPUT: '{{.BIN_DIR}}/{{.APP_NAME}}'
+ OUTPUT: '{{ .OUTPUT | default .DEFAULT_OUTPUT }}'
+ # Mount Go module cache for faster builds
+ GO_CACHE_MOUNT:
+ sh: 'echo "-v ${GOPATH:-$HOME/go}/pkg/mod:/go/pkg/mod"'
+ # Extract replace directives from go.mod and create -v mounts for each
+ REPLACE_MOUNTS:
+ sh: |
+ grep -E '^replace .* => ' go.mod 2>/dev/null | while read -r line; do
+ path=$(echo "$line" | sed -E 's/^replace .* => //' | tr -d '\r')
+ # Convert relative paths to absolute
+ if [ "${path#/}" = "$path" ]; then
+ path="$(cd "$(dirname "$path")" 2>/dev/null && pwd)/$(basename "$path")"
+ fi
+ # Only mount if directory exists
+ if [ -d "$path" ]; then
+ echo "-v $path:$path:ro"
+ fi
+ done | tr '\n' ' '
+
+ package:
+ summary: Packages the application for Linux
+ deps:
+ - task: build
+ cmds:
+ - task: create:appimage
+ - task: create:deb
+ - task: create:rpm
+ - task: create:aur
+
+ create:appimage:
+ summary: Creates an AppImage
+ dir: build/linux/appimage
+ deps:
+ - task: build
+ - task: generate:dotdesktop
+ cmds:
+ - cp "{{.APP_BINARY}}" "{{.APP_NAME}}"
+ - cp ../../appicon.png "{{.APP_NAME}}.png"
+ - wails3 generate appimage -binary "{{.APP_NAME}}" -icon {{.ICON}} -desktopfile {{.DESKTOP_FILE}} -outputdir {{.OUTPUT_DIR}} -builddir {{.ROOT_DIR}}/build/linux/appimage/build
+ vars:
+ APP_NAME: '{{.APP_NAME}}'
+ APP_BINARY: '../../../bin/{{.APP_NAME}}'
+ ICON: '{{.APP_NAME}}.png'
+ DESKTOP_FILE: '../{{.APP_NAME}}.desktop'
+ OUTPUT_DIR: '../../../bin'
+
+ create:deb:
+ summary: Creates a deb package
+ deps:
+ - task: build
+ cmds:
+ - task: generate:dotdesktop
+ - task: generate:deb
+
+ create:rpm:
+ summary: Creates a rpm package
+ deps:
+ - task: build
+ cmds:
+ - task: generate:dotdesktop
+ - task: generate:rpm
+
+ create:aur:
+ summary: Creates a arch linux packager package
+ deps:
+ - task: build
+ cmds:
+ - task: generate:dotdesktop
+ - task: generate:aur
+
+ generate:deb:
+ summary: Creates a deb package
+ cmds:
+ - wails3 tool package -name "{{.APP_NAME}}" -format deb -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin
+
+ generate:rpm:
+ summary: Creates a rpm package
+ cmds:
+ - wails3 tool package -name "{{.APP_NAME}}" -format rpm -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin
+
+ generate:aur:
+ summary: Creates a arch linux packager package
+ cmds:
+ - wails3 tool package -name "{{.APP_NAME}}" -format archlinux -config ./build/linux/nfpm/nfpm.yaml -out {{.ROOT_DIR}}/bin
+
+ generate:dotdesktop:
+ summary: Generates a `.desktop` file
+ dir: build
+ cmds:
+ - mkdir -p {{.ROOT_DIR}}/build/linux/appimage
+ - wails3 generate .desktop -name "{{.APP_NAME}}" -exec "{{.EXEC}}" -icon "{{.ICON}}" -outputfile "{{.ROOT_DIR}}/build/linux/{{.APP_NAME}}.desktop" -categories "{{.CATEGORIES}}"
+ vars:
+ APP_NAME: '{{.APP_NAME}}'
+ EXEC: '{{.APP_NAME}}'
+ ICON: '{{.APP_NAME}}'
+ CATEGORIES: 'Development;'
+ OUTPUTFILE: '{{.ROOT_DIR}}/build/linux/{{.APP_NAME}}.desktop'
+
+ run:
+ cmds:
+ - '{{.BIN_DIR}}/{{.APP_NAME}}'
+
+ sign:deb:
+ summary: Signs the DEB package
+ desc: |
+ Signs the .deb package with a PGP key.
+ Configure PGP_KEY in the vars section at the top of this file.
+ Password is retrieved from system keychain (run: wails3 setup signing)
+ deps:
+ - task: create:deb
+ cmds:
+ - wails3 tool sign --input "{{.BIN_DIR}}/{{.APP_NAME}}*.deb" --pgp-key {{.PGP_KEY}} {{if .SIGN_ROLE}}--role {{.SIGN_ROLE}}{{end}}
+ preconditions:
+ - sh: '[ -n "{{.PGP_KEY}}" ]'
+ msg: "PGP_KEY is required. Set it in the vars section at the top of build/linux/Taskfile.yml"
+
+ sign:rpm:
+ summary: Signs the RPM package
+ desc: |
+ Signs the .rpm package with a PGP key.
+ Configure PGP_KEY in the vars section at the top of this file.
+ Password is retrieved from system keychain (run: wails3 setup signing)
+ deps:
+ - task: create:rpm
+ cmds:
+ - wails3 tool sign --input "{{.BIN_DIR}}/{{.APP_NAME}}*.rpm" --pgp-key {{.PGP_KEY}}
+ preconditions:
+ - sh: '[ -n "{{.PGP_KEY}}" ]'
+ msg: "PGP_KEY is required. Set it in the vars section at the top of build/linux/Taskfile.yml"
+
+ sign:packages:
+ summary: Signs all Linux packages (DEB and RPM)
+ desc: |
+ Signs both .deb and .rpm packages with a PGP key.
+ Configure PGP_KEY in the vars section at the top of this file.
+ Password is retrieved from system keychain (run: wails3 setup signing)
+ cmds:
+ - task: sign:deb
+ - task: sign:rpm
+ preconditions:
+ - sh: '[ -n "{{.PGP_KEY}}" ]'
+ msg: "PGP_KEY is required. Set it in the vars section at the top of build/linux/Taskfile.yml"
diff --git a/build/linux/appimage/build.sh b/build/linux/appimage/build.sh
new file mode 100644
index 0000000..85901c3
--- /dev/null
+++ b/build/linux/appimage/build.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+# Copyright (c) 2018-Present Lea Anthony
+# SPDX-License-Identifier: MIT
+
+# Fail script on any error
+set -euxo pipefail
+
+# Define variables
+APP_DIR="${APP_NAME}.AppDir"
+
+# Create AppDir structure
+mkdir -p "${APP_DIR}/usr/bin"
+cp -r "${APP_BINARY}" "${APP_DIR}/usr/bin/"
+cp "${ICON_PATH}" "${APP_DIR}/"
+cp "${DESKTOP_FILE}" "${APP_DIR}/"
+
+if [[ $(uname -m) == *x86_64* ]]; then
+ # Download linuxdeploy and make it executable
+ wget -q -4 -N https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
+ chmod +x linuxdeploy-x86_64.AppImage
+
+ # Run linuxdeploy to bundle the application
+ ./linuxdeploy-x86_64.AppImage --appdir "${APP_DIR}" --output appimage
+else
+ # Download linuxdeploy and make it executable (arm64)
+ wget -q -4 -N https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-aarch64.AppImage
+ chmod +x linuxdeploy-aarch64.AppImage
+
+ # Run linuxdeploy to bundle the application (arm64)
+ ./linuxdeploy-aarch64.AppImage --appdir "${APP_DIR}" --output appimage
+fi
+
+# Rename the generated AppImage
+mv "${APP_NAME}*.AppImage" "${APP_NAME}.AppImage"
+
diff --git a/build/linux/desktop b/build/linux/desktop
new file mode 100644
index 0000000..ae0e997
--- /dev/null
+++ b/build/linux/desktop
@@ -0,0 +1,13 @@
+[Desktop Entry]
+Version=1.0
+Name=U-Desk
+Comment=A u-desk application
+# The Exec line includes %u to pass the URL to the application
+Exec=/usr/local/bin/u-desk.exe %u
+Terminal=false
+Type=Application
+Icon=u-desk.exe
+Categories=Utility;
+StartupWMClass=u-desk.exe
+
+
diff --git a/build/linux/nfpm/nfpm.yaml b/build/linux/nfpm/nfpm.yaml
new file mode 100644
index 0000000..28cb647
--- /dev/null
+++ b/build/linux/nfpm/nfpm.yaml
@@ -0,0 +1,67 @@
+# Feel free to remove those if you don't want/need to use them.
+# Make sure to check the documentation at https://nfpm.goreleaser.com
+#
+# The lines below are called `modelines`. See `:help modeline`
+
+name: "u-desk.exe"
+arch: ${GOARCH}
+platform: "linux"
+version: "0.1.0"
+section: "default"
+priority: "extra"
+maintainer: ${GIT_COMMITTER_NAME} <${GIT_COMMITTER_EMAIL}>
+description: "A u-desk application"
+vendor: "My Company"
+homepage: "https://wails.io"
+license: "MIT"
+release: "1"
+
+contents:
+ - src: "./bin/u-desk.exe"
+ dst: "/usr/local/bin/u-desk.exe"
+ - src: "./build/appicon.png"
+ dst: "/usr/share/icons/hicolor/128x128/apps/u-desk.exe.png"
+ - src: "./build/linux/u-desk.exe.desktop"
+ dst: "/usr/share/applications/u-desk.exe.desktop"
+
+# Default dependencies for Debian 12/Ubuntu 22.04+ with WebKit 4.1
+depends:
+ - libgtk-3-0
+ - libwebkit2gtk-4.1-0
+
+# Distribution-specific overrides for different package formats and WebKit versions
+overrides:
+ # RPM packages for RHEL/CentOS/AlmaLinux/Rocky Linux (WebKit 4.0)
+ rpm:
+ depends:
+ - gtk3
+ - webkit2gtk4.1
+
+ # Arch Linux packages (WebKit 4.1)
+ archlinux:
+ depends:
+ - gtk3
+ - webkit2gtk-4.1
+
+# scripts section to ensure desktop database is updated after install
+scripts:
+ postinstall: "./build/linux/nfpm/scripts/postinstall.sh"
+ # You can also add preremove, postremove if needed
+ # preremove: "./build/linux/nfpm/scripts/preremove.sh"
+ # postremove: "./build/linux/nfpm/scripts/postremove.sh"
+
+# replaces:
+# - foobar
+# provides:
+# - bar
+# depends:
+# - gtk3
+# - libwebkit2gtk
+# recommends:
+# - whatever
+# suggests:
+# - something-else
+# conflicts:
+# - not-foo
+# - not-bar
+# changelog: "changelog.yaml"
diff --git a/build/linux/nfpm/scripts/postinstall.sh b/build/linux/nfpm/scripts/postinstall.sh
new file mode 100644
index 0000000..4bbb815
--- /dev/null
+++ b/build/linux/nfpm/scripts/postinstall.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+# Update desktop database for .desktop file changes
+# This makes the application appear in application menus and registers its capabilities.
+if command -v update-desktop-database >/dev/null 2>&1; then
+ echo "Updating desktop database..."
+ update-desktop-database -q /usr/share/applications
+else
+ echo "Warning: update-desktop-database command not found. Desktop file may not be immediately recognized." >&2
+fi
+
+# Update MIME database for custom URL schemes (x-scheme-handler)
+# This ensures the system knows how to handle your custom protocols.
+if command -v update-mime-database >/dev/null 2>&1; then
+ echo "Updating MIME database..."
+ update-mime-database -n /usr/share/mime
+else
+ echo "Warning: update-mime-database command not found. Custom URL schemes may not be immediately recognized." >&2
+fi
+
+exit 0
diff --git a/build/linux/nfpm/scripts/postremove.sh b/build/linux/nfpm/scripts/postremove.sh
new file mode 100644
index 0000000..a9bf588
--- /dev/null
+++ b/build/linux/nfpm/scripts/postremove.sh
@@ -0,0 +1 @@
+#!/bin/bash
diff --git a/build/linux/nfpm/scripts/preinstall.sh b/build/linux/nfpm/scripts/preinstall.sh
new file mode 100644
index 0000000..a9bf588
--- /dev/null
+++ b/build/linux/nfpm/scripts/preinstall.sh
@@ -0,0 +1 @@
+#!/bin/bash
diff --git a/build/linux/nfpm/scripts/preremove.sh b/build/linux/nfpm/scripts/preremove.sh
new file mode 100644
index 0000000..a9bf588
--- /dev/null
+++ b/build/linux/nfpm/scripts/preremove.sh
@@ -0,0 +1 @@
+#!/bin/bash
diff --git a/build/windows/Taskfile.yml b/build/windows/Taskfile.yml
new file mode 100644
index 0000000..99c603a
--- /dev/null
+++ b/build/windows/Taskfile.yml
@@ -0,0 +1,184 @@
+version: '3'
+
+includes:
+ common: ../Taskfile.yml
+
+vars:
+ # Signing configuration - edit these values for your project
+ # SIGN_CERTIFICATE: "path/to/certificate.pfx"
+ # SIGN_THUMBPRINT: "certificate-thumbprint" # Alternative to SIGN_CERTIFICATE
+ # TIMESTAMP_SERVER: "http://timestamp.digicert.com"
+ #
+ # Password is stored securely in system keychain. Run: wails3 setup signing
+
+ # Docker image for cross-compilation with CGO (used when CGO_ENABLED=1 on non-Windows)
+ CROSS_IMAGE: wails-cross
+
+tasks:
+ build:
+ summary: Builds the application for Windows
+ cmds:
+ # Auto-detect CGO: if CGO_ENABLED=1, use Docker; otherwise use native Go cross-compile
+ - task: '{{if and (ne OS "windows") (eq .CGO_ENABLED "1")}}build:docker{{else}}build:native{{end}}'
+ vars:
+ ARCH: '{{.ARCH}}'
+ DEV: '{{.DEV}}'
+ EXTRA_TAGS: '{{.EXTRA_TAGS}}'
+ vars:
+ # Default to CGO_ENABLED=0 if not explicitly set
+ CGO_ENABLED: '{{.CGO_ENABLED | default "0"}}'
+
+ build:native:
+ summary: Builds the application using native Go cross-compilation
+ internal: true
+ deps:
+ - task: common:go:mod:tidy
+ - task: common:build:frontend
+ vars:
+ BUILD_FLAGS:
+ ref: .BUILD_FLAGS
+ DEV:
+ ref: .DEV
+ - task: common:generate:icons
+ cmds:
+ - task: generate:syso
+ - go build {{.BUILD_FLAGS}} -o "{{.BIN_DIR}}/{{.APP_NAME}}.exe"
+ - cmd: powershell Remove-item *.syso
+ platforms: [windows]
+ - cmd: rm -f *.syso
+ platforms: [linux, darwin]
+ vars:
+ BUILD_FLAGS: '{{if eq .DEV "true"}}{{if .EXTRA_TAGS}}-tags {{.EXTRA_TAGS}} {{end}}-buildvcs=false -gcflags=all="-l"{{else}}-tags production,devtools -trimpath -buildvcs=false -ldflags="-w -s -H windowsgui"{{end}}'
+ env:
+ GOOS: windows
+ CGO_ENABLED: '{{.CGO_ENABLED | default "0"}}'
+ GOARCH: '{{.ARCH | default ARCH}}'
+
+ build:docker:
+ summary: Cross-compiles for Windows using Docker with Zig (for CGO builds on non-Windows)
+ internal: true
+ deps:
+ - task: common:build:frontend
+ - task: common:generate:icons
+ preconditions:
+ - sh: docker info > /dev/null 2>&1
+ msg: "Docker is required for CGO cross-compilation. Please install Docker."
+ - sh: docker image inspect {{.CROSS_IMAGE}} > /dev/null 2>&1
+ msg: |
+ Docker image '{{.CROSS_IMAGE}}' not found.
+ Build it first: wails3 task setup:docker
+ cmds:
+ - task: generate:syso
+ - docker run --rm -v "{{.ROOT_DIR}}:/app" {{.GO_CACHE_MOUNT}} {{.REPLACE_MOUNTS}} -e APP_NAME="{{.APP_NAME}}" {{if .EXTRA_TAGS}}-e EXTRA_TAGS="{{.EXTRA_TAGS}}"{{end}} {{.CROSS_IMAGE}} windows {{.DOCKER_ARCH}}
+ - docker run --rm -v "{{.ROOT_DIR}}:/app" alpine chown -R $(id -u):$(id -g) /app/bin
+ - rm -f *.syso
+ vars:
+ DOCKER_ARCH: '{{.ARCH | default "amd64"}}'
+ # Mount Go module cache for faster builds
+ GO_CACHE_MOUNT:
+ sh: 'echo "-v ${GOPATH:-$HOME/go}/pkg/mod:/go/pkg/mod"'
+ # Extract replace directives from go.mod and create -v mounts for each
+ REPLACE_MOUNTS:
+ sh: |
+ grep -E '^replace .* => ' go.mod 2>/dev/null | while read -r line; do
+ path=$(echo "$line" | sed -E 's/^replace .* => //' | tr -d '\r')
+ # Convert relative paths to absolute
+ if [ "${path#/}" = "$path" ]; then
+ path="$(cd "$(dirname "$path")" 2>/dev/null && pwd)/$(basename "$path")"
+ fi
+ # Only mount if directory exists
+ if [ -d "$path" ]; then
+ echo "-v $path:$path:ro"
+ fi
+ done | tr '\n' ' '
+
+ package:
+ summary: Packages the application
+ cmds:
+ - task: '{{if eq (.FORMAT | default "nsis") "msix"}}create:msix:package{{else}}create:nsis:installer{{end}}'
+ vars:
+ FORMAT: '{{.FORMAT | default "nsis"}}'
+
+ generate:syso:
+ summary: Generates Windows `.syso` file
+ dir: build
+ cmds:
+ - wails3 generate syso -arch {{.ARCH}} -icon windows/icon.ico -manifest windows/wails.exe.manifest -info windows/info.json -out ../wails_windows_{{.ARCH}}.syso
+ vars:
+ ARCH: '{{.ARCH | default ARCH}}'
+
+ create:nsis:installer:
+ summary: Creates an NSIS installer
+ dir: build/windows/nsis
+ deps:
+ - task: build
+ cmds:
+ # Create the Microsoft WebView2 bootstrapper if it doesn't exist
+ - wails3 generate webview2bootstrapper -dir "{{.ROOT_DIR}}/build/windows/nsis"
+ - |
+ {{if eq OS "windows"}}
+ makensis -DARG_WAILS_{{.ARG_FLAG}}_BINARY="{{.ROOT_DIR}}\{{.BIN_DIR}}\{{.APP_NAME}}.exe" project.nsi
+ {{else}}
+ makensis -DARG_WAILS_{{.ARG_FLAG}}_BINARY="{{.ROOT_DIR}}/{{.BIN_DIR}}/{{.APP_NAME}}.exe" project.nsi
+ {{end}}
+ vars:
+ ARCH: '{{.ARCH | default ARCH}}'
+ ARG_FLAG: '{{if eq .ARCH "amd64"}}AMD64{{else}}ARM64{{end}}'
+
+ create:msix:package:
+ summary: Creates an MSIX package
+ deps:
+ - task: build
+ cmds:
+ - |-
+ wails3 tool msix \
+ --config "{{.ROOT_DIR}}/wails.json" \
+ --name "{{.APP_NAME}}" \
+ --executable "{{.ROOT_DIR}}/{{.BIN_DIR}}/{{.APP_NAME}}.exe" \
+ --arch "{{.ARCH}}" \
+ --out "{{.ROOT_DIR}}/{{.BIN_DIR}}/{{.APP_NAME}}-{{.ARCH}}.msix" \
+ {{if .CERT_PATH}}--cert "{{.CERT_PATH}}"{{end}} \
+ {{if .PUBLISHER}}--publisher "{{.PUBLISHER}}"{{end}} \
+ {{if .USE_MSIX_TOOL}}--use-msix-tool{{else}}--use-makeappx{{end}}
+ vars:
+ ARCH: '{{.ARCH | default ARCH}}'
+ CERT_PATH: '{{.CERT_PATH | default ""}}'
+ PUBLISHER: '{{.PUBLISHER | default ""}}'
+ USE_MSIX_TOOL: '{{.USE_MSIX_TOOL | default "false"}}'
+
+ install:msix:tools:
+ summary: Installs tools required for MSIX packaging
+ cmds:
+ - wails3 tool msix-install-tools
+
+ run:
+ cmds:
+ - '{{.BIN_DIR}}/{{.APP_NAME}}.exe'
+
+ sign:
+ summary: Signs the Windows executable
+ desc: |
+ Signs the .exe with an Authenticode certificate.
+ Configure SIGN_CERTIFICATE or SIGN_THUMBPRINT in the vars section at the top of this file.
+ Password is retrieved from system keychain (run: wails3 setup signing)
+ deps:
+ - task: build
+ cmds:
+ - wails3 tool sign --input "{{.BIN_DIR}}/{{.APP_NAME}}.exe" {{if .SIGN_CERTIFICATE}}--certificate {{.SIGN_CERTIFICATE}}{{end}} {{if .SIGN_THUMBPRINT}}--thumbprint {{.SIGN_THUMBPRINT}}{{end}} {{if .TIMESTAMP_SERVER}}--timestamp {{.TIMESTAMP_SERVER}}{{end}}
+ preconditions:
+ - sh: '[ -n "{{.SIGN_CERTIFICATE}}" ] || [ -n "{{.SIGN_THUMBPRINT}}" ]'
+ msg: "Either SIGN_CERTIFICATE or SIGN_THUMBPRINT is required. Set it in the vars section at the top of build/windows/Taskfile.yml"
+
+ sign:installer:
+ summary: Signs the NSIS installer
+ desc: |
+ Creates and signs the NSIS installer.
+ Configure SIGN_CERTIFICATE or SIGN_THUMBPRINT in the vars section at the top of this file.
+ Password is retrieved from system keychain (run: wails3 setup signing)
+ deps:
+ - task: create:nsis:installer
+ cmds:
+ - wails3 tool sign --input "build/windows/nsis/{{.APP_NAME}}-installer.exe" {{if .SIGN_CERTIFICATE}}--certificate {{.SIGN_CERTIFICATE}}{{end}} {{if .SIGN_THUMBPRINT}}--thumbprint {{.SIGN_THUMBPRINT}}{{end}} {{if .TIMESTAMP_SERVER}}--timestamp {{.TIMESTAMP_SERVER}}{{end}}
+ preconditions:
+ - sh: '[ -n "{{.SIGN_CERTIFICATE}}" ] || [ -n "{{.SIGN_THUMBPRINT}}" ]'
+ msg: "Either SIGN_CERTIFICATE or SIGN_THUMBPRINT is required. Set it in the vars section at the top of build/windows/Taskfile.yml"
diff --git a/build/windows/icon.ico b/build/windows/icon.ico
index 28e7c6e..d0085c5 100644
Binary files a/build/windows/icon.ico and b/build/windows/icon.ico differ
diff --git a/build/windows/info.json b/build/windows/info.json
index 9727946..09b3af3 100644
--- a/build/windows/info.json
+++ b/build/windows/info.json
@@ -1,15 +1,15 @@
{
"fixed": {
- "file_version": "{{.Info.ProductVersion}}"
+ "file_version": "0.1.0"
},
"info": {
"0000": {
- "ProductVersion": "{{.Info.ProductVersion}}",
- "CompanyName": "{{.Info.CompanyName}}",
- "FileDescription": "{{.Info.ProductName}}",
- "LegalCopyright": "{{.Info.Copyright}}",
- "ProductName": "{{.Info.ProductName}}",
- "Comments": "{{.Info.Comments}}"
+ "ProductVersion": "0.1.0",
+ "CompanyName": "My Company",
+ "FileDescription": "A u-desk application",
+ "LegalCopyright": "© 2026, My Company",
+ "ProductName": "U-Desk",
+ "Comments": "This is a comment"
}
}
}
\ No newline at end of file
diff --git a/build/windows/msix/app_manifest.xml b/build/windows/msix/app_manifest.xml
new file mode 100644
index 0000000..693eb97
--- /dev/null
+++ b/build/windows/msix/app_manifest.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+ U-Desk
+ My Company
+ A u-desk application
+ Assets\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/windows/msix/template.xml b/build/windows/msix/template.xml
new file mode 100644
index 0000000..4b997a2
--- /dev/null
+++ b/build/windows/msix/template.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ U-Desk
+ My Company
+ A u-desk application
+ Assets\AppIcon.png
+
+
+
+
+
+
+
diff --git a/build/windows/nsis/project.nsi b/build/windows/nsis/project.nsi
new file mode 100644
index 0000000..9d8e453
--- /dev/null
+++ b/build/windows/nsis/project.nsi
@@ -0,0 +1,114 @@
+Unicode true
+
+####
+## Please note: Template replacements don't work in this file. They are provided with default defines like
+## mentioned underneath.
+## If the keyword is not defined, "wails_tools.nsh" will populate them.
+## If they are defined here, "wails_tools.nsh" will not touch them. This allows you to use this project.nsi manually
+## from outside of Wails for debugging and development of the installer.
+##
+## For development first make a wails nsis build to populate the "wails_tools.nsh":
+## > wails build --target windows/amd64 --nsis
+## Then you can call makensis on this file with specifying the path to your binary:
+## For a AMD64 only installer:
+## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app.exe
+## For a ARM64 only installer:
+## > makensis -DARG_WAILS_ARM64_BINARY=..\..\bin\app.exe
+## For a installer with both architectures:
+## > makensis -DARG_WAILS_AMD64_BINARY=..\..\bin\app-amd64.exe -DARG_WAILS_ARM64_BINARY=..\..\bin\app-arm64.exe
+####
+## The following information is taken from the wails_tools.nsh file, but they can be overwritten here.
+####
+## !define INFO_PROJECTNAME "my-project" # Default "u-desk"
+## !define INFO_COMPANYNAME "My Company" # Default "My Company"
+## !define INFO_PRODUCTNAME "My Product Name" # Default "U-Desk"
+## !define INFO_PRODUCTVERSION "1.0.0" # Default "0.1.0"
+## !define INFO_COPYRIGHT "(c) Now, My Company" # Default "© 2026, My Company"
+###
+## !define PRODUCT_EXECUTABLE "Application.exe" # Default "${INFO_PROJECTNAME}.exe"
+## !define UNINST_KEY_NAME "UninstKeyInRegistry" # Default "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}"
+####
+## !define REQUEST_EXECUTION_LEVEL "admin" # Default "admin" see also https://nsis.sourceforge.io/Docs/Chapter4.html
+####
+## Include the wails tools
+####
+!include "wails_tools.nsh"
+
+# The version information for this two must consist of 4 parts
+VIProductVersion "${INFO_PRODUCTVERSION}.0"
+VIFileVersion "${INFO_PRODUCTVERSION}.0"
+
+VIAddVersionKey "CompanyName" "${INFO_COMPANYNAME}"
+VIAddVersionKey "FileDescription" "${INFO_PRODUCTNAME} Installer"
+VIAddVersionKey "ProductVersion" "${INFO_PRODUCTVERSION}"
+VIAddVersionKey "FileVersion" "${INFO_PRODUCTVERSION}"
+VIAddVersionKey "LegalCopyright" "${INFO_COPYRIGHT}"
+VIAddVersionKey "ProductName" "${INFO_PRODUCTNAME}"
+
+# Enable HiDPI support. https://nsis.sourceforge.io/Reference/ManifestDPIAware
+ManifestDPIAware true
+
+!include "MUI.nsh"
+
+!define MUI_ICON "..\icon.ico"
+!define MUI_UNICON "..\icon.ico"
+# !define MUI_WELCOMEFINISHPAGE_BITMAP "resources\leftimage.bmp" #Include this to add a bitmap on the left side of the Welcome Page. Must be a size of 164x314
+!define MUI_FINISHPAGE_NOAUTOCLOSE # Wait on the INSTFILES page so the user can take a look into the details of the installation steps
+!define MUI_ABORTWARNING # This will warn the user if they exit from the installer.
+
+!insertmacro MUI_PAGE_WELCOME # Welcome to the installer page.
+# !insertmacro MUI_PAGE_LICENSE "resources\eula.txt" # Adds a EULA page to the installer
+!insertmacro MUI_PAGE_DIRECTORY # In which folder install page.
+!insertmacro MUI_PAGE_INSTFILES # Installing page.
+!insertmacro MUI_PAGE_FINISH # Finished installation page.
+
+!insertmacro MUI_UNPAGE_INSTFILES # Uninstalling page
+
+!insertmacro MUI_LANGUAGE "English" # Set the Language of the installer
+
+## The following two statements can be used to sign the installer and the uninstaller. The path to the binaries are provided in %1
+#!uninstfinalize 'signtool --file "%1"'
+#!finalize 'signtool --file "%1"'
+
+Name "${INFO_PRODUCTNAME}"
+OutFile "..\..\..\bin\${INFO_PROJECTNAME}-${ARCH}-installer.exe" # Name of the installer's file.
+InstallDir "$PROGRAMFILES64\${INFO_COMPANYNAME}\${INFO_PRODUCTNAME}" # Default installing folder ($PROGRAMFILES is Program Files folder).
+ShowInstDetails show # This will always show the installation details.
+
+Function .onInit
+ !insertmacro wails.checkArchitecture
+FunctionEnd
+
+Section
+ !insertmacro wails.setShellContext
+
+ !insertmacro wails.webview2runtime
+
+ SetOutPath $INSTDIR
+
+ !insertmacro wails.files
+
+ CreateShortcut "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"
+ CreateShortCut "$DESKTOP\${INFO_PRODUCTNAME}.lnk" "$INSTDIR\${PRODUCT_EXECUTABLE}"
+
+ !insertmacro wails.associateFiles
+ !insertmacro wails.associateCustomProtocols
+
+ !insertmacro wails.writeUninstaller
+SectionEnd
+
+Section "uninstall"
+ !insertmacro wails.setShellContext
+
+ RMDir /r "$AppData\${PRODUCT_EXECUTABLE}" # Remove the WebView2 DataPath
+
+ RMDir /r $INSTDIR
+
+ Delete "$SMPROGRAMS\${INFO_PRODUCTNAME}.lnk"
+ Delete "$DESKTOP\${INFO_PRODUCTNAME}.lnk"
+
+ !insertmacro wails.unassociateFiles
+ !insertmacro wails.unassociateCustomProtocols
+
+ !insertmacro wails.deleteUninstaller
+SectionEnd
diff --git a/build/windows/nsis/wails_tools.nsh b/build/windows/nsis/wails_tools.nsh
new file mode 100644
index 0000000..fa66271
--- /dev/null
+++ b/build/windows/nsis/wails_tools.nsh
@@ -0,0 +1,236 @@
+# DO NOT EDIT - Generated automatically by `wails build`
+
+!include "x64.nsh"
+!include "WinVer.nsh"
+!include "FileFunc.nsh"
+
+!ifndef INFO_PROJECTNAME
+ !define INFO_PROJECTNAME "u-desk"
+!endif
+!ifndef INFO_COMPANYNAME
+ !define INFO_COMPANYNAME "My Company"
+!endif
+!ifndef INFO_PRODUCTNAME
+ !define INFO_PRODUCTNAME "U-Desk"
+!endif
+!ifndef INFO_PRODUCTVERSION
+ !define INFO_PRODUCTVERSION "0.1.0"
+!endif
+!ifndef INFO_COPYRIGHT
+ !define INFO_COPYRIGHT "© 2026, My Company"
+!endif
+!ifndef PRODUCT_EXECUTABLE
+ !define PRODUCT_EXECUTABLE "${INFO_PROJECTNAME}.exe"
+!endif
+!ifndef UNINST_KEY_NAME
+ !define UNINST_KEY_NAME "${INFO_COMPANYNAME}${INFO_PRODUCTNAME}"
+!endif
+!define UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${UNINST_KEY_NAME}"
+
+!ifndef REQUEST_EXECUTION_LEVEL
+ !define REQUEST_EXECUTION_LEVEL "admin"
+!endif
+
+RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}"
+
+!ifdef ARG_WAILS_AMD64_BINARY
+ !define SUPPORTS_AMD64
+!endif
+
+!ifdef ARG_WAILS_ARM64_BINARY
+ !define SUPPORTS_ARM64
+!endif
+
+!ifdef SUPPORTS_AMD64
+ !ifdef SUPPORTS_ARM64
+ !define ARCH "amd64_arm64"
+ !else
+ !define ARCH "amd64"
+ !endif
+!else
+ !ifdef SUPPORTS_ARM64
+ !define ARCH "arm64"
+ !else
+ !error "Wails: Undefined ARCH, please provide at least one of ARG_WAILS_AMD64_BINARY or ARG_WAILS_ARM64_BINARY"
+ !endif
+!endif
+
+!macro wails.checkArchitecture
+ !ifndef WAILS_WIN10_REQUIRED
+ !define WAILS_WIN10_REQUIRED "This product is only supported on Windows 10 (Server 2016) and later."
+ !endif
+
+ !ifndef WAILS_ARCHITECTURE_NOT_SUPPORTED
+ !define WAILS_ARCHITECTURE_NOT_SUPPORTED "This product can't be installed on the current Windows architecture. Supports: ${ARCH}"
+ !endif
+
+ ${If} ${AtLeastWin10}
+ !ifdef SUPPORTS_AMD64
+ ${if} ${IsNativeAMD64}
+ Goto ok
+ ${EndIf}
+ !endif
+
+ !ifdef SUPPORTS_ARM64
+ ${if} ${IsNativeARM64}
+ Goto ok
+ ${EndIf}
+ !endif
+
+ IfSilent silentArch notSilentArch
+ silentArch:
+ SetErrorLevel 65
+ Abort
+ notSilentArch:
+ MessageBox MB_OK "${WAILS_ARCHITECTURE_NOT_SUPPORTED}"
+ Quit
+ ${else}
+ IfSilent silentWin notSilentWin
+ silentWin:
+ SetErrorLevel 64
+ Abort
+ notSilentWin:
+ MessageBox MB_OK "${WAILS_WIN10_REQUIRED}"
+ Quit
+ ${EndIf}
+
+ ok:
+!macroend
+
+!macro wails.files
+ !ifdef SUPPORTS_AMD64
+ ${if} ${IsNativeAMD64}
+ File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_AMD64_BINARY}"
+ ${EndIf}
+ !endif
+
+ !ifdef SUPPORTS_ARM64
+ ${if} ${IsNativeARM64}
+ File "/oname=${PRODUCT_EXECUTABLE}" "${ARG_WAILS_ARM64_BINARY}"
+ ${EndIf}
+ !endif
+!macroend
+
+!macro wails.writeUninstaller
+ WriteUninstaller "$INSTDIR\uninstall.exe"
+
+ SetRegView 64
+ WriteRegStr HKLM "${UNINST_KEY}" "Publisher" "${INFO_COMPANYNAME}"
+ WriteRegStr HKLM "${UNINST_KEY}" "DisplayName" "${INFO_PRODUCTNAME}"
+ WriteRegStr HKLM "${UNINST_KEY}" "DisplayVersion" "${INFO_PRODUCTVERSION}"
+ WriteRegStr HKLM "${UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_EXECUTABLE}"
+ WriteRegStr HKLM "${UNINST_KEY}" "UninstallString" "$\"$INSTDIR\uninstall.exe$\""
+ WriteRegStr HKLM "${UNINST_KEY}" "QuietUninstallString" "$\"$INSTDIR\uninstall.exe$\" /S"
+
+ ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2
+ IntFmt $0 "0x%08X" $0
+ WriteRegDWORD HKLM "${UNINST_KEY}" "EstimatedSize" "$0"
+!macroend
+
+!macro wails.deleteUninstaller
+ Delete "$INSTDIR\uninstall.exe"
+
+ SetRegView 64
+ DeleteRegKey HKLM "${UNINST_KEY}"
+!macroend
+
+!macro wails.setShellContext
+ ${If} ${REQUEST_EXECUTION_LEVEL} == "admin"
+ SetShellVarContext all
+ ${else}
+ SetShellVarContext current
+ ${EndIf}
+!macroend
+
+# Install webview2 by launching the bootstrapper
+# See https://docs.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment
+!macro wails.webview2runtime
+ !ifndef WAILS_INSTALL_WEBVIEW_DETAILPRINT
+ !define WAILS_INSTALL_WEBVIEW_DETAILPRINT "Installing: WebView2 Runtime"
+ !endif
+
+ SetRegView 64
+ # If the admin key exists and is not empty then webview2 is already installed
+ ReadRegStr $0 HKLM "SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
+ ${If} $0 != ""
+ Goto ok
+ ${EndIf}
+
+ ${If} ${REQUEST_EXECUTION_LEVEL} == "user"
+ # If the installer is run in user level, check the user specific key exists and is not empty then webview2 is already installed
+ ReadRegStr $0 HKCU "Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" "pv"
+ ${If} $0 != ""
+ Goto ok
+ ${EndIf}
+ ${EndIf}
+
+ SetDetailsPrint both
+ DetailPrint "${WAILS_INSTALL_WEBVIEW_DETAILPRINT}"
+ SetDetailsPrint listonly
+
+ InitPluginsDir
+ CreateDirectory "$pluginsdir\webview2bootstrapper"
+ SetOutPath "$pluginsdir\webview2bootstrapper"
+ File "MicrosoftEdgeWebview2Setup.exe"
+ ExecWait '"$pluginsdir\webview2bootstrapper\MicrosoftEdgeWebview2Setup.exe" /silent /install'
+
+ SetDetailsPrint both
+ ok:
+!macroend
+
+# Copy of APP_ASSOCIATE and APP_UNASSOCIATE macros from here https://gist.github.com/nikku/281d0ef126dbc215dd58bfd5b3a5cd5b
+!macro APP_ASSOCIATE EXT FILECLASS DESCRIPTION ICON COMMANDTEXT COMMAND
+ ; Backup the previously associated file class
+ ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" ""
+ WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "${FILECLASS}_backup" "$R0"
+
+ WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "${FILECLASS}"
+
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}" "" `${DESCRIPTION}`
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\DefaultIcon" "" `${ICON}`
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell" "" "open"
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open" "" `${COMMANDTEXT}`
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${FILECLASS}\shell\open\command" "" `${COMMAND}`
+!macroend
+
+!macro APP_UNASSOCIATE EXT FILECLASS
+ ; Backup the previously associated file class
+ ReadRegStr $R0 SHELL_CONTEXT "Software\Classes\.${EXT}" `${FILECLASS}_backup`
+ WriteRegStr SHELL_CONTEXT "Software\Classes\.${EXT}" "" "$R0"
+
+ DeleteRegKey SHELL_CONTEXT `Software\Classes\${FILECLASS}`
+!macroend
+
+!macro wails.associateFiles
+ ; Create file associations
+
+!macroend
+
+!macro wails.unassociateFiles
+ ; Delete app associations
+
+!macroend
+
+!macro CUSTOM_PROTOCOL_ASSOCIATE PROTOCOL DESCRIPTION ICON COMMAND
+ DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}"
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}"
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" ""
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}"
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" ""
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" ""
+ WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}"
+!macroend
+
+!macro CUSTOM_PROTOCOL_UNASSOCIATE PROTOCOL
+ DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}"
+!macroend
+
+!macro wails.associateCustomProtocols
+ ; Create custom protocols associations
+
+!macroend
+
+!macro wails.unassociateCustomProtocols
+ ; Delete app custom protocol associations
+
+!macroend
\ No newline at end of file
diff --git a/build/windows/wails.exe.manifest b/build/windows/wails.exe.manifest
index 17e1a23..6d44a91 100644
--- a/build/windows/wails.exe.manifest
+++ b/build/windows/wails.exe.manifest
@@ -1,6 +1,6 @@
-
+
@@ -12,4 +12,11 @@
permonitorv2,permonitor
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cmd/agent/clipboard_20260429_195256.png b/cmd/agent/clipboard_20260429_195256.png
deleted file mode 100644
index 3b73c12..0000000
Binary files a/cmd/agent/clipboard_20260429_195256.png and /dev/null differ
diff --git a/web/.eslintrc.js b/frontend/.eslintrc.js
similarity index 100%
rename from web/.eslintrc.js
rename to frontend/.eslintrc.js
diff --git a/web/.gitignore b/frontend/.gitignore
similarity index 100%
rename from web/.gitignore
rename to frontend/.gitignore
diff --git a/frontend/bindings/github.com/wailsapp/wails/v3/internal/eventcreate.ts b/frontend/bindings/github.com/wailsapp/wails/v3/internal/eventcreate.ts
new file mode 100644
index 0000000..1ea1058
--- /dev/null
+++ b/frontend/bindings/github.com/wailsapp/wails/v3/internal/eventcreate.ts
@@ -0,0 +1,9 @@
+//@ts-check
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore: Unused imports
+import { Create as $Create } from "@wailsio/runtime";
+
+Object.freeze($Create.Events);
diff --git a/frontend/bindings/github.com/wailsapp/wails/v3/internal/eventdata.d.ts b/frontend/bindings/github.com/wailsapp/wails/v3/internal/eventdata.d.ts
new file mode 100644
index 0000000..3dd1807
--- /dev/null
+++ b/frontend/bindings/github.com/wailsapp/wails/v3/internal/eventdata.d.ts
@@ -0,0 +1,2 @@
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
diff --git a/frontend/bindings/github.com/wailsapp/wails/v3/pkg/application/index.ts b/frontend/bindings/github.com/wailsapp/wails/v3/pkg/application/index.ts
new file mode 100644
index 0000000..ed5448d
--- /dev/null
+++ b/frontend/bindings/github.com/wailsapp/wails/v3/pkg/application/index.ts
@@ -0,0 +1,6 @@
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+export {
+ WebviewWindow
+} from "./models.js";
diff --git a/frontend/bindings/github.com/wailsapp/wails/v3/pkg/application/models.ts b/frontend/bindings/github.com/wailsapp/wails/v3/pkg/application/models.ts
new file mode 100644
index 0000000..dc6d683
--- /dev/null
+++ b/frontend/bindings/github.com/wailsapp/wails/v3/pkg/application/models.ts
@@ -0,0 +1,23 @@
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore: Unused imports
+import { Create as $Create } from "@wailsio/runtime";
+
+export class WebviewWindow {
+
+ /** Creates a new WebviewWindow instance. */
+ constructor($$source: Partial = {}) {
+
+ Object.assign(this, $$source);
+ }
+
+ /**
+ * Creates a new WebviewWindow instance from a string or object.
+ */
+ static createFrom($$source: any = {}): WebviewWindow {
+ let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
+ return new WebviewWindow($$parsedSource as Partial);
+ }
+}
diff --git a/frontend/bindings/u-desk/app.ts b/frontend/bindings/u-desk/app.ts
new file mode 100644
index 0000000..d1b3e0d
--- /dev/null
+++ b/frontend/bindings/u-desk/app.ts
@@ -0,0 +1,430 @@
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+/**
+ * App 应用结构体
+ * @module
+ */
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore: Unused imports
+import { Call as $Call, CancellablePromise as $CancellablePromise, Create as $Create } from "@wailsio/runtime";
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore: Unused imports
+import * as application$0 from "../github.com/wailsapp/wails/v3/pkg/application/models.js";
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore: Unused imports
+import * as filesystem$0 from "./internal/filesystem/models.js";
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore: Unused imports
+import * as $models from "./models.js";
+
+/**
+ * CheckUpdate 检查更新
+ */
+export function CheckUpdate(): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(586574094).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * ClearCache 清理本地缓存(用于菜单项)
+ */
+export function ClearCache(): $CancellablePromise {
+ return $Call.ByID(1413834504);
+}
+
+/**
+ * CreateDir 创建目录
+ */
+export function CreateDir(path: string): $CancellablePromise {
+ return $Call.ByID(632035444, path).then(($result: any) => {
+ return $$createType2($result);
+ });
+}
+
+/**
+ * CreateFile 创建文件
+ */
+export function CreateFile(path: string): $CancellablePromise {
+ return $Call.ByID(3418645411, path).then(($result: any) => {
+ return $$createType2($result);
+ });
+}
+
+/**
+ * DeletePath 删除文件或目录
+ */
+export function DeletePath(path: string): $CancellablePromise {
+ return $Call.ByID(1564637217, path).then(($result: any) => {
+ return $$createType2($result);
+ });
+}
+
+/**
+ * DeletePermanently 永久删除回收站中的文件
+ */
+export function DeletePermanently(recyclePath: string): $CancellablePromise {
+ return $Call.ByID(1697000327, recyclePath);
+}
+
+/**
+ * DetectFileTypeByContent 通过文件内容检测文件类型
+ */
+export function DetectFileTypeByContent(path: string): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(3067282982, path).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * DownloadUpdate 下载更新包
+ */
+export function DownloadUpdate(downloadURL: string): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(115027584, downloadURL).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * EmptyRecycleBin 清空回收站
+ */
+export function EmptyRecycleBin(): $CancellablePromise {
+ return $Call.ByID(4176312624);
+}
+
+/**
+ * ExportPDF 导出PDF文件
+ */
+export function ExportPDF(content: string, title: string, fileName: string, fontSize: number, pageWidth: number, pageHeight: number): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(1770450987, content, title, fileName, fontSize, pageWidth, pageHeight).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * ExtractFileFromZip 从 zip 文件中提取单个文件内容
+ */
+export function ExtractFileFromZip(zipPath: string, filePath: string): $CancellablePromise {
+ return $Call.ByID(1578144127, zipPath, filePath);
+}
+
+/**
+ * ExtractFileFromZipToTemp 从 zip 文件中提取单个文件到临时目录
+ */
+export function ExtractFileFromZipToTemp(zipPath: string, filePath: string): $CancellablePromise {
+ return $Call.ByID(1720007904, zipPath, filePath);
+}
+
+/**
+ * GetAppConfig 获取应用配置
+ */
+export function GetAppConfig(): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(2006534548).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * GetAuditLogs 获取审计日志
+ */
+export function GetAuditLogs(limit: number): $CancellablePromise<{ [_ in string]?: any }[]> {
+ return $Call.ByID(3554903517, limit).then(($result: any) => {
+ return $$createType3($result);
+ });
+}
+
+/**
+ * GetCPUInfo 获取 CPU 信息
+ */
+export function GetCPUInfo(): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(2509681007).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * GetCommonPaths 获取常用系统路径
+ */
+export function GetCommonPaths(): $CancellablePromise<{ [_ in string]?: string }> {
+ return $Call.ByID(3953343786).then(($result: any) => {
+ return $$createType4($result);
+ });
+}
+
+/**
+ * GetCurrentVersion 获取当前版本号
+ */
+export function GetCurrentVersion(): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(1827245900).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * GetDiskInfo 获取磁盘信息
+ */
+export function GetDiskInfo(): $CancellablePromise<{ [_ in string]?: any }[]> {
+ return $Call.ByID(3756377758).then(($result: any) => {
+ return $$createType3($result);
+ });
+}
+
+/**
+ * GetEnvVars 获取环境变量
+ */
+export function GetEnvVars(): $CancellablePromise<{ [_ in string]?: string }> {
+ return $Call.ByID(363814436).then(($result: any) => {
+ return $$createType4($result);
+ });
+}
+
+/**
+ * GetFileInfo 获取文件信息
+ */
+export function GetFileInfo(path: string): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(2071650585, path).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * GetFileServerURL 获取本地文件服务器的URL
+ */
+export function GetFileServerURL(): $CancellablePromise {
+ return $Call.ByID(4117667287);
+}
+
+/**
+ * GetMemoryInfo 获取内存信息
+ */
+export function GetMemoryInfo(): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(2096905876).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * GetRecycleBinEntries 获取回收站条目
+ */
+export function GetRecycleBinEntries(): $CancellablePromise<{ [_ in string]?: any }[]> {
+ return $Call.ByID(2312855399).then(($result: any) => {
+ return $$createType3($result);
+ });
+}
+
+/**
+ * GetSystemInfo 获取系统信息
+ */
+export function GetSystemInfo(): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(1347250254).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * GetUpdateConfig 获取更新配置
+ */
+export function GetUpdateConfig(): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(680804904).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * GetZipFileInfo 获取 zip 文件中特定文件的信息
+ */
+export function GetZipFileInfo(zipPath: string, filePath: string): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(2031617692, zipPath, filePath).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * InstallUpdate 安装更新包
+ */
+export function InstallUpdate(installerPath: string, autoRestart: boolean): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(2443992793, installerPath, autoRestart).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * InstallUpdateWithHash 安装更新包(带哈希验证)
+ */
+export function InstallUpdateWithHash(installerPath: string, autoRestart: boolean, expectedHash: string, hashType: string): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(3787276601, installerPath, autoRestart, expectedHash, hashType).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * ListDir 列出目录
+ */
+export function ListDir(path: string): $CancellablePromise<{ [_ in string]?: any }[]> {
+ return $Call.ByID(2120475736, path).then(($result: any) => {
+ return $$createType3($result);
+ });
+}
+
+/**
+ * ListZipContents 列出 zip 文件内容
+ */
+export function ListZipContents(zipPath: string): $CancellablePromise<{ [_ in string]?: any }[]> {
+ return $Call.ByID(3013109042, zipPath).then(($result: any) => {
+ return $$createType3($result);
+ });
+}
+
+/**
+ * OpenPath 使用系统默认程序打开文件或目录
+ */
+export function OpenPath(path: string): $CancellablePromise {
+ return $Call.ByID(1591734570, path);
+}
+
+/**
+ * ReadFile 读取文件
+ */
+export function ReadFile(path: string): $CancellablePromise {
+ return $Call.ByID(1160596971, path);
+}
+
+/**
+ * Reload 重新加载窗口(用于菜单项)
+ */
+export function Reload(): $CancellablePromise {
+ return $Call.ByID(2733532980);
+}
+
+/**
+ * RenamePath 重命名文件或目录
+ */
+export function RenamePath(req: $models.RenamePathRequest): $CancellablePromise {
+ return $Call.ByID(1959759948, req).then(($result: any) => {
+ return $$createType2($result);
+ });
+}
+
+/**
+ * ResolveShortcut 解析快捷方式文件,返回目标路径信息
+ */
+export function ResolveShortcut(lnkPath: string): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(4051288361, lnkPath).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * RestoreFromRecycleBin 从回收站恢复文件
+ */
+export function RestoreFromRecycleBin(recyclePath: string): $CancellablePromise {
+ return $Call.ByID(3682437655, recyclePath);
+}
+
+/**
+ * SaveAppConfig 保存应用配置
+ */
+export function SaveAppConfig(req: $models.SaveAppConfigRequest): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(1942219977, req).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * SaveBase64File 将 base64 内容解码后写入文件(用于图片等二进制数据)
+ */
+export function SaveBase64File(req: $models.SaveBase64FileRequest): $CancellablePromise {
+ return $Call.ByID(1355120553, req);
+}
+
+/**
+ * SelectPDFSaveDirectory 选择PDF保存目录
+ */
+export function SelectPDFSaveDirectory(): $CancellablePromise {
+ return $Call.ByID(1403263131);
+}
+
+/**
+ * SetMainWindow 设置主窗口引用(由 main.go 在创建窗口后调用)
+ */
+export function SetMainWindow(w: application$0.WebviewWindow | null): $CancellablePromise {
+ return $Call.ByID(843697430, w);
+}
+
+/**
+ * SetUpdateConfig 设置更新配置
+ */
+export function SetUpdateConfig(autoCheckEnabled: boolean, checkIntervalMinutes: number, checkURL: string): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(4271731092, autoCheckEnabled, checkIntervalMinutes, checkURL).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * SetWindowTitleBarColor 设置原生标题栏颜色 + 主题模式(0x00BBGGRR 格式)
+ */
+export function SetWindowTitleBarColor(color: number, isDark: boolean): $CancellablePromise {
+ return $Call.ByID(1570627619, color, isDark);
+}
+
+/**
+ * VerifyUpdateFile 验证更新文件哈希值
+ */
+export function VerifyUpdateFile(filePath: string, expectedHash: string, hashType: string): $CancellablePromise<{ [_ in string]?: any }> {
+ return $Call.ByID(2181909867, filePath, expectedHash, hashType).then(($result: any) => {
+ return $$createType0($result);
+ });
+}
+
+/**
+ * WindowClose 关闭窗口
+ */
+export function WindowClose(): $CancellablePromise {
+ return $Call.ByID(1474073651);
+}
+
+/**
+ * WindowIsMaximized 检查窗口是否最大化
+ */
+export function WindowIsMaximized(): $CancellablePromise {
+ return $Call.ByID(854232017);
+}
+
+/**
+ * WindowMaximize 最大化/还原窗口
+ */
+export function WindowMaximize(): $CancellablePromise {
+ return $Call.ByID(2739663967);
+}
+
+/**
+ * WindowMinimize 最小化窗口
+ */
+export function WindowMinimize(): $CancellablePromise {
+ return $Call.ByID(1846147565);
+}
+
+/**
+ * WindowToggleAlwaysOnTop 切换窗口置顶
+ */
+export function WindowToggleAlwaysOnTop(): $CancellablePromise {
+ return $Call.ByID(3391208916);
+}
+
+/**
+ * WriteFile 写入文件
+ */
+export function WriteFile(req: $models.WriteFileRequest): $CancellablePromise {
+ return $Call.ByID(3562730546, req);
+}
+
+// Private type creation functions
+const $$createType0 = $Create.Map($Create.Any, $Create.Any);
+const $$createType1 = filesystem$0.FileOperationResult.createFrom;
+const $$createType2 = $Create.Nullable($$createType1);
+const $$createType3 = $Create.Array($$createType0);
+const $$createType4 = $Create.Map($Create.Any, $Create.Any);
diff --git a/frontend/bindings/u-desk/index.ts b/frontend/bindings/u-desk/index.ts
new file mode 100644
index 0000000..cd4a868
--- /dev/null
+++ b/frontend/bindings/u-desk/index.ts
@@ -0,0 +1,14 @@
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+import * as App from "./app.js";
+export {
+ App
+};
+
+export {
+ RenamePathRequest,
+ SaveAppConfigRequest,
+ SaveBase64FileRequest,
+ WriteFileRequest
+} from "./models.js";
diff --git a/frontend/bindings/u-desk/internal/api/index.ts b/frontend/bindings/u-desk/internal/api/index.ts
new file mode 100644
index 0000000..c016da9
--- /dev/null
+++ b/frontend/bindings/u-desk/internal/api/index.ts
@@ -0,0 +1,6 @@
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+export {
+ AppTabDefinition
+} from "./models.js";
diff --git a/frontend/bindings/u-desk/internal/api/models.ts b/frontend/bindings/u-desk/internal/api/models.ts
new file mode 100644
index 0000000..8b86ae2
--- /dev/null
+++ b/frontend/bindings/u-desk/internal/api/models.ts
@@ -0,0 +1,42 @@
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore: Unused imports
+import { Create as $Create } from "@wailsio/runtime";
+
+/**
+ * AppTabDefinition 应用 Tab 定义(前端格式)
+ */
+export class AppTabDefinition {
+ "key": string;
+ "title": string;
+ "visible": boolean;
+ "enabled": boolean;
+
+ /** Creates a new AppTabDefinition instance. */
+ constructor($$source: Partial = {}) {
+ if (!("key" in $$source)) {
+ this["key"] = "";
+ }
+ if (!("title" in $$source)) {
+ this["title"] = "";
+ }
+ if (!("visible" in $$source)) {
+ this["visible"] = false;
+ }
+ if (!("enabled" in $$source)) {
+ this["enabled"] = false;
+ }
+
+ Object.assign(this, $$source);
+ }
+
+ /**
+ * Creates a new AppTabDefinition instance from a string or object.
+ */
+ static createFrom($$source: any = {}): AppTabDefinition {
+ let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
+ return new AppTabDefinition($$parsedSource as Partial);
+ }
+}
diff --git a/frontend/bindings/u-desk/internal/filesystem/index.ts b/frontend/bindings/u-desk/internal/filesystem/index.ts
new file mode 100644
index 0000000..3b6cbf4
--- /dev/null
+++ b/frontend/bindings/u-desk/internal/filesystem/index.ts
@@ -0,0 +1,6 @@
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+export {
+ FileOperationResult
+} from "./models.js";
diff --git a/frontend/bindings/u-desk/internal/filesystem/models.ts b/frontend/bindings/u-desk/internal/filesystem/models.ts
new file mode 100644
index 0000000..97f9657
--- /dev/null
+++ b/frontend/bindings/u-desk/internal/filesystem/models.ts
@@ -0,0 +1,55 @@
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore: Unused imports
+import { Create as $Create } from "@wailsio/runtime";
+
+/**
+ * FileOperationResult 文件操作结果
+ */
+export class FileOperationResult {
+ "path": string;
+ "name": string;
+ "size": number;
+ "size_str"?: string;
+ "is_dir": boolean;
+ "mod_time"?: string;
+ "mode"?: string;
+
+ /**
+ * 仅重命名操作时有值
+ */
+ "old_path"?: string;
+
+ /**
+ * 仅删除操作时有值
+ */
+ "deleted"?: boolean;
+
+ /** Creates a new FileOperationResult instance. */
+ constructor($$source: Partial = {}) {
+ if (!("path" in $$source)) {
+ this["path"] = "";
+ }
+ if (!("name" in $$source)) {
+ this["name"] = "";
+ }
+ if (!("size" in $$source)) {
+ this["size"] = 0;
+ }
+ if (!("is_dir" in $$source)) {
+ this["is_dir"] = false;
+ }
+
+ Object.assign(this, $$source);
+ }
+
+ /**
+ * Creates a new FileOperationResult instance from a string or object.
+ */
+ static createFrom($$source: any = {}): FileOperationResult {
+ let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
+ return new FileOperationResult($$parsedSource as Partial);
+ }
+}
diff --git a/frontend/bindings/u-desk/models.ts b/frontend/bindings/u-desk/models.ts
new file mode 100644
index 0000000..8666d8e
--- /dev/null
+++ b/frontend/bindings/u-desk/models.ts
@@ -0,0 +1,143 @@
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore: Unused imports
+import { Create as $Create } from "@wailsio/runtime";
+
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore: Unused imports
+import * as api$0 from "./internal/api/models.js";
+
+/**
+ * RenamePathRequest 重命名文件或目录请求结构体
+ */
+export class RenamePathRequest {
+ "oldPath": string;
+ "newPath": string;
+
+ /** Creates a new RenamePathRequest instance. */
+ constructor($$source: Partial = {}) {
+ if (!("oldPath" in $$source)) {
+ this["oldPath"] = "";
+ }
+ if (!("newPath" in $$source)) {
+ this["newPath"] = "";
+ }
+
+ Object.assign(this, $$source);
+ }
+
+ /**
+ * Creates a new RenamePathRequest instance from a string or object.
+ */
+ static createFrom($$source: any = {}): RenamePathRequest {
+ let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
+ return new RenamePathRequest($$parsedSource as Partial);
+ }
+}
+
+/**
+ * SaveAppConfigRequest 保存应用配置请求
+ */
+export class SaveAppConfigRequest {
+ "tabs": api$0.AppTabDefinition[];
+ "visibleTabs": string[];
+ "defaultTab": string;
+
+ /** Creates a new SaveAppConfigRequest instance. */
+ constructor($$source: Partial = {}) {
+ if (!("tabs" in $$source)) {
+ this["tabs"] = [];
+ }
+ if (!("visibleTabs" in $$source)) {
+ this["visibleTabs"] = [];
+ }
+ if (!("defaultTab" in $$source)) {
+ this["defaultTab"] = "";
+ }
+
+ Object.assign(this, $$source);
+ }
+
+ /**
+ * Creates a new SaveAppConfigRequest instance from a string or object.
+ */
+ static createFrom($$source: any = {}): SaveAppConfigRequest {
+ const $$createField0_0 = $$createType1;
+ const $$createField1_0 = $$createType2;
+ let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
+ if ("tabs" in $$parsedSource) {
+ $$parsedSource["tabs"] = $$createField0_0($$parsedSource["tabs"]);
+ }
+ if ("visibleTabs" in $$parsedSource) {
+ $$parsedSource["visibleTabs"] = $$createField1_0($$parsedSource["visibleTabs"]);
+ }
+ return new SaveAppConfigRequest($$parsedSource as Partial);
+ }
+}
+
+/**
+ * SaveBase64FileRequest 保存 Base64 编码的二进制文件
+ */
+export class SaveBase64FileRequest {
+ "path": string;
+
+ /**
+ * base64 编码的文件内容
+ */
+ "content": string;
+
+ /** Creates a new SaveBase64FileRequest instance. */
+ constructor($$source: Partial = {}) {
+ if (!("path" in $$source)) {
+ this["path"] = "";
+ }
+ if (!("content" in $$source)) {
+ this["content"] = "";
+ }
+
+ Object.assign(this, $$source);
+ }
+
+ /**
+ * Creates a new SaveBase64FileRequest instance from a string or object.
+ */
+ static createFrom($$source: any = {}): SaveBase64FileRequest {
+ let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
+ return new SaveBase64FileRequest($$parsedSource as Partial);
+ }
+}
+
+/**
+ * WriteFileRequest 写入文件请求结构体
+ */
+export class WriteFileRequest {
+ "path": string;
+ "content": string;
+
+ /** Creates a new WriteFileRequest instance. */
+ constructor($$source: Partial = {}) {
+ if (!("path" in $$source)) {
+ this["path"] = "";
+ }
+ if (!("content" in $$source)) {
+ this["content"] = "";
+ }
+
+ Object.assign(this, $$source);
+ }
+
+ /**
+ * Creates a new WriteFileRequest instance from a string or object.
+ */
+ static createFrom($$source: any = {}): WriteFileRequest {
+ let $$parsedSource = typeof $$source === 'string' ? JSON.parse($$source) : $$source;
+ return new WriteFileRequest($$parsedSource as Partial);
+ }
+}
+
+// Private type creation functions
+const $$createType0 = api$0.AppTabDefinition.createFrom;
+const $$createType1 = $Create.Array($$createType0);
+const $$createType2 = $Create.Array($Create.Any);
diff --git a/web/index.html b/frontend/index.html
similarity index 100%
rename from web/index.html
rename to frontend/index.html
diff --git a/web/package-lock.json b/frontend/package-lock.json
similarity index 75%
rename from web/package-lock.json
rename to frontend/package-lock.json
index 09e0f43..9037dbc 100644
--- a/web/package-lock.json
+++ b/frontend/package-lock.json
@@ -29,6 +29,7 @@
"@codemirror/state": "^6.5.3",
"@codemirror/theme-one-dark": "^6.1.3",
"@codemirror/view": "^6.39.8",
+ "@wailsio/runtime": "latest",
"highlight.js": "^11.11.1",
"mammoth": "^1.11.0",
"marked": "^17.0.1",
@@ -71,13 +72,17 @@
},
"node_modules/@arco-design/color": {
"version": "0.4.0",
+ "resolved": "https://registry.npmmirror.com/@arco-design/color/-/color-0.4.0.tgz",
+ "integrity": "sha512-s7p9MSwJgHeL8DwcATaXvWT3m2SigKpxx4JA1BGPHL4gfvaQsmQfrLBDpjOJFJuJ2jG2dMt3R3P8Pm9E65q18g==",
"license": "MIT",
"dependencies": {
"color": "^3.1.3"
}
},
"node_modules/@arco-design/web-vue": {
- "version": "2.57.0",
+ "version": "2.58.0",
+ "resolved": "https://registry.npmmirror.com/@arco-design/web-vue/-/web-vue-2.58.0.tgz",
+ "integrity": "sha512-b1vdPYOmjG5VAkVa7jlVwCb+WynBK+rnKN8zH3yKohpZObZbostRd3HgYNtjjZjGVU3OqR0Yy2FX7ftgF0bcOw==",
"license": "MIT",
"dependencies": {
"@arco-design/color": "^0.4.0",
@@ -91,11 +96,13 @@
"vue": "^3.1.0"
},
"peerDependencies": {
- "vue": "^3.1.0"
+ "vue": ">=3.1.0"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.27.1",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -103,16 +110,20 @@
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.28.5",
+ "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+ "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
- "version": "7.28.5",
+ "version": "7.29.3",
+ "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.3.tgz",
+ "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==",
"license": "MIT",
"dependencies": {
- "@babel/types": "^7.28.5"
+ "@babel/types": "^7.29.0"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -122,7 +133,9 @@
}
},
"node_modules/@babel/types": {
- "version": "7.28.5",
+ "version": "7.29.0",
+ "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.29.0.tgz",
+ "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
"license": "MIT",
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
@@ -139,60 +152,46 @@
"license": "MIT"
},
"node_modules/@chevrotain/cst-dts-gen": {
- "version": "11.0.3",
- "resolved": "https://registry.npmmirror.com/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz",
- "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==",
+ "version": "12.0.0",
+ "resolved": "https://registry.npmmirror.com/@chevrotain/cst-dts-gen/-/cst-dts-gen-12.0.0.tgz",
+ "integrity": "sha512-fSL4KXjTl7cDgf0B5Rip9Q05BOrYvkJV/RrBTE/bKDN096E4hN/ySpcBK5B24T76dlQ2i32Zc3PAE27jFnFrKg==",
"license": "Apache-2.0",
"dependencies": {
- "@chevrotain/gast": "11.0.3",
- "@chevrotain/types": "11.0.3",
- "lodash-es": "4.17.21"
+ "@chevrotain/gast": "12.0.0",
+ "@chevrotain/types": "12.0.0"
}
},
- "node_modules/@chevrotain/cst-dts-gen/node_modules/lodash-es": {
- "version": "4.17.21",
- "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz",
- "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
- "license": "MIT"
- },
"node_modules/@chevrotain/gast": {
- "version": "11.0.3",
- "resolved": "https://registry.npmmirror.com/@chevrotain/gast/-/gast-11.0.3.tgz",
- "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==",
+ "version": "12.0.0",
+ "resolved": "https://registry.npmmirror.com/@chevrotain/gast/-/gast-12.0.0.tgz",
+ "integrity": "sha512-1ne/m3XsIT8aEdrvT33so0GUC+wkctpUPK6zU9IlOyJLUbR0rg4G7ZiApiJbggpgPir9ERy3FRjT6T7lpgetnQ==",
"license": "Apache-2.0",
"dependencies": {
- "@chevrotain/types": "11.0.3",
- "lodash-es": "4.17.21"
+ "@chevrotain/types": "12.0.0"
}
},
- "node_modules/@chevrotain/gast/node_modules/lodash-es": {
- "version": "4.17.21",
- "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz",
- "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
- "license": "MIT"
- },
"node_modules/@chevrotain/regexp-to-ast": {
- "version": "11.0.3",
- "resolved": "https://registry.npmmirror.com/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz",
- "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==",
+ "version": "12.0.0",
+ "resolved": "https://registry.npmmirror.com/@chevrotain/regexp-to-ast/-/regexp-to-ast-12.0.0.tgz",
+ "integrity": "sha512-p+EW9MaJwgaHguhoqwOtx/FwuGr+DnNn857sXWOi/mClXIkPGl3rn7hGNWvo31HA3vyeQxjqe+H36yZJwYU8cA==",
"license": "Apache-2.0"
},
"node_modules/@chevrotain/types": {
- "version": "11.0.3",
- "resolved": "https://registry.npmmirror.com/@chevrotain/types/-/types-11.0.3.tgz",
- "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==",
+ "version": "12.0.0",
+ "resolved": "https://registry.npmmirror.com/@chevrotain/types/-/types-12.0.0.tgz",
+ "integrity": "sha512-S+04vjFQKeuYw0/eW3U52LkAHQsB1ASxsPGsLPUyQgrZ2iNNibQrsidruDzjEX2JYfespXMG0eZmXlhA6z7nWA==",
"license": "Apache-2.0"
},
"node_modules/@chevrotain/utils": {
- "version": "11.0.3",
- "resolved": "https://registry.npmmirror.com/@chevrotain/utils/-/utils-11.0.3.tgz",
- "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==",
+ "version": "12.0.0",
+ "resolved": "https://registry.npmmirror.com/@chevrotain/utils/-/utils-12.0.0.tgz",
+ "integrity": "sha512-lB59uJoaGIfOOL9knQqQRfhl9g7x8/wqFkp13zTdkRu1huG9kg6IJs1O8hqj9rs6h7orGxHJUKb+mX3rPbWGhA==",
"license": "Apache-2.0"
},
"node_modules/@codemirror/autocomplete": {
- "version": "6.20.0",
- "resolved": "https://registry.npmmirror.com/@codemirror/autocomplete/-/autocomplete-6.20.0.tgz",
- "integrity": "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==",
+ "version": "6.20.1",
+ "resolved": "https://registry.npmmirror.com/@codemirror/autocomplete/-/autocomplete-6.20.1.tgz",
+ "integrity": "sha512-1cvg3Vz1dSSToCNlJfRA2WSI4ht3K+WplO0UMOgmUYPivCyy2oueZY6Lx7M9wThm7SDUBViRmuT+OG/i8+ON9A==",
"license": "MIT",
"dependencies": {
"@codemirror/language": "^6.0.0",
@@ -202,13 +201,13 @@
}
},
"node_modules/@codemirror/commands": {
- "version": "6.10.1",
- "resolved": "https://registry.npmmirror.com/@codemirror/commands/-/commands-6.10.1.tgz",
- "integrity": "sha512-uWDWFypNdQmz2y1LaNJzK7fL7TYKLeUAU0npEC685OKTF3KcQ2Vu3klIM78D7I6wGhktme0lh3CuQLv0ZCrD9Q==",
+ "version": "6.10.3",
+ "resolved": "https://registry.npmmirror.com/@codemirror/commands/-/commands-6.10.3.tgz",
+ "integrity": "sha512-JFRiqhKu+bvSkDLI+rUhJwSxQxYb759W5GBezE8Uc8mHLqC9aV/9aTC7yJSqCtB3F00pylrLCwnyS91Ap5ej4Q==",
"license": "MIT",
"dependencies": {
"@codemirror/language": "^6.0.0",
- "@codemirror/state": "^6.4.0",
+ "@codemirror/state": "^6.6.0",
"@codemirror/view": "^6.27.0",
"@lezer/common": "^1.1.0"
}
@@ -277,9 +276,9 @@
}
},
"node_modules/@codemirror/lang-javascript": {
- "version": "6.2.4",
- "resolved": "https://registry.npmmirror.com/@codemirror/lang-javascript/-/lang-javascript-6.2.4.tgz",
- "integrity": "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA==",
+ "version": "6.2.5",
+ "resolved": "https://registry.npmmirror.com/@codemirror/lang-javascript/-/lang-javascript-6.2.5.tgz",
+ "integrity": "sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
@@ -367,9 +366,9 @@
}
},
"node_modules/@codemirror/lang-yaml": {
- "version": "6.1.2",
- "resolved": "https://registry.npmmirror.com/@codemirror/lang-yaml/-/lang-yaml-6.1.2.tgz",
- "integrity": "sha512-dxrfG8w5Ce/QbT7YID7mWZFKhdhsaTNOYjOkSIMt1qmC4VQnXSDSYVHHHn8k6kJUfIhtLo8t1JJgltlxWdsITw==",
+ "version": "6.1.3",
+ "resolved": "https://registry.npmmirror.com/@codemirror/lang-yaml/-/lang-yaml-6.1.3.tgz",
+ "integrity": "sha512-AZ8DJBuXGVHybpBQhmZtgew5//4hv3tdkXnr3vDmOUMJRuB6vn/uuwtmTOTlqEaQFg3hQSVeA90NmvIQyUV6FQ==",
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.0.0",
@@ -382,9 +381,9 @@
}
},
"node_modules/@codemirror/language": {
- "version": "6.12.1",
- "resolved": "https://registry.npmmirror.com/@codemirror/language/-/language-6.12.1.tgz",
- "integrity": "sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ==",
+ "version": "6.12.3",
+ "resolved": "https://registry.npmmirror.com/@codemirror/language/-/language-6.12.3.tgz",
+ "integrity": "sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA==",
"license": "MIT",
"dependencies": {
"@codemirror/state": "^6.0.0",
@@ -405,9 +404,9 @@
}
},
"node_modules/@codemirror/lint": {
- "version": "6.9.2",
- "resolved": "https://registry.npmmirror.com/@codemirror/lint/-/lint-6.9.2.tgz",
- "integrity": "sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==",
+ "version": "6.9.5",
+ "resolved": "https://registry.npmmirror.com/@codemirror/lint/-/lint-6.9.5.tgz",
+ "integrity": "sha512-GElsbU9G7QT9xXhpUg1zWGmftA/7jamh+7+ydKRuT0ORpWS3wOSP0yT1FOlIZa7mIJjpVPipErsyvVqB9cfTFA==",
"license": "MIT",
"dependencies": {
"@codemirror/state": "^6.0.0",
@@ -416,9 +415,9 @@
}
},
"node_modules/@codemirror/search": {
- "version": "6.6.0",
- "resolved": "https://registry.npmmirror.com/@codemirror/search/-/search-6.6.0.tgz",
- "integrity": "sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw==",
+ "version": "6.7.0",
+ "resolved": "https://registry.npmmirror.com/@codemirror/search/-/search-6.7.0.tgz",
+ "integrity": "sha512-ZvGm99wc/s2cITtMT15LFdn8aH/aS+V+DqyGq/N5ZlV5vWtH+nILvC2nw0zX7ByNoHHDZ2IxxdW38O0tc5nVHg==",
"license": "MIT",
"dependencies": {
"@codemirror/state": "^6.0.0",
@@ -427,9 +426,9 @@
}
},
"node_modules/@codemirror/state": {
- "version": "6.5.3",
- "resolved": "https://registry.npmmirror.com/@codemirror/state/-/state-6.5.3.tgz",
- "integrity": "sha512-MerMzJzlXogk2fxWFU1nKp36bY5orBG59HnPiz0G9nLRebWa0zXuv2siH6PLIHBvv5TH8CkQRqjBs0MlxCZu+A==",
+ "version": "6.6.0",
+ "resolved": "https://registry.npmmirror.com/@codemirror/state/-/state-6.6.0.tgz",
+ "integrity": "sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==",
"license": "MIT",
"dependencies": {
"@marijn/find-cluster-break": "^1.0.0"
@@ -448,21 +447,21 @@
}
},
"node_modules/@codemirror/view": {
- "version": "6.39.8",
- "resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.39.8.tgz",
- "integrity": "sha512-1rASYd9Z/mE3tkbC9wInRlCNyCkSn+nLsiQKZhEDUUJiUfs/5FHDpCUDaQpoTIaNGeDc6/bhaEAyLmeEucEFPw==",
+ "version": "6.41.1",
+ "resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.41.1.tgz",
+ "integrity": "sha512-ToDnWKbBnke+ZLrP6vgTTDScGi5H37YYuZGniQaBzxMVdtCxMrslsmtnOvbPZk4RX9bvkQqnWR/WS/35tJA0qg==",
"license": "MIT",
"dependencies": {
- "@codemirror/state": "^6.5.0",
+ "@codemirror/state": "^6.6.0",
"crelt": "^1.0.6",
"style-mod": "^4.1.0",
"w3c-keyname": "^2.2.4"
}
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz",
- "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz",
+ "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==",
"cpu": [
"ppc64"
],
@@ -477,9 +476,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.27.2.tgz",
- "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.27.7.tgz",
+ "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==",
"cpu": [
"arm"
],
@@ -494,9 +493,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz",
- "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz",
+ "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==",
"cpu": [
"arm64"
],
@@ -511,9 +510,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.27.2.tgz",
- "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.27.7.tgz",
+ "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==",
"cpu": [
"x64"
],
@@ -528,9 +527,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz",
- "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz",
+ "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==",
"cpu": [
"arm64"
],
@@ -545,9 +544,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz",
- "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz",
+ "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==",
"cpu": [
"x64"
],
@@ -562,9 +561,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz",
- "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz",
+ "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==",
"cpu": [
"arm64"
],
@@ -579,9 +578,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz",
- "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz",
+ "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==",
"cpu": [
"x64"
],
@@ -596,9 +595,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz",
- "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz",
+ "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==",
"cpu": [
"arm"
],
@@ -613,9 +612,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz",
- "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz",
+ "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==",
"cpu": [
"arm64"
],
@@ -630,9 +629,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz",
- "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz",
+ "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==",
"cpu": [
"ia32"
],
@@ -647,9 +646,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz",
- "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz",
+ "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==",
"cpu": [
"loong64"
],
@@ -664,9 +663,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz",
- "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz",
+ "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==",
"cpu": [
"mips64el"
],
@@ -681,9 +680,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz",
- "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz",
+ "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==",
"cpu": [
"ppc64"
],
@@ -698,9 +697,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz",
- "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz",
+ "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==",
"cpu": [
"riscv64"
],
@@ -715,9 +714,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz",
- "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz",
+ "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==",
"cpu": [
"s390x"
],
@@ -732,9 +731,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz",
- "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz",
+ "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==",
"cpu": [
"x64"
],
@@ -749,9 +748,9 @@
}
},
"node_modules/@esbuild/netbsd-arm64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz",
- "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz",
+ "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==",
"cpu": [
"arm64"
],
@@ -766,9 +765,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz",
- "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz",
+ "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==",
"cpu": [
"x64"
],
@@ -783,9 +782,9 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz",
- "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz",
+ "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==",
"cpu": [
"arm64"
],
@@ -800,9 +799,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz",
- "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz",
+ "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==",
"cpu": [
"x64"
],
@@ -817,9 +816,9 @@
}
},
"node_modules/@esbuild/openharmony-arm64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz",
- "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz",
+ "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==",
"cpu": [
"arm64"
],
@@ -834,9 +833,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz",
- "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz",
+ "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==",
"cpu": [
"x64"
],
@@ -851,9 +850,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz",
- "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz",
+ "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==",
"cpu": [
"arm64"
],
@@ -868,9 +867,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz",
- "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz",
+ "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==",
"cpu": [
"ia32"
],
@@ -885,9 +884,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz",
- "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz",
+ "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==",
"cpu": [
"x64"
],
@@ -908,24 +907,26 @@
"license": "MIT"
},
"node_modules/@iconify/utils": {
- "version": "3.1.0",
- "resolved": "https://registry.npmmirror.com/@iconify/utils/-/utils-3.1.0.tgz",
- "integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmmirror.com/@iconify/utils/-/utils-3.1.1.tgz",
+ "integrity": "sha512-MwzoDtw9rO1x+qfgLTV/IVXsHDBqeYZoMIQC8SfxfYSlaSUG+oWiAcoiB1yajAda6mqblm4/1/w2E8tRu7a7Tw==",
"license": "MIT",
"dependencies": {
"@antfu/install-pkg": "^1.1.0",
"@iconify/types": "^2.0.0",
- "mlly": "^1.8.0"
+ "mlly": "^1.8.2"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.5",
+ "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
"license": "MIT"
},
"node_modules/@lezer/common": {
- "version": "1.5.0",
- "resolved": "https://registry.npmmirror.com/@lezer/common/-/common-1.5.0.tgz",
- "integrity": "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA==",
+ "version": "1.5.2",
+ "resolved": "https://registry.npmmirror.com/@lezer/common/-/common-1.5.2.tgz",
+ "integrity": "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==",
"license": "MIT"
},
"node_modules/@lezer/cpp": {
@@ -940,9 +941,9 @@
}
},
"node_modules/@lezer/css": {
- "version": "1.3.0",
- "resolved": "https://registry.npmmirror.com/@lezer/css/-/css-1.3.0.tgz",
- "integrity": "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw==",
+ "version": "1.3.3",
+ "resolved": "https://registry.npmmirror.com/@lezer/css/-/css-1.3.3.tgz",
+ "integrity": "sha512-RzBo8r+/6QJeow7aPHIpGVIH59xTcJXp399820gZoMo9noQDRVpJLheIBUicYwKcsbOYoBRoLZlf2720dG/4Tg==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
@@ -1015,9 +1016,9 @@
}
},
"node_modules/@lezer/lr": {
- "version": "1.4.5",
- "resolved": "https://registry.npmmirror.com/@lezer/lr/-/lr-1.4.5.tgz",
- "integrity": "sha512-/YTRKP5yPPSo1xImYQk7AZZMAgap0kegzqCSYHjAL9x1AZ0ZQW+IpcEzMKagCsbTsLnVeWkxYrCNeXG8xEPrjg==",
+ "version": "1.4.10",
+ "resolved": "https://registry.npmmirror.com/@lezer/lr/-/lr-1.4.10.tgz",
+ "integrity": "sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.0.0"
@@ -1067,9 +1068,9 @@
}
},
"node_modules/@lezer/yaml": {
- "version": "1.0.3",
- "resolved": "https://registry.npmmirror.com/@lezer/yaml/-/yaml-1.0.3.tgz",
- "integrity": "sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA==",
+ "version": "1.0.4",
+ "resolved": "https://registry.npmmirror.com/@lezer/yaml/-/yaml-1.0.4.tgz",
+ "integrity": "sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw==",
"license": "MIT",
"dependencies": {
"@lezer/common": "^1.2.0",
@@ -1084,12 +1085,12 @@
"license": "MIT"
},
"node_modules/@mermaid-js/parser": {
- "version": "0.6.3",
- "resolved": "https://registry.npmmirror.com/@mermaid-js/parser/-/parser-0.6.3.tgz",
- "integrity": "sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/@mermaid-js/parser/-/parser-1.1.0.tgz",
+ "integrity": "sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==",
"license": "MIT",
"dependencies": {
- "langium": "3.3.1"
+ "langium": "^4.0.0"
}
},
"node_modules/@nodelib/fs.scandir": {
@@ -1131,9 +1132,9 @@
}
},
"node_modules/@rolldown/pluginutils": {
- "version": "1.0.0-beta.53",
- "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz",
- "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==",
+ "version": "1.0.0-rc.13",
+ "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.13.tgz",
+ "integrity": "sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA==",
"dev": true,
"license": "MIT"
},
@@ -1160,8 +1161,332 @@
}
}
},
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz",
+ "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz",
+ "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz",
+ "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz",
+ "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz",
+ "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz",
+ "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz",
+ "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz",
+ "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz",
+ "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz",
+ "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz",
+ "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-musl": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz",
+ "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz",
+ "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-musl": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz",
+ "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz",
+ "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz",
+ "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz",
+ "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz",
+ "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz",
+ "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openbsd-x64": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz",
+ "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz",
+ "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz",
+ "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz",
+ "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
"node_modules/@rollup/rollup-win32-x64-gnu": {
- "version": "4.54.0",
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz",
+ "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==",
"cpu": [
"x64"
],
@@ -1173,7 +1498,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.54.0",
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz",
+ "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==",
"cpu": [
"x64"
],
@@ -1439,6 +1766,8 @@
},
"node_modules/@types/estree": {
"version": "1.0.8",
+ "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
"dev": true,
"license": "MIT"
},
@@ -1469,63 +1798,81 @@
"license": "MIT",
"optional": true
},
+ "node_modules/@upsetjs/venn.js": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/@upsetjs/venn.js/-/venn.js-2.0.0.tgz",
+ "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==",
+ "license": "MIT",
+ "optionalDependencies": {
+ "d3-selection": "^3.0.0",
+ "d3-transition": "^3.0.1"
+ }
+ },
"node_modules/@vitejs/plugin-vue": {
- "version": "6.0.3",
- "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-6.0.3.tgz",
- "integrity": "sha512-TlGPkLFLVOY3T7fZrwdvKpjprR3s4fxRln0ORDo1VQ7HHyxJwTlrjKU3kpVWTlaAjIEuCTokmjkZnr8Tpc925w==",
+ "version": "6.0.6",
+ "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-6.0.6.tgz",
+ "integrity": "sha512-u9HHgfrq3AjXlysn0eINFnWQOJQLO9WN6VprZ8FXl7A2bYisv3Hui9Ij+7QZ41F/WYWarHjwBbXtD7dKg3uxbg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@rolldown/pluginutils": "1.0.0-beta.53"
+ "@rolldown/pluginutils": "1.0.0-rc.13"
},
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"peerDependencies": {
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0",
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
"vue": "^3.2.25"
}
},
"node_modules/@vue/compiler-core": {
- "version": "3.5.26",
+ "version": "3.5.33",
+ "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.33.tgz",
+ "integrity": "sha512-3PZLQwFw4Za3TC8t0FvTy3wI16Kt+pmwcgNZca4Pj9iWL2E72a/gZlpBtAJvEdDMdCxdG/qq0C7PN0bsJuv0Rw==",
"license": "MIT",
"dependencies": {
- "@babel/parser": "^7.28.5",
- "@vue/shared": "3.5.26",
- "entities": "^7.0.0",
+ "@babel/parser": "^7.29.2",
+ "@vue/shared": "3.5.33",
+ "entities": "^7.0.1",
"estree-walker": "^2.0.2",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-dom": {
- "version": "3.5.26",
+ "version": "3.5.33",
+ "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.33.tgz",
+ "integrity": "sha512-PXq0yrfCLzzL07rbXO4awtXY1Z06LG2eu6Adg3RJFa/j3Cii217XxxLXG22N330gw7GmALCY0Z8RgXEviwgpjA==",
"license": "MIT",
"dependencies": {
- "@vue/compiler-core": "3.5.26",
- "@vue/shared": "3.5.26"
+ "@vue/compiler-core": "3.5.33",
+ "@vue/shared": "3.5.33"
}
},
"node_modules/@vue/compiler-sfc": {
- "version": "3.5.26",
+ "version": "3.5.33",
+ "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.33.tgz",
+ "integrity": "sha512-UTUvRO9cY+rROrx/pvN9P5Z7FgA6QGfokUCfhQE4EnmUj3rVnK+CHI0LsEO1pg+I7//iRYMUfcNcCPe7tg0CoA==",
"license": "MIT",
"dependencies": {
- "@babel/parser": "^7.28.5",
- "@vue/compiler-core": "3.5.26",
- "@vue/compiler-dom": "3.5.26",
- "@vue/compiler-ssr": "3.5.26",
- "@vue/shared": "3.5.26",
+ "@babel/parser": "^7.29.2",
+ "@vue/compiler-core": "3.5.33",
+ "@vue/compiler-dom": "3.5.33",
+ "@vue/compiler-ssr": "3.5.33",
+ "@vue/shared": "3.5.33",
"estree-walker": "^2.0.2",
"magic-string": "^0.30.21",
- "postcss": "^8.5.6",
+ "postcss": "^8.5.10",
"source-map-js": "^1.2.1"
}
},
"node_modules/@vue/compiler-ssr": {
- "version": "3.5.26",
+ "version": "3.5.33",
+ "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.33.tgz",
+ "integrity": "sha512-IErjYdnj1qIupG5xxiVIYiiRvDhGWV4zuh/RCrwfYpuL+HWQzeU6lCk/nF9r7olWMnjKxCAkOctT2qFWFkzb1A==",
"license": "MIT",
"dependencies": {
- "@vue/compiler-dom": "3.5.26",
- "@vue/shared": "3.5.26"
+ "@vue/compiler-dom": "3.5.33",
+ "@vue/shared": "3.5.33"
}
},
"node_modules/@vue/devtools-api": {
@@ -1562,58 +1909,74 @@
}
},
"node_modules/@vue/reactivity": {
- "version": "3.5.26",
+ "version": "3.5.33",
+ "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.33.tgz",
+ "integrity": "sha512-p8UfIqyIhb0rYGlSgSBV+lPhF2iUSBcRy7enhTmPqKWadHy9kcOFYF1AejYBP9P+avnd3OBbD49DU4pLWX/94A==",
"license": "MIT",
"dependencies": {
- "@vue/shared": "3.5.26"
+ "@vue/shared": "3.5.33"
}
},
"node_modules/@vue/runtime-core": {
- "version": "3.5.26",
+ "version": "3.5.33",
+ "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.33.tgz",
+ "integrity": "sha512-UpFF45RI9//a7rvq7RdOQblb4tup7hHG9QsmIrxkFQLzQ7R8/iNQ5LE15NhLZ1/WcHMU2b47u6P33CPUelHyIQ==",
"license": "MIT",
"dependencies": {
- "@vue/reactivity": "3.5.26",
- "@vue/shared": "3.5.26"
+ "@vue/reactivity": "3.5.33",
+ "@vue/shared": "3.5.33"
}
},
"node_modules/@vue/runtime-dom": {
- "version": "3.5.26",
+ "version": "3.5.33",
+ "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.33.tgz",
+ "integrity": "sha512-IOxMsAOwquhfITgmOgaPYl7/j8gKUxUFoflRc+u4LxyD3+783xne8vNta1PONVCvCV9A0w7hkyEepINDqfO0tw==",
"license": "MIT",
"dependencies": {
- "@vue/reactivity": "3.5.26",
- "@vue/runtime-core": "3.5.26",
- "@vue/shared": "3.5.26",
+ "@vue/reactivity": "3.5.33",
+ "@vue/runtime-core": "3.5.33",
+ "@vue/shared": "3.5.33",
"csstype": "^3.2.3"
}
},
"node_modules/@vue/server-renderer": {
- "version": "3.5.26",
+ "version": "3.5.33",
+ "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.33.tgz",
+ "integrity": "sha512-0xylq/8/h44lVG0pZFknv1XIdEgymq2E9n59uTWJBG+dIgiT0TMCSsxrN7nO16Z0MU0MPjFcguBbZV8Itk52Hw==",
"license": "MIT",
"dependencies": {
- "@vue/compiler-ssr": "3.5.26",
- "@vue/shared": "3.5.26"
+ "@vue/compiler-ssr": "3.5.33",
+ "@vue/shared": "3.5.33"
},
"peerDependencies": {
- "vue": "3.5.26"
+ "vue": "3.5.33"
}
},
"node_modules/@vue/shared": {
- "version": "3.5.26",
+ "version": "3.5.33",
+ "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.33.tgz",
+ "integrity": "sha512-5vR2QIlmaLG77Ygd4pMP6+SGQ5yox9VhtnbDWTy9DzMzdmeLxZ1QqxrywEZ9sa1AVubfIJyaCG3ytyWU81ufcQ==",
+ "license": "MIT"
+ },
+ "node_modules/@wailsio/runtime": {
+ "version": "3.0.0-alpha.79",
+ "resolved": "https://registry.npmmirror.com/@wailsio/runtime/-/runtime-3.0.0-alpha.79.tgz",
+ "integrity": "sha512-NITzxKmJsMEruc39L166lbPJVECxzcbdqpHVqOOF7Cu/7Zqk/e3B/gNpkUjhNyo5rVb3V1wpS8oEgLUmpu1cwA==",
"license": "MIT"
},
"node_modules/@xmldom/xmldom": {
- "version": "0.8.11",
- "resolved": "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.11.tgz",
- "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==",
+ "version": "0.8.13",
+ "resolved": "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.13.tgz",
+ "integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/acorn": {
- "version": "8.15.0",
- "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz",
- "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "version": "8.16.0",
+ "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.16.0.tgz",
+ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
@@ -1646,9 +2009,9 @@
}
},
"node_modules/anymatch/node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -1669,10 +2032,14 @@
},
"node_modules/b-tween": {
"version": "0.3.3",
+ "resolved": "https://registry.npmmirror.com/b-tween/-/b-tween-0.3.3.tgz",
+ "integrity": "sha512-oEHegcRpA7fAuc9KC4nktucuZn2aS8htymCPcP3qkEGPqiBH+GfqtqoG2l7LxHngg6O0HFM7hOeOYExl1Oz4ZA==",
"license": "MIT"
},
"node_modules/b-validate": {
"version": "1.5.3",
+ "resolved": "https://registry.npmmirror.com/b-validate/-/b-validate-1.5.3.tgz",
+ "integrity": "sha512-iCvCkGFskbaYtfQ0a3GmcQCHl/Sv1GufXFGuUQ+FE+WJa7A/espLOuFIn09B944V8/ImPj71T4+rTASxO2PAuA==",
"license": "MIT"
},
"node_modules/balanced-match": {
@@ -1731,9 +2098,9 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.1.0.tgz",
+ "integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1767,37 +2134,34 @@
}
},
"node_modules/chevrotain": {
- "version": "11.0.3",
- "resolved": "https://registry.npmmirror.com/chevrotain/-/chevrotain-11.0.3.tgz",
- "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==",
+ "version": "12.0.0",
+ "resolved": "https://registry.npmmirror.com/chevrotain/-/chevrotain-12.0.0.tgz",
+ "integrity": "sha512-csJvb+6kEiQaqo1woTdSAuOWdN0WTLIydkKrBnS+V5gZz0oqBrp4kQ35519QgK6TpBThiG3V1vNSHlIkv4AglQ==",
"license": "Apache-2.0",
+ "peer": true,
"dependencies": {
- "@chevrotain/cst-dts-gen": "11.0.3",
- "@chevrotain/gast": "11.0.3",
- "@chevrotain/regexp-to-ast": "11.0.3",
- "@chevrotain/types": "11.0.3",
- "@chevrotain/utils": "11.0.3",
- "lodash-es": "4.17.21"
+ "@chevrotain/cst-dts-gen": "12.0.0",
+ "@chevrotain/gast": "12.0.0",
+ "@chevrotain/regexp-to-ast": "12.0.0",
+ "@chevrotain/types": "12.0.0",
+ "@chevrotain/utils": "12.0.0"
+ },
+ "engines": {
+ "node": ">=22.0.0"
}
},
"node_modules/chevrotain-allstar": {
- "version": "0.3.1",
- "resolved": "https://registry.npmmirror.com/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz",
- "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==",
+ "version": "0.4.3",
+ "resolved": "https://registry.npmmirror.com/chevrotain-allstar/-/chevrotain-allstar-0.4.3.tgz",
+ "integrity": "sha512-2X4mkroolSMKqW+H22pyPMUVDqYZzPhephTmg/NODKb1IGYPHfxfhcW0EjS7wcPJNbze2i4vBWT7zT5FKF2lrQ==",
"license": "MIT",
"dependencies": {
- "lodash-es": "^4.17.21"
+ "lodash-es": "^4.18.1"
},
"peerDependencies": {
- "chevrotain": "^11.0.0"
+ "chevrotain": "^12.0.0"
}
},
- "node_modules/chevrotain/node_modules/lodash-es": {
- "version": "4.17.21",
- "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz",
- "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
- "license": "MIT"
- },
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz",
@@ -1834,6 +2198,8 @@
},
"node_modules/color": {
"version": "3.2.1",
+ "resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz",
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
"license": "MIT",
"dependencies": {
"color-convert": "^1.9.3",
@@ -1842,6 +2208,8 @@
},
"node_modules/color-convert": {
"version": "1.9.3",
+ "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"license": "MIT",
"dependencies": {
"color-name": "1.1.3"
@@ -1849,10 +2217,14 @@
},
"node_modules/color-name": {
"version": "1.1.3",
+ "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"license": "MIT"
},
"node_modules/color-string": {
"version": "1.9.1",
+ "resolved": "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
"license": "MIT",
"dependencies": {
"color-name": "^1.0.0",
@@ -1870,6 +2242,8 @@
},
"node_modules/compute-scroll-into-view": {
"version": "1.0.20",
+ "resolved": "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
+ "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==",
"license": "MIT"
},
"node_modules/confbox": {
@@ -1928,12 +2302,14 @@
},
"node_modules/csstype": {
"version": "3.2.3",
+ "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"license": "MIT"
},
"node_modules/cytoscape": {
- "version": "3.33.1",
- "resolved": "https://registry.npmmirror.com/cytoscape/-/cytoscape-3.33.1.tgz",
- "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==",
+ "version": "3.33.3",
+ "resolved": "https://registry.npmmirror.com/cytoscape/-/cytoscape-3.33.3.tgz",
+ "integrity": "sha512-Gej7U+OKR+LZ8kvX7rb2HhCYJ0IhvEFsnkud4SB1PR+BUY/TsSO0dmOW59WEVLu51b1Rm+gQRKoz4bLYxGSZ2g==",
"license": "MIT",
"peer": true,
"engines": {
@@ -2422,9 +2798,9 @@
}
},
"node_modules/dagre-d3-es": {
- "version": "7.0.13",
- "resolved": "https://registry.npmmirror.com/dagre-d3-es/-/dagre-d3-es-7.0.13.tgz",
- "integrity": "sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==",
+ "version": "7.0.14",
+ "resolved": "https://registry.npmmirror.com/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz",
+ "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==",
"license": "MIT",
"dependencies": {
"d3": "^7.9.0",
@@ -2432,7 +2808,9 @@
}
},
"node_modules/dayjs": {
- "version": "1.11.19",
+ "version": "1.11.20",
+ "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.20.tgz",
+ "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==",
"license": "MIT"
},
"node_modules/debug": {
@@ -2454,9 +2832,9 @@
}
},
"node_modules/delaunator": {
- "version": "5.0.1",
- "resolved": "https://registry.npmmirror.com/delaunator/-/delaunator-5.0.1.tgz",
- "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmmirror.com/delaunator/-/delaunator-5.1.0.tgz",
+ "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==",
"license": "ISC",
"dependencies": {
"robust-predicates": "^3.0.2"
@@ -2469,9 +2847,9 @@
"license": "BSD-2-Clause"
},
"node_modules/dompurify": {
- "version": "3.3.1",
- "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.3.1.tgz",
- "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==",
+ "version": "3.4.2",
+ "resolved": "https://registry.npmmirror.com/dompurify/-/dompurify-3.4.2.tgz",
+ "integrity": "sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==",
"license": "(MPL-2.0 OR Apache-2.0)",
"optionalDependencies": {
"@types/trusted-types": "^2.0.7"
@@ -2487,7 +2865,9 @@
}
},
"node_modules/entities": {
- "version": "7.0.0",
+ "version": "7.0.1",
+ "resolved": "https://registry.npmmirror.com/entities/-/entities-7.0.1.tgz",
+ "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
@@ -2497,9 +2877,9 @@
}
},
"node_modules/esbuild": {
- "version": "0.27.2",
- "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.27.2.tgz",
- "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==",
+ "version": "0.27.7",
+ "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.27.7.tgz",
+ "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
@@ -2510,32 +2890,32 @@
"node": ">=18"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.27.2",
- "@esbuild/android-arm": "0.27.2",
- "@esbuild/android-arm64": "0.27.2",
- "@esbuild/android-x64": "0.27.2",
- "@esbuild/darwin-arm64": "0.27.2",
- "@esbuild/darwin-x64": "0.27.2",
- "@esbuild/freebsd-arm64": "0.27.2",
- "@esbuild/freebsd-x64": "0.27.2",
- "@esbuild/linux-arm": "0.27.2",
- "@esbuild/linux-arm64": "0.27.2",
- "@esbuild/linux-ia32": "0.27.2",
- "@esbuild/linux-loong64": "0.27.2",
- "@esbuild/linux-mips64el": "0.27.2",
- "@esbuild/linux-ppc64": "0.27.2",
- "@esbuild/linux-riscv64": "0.27.2",
- "@esbuild/linux-s390x": "0.27.2",
- "@esbuild/linux-x64": "0.27.2",
- "@esbuild/netbsd-arm64": "0.27.2",
- "@esbuild/netbsd-x64": "0.27.2",
- "@esbuild/openbsd-arm64": "0.27.2",
- "@esbuild/openbsd-x64": "0.27.2",
- "@esbuild/openharmony-arm64": "0.27.2",
- "@esbuild/sunos-x64": "0.27.2",
- "@esbuild/win32-arm64": "0.27.2",
- "@esbuild/win32-ia32": "0.27.2",
- "@esbuild/win32-x64": "0.27.2"
+ "@esbuild/aix-ppc64": "0.27.7",
+ "@esbuild/android-arm": "0.27.7",
+ "@esbuild/android-arm64": "0.27.7",
+ "@esbuild/android-x64": "0.27.7",
+ "@esbuild/darwin-arm64": "0.27.7",
+ "@esbuild/darwin-x64": "0.27.7",
+ "@esbuild/freebsd-arm64": "0.27.7",
+ "@esbuild/freebsd-x64": "0.27.7",
+ "@esbuild/linux-arm": "0.27.7",
+ "@esbuild/linux-arm64": "0.27.7",
+ "@esbuild/linux-ia32": "0.27.7",
+ "@esbuild/linux-loong64": "0.27.7",
+ "@esbuild/linux-mips64el": "0.27.7",
+ "@esbuild/linux-ppc64": "0.27.7",
+ "@esbuild/linux-riscv64": "0.27.7",
+ "@esbuild/linux-s390x": "0.27.7",
+ "@esbuild/linux-x64": "0.27.7",
+ "@esbuild/netbsd-arm64": "0.27.7",
+ "@esbuild/netbsd-x64": "0.27.7",
+ "@esbuild/openbsd-arm64": "0.27.7",
+ "@esbuild/openbsd-x64": "0.27.7",
+ "@esbuild/openharmony-arm64": "0.27.7",
+ "@esbuild/sunos-x64": "0.27.7",
+ "@esbuild/win32-arm64": "0.27.7",
+ "@esbuild/win32-ia32": "0.27.7",
+ "@esbuild/win32-x64": "0.27.7"
}
},
"node_modules/escape-string-regexp": {
@@ -2553,6 +2933,8 @@
},
"node_modules/estree-walker": {
"version": "2.0.2",
+ "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"license": "MIT"
},
"node_modules/exsolve": {
@@ -2713,6 +3095,8 @@
},
"node_modules/is-arrayish": {
"version": "0.3.4",
+ "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.4.tgz",
+ "integrity": "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==",
"license": "MIT"
},
"node_modules/is-binary-path": {
@@ -2799,9 +3183,9 @@
}
},
"node_modules/katex": {
- "version": "0.16.28",
- "resolved": "https://registry.npmmirror.com/katex/-/katex-0.16.28.tgz",
- "integrity": "sha512-YHzO7721WbmAL6Ov1uzN/l5mY5WWWhJBSW+jq4tkfZfsxmo1hu6frS0EOswvjBUnWE6NtjEs48SFn5CQESRLZg==",
+ "version": "0.16.45",
+ "resolved": "https://registry.npmmirror.com/katex/-/katex-0.16.45.tgz",
+ "integrity": "sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==",
"funding": [
"https://opencollective.com/katex",
"https://github.com/sponsors/katex"
@@ -2829,19 +3213,21 @@
"integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw=="
},
"node_modules/langium": {
- "version": "3.3.1",
- "resolved": "https://registry.npmmirror.com/langium/-/langium-3.3.1.tgz",
- "integrity": "sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==",
+ "version": "4.2.2",
+ "resolved": "https://registry.npmmirror.com/langium/-/langium-4.2.2.tgz",
+ "integrity": "sha512-JUshTRAfHI4/MF9dH2WupvjSXyn8JBuUEWazB8ZVJUtXutT0doDlAv1XKbZ1Pb5sMexa8FF4CFBc0iiul7gbUQ==",
"license": "MIT",
"dependencies": {
- "chevrotain": "~11.0.3",
- "chevrotain-allstar": "~0.3.0",
+ "@chevrotain/regexp-to-ast": "~12.0.0",
+ "chevrotain": "~12.0.0",
+ "chevrotain-allstar": "~0.4.1",
"vscode-languageserver": "~9.0.1",
"vscode-languageserver-textdocument": "~1.0.11",
- "vscode-uri": "~3.0.8"
+ "vscode-uri": "~3.1.0"
},
"engines": {
- "node": ">=16.0.0"
+ "node": ">=20.10.0",
+ "npm": ">=10.2.3"
}
},
"node_modules/layout-base": {
@@ -2877,9 +3263,9 @@
}
},
"node_modules/lodash-es": {
- "version": "4.17.23",
- "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.23.tgz",
- "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==",
+ "version": "4.18.1",
+ "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.18.1.tgz",
+ "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==",
"license": "MIT"
},
"node_modules/lop": {
@@ -2895,15 +3281,17 @@
},
"node_modules/magic-string": {
"version": "0.30.21",
+ "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"license": "MIT",
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/mammoth": {
- "version": "1.11.0",
- "resolved": "https://registry.npmmirror.com/mammoth/-/mammoth-1.11.0.tgz",
- "integrity": "sha512-BcEqqY/BOwIcI1iR5tqyVlqc3KIaMRa4egSoK83YAVrBf6+yqdAAbtUcFDCWX8Zef8/fgNZ6rl4VUv+vVX8ddQ==",
+ "version": "1.12.0",
+ "resolved": "https://registry.npmmirror.com/mammoth/-/mammoth-1.12.0.tgz",
+ "integrity": "sha512-cwnK1RIcRdDMi2HRx2EXGYlxqIEh0Oo3bLhorgnsVJi2UkbX1+jKxuBNR9PC5+JaX7EkmJxFPmo6mjLpqShI2w==",
"license": "BSD-2-Clause",
"dependencies": {
"@xmldom/xmldom": "^0.8.6",
@@ -2925,9 +3313,9 @@
}
},
"node_modules/marked": {
- "version": "17.0.1",
- "resolved": "https://registry.npmmirror.com/marked/-/marked-17.0.1.tgz",
- "integrity": "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==",
+ "version": "17.0.6",
+ "resolved": "https://registry.npmmirror.com/marked/-/marked-17.0.6.tgz",
+ "integrity": "sha512-gB0gkNafnonOw0obSTEGZTT86IuhILt2Wfx0mWH/1Au83kybTayroZ/V6nS25mN7u8ASy+5fMhgB3XPNrOZdmA==",
"license": "MIT",
"bin": {
"marked": "bin/marked.js"
@@ -2947,27 +3335,28 @@
}
},
"node_modules/mermaid": {
- "version": "11.12.2",
- "resolved": "https://registry.npmmirror.com/mermaid/-/mermaid-11.12.2.tgz",
- "integrity": "sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w==",
+ "version": "11.14.0",
+ "resolved": "https://registry.npmmirror.com/mermaid/-/mermaid-11.14.0.tgz",
+ "integrity": "sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==",
"license": "MIT",
"dependencies": {
"@braintree/sanitize-url": "^7.1.1",
- "@iconify/utils": "^3.0.1",
- "@mermaid-js/parser": "^0.6.3",
+ "@iconify/utils": "^3.0.2",
+ "@mermaid-js/parser": "^1.1.0",
"@types/d3": "^7.4.3",
- "cytoscape": "^3.29.3",
+ "@upsetjs/venn.js": "^2.0.0",
+ "cytoscape": "^3.33.1",
"cytoscape-cose-bilkent": "^4.1.0",
"cytoscape-fcose": "^2.2.0",
"d3": "^7.9.0",
"d3-sankey": "^0.12.3",
- "dagre-d3-es": "7.0.13",
- "dayjs": "^1.11.18",
- "dompurify": "^3.2.5",
- "katex": "^0.16.22",
+ "dagre-d3-es": "7.0.14",
+ "dayjs": "^1.11.19",
+ "dompurify": "^3.3.1",
+ "katex": "^0.16.25",
"khroma": "^2.1.0",
- "lodash-es": "^4.17.21",
- "marked": "^16.2.1",
+ "lodash-es": "^4.17.23",
+ "marked": "^16.3.0",
"roughjs": "^4.6.6",
"stylis": "^4.3.6",
"ts-dedent": "^2.2.0",
@@ -3001,9 +3390,9 @@
}
},
"node_modules/micromatch/node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3014,13 +3403,13 @@
}
},
"node_modules/minimatch": {
- "version": "9.0.5",
- "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz",
- "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "version": "9.0.9",
+ "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.9.tgz",
+ "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"dev": true,
"license": "ISC",
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "brace-expansion": "^2.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -3036,15 +3425,15 @@
"license": "MIT"
},
"node_modules/mlly": {
- "version": "1.8.0",
- "resolved": "https://registry.npmmirror.com/mlly/-/mlly-1.8.0.tgz",
- "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==",
+ "version": "1.8.2",
+ "resolved": "https://registry.npmmirror.com/mlly/-/mlly-1.8.2.tgz",
+ "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==",
"license": "MIT",
"dependencies": {
- "acorn": "^8.15.0",
+ "acorn": "^8.16.0",
"pathe": "^2.0.3",
"pkg-types": "^1.3.1",
- "ufo": "^1.6.1"
+ "ufo": "^1.6.3"
}
},
"node_modules/ms": {
@@ -3055,7 +3444,9 @@
"license": "MIT"
},
"node_modules/nanoid": {
- "version": "3.3.11",
+ "version": "3.3.12",
+ "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.12.tgz",
+ "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
"funding": [
{
"type": "github",
@@ -3082,6 +3473,8 @@
},
"node_modules/number-precision": {
"version": "1.6.0",
+ "resolved": "https://registry.npmmirror.com/number-precision/-/number-precision-1.6.0.tgz",
+ "integrity": "sha512-05OLPgbgmnixJw+VvEh18yNPUo3iyp4BEWJcrLu4X9W05KmMifN7Mu5exYvQXqxxeNWhvIF+j3Rij+HmddM/hQ==",
"license": "MIT"
},
"node_modules/option": {
@@ -3131,12 +3524,14 @@
},
"node_modules/picocolors": {
"version": "1.1.1",
+ "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3195,7 +3590,9 @@
}
},
"node_modules/postcss": {
- "version": "8.5.6",
+ "version": "8.5.13",
+ "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.13.tgz",
+ "integrity": "sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==",
"funding": [
{
"type": "opencollective",
@@ -3293,9 +3690,9 @@
}
},
"node_modules/readdirp/node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3307,6 +3704,8 @@
},
"node_modules/resize-observer-polyfill": {
"version": "1.5.1",
+ "resolved": "https://registry.npmmirror.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
+ "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==",
"license": "MIT"
},
"node_modules/reusify": {
@@ -3327,13 +3726,15 @@
"license": "MIT"
},
"node_modules/robust-predicates": {
- "version": "3.0.2",
- "resolved": "https://registry.npmmirror.com/robust-predicates/-/robust-predicates-3.0.2.tgz",
- "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmmirror.com/robust-predicates/-/robust-predicates-3.0.3.tgz",
+ "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==",
"license": "Unlicense"
},
"node_modules/rollup": {
- "version": "4.54.0",
+ "version": "4.60.2",
+ "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.60.2.tgz",
+ "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -3348,28 +3749,31 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.54.0",
- "@rollup/rollup-android-arm64": "4.54.0",
- "@rollup/rollup-darwin-arm64": "4.54.0",
- "@rollup/rollup-darwin-x64": "4.54.0",
- "@rollup/rollup-freebsd-arm64": "4.54.0",
- "@rollup/rollup-freebsd-x64": "4.54.0",
- "@rollup/rollup-linux-arm-gnueabihf": "4.54.0",
- "@rollup/rollup-linux-arm-musleabihf": "4.54.0",
- "@rollup/rollup-linux-arm64-gnu": "4.54.0",
- "@rollup/rollup-linux-arm64-musl": "4.54.0",
- "@rollup/rollup-linux-loong64-gnu": "4.54.0",
- "@rollup/rollup-linux-ppc64-gnu": "4.54.0",
- "@rollup/rollup-linux-riscv64-gnu": "4.54.0",
- "@rollup/rollup-linux-riscv64-musl": "4.54.0",
- "@rollup/rollup-linux-s390x-gnu": "4.54.0",
- "@rollup/rollup-linux-x64-gnu": "4.54.0",
- "@rollup/rollup-linux-x64-musl": "4.54.0",
- "@rollup/rollup-openharmony-arm64": "4.54.0",
- "@rollup/rollup-win32-arm64-msvc": "4.54.0",
- "@rollup/rollup-win32-ia32-msvc": "4.54.0",
- "@rollup/rollup-win32-x64-gnu": "4.54.0",
- "@rollup/rollup-win32-x64-msvc": "4.54.0",
+ "@rollup/rollup-android-arm-eabi": "4.60.2",
+ "@rollup/rollup-android-arm64": "4.60.2",
+ "@rollup/rollup-darwin-arm64": "4.60.2",
+ "@rollup/rollup-darwin-x64": "4.60.2",
+ "@rollup/rollup-freebsd-arm64": "4.60.2",
+ "@rollup/rollup-freebsd-x64": "4.60.2",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.60.2",
+ "@rollup/rollup-linux-arm-musleabihf": "4.60.2",
+ "@rollup/rollup-linux-arm64-gnu": "4.60.2",
+ "@rollup/rollup-linux-arm64-musl": "4.60.2",
+ "@rollup/rollup-linux-loong64-gnu": "4.60.2",
+ "@rollup/rollup-linux-loong64-musl": "4.60.2",
+ "@rollup/rollup-linux-ppc64-gnu": "4.60.2",
+ "@rollup/rollup-linux-ppc64-musl": "4.60.2",
+ "@rollup/rollup-linux-riscv64-gnu": "4.60.2",
+ "@rollup/rollup-linux-riscv64-musl": "4.60.2",
+ "@rollup/rollup-linux-s390x-gnu": "4.60.2",
+ "@rollup/rollup-linux-x64-gnu": "4.60.2",
+ "@rollup/rollup-linux-x64-musl": "4.60.2",
+ "@rollup/rollup-openbsd-x64": "4.60.2",
+ "@rollup/rollup-openharmony-arm64": "4.60.2",
+ "@rollup/rollup-win32-arm64-msvc": "4.60.2",
+ "@rollup/rollup-win32-ia32-msvc": "4.60.2",
+ "@rollup/rollup-win32-x64-gnu": "4.60.2",
+ "@rollup/rollup-win32-x64-msvc": "4.60.2",
"fsevents": "~2.3.2"
}
},
@@ -3429,6 +3833,8 @@
},
"node_modules/scroll-into-view-if-needed": {
"version": "2.2.31",
+ "resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz",
+ "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==",
"license": "MIT",
"dependencies": {
"compute-scroll-into-view": "^1.0.20"
@@ -3449,6 +3855,8 @@
},
"node_modules/simple-swizzle": {
"version": "0.2.4",
+ "resolved": "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.4.tgz",
+ "integrity": "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==",
"license": "MIT",
"dependencies": {
"is-arrayish": "^0.3.1"
@@ -3456,6 +3864,8 @@
},
"node_modules/source-map-js": {
"version": "1.2.1",
+ "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -3517,9 +3927,9 @@
"license": "MIT"
},
"node_modules/stylis": {
- "version": "4.3.6",
- "resolved": "https://registry.npmmirror.com/stylis/-/stylis-4.3.6.tgz",
- "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==",
+ "version": "4.4.0",
+ "resolved": "https://registry.npmmirror.com/stylis/-/stylis-4.4.0.tgz",
+ "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==",
"license": "MIT"
},
"node_modules/superjson": {
@@ -3535,23 +3945,23 @@
}
},
"node_modules/tinyexec": {
- "version": "1.0.2",
- "resolved": "https://registry.npmmirror.com/tinyexec/-/tinyexec-1.0.2.tgz",
- "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==",
+ "version": "1.1.2",
+ "resolved": "https://registry.npmmirror.com/tinyexec/-/tinyexec-1.1.2.tgz",
+ "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/tinyglobby": {
- "version": "0.2.15",
- "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.15.tgz",
- "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "version": "0.2.16",
+ "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.16.tgz",
+ "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
"dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
- "picomatch": "^4.0.3"
+ "picomatch": "^4.0.4"
},
"engines": {
"node": ">=12.0.0"
@@ -3583,15 +3993,15 @@
}
},
"node_modules/ufo": {
- "version": "1.6.3",
- "resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.6.3.tgz",
- "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==",
+ "version": "1.6.4",
+ "resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.6.4.tgz",
+ "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==",
"license": "MIT"
},
"node_modules/underscore": {
- "version": "1.13.7",
- "resolved": "https://registry.npmmirror.com/underscore/-/underscore-1.13.7.tgz",
- "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==",
+ "version": "1.13.8",
+ "resolved": "https://registry.npmmirror.com/underscore/-/underscore-1.13.8.tgz",
+ "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==",
"license": "MIT"
},
"node_modules/unimport": {
@@ -3618,9 +4028,9 @@
}
},
"node_modules/unimport/node_modules/confbox": {
- "version": "0.2.2",
- "resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.2.2.tgz",
- "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
+ "version": "0.2.4",
+ "resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.2.4.tgz",
+ "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==",
"dev": true,
"license": "MIT"
},
@@ -3653,14 +4063,14 @@
}
},
"node_modules/unimport/node_modules/local-pkg/node_modules/pkg-types": {
- "version": "2.3.0",
- "resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-2.3.0.tgz",
- "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==",
+ "version": "2.3.1",
+ "resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-2.3.1.tgz",
+ "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==",
"dev": true,
"license": "MIT",
"dependencies": {
- "confbox": "^0.2.2",
- "exsolve": "^1.0.7",
+ "confbox": "^0.2.4",
+ "exsolve": "^1.0.8",
"pathe": "^2.0.3"
}
},
@@ -3758,9 +4168,9 @@
"license": "MIT"
},
"node_modules/uuid": {
- "version": "11.1.0",
- "resolved": "https://registry.npmmirror.com/uuid/-/uuid-11.1.0.tgz",
- "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
+ "version": "11.1.1",
+ "resolved": "https://registry.npmmirror.com/uuid/-/uuid-11.1.1.tgz",
+ "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
@@ -3771,9 +4181,9 @@
}
},
"node_modules/vite": {
- "version": "7.3.0",
- "resolved": "https://registry.npmmirror.com/vite/-/vite-7.3.0.tgz",
- "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==",
+ "version": "7.3.2",
+ "resolved": "https://registry.npmmirror.com/vite/-/vite-7.3.2.tgz",
+ "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==",
"dev": true,
"license": "MIT",
"peer": true,
@@ -3890,21 +4300,23 @@
"license": "MIT"
},
"node_modules/vscode-uri": {
- "version": "3.0.8",
- "resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.0.8.tgz",
- "integrity": "sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz",
+ "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
"license": "MIT"
},
"node_modules/vue": {
- "version": "3.5.26",
+ "version": "3.5.33",
+ "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.33.tgz",
+ "integrity": "sha512-1AgChhx5w3ALgT4oK3acm2Es/7jyZhWSVUfs3rOBlGQC0rjEDkS7G4lWlJJGGNQD+BV3reCwbQrOe1mPNwKHBQ==",
"license": "MIT",
"peer": true,
"dependencies": {
- "@vue/compiler-dom": "3.5.26",
- "@vue/compiler-sfc": "3.5.26",
- "@vue/runtime-dom": "3.5.26",
- "@vue/server-renderer": "3.5.26",
- "@vue/shared": "3.5.26"
+ "@vue/compiler-dom": "3.5.33",
+ "@vue/compiler-sfc": "3.5.33",
+ "@vue/runtime-dom": "3.5.33",
+ "@vue/server-renderer": "3.5.33",
+ "@vue/shared": "3.5.33"
},
"peerDependencies": {
"typescript": "*"
diff --git a/web/package.json b/frontend/package.json
similarity index 94%
rename from web/package.json
rename to frontend/package.json
index 04fb609..9681ddb 100644
--- a/web/package.json
+++ b/frontend/package.json
@@ -5,6 +5,7 @@
"scripts": {
"dev": "vite",
"build": "vite build",
+ "build:dev": "vite build --mode development",
"preview": "vite preview"
},
"dependencies": {
@@ -33,6 +34,7 @@
"mammoth": "^1.11.0",
"marked": "^17.0.1",
"mermaid": "^11.12.2",
+ "@wailsio/runtime": "latest",
"pinia": "^3.0.4",
"vue": "^3.5.26",
"xlsx": "^0.18.5"
diff --git a/web/scripts/check.sh b/frontend/scripts/check.sh
similarity index 100%
rename from web/scripts/check.sh
rename to frontend/scripts/check.sh
diff --git a/web/src/App.vue b/frontend/src/App.vue
similarity index 90%
rename from web/src/App.vue
rename to frontend/src/App.vue
index 00e317c..4e9c3f7 100644
--- a/web/src/App.vue
+++ b/frontend/src/App.vue
@@ -1,6 +1,6 @@
-