inputs > defaults.
+- Supported envs:
+ - `DENO_ENABLE` — `true`/`1`/`yes`/`on` explicitly enables Deno
+ - `DENO_BUILD` — full command to run (e.g., `deno task build`)
+ - `DENO_VERSION` — e.g., `v1.44.x`
+ - `DENO_WORKDIR` — working directory for Deno (default `.`)
+ - Pass-through: `DENO_AUTH_TOKEN`, `DENO_DIR`, proxies, etc.
+
+Behavior
+- Calls sub-actions in order: `setup/go`, `setup/npm`, `setup/deno`, and optionally `setup/conan`.
+- Resolves Deno configuration and sets up Deno only when enabled; runs the command when provided.
+
+Usage
+```yaml
+- name: Setup toolchains
+ uses: snider/build/actions/setup@v3
+ with:
+ go-version: '1.23'
+ build-cache: 'true'
+ build-obfuscate: 'false'
+ wails-version: 'latest'
+ node-version: '18.x'
+ npm-working-directory: 'build/wails2'
+ npm-install: 'true'
+ env:
+ # Optional Deno via env
+ DENO_ENABLE: 'true'
+ DENO_VERSION: 'v1.44.x'
+ DENO_WORKDIR: 'frontend'
+ DENO_BUILD: 'deno task build'
+```
+
+Notes
+- On macOS, `gon` is installed for later signing steps. No-op on other OSes.
+- If you do not need Deno, leave envs and inputs empty — it will be skipped.
+- If `wails-dev-build` is `true`, ensure `wails` is already available on PATH.
diff --git a/actions/setup/action.yml b/actions/setup/action.yml
new file mode 100644
index 0000000..0da2adf
--- /dev/null
+++ b/actions/setup/action.yml
@@ -0,0 +1,69 @@
+name: "Setup toolchains"
+description: "Orchestrates language/tool setup by delegating to sub-actions: setup/go, setup/npm, setup/deno, setup/conan"
+inputs:
+ # Go/Wails
+ go-version:
+ required: false
+ default: "1.23"
+ build-cache:
+ required: false
+ default: "true"
+ build-obfuscate:
+ required: false
+ default: "false"
+ wails-version:
+ required: false
+ default: "latest"
+ wails-dev-build:
+ required: false
+ default: "false"
+ # Node/npm
+ node-version:
+ required: false
+ default: "18.x"
+ npm-working-directory:
+ required: false
+ default: "."
+ npm-install:
+ required: false
+ default: "true"
+ # Deno
+ deno-build:
+ required: false
+ default: ""
+ deno-version:
+ required: false
+ default: "v1.20.x"
+ deno-working-directory:
+ required: false
+ default: "."
+ # Conan (placeholder)
+ conan-enable:
+ required: false
+ default: "false"
+runs:
+ using: "composite"
+ steps:
+ - name: Setup Go
+ uses: ./actions/setup/go
+ with:
+ go-version: ${{ inputs.go-version }}
+ build-cache: ${{ inputs.build-cache }}
+ build-obfuscate: ${{ inputs.build-obfuscate }}
+ wails-version: ${{ inputs.wails-version }}
+ wails-dev-build: ${{ inputs.wails-dev-build }}
+ - name: Setup Node/npm
+ uses: ./actions/setup/npm
+ with:
+ node-version: ${{ inputs.node-version }}
+ working-directory: ${{ inputs.npm-working-directory }}
+ install: ${{ inputs.npm-install }}
+ - name: Setup Deno (optional)
+ uses: ./actions/setup/deno
+ with:
+ deno-build: ${{ inputs.deno-build }}
+ deno-version: ${{ inputs.deno-version }}
+ deno-working-directory: ${{ inputs.deno-working-directory }}
+ - name: Setup Conan (optional)
+ if: inputs.conan-enable == 'true'
+ uses: ./actions/setup/conan
diff --git a/actions/setup/conan/action.yml b/actions/setup/conan/action.yml
new file mode 100644
index 0000000..fbaf542
--- /dev/null
+++ b/actions/setup/conan/action.yml
@@ -0,0 +1,25 @@
+name: "Setup Conan (placeholder)"
+description: "Installs Conan package manager for C/C++ projects (future use)"
+inputs:
+ version:
+ required: false
+ default: "latest"
+runs:
+ using: "composite"
+ steps:
+ - name: Install Python (for pip)
+ if: runner.os == 'Windows'
+ uses: actions/setup-python@v5
+ with:
+ python-version: '3.x'
+ - name: Install Conan via pip
+ shell: bash
+ run: |
+ set -euo pipefail
+ if command -v pip3 >/dev/null 2>&1; then PIP=pip3; elif command -v pip >/dev/null 2>&1; then PIP=pip; else echo "pip not found" && exit 1; fi
+ if [ "${{ inputs.version }}" = "latest" ]; then
+ $PIP install --user conan
+ else
+ $PIP install --user conan=="${{ inputs.version }}"
+ fi
+ echo "Conan installed. Add ~/.local/bin to PATH if needed."
diff --git a/actions/setup/deno/README.md b/actions/setup/deno/README.md
new file mode 100644
index 0000000..ae2685a
--- /dev/null
+++ b/actions/setup/deno/README.md
@@ -0,0 +1,50 @@
+# Setup Deno (sub-action)
+
+Purpose
+- Optional Deno setup and command runner with ENV-first configuration.
+- Can be used independently or via the `actions/setup` orchestrator.
+
+Behavior
+- Resolves configuration from environment variables first, then falls back to inputs.
+- Installs the requested Deno version on Linux/macOS/Windows.
+- Runs the provided Deno command in the specified working directory when present.
+
+ENV-first precedence
+- Environment variables > inputs > defaults.
+- Supported envs:
+ - `DENO_ENABLE` — `true`/`1`/`yes`/`on` to explicitly enable Deno setup.
+ - `DENO_BUILD` — full command to run (e.g., `deno task build`, `deno run -A build.ts`).
+ - `DENO_VERSION` — e.g., `v1.44.x`.
+ - `DENO_WORKDIR` — working directory for Deno (default `.`).
+- Pass-through (if set in your workflow env): `DENO_AUTH_TOKEN`, `DENO_DIR`, `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`, etc.
+
+Inputs (fallbacks)
+- `deno-build` (default `''`)
+- `deno-version` (default `v1.20.x`)
+- `deno-working-directory` (default `.`)
+
+Usage (direct)
+```yaml
+- name: Setup Deno (direct)
+ uses: snider/build/actions/setup/deno@v3
+ with:
+ deno-version: 'v1.44.x'
+ deno-working-directory: 'frontend'
+ deno-build: 'deno task build'
+```
+
+Usage (ENV-first; recommended)
+```yaml
+- name: Configure Deno via env
+ run: |
+ echo "DENO_ENABLE=true" >> "$GITHUB_ENV"
+ echo "DENO_VERSION=v1.44.x" >> "$GITHUB_ENV"
+ echo "DENO_WORKDIR=frontend" >> "$GITHUB_ENV"
+ echo "DENO_BUILD=deno task build" >> "$GITHUB_ENV"
+- name: Setup toolchains (orchestrator)
+ uses: snider/build/actions/setup@v3
+```
+
+Notes
+- If you do not set any of the envs or inputs, this action is a no-op.
+- This sub-action is stack-agnostic and can be used for non-Wails projects as well.
diff --git a/actions/setup/deno/action.yml b/actions/setup/deno/action.yml
new file mode 100644
index 0000000..cdfd5d8
--- /dev/null
+++ b/actions/setup/deno/action.yml
@@ -0,0 +1,51 @@
+name: "Setup Deno (ENV-first)"
+description: "Sets up Deno and optionally runs a Deno command; configuration comes from env first, then inputs"
+inputs:
+ deno-build:
+ required: false
+ default: ""
+ deno-version:
+ required: false
+ default: "v1.20.x"
+ deno-working-directory:
+ required: false
+ default: "."
+runs:
+ using: "composite"
+ steps:
+ - name: Resolve Deno configuration
+ id: deno_cfg
+ shell: bash
+ env:
+ INPUT_DENO_BUILD: ${{ inputs.deno-build }}
+ INPUT_DENO_VERSION: ${{ inputs.deno-version }}
+ INPUT_DENO_WORKDIR: ${{ inputs.deno-working-directory }}
+ run: |
+ set -euo pipefail
+ deno_enable="${DENO_ENABLE:-}"
+ deno_build="${DENO_BUILD:-}"
+ deno_version="${DENO_VERSION:-}"
+ deno_workdir="${DENO_WORKDIR:-}"
+ # Fallback to inputs if env not set
+ if [ -z "$deno_build" ]; then deno_build="$INPUT_DENO_BUILD"; fi
+ if [ -z "$deno_version" ]; then deno_version="$INPUT_DENO_VERSION"; fi
+ if [ -z "$deno_workdir" ]; then deno_workdir="$INPUT_DENO_WORKDIR"; fi
+ enabled=0
+ case "${deno_enable,,}" in
+ true|1|yes|on) enabled=1;;
+ esac
+ if [ -n "$deno_build" ]; then enabled=1; fi
+ echo "ENABLED=$enabled" >> "$GITHUB_OUTPUT"
+ echo "BUILD=$deno_build" >> "$GITHUB_OUTPUT"
+ echo "VERSION=$deno_version" >> "$GITHUB_OUTPUT"
+ echo "WORKDIR=${deno_workdir:-.}" >> "$GITHUB_OUTPUT"
+ - name: Setup Deno
+ uses: denoland/setup-deno@v2
+ if: steps.deno_cfg.outputs.ENABLED == '1'
+ with:
+ deno-version: ${{ steps.deno_cfg.outputs.VERSION }}
+ - name: Run Deno Command
+ if: steps.deno_cfg.outputs.BUILD != ''
+ shell: bash
+ working-directory: ${{ steps.deno_cfg.outputs.WORKDIR }}
+ run: ${{ steps.deno_cfg.outputs.BUILD }}
diff --git a/actions/setup/go/action.yml b/actions/setup/go/action.yml
new file mode 100644
index 0000000..dc4c8dc
--- /dev/null
+++ b/actions/setup/go/action.yml
@@ -0,0 +1,43 @@
+name: "Setup Go (and Wails)"
+description: "Sets up Go (with optional cache), installs Garble when obfuscating, installs Wails CLI unless wails-dev-build is true; installs gon on macOS"
+inputs:
+ go-version:
+ required: false
+ default: "1.23"
+ build-cache:
+ required: false
+ default: "true"
+ build-obfuscate:
+ required: false
+ default: "false"
+ wails-version:
+ required: false
+ default: "latest"
+ wails-dev-build:
+ required: false
+ default: "false"
+runs:
+ using: "composite"
+ steps:
+ - name: Setup GoLang
+ uses: actions/setup-go@v5
+ if: inputs.wails-dev-build == 'false'
+ with:
+ check-latest: true
+ cache: ${{ inputs.build-cache }}
+ cache-dependency-path: 'go.sum'
+ go-version: ${{ inputs.go-version }}
+ - name: Install Garble
+ if: inputs.build-obfuscate == 'true'
+ run: go install mvdan.cc/garble@latest
+ shell: bash
+ - run: go version
+ shell: bash
+ - name: Install Wails
+ if: inputs.wails-dev-build == 'false'
+ run: go install github.com/wailsapp/wails/v2/cmd/wails@${{ inputs.wails-version }}
+ shell: bash
+ - name: Install macOS deps (gon)
+ if: runner.os == 'macOS'
+ run: brew install mitchellh/gon/gon
+ shell: bash
diff --git a/actions/setup/npm/README.md b/actions/setup/npm/README.md
new file mode 100644
index 0000000..896748b
--- /dev/null
+++ b/actions/setup/npm/README.md
@@ -0,0 +1,24 @@
+# Setup Node and npm (sub-action)
+
+Purpose
+- Installs Node.js and optionally installs dependencies with npm.
+- Auto-detects where to install: current `working-directory` or `frontend/` fallback.
+
+Inputs
+- `node-version` (default `18.x`) — Node.js version to install.
+- `working-directory` (default `.`) — base path to check for `package.json`.
+- `install` (default `true`) — when `true`, runs `npm ci` (falls back to `npm install`).
+
+Usage
+```yaml
+- name: Setup Node/npm
+ uses: snider/build/actions/setup/npm@v3
+ with:
+ node-version: '20.x'
+ working-directory: 'build/wails2' # or '.'
+ install: 'true'
+```
+
+Notes
+- If no `package.json` exists in the working dir, the action will try `frontend/`.
+- Disable installs with `install: 'false'` if you manage dependencies yourself.
diff --git a/actions/setup/npm/action.yml b/actions/setup/npm/action.yml
new file mode 100644
index 0000000..28cad84
--- /dev/null
+++ b/actions/setup/npm/action.yml
@@ -0,0 +1,42 @@
+name: "Setup Node and npm"
+description: "Installs Node.js and optionally installs dependencies (npm ci) in a detected project directory"
+inputs:
+ node-version:
+ required: false
+ default: "18.x"
+ working-directory:
+ required: false
+ default: "."
+ install:
+ required: false
+ default: "true"
+runs:
+ using: "composite"
+ steps:
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ inputs.node-version }}
+ check-latest: true
+ - name: Show node and npm versions
+ shell: bash
+ run: |
+ node -v
+ npm -v
+ - name: Install npm dependencies (auto-detect path)
+ if: inputs.install == 'true'
+ shell: bash
+ working-directory: ${{ inputs.working-directory }}
+ run: |
+ set -euo pipefail
+ install_dir="${{ inputs.working-directory }}"
+ if [ -f "package.json" ]; then
+ echo "Installing npm deps in $PWD"
+ npm ci || npm install
+ elif [ -f "frontend/package.json" ]; then
+ echo "Installing npm deps in frontend/"
+ cd frontend
+ npm ci || npm install
+ else
+ echo "No package.json found in working-directory or frontend/. Skipping npm install."
+ fi
diff --git a/actions/sign/README.md b/actions/sign/README.md
new file mode 100644
index 0000000..91c8b89
--- /dev/null
+++ b/actions/sign/README.md
@@ -0,0 +1,56 @@
+# Sign (sub-action)
+
+Purpose
+- Unified signing step for macOS and Windows.
+- macOS: imports certificates, signs the `.app` with `gon`, zips the `.app`, builds a `.pkg` (signed or unsigned), and notarizes on tag builds.
+- Windows: signs the `.exe` and the NSIS installer using a provided PFX (base64) and password.
+
+When it runs
+- macOS: meaningful on `macOS` runners. Most operations only run when `sign != 'false'` AND the ref is a tag (`refs/tags/*`).
+- Windows: meaningful on `Windows` runners. Runs when `sign != 'false'` AND `sign-windows-cert` is provided.
+
+Inputs (union of previous per-OS signers)
+- `sign` (default `false`) — enable/disable signing.
+- `app-working-directory` (default `.`)
+- `build-name` (required)
+- macOS:
+ - `sign-macos-apple-password` — app-specific password for Apple ID (`gon` uses this)
+ - `sign-macos-app-id` — Developer ID Application subject
+ - `sign-macos-app-cert` — Base64-encoded `.p12`
+ - `sign-macos-app-cert-password` — Password for the Application certificate
+ - `sign-macos-installer-id` — Developer ID Installer subject (optional)
+ - `sign-macos-installer-cert` — Base64-encoded `.p12` (Installer)
+ - `sign-macos-installer-cert-password` — Password for the Installer certificate
+- Windows:
+ - `sign-windows-cert` — Base64-encoded PFX contents
+ - `sign-windows-cert-password` — Password for the PFX
+
+Required project files (macOS)
+- `build/darwin/gon-sign.json` — config for signing the `.app`
+- `build/darwin/gon-notarize.json` — config for notarizing `.pkg` and `.app.zip`
+
+Usage
+```yaml
+- name: Sign artifacts
+ uses: snider/build/actions/sign@v3
+ with:
+ sign: 'true'
+ app-working-directory: '.'
+ build-name: 'wailsApp'
+ # macOS
+ sign-macos-apple-password: ${{ secrets.APPLE_PASSWORD }}
+ sign-macos-app-id: ${{ secrets.MACOS_DEVELOPER_CERT_ID }}
+ sign-macos-app-cert: ${{ secrets.MACOS_DEVELOPER_CERT }}
+ sign-macos-app-cert-password: ${{ secrets.MACOS_DEVELOPER_CERT_PASSWORD }}
+ sign-macos-installer-id: ${{ secrets.MACOS_INSTALLER_CERT_ID }}
+ sign-macos-installer-cert: ${{ secrets.MACOS_INSTALLER_CERT }}
+ sign-macos-installer-cert-password: ${{ secrets.MACOS_INSTALLER_CERT_PASSWORD }}
+ # Windows
+ sign-windows-cert: ${{ secrets.WIN_CERT_PFX_BASE64 }}
+ sign-windows-cert-password: ${{ secrets.WIN_CERT_PASSWORD }}
+```
+
+Notes
+- On macOS, `gon` must be installed (`actions/setup/go` installs it automatically on macOS).
+- The `.app` zip is produced regardless of signing to ease distribution.
+- Installer `.pkg` is signed when `sign == 'true'` and an installer ID is provided; otherwise an unsigned pkg is built on tags.
diff --git a/actions/sign/action.yml b/actions/sign/action.yml
new file mode 100644
index 0000000..213cf3e
--- /dev/null
+++ b/actions/sign/action.yml
@@ -0,0 +1,109 @@
+name: "Sign"
+description: "Unified signing for macOS and Windows (conditional by OS); notarizes on tags for macOS"
+inputs:
+ sign:
+ required: false
+ default: "false"
+ app-working-directory:
+ required: false
+ default: "."
+ build-name:
+ required: true
+ # macOS
+ sign-macos-apple-password:
+ required: false
+ default: ''
+ sign-macos-app-id:
+ required: false
+ default: ''
+ sign-macos-app-cert:
+ required: false
+ default: ''
+ sign-macos-app-cert-password:
+ required: false
+ default: ''
+ sign-macos-installer-id:
+ required: false
+ default: ''
+ sign-macos-installer-cert:
+ required: false
+ default: ''
+ sign-macos-installer-cert-password:
+ required: false
+ default: ''
+ # Windows
+ sign-windows-cert:
+ required: false
+ default: ''
+ sign-windows-cert-password:
+ required: false
+ default: ''
+runs:
+ using: "composite"
+ steps:
+ # macOS signing flow
+ - name: Import Code-Signing Certificates for macOS
+ if: runner.os == 'macOS' && inputs.sign != 'false' && startsWith(github.ref, 'refs/tags/')
+ uses: Apple-Actions/import-codesign-certs@v1
+ with:
+ keychain-password: ${{ inputs.sign-macos-apple-password }}
+ p12-file-base64: ${{ inputs.sign-macos-app-cert }}
+ p12-password: ${{ inputs.sign-macos-app-cert-password }}
+ - name: Import Code-Signing Certificates for macOS Installer
+ if: runner.os == 'macOS' && inputs.sign != 'false' && startsWith(github.ref, 'refs/tags/')
+ uses: Apple-Actions/import-codesign-certs@v1
+ with:
+ keychain-password: ${{ inputs.sign-macos-apple-password }}
+ p12-file-base64: ${{ inputs.sign-macos-installer-cert }}
+ p12-password: ${{ inputs.sign-macos-installer-cert-password }}
+ create-keychain: false
+ - name: Sign macOS .app with gon
+ if: runner.os == 'macOS' && inputs.sign != 'false' && startsWith(github.ref, 'refs/tags/')
+ shell: bash
+ working-directory: ${{ inputs.app-working-directory }}
+ env:
+ APPLE_PASSWORD: ${{ inputs.sign-macos-apple-password }}
+ run: |
+ echo "Signing Package"
+ gon -log-level=info ./build/darwin/gon-sign.json
+ - name: Build .app zip file
+ if: runner.os == 'macOS'
+ working-directory: ${{ inputs.app-working-directory }}
+ shell: bash
+ run: |
+ ditto -c -k --keepParent ${{ inputs.app-working-directory }}/build/bin/${{ inputs.build-name }}.app ${{ inputs.app-working-directory }}/build/bin/${{ inputs.build-name }}.app.zip
+ - name: Build Installer (signed)
+ if: runner.os == 'macOS' && inputs.sign != 'false' && inputs.sign-macos-installer-id != '' && startsWith(github.ref, 'refs/tags/')
+ shell: bash
+ working-directory: ${{ inputs.app-working-directory }}
+ run: |
+ productbuild --sign '${{ inputs.sign-macos-installer-id }}' --component ${{ inputs.app-working-directory }}/build/bin/${{ inputs.build-name }}.app /Applications ${{ inputs.app-working-directory }}/build/bin/${{ inputs.build-name }}.pkg
+ - name: Build Installer (unsigned)
+ if: runner.os == 'macOS' && inputs.sign-macos-installer-id == '' && startsWith(github.ref, 'refs/tags/')
+ shell: bash
+ working-directory: ${{ inputs.app-working-directory }}
+ run: |
+ productbuild --component ${{ inputs.app-working-directory }}/build/bin/${{ inputs.build-name }}.app /Applications ${{ inputs.app-working-directory }}/build/bin/${{ inputs.build-name }}.pkg
+ - name: Notarize Installer and zip with gon
+ if: runner.os == 'macOS' && inputs.sign != 'false' && startsWith(github.ref, 'refs/tags/')
+ shell: bash
+ working-directory: ${{ inputs.app-working-directory }}
+ env:
+ APPLE_PASSWORD: ${{ inputs.sign-macos-apple-password }}
+ run: |
+ gon -log-level=info ${{ inputs.app-working-directory }}/build/darwin/gon-notarize.json
+
+ # Windows signing flow
+ - name: Sign Windows binaries
+ shell: powershell
+ if: runner.os == 'Windows' && inputs.sign != 'false' && inputs.sign-windows-cert != ''
+ working-directory: ${{ inputs.app-working-directory }}
+ run: |
+ echo "Creating certificate file"
+ New-Item -ItemType directory -Path certificate
+ Set-Content -Path certificate\certificate.txt -Value '${{ inputs.sign-windows-cert }}'
+ certutil -decode certificate\certificate.txt certificate\certificate.pfx
+ echo "Signing our binaries"
+ & 'C:/Program Files (x86)/Windows Kits/10/bin/10.0.17763.0/x86/signtool.exe' sign /fd sha256 /tr http://ts.ssl.com /f certificate\certificate.pfx /p '${{ inputs.sign-windows-cert-password }}' .\build\bin\${{ inputs.build-name }}.exe
+ echo "Signing Installer"
+ & 'C:/Program Files (x86)/Windows Kits/10/bin/10.0.17763.0/x86/signtool.exe' sign /fd sha256 /tr http://ts.ssl.com /f certificate\certificate.pfx /p '${{ inputs.sign-windows-cert-password }}' .\build\bin\${{ inputs.build-name }}-amd64-installer.exe
diff --git a/docs/GOLANG_BUILDER_PLAN.md b/docs/GOLANG_BUILDER_PLAN.md
new file mode 100644
index 0000000..748c8f3
--- /dev/null
+++ b/docs/GOLANG_BUILDER_PLAN.md
@@ -0,0 +1,560 @@
+# GoLang Binary Builder Plan
+
+## Overview
+
+This document outlines a plan to refactor the build action to use **GoTask (go-task/task)** as the build orchestrator instead of inline shell scripts in GitHub Actions. This approach provides:
+
+- **Cross-platform consistency**: Taskfiles work identically on Linux, macOS, and Windows
+- **Local development parity**: Developers can run the same tasks locally that run in CI
+- **Cleaner separation**: GitHub Actions handle CI concerns (checkout, caching, artifacts); GoTask handles build logic
+- **Extensibility**: Easy to add new stacks (Wails3, pure Go CLI, Docker, etc.)
+
+## Primary Goals
+
+1. **Wails 2 builds** - Full support (current functionality preserved)
+2. **Wails 3 builds** - New support for Wails v3 architecture
+
+## Stretch Goals
+
+3. Pure Go CLI/binary builds (no Wails)
+4. Docker image builds
+5. C++ builds (via Conan/CMake)
+6. PHP builds (Composer-based)
+
+---
+
+## Architecture
+
+### Current v3 Architecture (Shell-based)
+
+```
+action.yml (root)
+├── actions/discovery/action.yml # Detect OS/ARCH/project-type
+├── actions/action.yml # Directory orchestrator (stack router)
+│ └── actions/build/wails2/action.yml # Wails2 full pipeline
+│ ├── actions/options/action.yml # Compute build flags
+│ ├── actions/setup/action.yml # Install toolchains
+│ ├── actions/build/wails2/build/ # Run wails build
+│ └── actions/sign/action.yml # Code signing
+└── actions/package/action.yml # Artifacts & releases
+```
+
+### Proposed GoTask Architecture
+
+```
+action.yml (root)
+├── actions/discovery/action.yml # Keep: Detect OS/ARCH/project-type
+├── actions/setup/gotask/action.yml # NEW: Install go-task
+├── actions/action.yml # Orchestrator runs: task build:$STACK
+│ └── Taskfile.yml # Master taskfile includes stack taskfiles
+│ ├── tasks/wails2.yml # Wails 2 build tasks
+│ ├── tasks/wails3.yml # Wails 3 build tasks
+│ ├── tasks/go-cli.yml # Pure Go CLI builds
+│ └── tasks/common.yml # Shared tasks (setup, sign, package)
+└── actions/package/action.yml # Keep: Artifacts & releases
+```
+
+---
+
+## Taskfile Structure
+
+### Root Taskfile.yml
+
+```yaml
+version: '3'
+
+includes:
+ common: ./tasks/common.yml
+ wails2: ./tasks/wails2.yml
+ wails3: ./tasks/wails3.yml
+ go: ./tasks/go-cli.yml
+
+vars:
+ BUILD_NAME: '{{.BUILD_NAME | default "app"}}'
+ BUILD_PLATFORM: '{{.BUILD_PLATFORM | default "linux/amd64"}}'
+ BUILD_OUTPUT: '{{.BUILD_OUTPUT | default "build/bin"}}'
+
+tasks:
+ default:
+ desc: "Show available tasks"
+ cmds:
+ - task --list
+
+ build:
+ desc: "Auto-detect stack and build"
+ cmds:
+ - task: "build:{{.STACK | default \"wails2\"}}"
+ vars:
+ STACK:
+ sh: |
+ if [ -f "wails.json" ]; then
+ if grep -q '"wailsVersion": "v3' wails.json 2>/dev/null; then
+ echo "wails3"
+ else
+ echo "wails2"
+ fi
+ elif [ -f "go.mod" ] && [ -f "main.go" ]; then
+ echo "go"
+ else
+ echo "wails2"
+ fi
+
+ build:wails2:
+ desc: "Build Wails 2 application"
+ cmds:
+ - task: wails2:build
+
+ build:wails3:
+ desc: "Build Wails 3 application"
+ cmds:
+ - task: wails3:build
+
+ build:go:
+ desc: "Build Go CLI/binary"
+ cmds:
+ - task: go:build
+```
+
+### tasks/wails2.yml
+
+```yaml
+version: '3'
+
+vars:
+ WAILS_VERSION: '{{.WAILS_VERSION | default "latest"}}'
+ WEBVIEW2: '{{.WEBVIEW2 | default "download"}}'
+ BUILD_TAGS: '{{.BUILD_TAGS | default ""}}'
+ OBFUSCATE: '{{.OBFUSCATE | default "false"}}'
+ NSIS: '{{.NSIS | default "false"}}'
+
+tasks:
+ setup:
+ desc: "Install Wails v2 CLI"
+ cmds:
+ - go install github.com/wailsapp/wails/v2/cmd/wails@{{.WAILS_VERSION}}
+ status:
+ - which wails
+
+ setup:garble:
+ desc: "Install Garble for obfuscation"
+ cmds:
+ - go install mvdan.cc/garble@latest
+ status:
+ - which garble
+
+ build:
+ desc: "Build Wails 2 application"
+ deps: [setup]
+ cmds:
+ - |
+ BUILD_OPTS=""
+ {{if eq .OBFUSCATE "true"}}BUILD_OPTS="$BUILD_OPTS -obfuscated"{{end}}
+ {{if .BUILD_TAGS}}BUILD_OPTS="$BUILD_OPTS -tags {{.BUILD_TAGS}}"{{end}}
+ {{if eq .NSIS "true"}}BUILD_OPTS="$BUILD_OPTS -nsis"{{end}}
+ wails build --platform {{.BUILD_PLATFORM}} -webview2 {{.WEBVIEW2}} -o {{.BUILD_NAME}} $BUILD_OPTS
+ generates:
+ - "{{.BUILD_OUTPUT}}/*"
+
+ build:all:
+ desc: "Build for all platforms"
+ cmds:
+ - task: build
+ vars: { BUILD_PLATFORM: "linux/amd64" }
+ - task: build
+ vars: { BUILD_PLATFORM: "windows/amd64" }
+ - task: build
+ vars: { BUILD_PLATFORM: "darwin/universal" }
+```
+
+### tasks/wails3.yml
+
+```yaml
+version: '3'
+
+vars:
+ WAILS3_VERSION: '{{.WAILS3_VERSION | default "latest"}}'
+
+tasks:
+ setup:
+ desc: "Install Wails v3 CLI"
+ cmds:
+ - go install github.com/wailsapp/wails/v3/cmd/wails3@{{.WAILS3_VERSION}}
+ status:
+ - which wails3
+
+ build:
+ desc: "Build Wails 3 application"
+ deps: [setup]
+ cmds:
+ - |
+ # Wails 3 uses a different build command structure
+ # Platform is specified differently in v3
+ GOOS={{.GOOS}} GOARCH={{.GOARCH}} wails3 build -o {{.BUILD_NAME}}
+ vars:
+ GOOS:
+ sh: echo "{{.BUILD_PLATFORM}}" | cut -d'/' -f1 | sed 's/darwin/darwin/;s/linux/linux/;s/windows/windows/'
+ GOARCH:
+ sh: echo "{{.BUILD_PLATFORM}}" | cut -d'/' -f2
+ generates:
+ - "{{.BUILD_OUTPUT}}/*"
+
+ dev:
+ desc: "Run Wails 3 in dev mode"
+ deps: [setup]
+ cmds:
+ - wails3 dev
+```
+
+### tasks/common.yml
+
+```yaml
+version: '3'
+
+tasks:
+ setup:go:
+ desc: "Verify Go installation"
+ cmds:
+ - go version
+ preconditions:
+ - sh: which go
+ msg: "Go is not installed"
+
+ setup:node:
+ desc: "Install frontend dependencies"
+ dir: "{{.FRONTEND_DIR | default \"frontend\"}}"
+ cmds:
+ - npm ci --prefer-offline
+ sources:
+ - package-lock.json
+ generates:
+ - node_modules/**/*
+ status:
+ - test -d node_modules
+
+ clean:
+ desc: "Clean build artifacts"
+ cmds:
+ - rm -rf build/bin/*
+ - rm -rf dist/*
+ ignore_error: true
+
+ lint:
+ desc: "Run linters"
+ cmds:
+ - go vet ./...
+ - |
+ if which golangci-lint >/dev/null 2>&1; then
+ golangci-lint run
+ fi
+
+ test:
+ desc: "Run tests"
+ cmds:
+ - go test -v ./...
+
+ sign:macos:
+ desc: "Sign macOS application"
+ platforms: [darwin]
+ cmds:
+ - |
+ if [ -n "$SIGN_MACOS_APP_ID" ]; then
+ codesign --deep --force --options runtime \
+ --sign "$SIGN_MACOS_APP_ID" \
+ "{{.BUILD_OUTPUT}}/{{.BUILD_NAME}}.app"
+ else
+ echo "Skipping signing: SIGN_MACOS_APP_ID not set"
+ fi
+
+ sign:windows:
+ desc: "Sign Windows executable"
+ platforms: [windows]
+ cmds:
+ - |
+ if [ -n "$SIGN_WINDOWS_CERT" ]; then
+ # Windows signing via signtool
+ echo "Windows signing configured"
+ else
+ echo "Skipping signing: SIGN_WINDOWS_CERT not set"
+ fi
+
+ package:
+ desc: "Create distributable package"
+ cmds:
+ - |
+ OS=$(echo "{{.BUILD_PLATFORM}}" | cut -d'/' -f1)
+ ARCH=$(echo "{{.BUILD_PLATFORM}}" | cut -d'/' -f2)
+ ARTIFACT_NAME="{{.BUILD_NAME}}_${OS}_${ARCH}"
+
+ mkdir -p dist
+ case $OS in
+ darwin)
+ ditto -c -k --keepParent "{{.BUILD_OUTPUT}}/{{.BUILD_NAME}}.app" "dist/${ARTIFACT_NAME}.zip"
+ ;;
+ windows)
+ zip -r "dist/${ARTIFACT_NAME}.zip" "{{.BUILD_OUTPUT}}/{{.BUILD_NAME}}.exe"
+ ;;
+ linux)
+ tar -czvf "dist/${ARTIFACT_NAME}.tar.gz" -C "{{.BUILD_OUTPUT}}" "{{.BUILD_NAME}}"
+ ;;
+ esac
+```
+
+---
+
+## GitHub Action Integration
+
+### actions/setup/gotask/action.yml
+
+```yaml
+name: "Setup GoTask"
+description: "Install go-task/task CLI"
+inputs:
+ version:
+ description: "Task version to install"
+ required: false
+ default: "latest"
+runs:
+ using: "composite"
+ steps:
+ - name: Install Task (Linux/macOS)
+ if: runner.os != 'Windows'
+ shell: bash
+ run: |
+ sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b ~/.local/bin
+ echo "$HOME/.local/bin" >> $GITHUB_PATH
+
+ - name: Install Task (Windows)
+ if: runner.os == 'Windows'
+ shell: powershell
+ run: |
+ choco install go-task -y
+
+ - name: Verify Task installation
+ shell: bash
+ run: task --version
+```
+
+### Modified actions/action.yml (Orchestrator)
+
+```yaml
+name: "Directory Orchestrator"
+description: "Runs GoTask with detected stack"
+inputs:
+ build:
+ required: false
+ default: "true"
+ build-name:
+ required: true
+ build-platform:
+ required: false
+ default: "darwin/universal"
+ app-working-directory:
+ required: false
+ default: "."
+ STACK:
+ required: false
+ default: ""
+
+runs:
+ using: "composite"
+ steps:
+ - name: Setup GoTask
+ uses: ./actions/setup/gotask
+
+ - name: Determine stack
+ id: stack
+ shell: bash
+ working-directory: ${{ inputs.app-working-directory }}
+ run: |
+ if [ -n "${{ inputs.STACK }}" ]; then
+ echo "STACK=${{ inputs.STACK }}" >> "$GITHUB_OUTPUT"
+ elif [ -f "wails.json" ]; then
+ if grep -q '"wailsVersion": "v3' wails.json 2>/dev/null; then
+ echo "STACK=wails3" >> "$GITHUB_OUTPUT"
+ else
+ echo "STACK=wails2" >> "$GITHUB_OUTPUT"
+ fi
+ elif [ -f "go.mod" ]; then
+ echo "STACK=go" >> "$GITHUB_OUTPUT"
+ else
+ echo "STACK=wails2" >> "$GITHUB_OUTPUT"
+ fi
+
+ - name: Run build task
+ if: inputs.build == 'true'
+ shell: bash
+ working-directory: ${{ inputs.app-working-directory }}
+ env:
+ BUILD_NAME: ${{ inputs.build-name }}
+ BUILD_PLATFORM: ${{ inputs.build-platform }}
+ run: |
+ task build:${{ steps.stack.outputs.STACK }}
+
+outputs:
+ SELECTED_STACK:
+ description: "Stack that was built"
+ value: ${{ steps.stack.outputs.STACK }}
+```
+
+---
+
+## Wails 2 vs Wails 3 Detection
+
+The system will auto-detect Wails version by examining `wails.json`:
+
+| Indicator | Wails 2 | Wails 3 |
+|-----------|---------|---------|
+| `wails.json` schema | Has `name`, `frontend:install` | Has `wailsVersion: "v3..."` |
+| CLI command | `wails build` | `wails3 build` |
+| Output structure | `build/bin/{name}.app` | Different structure |
+| Go module | `github.com/wailsapp/wails/v2` | `github.com/wailsapp/wails/v3` |
+
+### Detection Logic
+
+```bash
+# In Taskfile or action
+if [ -f "wails.json" ]; then
+ if grep -q '"wailsVersion":\s*"v3' wails.json; then
+ STACK="wails3"
+ else
+ STACK="wails2"
+ fi
+elif grep -q 'github.com/wailsapp/wails/v3' go.mod 2>/dev/null; then
+ STACK="wails3"
+elif grep -q 'github.com/wailsapp/wails/v2' go.mod 2>/dev/null; then
+ STACK="wails2"
+else
+ STACK="go" # fallback to pure Go
+fi
+```
+
+---
+
+## Implementation Phases
+
+### Phase 1: Foundation (Primary Goal)
+
+1. **Add GoTask setup action** (`actions/setup/gotask/action.yml`)
+2. **Create root Taskfile.yml** with basic structure
+3. **Migrate Wails 2 build logic** to `tasks/wails2.yml`
+4. **Update orchestrator** to call `task build:wails2`
+5. **Preserve all existing inputs/outputs** for backward compatibility
+
+### Phase 2: Wails 3 Support (Primary Goal)
+
+1. **Create `tasks/wails3.yml`** with Wails 3 build commands
+2. **Add Wails 3 detection** to discovery and Taskfile
+3. **Create TDD fixture** for Wails 3 (`tdd/wails3-root/`)
+4. **Add CI tests** for Wails 3 builds
+
+### Phase 3: Refactor Remaining Shell Logic
+
+1. **Move signing logic** to `tasks/common.yml` (sign:macos, sign:windows)
+2. **Move npm setup** to common tasks
+3. **Simplify GitHub Actions** to thin wrappers around `task` commands
+
+### Phase 4: Stretch Goals
+
+1. **Pure Go CLI** (`tasks/go-cli.yml`)
+2. **Docker builds** (`tasks/docker.yml`)
+3. **C++ builds** (`tasks/cpp.yml`)
+4. **PHP builds** (`tasks/php.yml`)
+
+---
+
+## File Changes Summary
+
+### New Files
+
+| File | Description |
+|------|-------------|
+| `Taskfile.yml` | Root taskfile with includes |
+| `tasks/common.yml` | Shared tasks (setup, sign, package) |
+| `tasks/wails2.yml` | Wails 2 build tasks |
+| `tasks/wails3.yml` | Wails 3 build tasks |
+| `tasks/go-cli.yml` | Pure Go CLI build tasks |
+| `actions/setup/gotask/action.yml` | GoTask installation action |
+| `tdd/wails3-root/` | Wails 3 test fixture |
+
+### Modified Files
+
+| File | Changes |
+|------|---------|
+| `actions/action.yml` | Add GoTask setup, call `task build:$STACK` |
+| `actions/discovery/action.yml` | Add Wails 3 detection |
+| `.github/workflows/ci.yml` | Add Wails 3 build tests |
+
+### Deprecated (Phase 3)
+
+| File | Status |
+|------|--------|
+| `actions/build/wails2/build/action.yml` | Replaced by `task wails2:build` |
+| `actions/options/action.yml` | Logic moves to Taskfile vars |
+
+---
+
+## Environment Variables
+
+All existing `WAILS_*` environment variables remain supported:
+
+| Variable | Taskfile Var | Default |
+|----------|--------------|---------|
+| `WAILS_VERSION` | `WAILS_VERSION` | `latest` |
+| `WAILS_GO_VERSION` | N/A (Go setup) | `1.23` |
+| `WAILS_BUILD_TAGS` | `BUILD_TAGS` | `""` |
+| `WAILS_OBFUSCATE` | `OBFUSCATE` | `false` |
+| `WAILS_NSIS` | `NSIS` | `false` |
+| `WAILS_WEBVIEW2` | `WEBVIEW2` | `download` |
+
+New for Wails 3:
+
+| Variable | Taskfile Var | Default |
+|----------|--------------|---------|
+| `WAILS3_VERSION` | `WAILS3_VERSION` | `latest` |
+
+---
+
+## Local Development Usage
+
+With GoTask, developers can run the same builds locally:
+
+```bash
+# Install task (one-time)
+brew install go-task # macOS
+# or: sh -c "$(curl --location https://taskfile.dev/install.sh)"
+
+# Run builds
+task build # Auto-detect stack
+task build:wails2 # Explicit Wails 2
+task build:wails3 # Explicit Wails 3
+task wails2:build:all # Build all platforms
+
+# Other tasks
+task clean # Clean build artifacts
+task lint # Run linters
+task test # Run tests
+```
+
+---
+
+## Backward Compatibility
+
+The action maintains full backward compatibility:
+
+1. **Same inputs** - All existing action inputs work identically
+2. **Same outputs** - Same artifacts, same naming conventions
+3. **Same ENV mapping** - `WAILS_*` variables work as before
+4. **Gradual migration** - Shell scripts coexist with Taskfiles during transition
+
+---
+
+## Next Steps
+
+1. [ ] Create `actions/setup/gotask/action.yml`
+2. [ ] Create `Taskfile.yml` and `tasks/` directory
+3. [ ] Implement `tasks/wails2.yml` matching current behavior
+4. [ ] Update orchestrator to use GoTask
+5. [ ] Add Wails 3 detection and `tasks/wails3.yml`
+6. [ ] Create Wails 3 TDD fixture
+7. [ ] Update CI workflow with new tests
+8. [ ] Document new local development workflow
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 0000000..e376450
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,15 @@
+# Documentation
+
+Welcome to the documentation for `snider/build@v3`. This repository contains a modular build action for multi-stack projects, primarily focused on Wails v2 but designed to be extensible.
+
+## Contents
+
+- [Getting Started](getting-started.md) - Learn how to use the action in your workflows.
+- [Configuration](configuration.md) - Detailed reference for inputs and environment variables.
+- [Architecture](architecture.md) - Understand the modular design and sub-actions.
+- [Stacks](stacks.md) - Specific information about supported stacks (Wails v2, Deno, etc.).
+
+## Quick Links
+
+- [Root README](../README.md)
+- [Action Definition](../action.yml)
diff --git a/docs/architecture.md b/docs/architecture.md
new file mode 100644
index 0000000..373764d
--- /dev/null
+++ b/docs/architecture.md
@@ -0,0 +1,32 @@
+# Architecture
+
+`snider/build@v3` is designed as a modular, multi-stack build system.
+
+## Overview
+
+The root action acts as a gateway. It performs discovery and then delegates the heavy lifting to specialized sub-actions.
+
+1. **Discovery**: Scans the repository to identify the OS, architecture, and project type (stack).
+2. **Orchestration**: Decides which specific build pipeline (stack) to run.
+3. **Setup**: Installs dependencies (Go, Node, Deno, etc.) based on the selected stack or configuration.
+4. **Build**: Compiles the application.
+5. **Sign**: Signs the binaries (if configured).
+6. **Package**: Archives the output and uploads it as an artifact (and release asset on tags).
+
+## Directory Structure
+
+- `actions/`
+ - `discovery/`: Detects environment and project metadata.
+ - `options/`: Computes build options (e.g., tags).
+ - `setup/`: Orchestrates dependency installation.
+ - `go/`, `npm/`, `deno/`, `conan/`: Specific setup actions.
+ - `build/`: Contains stack-specific build logic.
+ - `wails2/`: Logic for Wails v2 builds.
+ - `sign/`: Unified signing for macOS and Windows.
+ - `package/`: Handles artifact upload and releases.
+
+## Design Principles
+
+- **Modular**: Each step is a separate composite action. You can use them individually if needed.
+- **Smart Defaults**: The system tries to guess the right thing to do (Auto-Stack, Auto-Setup) but allows full override.
+- **CI Gating**: The repository includes self-tests that run sub-actions to ensure stability.
diff --git a/docs/configuration.md b/docs/configuration.md
new file mode 100644
index 0000000..83d1c39
--- /dev/null
+++ b/docs/configuration.md
@@ -0,0 +1,58 @@
+# Configuration
+
+This document covers the inputs and configuration options for the `snider/build@v3` action.
+
+## Action Inputs
+
+These inputs are defined in `action.yml` and are passed to the `with` block in your workflow.
+
+| Input | Description | Required | Default |
+| :--- | :--- | :--- | :--- |
+| `build-name` | The name of the binary or app bundle. | **Yes** | - |
+| `build-platform` | Target platform (e.g., `linux/amd64`, `windows/amd64`, `darwin/universal`). | No | `darwin/universal` |
+| `build` | Whether to run the build step. | No | `true` |
+| `package` | Upload artifacts and publish release on tags. | No | `true` |
+| `sign` | Enable platform signing (if configured). | No | `false` |
+| `app-working-directory` | Root directory of the app being built. | No | `.` |
+| `AUTO_STACK` | Allow auto-selection of stack based on discovery. | No | `true` |
+| `AUTO_SETUP` | Allow sub-setup enabling based on env toggles. | No | `true` |
+| `STACK` | Explicitly override the stack (e.g., `wails2`). | No | `""` |
+
+## Environment Variables
+
+The action uses environment variables for certain configurations, particularly for sub-actions like Deno setup.
+
+### Deno Configuration
+
+You can configure Deno usage via environment variables. These take precedence over inputs in the setup phase.
+
+| Variable | Description | Example |
+| :--- | :--- | :--- |
+| `DENO_ENABLE` | Explicitly enable Deno setup. | `true`, `1`, `on` |
+| `DENO_BUILD` | Full command to run for Deno build. | `deno task build` |
+| `DENO_VERSION` | Version of Deno to install. | `v1.44.x` |
+| `DENO_WORKDIR` | Working directory for Deno command. | `frontend` |
+
+### Example with Environment Variables
+
+```yaml
+steps:
+ - uses: actions/checkout@v4
+ - uses: snider/build@v3
+ env:
+ DENO_ENABLE: 'true'
+ DENO_VERSION: 'v1.44.x'
+ DENO_WORKDIR: 'frontend'
+ DENO_BUILD: 'deno task build'
+ with:
+ build-name: wailsApp
+ build-platform: linux/amd64
+```
+
+## Orchestration Control
+
+You can control how the action delegates tasks.
+
+- **Auto-Stack**: By default (`AUTO_STACK: true`), the action tries to detect if you are building a Wails v2 app, etc., and uses the appropriate sub-action.
+- **Auto-Setup**: By default (`AUTO_SETUP: true`), the orchestrator looks at environment variables to decide if it should set up Go, Node, Deno, etc.
+- **Manual Stack**: Set `STACK: wails2` to force the Wails v2 pipeline, ignoring auto-detection.
diff --git a/docs/getting-started.md b/docs/getting-started.md
new file mode 100644
index 0000000..6a02d81
--- /dev/null
+++ b/docs/getting-started.md
@@ -0,0 +1,60 @@
+# Getting Started
+
+This guide will help you get started with the `snider/build@v3` action.
+
+## Basic Usage
+
+The simplest way to use this action is to let it auto-detect your project type.
+
+```yaml
+steps:
+ - uses: actions/checkout@v4
+ - uses: snider/build@v3
+ with:
+ build-name: myApp
+ build-platform: linux/amd64
+```
+
+This configuration will:
+1. Detect your project stack (e.g., Wails v2).
+2. Set up the necessary environment (Go, Node.js, etc.).
+3. Build your application.
+4. Package the artifacts.
+5. Upload artifacts (and publish release on tags).
+
+## Common Examples
+
+### Build Only (No Packaging)
+
+If you only want to verify the build without uploading artifacts:
+
+```yaml
+- uses: snider/build@v3
+ with:
+ build-name: myApp
+ build-platform: linux/amd64
+ package: false
+```
+
+### macOS Build
+
+```yaml
+- uses: snider/build@v3
+ with:
+ build-name: myApp
+ build-platform: darwin/universal
+```
+
+### Windows Build
+
+```yaml
+- uses: snider/build@v3
+ with:
+ build-name: myApp
+ build-platform: windows/amd64
+```
+
+## Next Steps
+
+- Check [Configuration](configuration.md) for more advanced options.
+- Read about [Stacks](stacks.md) for specific stack details.
diff --git a/docs/stacks.md b/docs/stacks.md
new file mode 100644
index 0000000..fc94cff
--- /dev/null
+++ b/docs/stacks.md
@@ -0,0 +1,34 @@
+# Stacks
+
+This action supports multiple stacks, with Wails v2 being the primary one currently.
+
+## Wails v2
+
+This is the default stack. It handles the complete lifecycle of a Wails v2 application.
+
+- **Detection**: Automatically detected if `wails.json` is present (logic in `discovery`).
+- **Setup**: Installs Go, Node.js, and the Wails CLI.
+- **Build**: Runs `wails build` with appropriate flags for the target platform.
+- **Signing**: Supports macOS code signing and notarization (requires secrets) and Windows signing.
+
+For detailed documentation on Wails v2 inputs and usage, refer to:
+- [Wails v2 Wrapper README](../actions/build/wails2/README.md)
+- [Wails Build Sub-action README](../actions/build/wails2/build/README.md)
+
+### macOS Code Signing
+
+Detailed instructions for setting up macOS code signing (Certificate, Notarization) can be found in the [Wails v2 README](../actions/build/wails2/README.md).
+
+## Deno
+
+Deno support is integrated into the setup phase and can be used alongside other stacks or independently.
+
+- **Enable**: Set `DENO_ENABLE: true` or define `DENO_BUILD`.
+- **Usage**: Useful for running frontend build steps before the main application build.
+
+For more details, see [Deno Setup README](../actions/setup/deno/README.md).
+
+## Future Stacks
+
+- **Wails v3**: Planned support once upstream stabilizes.
+- **C++**: Placeholder support exists via `conan` setup action.
diff --git a/tdd/cpp-root/CMakeLists.txt b/tdd/cpp-root/CMakeLists.txt
new file mode 100644
index 0000000..c91b06a
--- /dev/null
+++ b/tdd/cpp-root/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 3.16)
+project(CppRootFixture)
+
+add_executable(dummy main.cpp)
diff --git a/tdd/docs/mkdocs.yml b/tdd/docs/mkdocs.yml
new file mode 100644
index 0000000..55a6dd0
--- /dev/null
+++ b/tdd/docs/mkdocs.yml
@@ -0,0 +1,3 @@
+site_name: Docs Fixture
+nav:
+ - Home: index.md
diff --git a/tdd/node-only/package.json b/tdd/node-only/package.json
new file mode 100644
index 0000000..04770db
--- /dev/null
+++ b/tdd/node-only/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "node-only-fixture",
+ "version": "0.0.1",
+ "private": true
+}
diff --git a/tdd/wails2-root/README.md b/tdd/wails2-root/README.md
new file mode 100644
index 0000000..1ae2f67
--- /dev/null
+++ b/tdd/wails2-root/README.md
@@ -0,0 +1,35 @@
+# Build Directory
+
+The build directory is used to house all the build files and assets for your application.
+
+The structure is:
+
+* bin - Output directory
+* darwin - macOS specific files
+* windows - Windows specific files
+
+## Mac
+
+The `darwin` directory holds files specific to Mac builds.
+These may be customised and used as part of the build. To return these files to the default state, simply delete them
+and
+build with `wails build`.
+
+The directory contains the following files:
+
+- `Info.plist` - the main plist file used for Mac builds. It is used when building using `wails build`.
+- `Info.dev.plist` - same as the main plist file but used when building using `wails dev`.
+
+## Windows
+
+The `windows` directory contains the manifest and rc files used when building with `wails build`.
+These may be customised for your application. To return these files to the default state, simply delete them and
+build with `wails build`.
+
+- `icon.ico` - The icon used for the application. This is used when building using `wails build`. If you wish to
+ use a different icon, simply replace this file with your own. If it is missing, a new `icon.ico` file
+ will be created using the `appicon.png` file in the build directory.
+- `installer/*` - The files used to create the Windows installer. These are used when building using `wails build`.
+- `info.json` - Application details used for Windows builds. The data here will be used by the Windows installer,
+ as well as the application itself (right click the exe -> properties -> details)
+- `wails.exe.manifest` - The main application manifest file.
\ No newline at end of file
diff --git a/tdd/wails2-root/app.go b/tdd/wails2-root/app.go
new file mode 100644
index 0000000..af53038
--- /dev/null
+++ b/tdd/wails2-root/app.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+ "context"
+ "fmt"
+)
+
+// App struct
+type App struct {
+ ctx context.Context
+}
+
+// NewApp creates a new App application struct
+func NewApp() *App {
+ return &App{}
+}
+
+// startup is called when the app starts. The context is saved
+// so we can call the runtime methods
+func (a *App) startup(ctx context.Context) {
+ a.ctx = ctx
+}
+
+// Greet returns a greeting for the given name
+func (a *App) Greet(name string) string {
+ return fmt.Sprintf("Hello %s, It's show time!", name)
+}
diff --git a/tdd/wails2-root/appicon.png b/tdd/wails2-root/appicon.png
new file mode 100644
index 0000000..63617fe
Binary files /dev/null and b/tdd/wails2-root/appicon.png differ
diff --git a/tdd/wails2-root/build/darwin/Info.dev.plist b/tdd/wails2-root/build/darwin/Info.dev.plist
new file mode 100644
index 0000000..04727c2
--- /dev/null
+++ b/tdd/wails2-root/build/darwin/Info.dev.plist
@@ -0,0 +1,68 @@
+
+
+
+ CFBundlePackageType
+ APPL
+ CFBundleName
+ {{.Info.ProductName}}
+ CFBundleExecutable
+ {{.Name}}
+ CFBundleIdentifier
+ com.wails.{{.Name}}
+ CFBundleVersion
+ {{.Info.ProductVersion}}
+ CFBundleGetInfoString
+ {{.Info.Comments}}
+ CFBundleShortVersionString
+ {{.Info.ProductVersion}}
+ CFBundleIconFile
+ iconfile
+ LSMinimumSystemVersion
+ 10.13.0
+ NSHighResolutionCapable
+ true
+ NSHumanReadableCopyright
+ {{.Info.Copyright}}
+ {{if .Info.FileAssociations}}
+ CFBundleDocumentTypes
+
+ {{range .Info.FileAssociations}}
+
+ CFBundleTypeExtensions
+
+ {{.Ext}}
+
+ CFBundleTypeName
+ {{.Name}}
+ CFBundleTypeRole
+ {{.Role}}
+ CFBundleTypeIconFile
+ {{.IconName}}
+
+ {{end}}
+
+ {{end}}
+ {{if .Info.Protocols}}
+ CFBundleURLTypes
+
+ {{range .Info.Protocols}}
+
+ CFBundleURLName
+ com.wails.{{.Scheme}}
+ CFBundleURLSchemes
+
+ {{.Scheme}}
+
+ CFBundleTypeRole
+ {{.Role}}
+
+ {{end}}
+
+ {{end}}
+ NSAppTransportSecurity
+
+ NSAllowsLocalNetworking
+
+
+
+
diff --git a/tdd/wails2-root/build/darwin/Info.plist b/tdd/wails2-root/build/darwin/Info.plist
new file mode 100644
index 0000000..19cc937
--- /dev/null
+++ b/tdd/wails2-root/build/darwin/Info.plist
@@ -0,0 +1,63 @@
+
+
+
+ CFBundlePackageType
+ APPL
+ CFBundleName
+ {{.Info.ProductName}}
+ CFBundleExecutable
+ {{.Name}}
+ CFBundleIdentifier
+ com.wails.{{.Name}}
+ CFBundleVersion
+ {{.Info.ProductVersion}}
+ CFBundleGetInfoString
+ {{.Info.Comments}}
+ CFBundleShortVersionString
+ {{.Info.ProductVersion}}
+ CFBundleIconFile
+ iconfile
+ LSMinimumSystemVersion
+ 10.13.0
+ NSHighResolutionCapable
+ true
+ NSHumanReadableCopyright
+ {{.Info.Copyright}}
+ {{if .Info.FileAssociations}}
+ CFBundleDocumentTypes
+
+ {{range .Info.FileAssociations}}
+
+ CFBundleTypeExtensions
+
+ {{.Ext}}
+
+ CFBundleTypeName
+ {{.Name}}
+ CFBundleTypeRole
+ {{.Role}}
+ CFBundleTypeIconFile
+ {{.IconName}}
+
+ {{end}}
+
+ {{end}}
+ {{if .Info.Protocols}}
+ CFBundleURLTypes
+
+ {{range .Info.Protocols}}
+
+ CFBundleURLName
+ com.wails.{{.Scheme}}
+ CFBundleURLSchemes
+
+ {{.Scheme}}
+
+ CFBundleTypeRole
+ {{.Role}}
+
+ {{end}}
+
+ {{end}}
+
+
diff --git a/tdd/wails2-root/build/windows/icon.ico b/tdd/wails2-root/build/windows/icon.ico
new file mode 100644
index 0000000..f334798
Binary files /dev/null and b/tdd/wails2-root/build/windows/icon.ico differ
diff --git a/tdd/wails2-root/build/windows/info.json b/tdd/wails2-root/build/windows/info.json
new file mode 100644
index 0000000..9727946
--- /dev/null
+++ b/tdd/wails2-root/build/windows/info.json
@@ -0,0 +1,15 @@
+{
+ "fixed": {
+ "file_version": "{{.Info.ProductVersion}}"
+ },
+ "info": {
+ "0000": {
+ "ProductVersion": "{{.Info.ProductVersion}}",
+ "CompanyName": "{{.Info.CompanyName}}",
+ "FileDescription": "{{.Info.ProductName}}",
+ "LegalCopyright": "{{.Info.Copyright}}",
+ "ProductName": "{{.Info.ProductName}}",
+ "Comments": "{{.Info.Comments}}"
+ }
+ }
+}
\ No newline at end of file
diff --git a/tdd/wails2-root/build/windows/installer/project.nsi b/tdd/wails2-root/build/windows/installer/project.nsi
new file mode 100644
index 0000000..654ae2e
--- /dev/null
+++ b/tdd/wails2-root/build/windows/installer/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 with the values from ProjectInfo.
+## If they are defined here, "wails_tools.nsh" will not touch them. This allows 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 ProjectInfo file, but they can be overwritten here.
+####
+## !define INFO_PROJECTNAME "MyProject" # Default "{{.Name}}"
+## !define INFO_COMPANYNAME "MyCompany" # Default "{{.Info.CompanyName}}"
+## !define INFO_PRODUCTNAME "MyProduct" # Default "{{.Info.ProductName}}"
+## !define INFO_PRODUCTVERSION "1.0.0" # Default "{{.Info.ProductVersion}}"
+## !define INFO_COPYRIGHT "Copyright" # Default "{{.Info.Copyright}}"
+###
+## !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 # Uinstalling 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/tdd/wails2-root/build/windows/installer/wails_tools.nsh b/tdd/wails2-root/build/windows/installer/wails_tools.nsh
new file mode 100644
index 0000000..f9c0f88
--- /dev/null
+++ b/tdd/wails2-root/build/windows/installer/wails_tools.nsh
@@ -0,0 +1,249 @@
+# DO NOT EDIT - Generated automatically by `wails build`
+
+!include "x64.nsh"
+!include "WinVer.nsh"
+!include "FileFunc.nsh"
+
+!ifndef INFO_PROJECTNAME
+ !define INFO_PROJECTNAME "{{.Name}}"
+!endif
+!ifndef INFO_COMPANYNAME
+ !define INFO_COMPANYNAME "{{.Info.CompanyName}}"
+!endif
+!ifndef INFO_PRODUCTNAME
+ !define INFO_PRODUCTNAME "{{.Info.ProductName}}"
+!endif
+!ifndef INFO_PRODUCTVERSION
+ !define INFO_PRODUCTVERSION "{{.Info.ProductVersion}}"
+!endif
+!ifndef INFO_COPYRIGHT
+ !define INFO_COPYRIGHT "{{.Info.Copyright}}"
+!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 "tmp\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
+ {{range .Info.FileAssociations}}
+ !insertmacro APP_ASSOCIATE "{{.Ext}}" "{{.Name}}" "{{.Description}}" "$INSTDIR\{{.IconName}}.ico" "Open with ${INFO_PRODUCTNAME}" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\""
+
+ File "..\{{.IconName}}.ico"
+ {{end}}
+!macroend
+
+!macro wails.unassociateFiles
+ ; Delete app associations
+ {{range .Info.FileAssociations}}
+ !insertmacro APP_UNASSOCIATE "{{.Ext}}" "{{.Name}}"
+
+ Delete "$INSTDIR\{{.IconName}}.ico"
+ {{end}}
+!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
+ {{range .Info.Protocols}}
+ !insertmacro CUSTOM_PROTOCOL_ASSOCIATE "{{.Scheme}}" "{{.Description}}" "$INSTDIR\${PRODUCT_EXECUTABLE},0" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\""
+
+ {{end}}
+!macroend
+
+!macro wails.unassociateCustomProtocols
+ ; Delete app custom protocol associations
+ {{range .Info.Protocols}}
+ !insertmacro CUSTOM_PROTOCOL_UNASSOCIATE "{{.Scheme}}"
+ {{end}}
+!macroend
diff --git a/tdd/wails2-root/build/windows/wails.exe.manifest b/tdd/wails2-root/build/windows/wails.exe.manifest
new file mode 100644
index 0000000..17e1a23
--- /dev/null
+++ b/tdd/wails2-root/build/windows/wails.exe.manifest
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+ true/pm
+ permonitorv2,permonitor
+
+
+
\ No newline at end of file
diff --git a/tdd/wails2-root/frontend/index.html b/tdd/wails2-root/frontend/index.html
new file mode 100644
index 0000000..bc06d9e
--- /dev/null
+++ b/tdd/wails2-root/frontend/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ wails
+
+
+
+
+
+
diff --git a/tdd/wails2-root/frontend/package-lock.json b/tdd/wails2-root/frontend/package-lock.json
new file mode 100644
index 0000000..dc4c123
--- /dev/null
+++ b/tdd/wails2-root/frontend/package-lock.json
@@ -0,0 +1,653 @@
+{
+ "name": "frontend",
+ "version": "0.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "frontend",
+ "version": "0.0.0",
+ "devDependencies": {
+ "vite": "^3.0.7"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
+ "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz",
+ "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz",
+ "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "optionalDependencies": {
+ "@esbuild/android-arm": "0.15.18",
+ "@esbuild/linux-loong64": "0.15.18",
+ "esbuild-android-64": "0.15.18",
+ "esbuild-android-arm64": "0.15.18",
+ "esbuild-darwin-64": "0.15.18",
+ "esbuild-darwin-arm64": "0.15.18",
+ "esbuild-freebsd-64": "0.15.18",
+ "esbuild-freebsd-arm64": "0.15.18",
+ "esbuild-linux-32": "0.15.18",
+ "esbuild-linux-64": "0.15.18",
+ "esbuild-linux-arm": "0.15.18",
+ "esbuild-linux-arm64": "0.15.18",
+ "esbuild-linux-mips64le": "0.15.18",
+ "esbuild-linux-ppc64le": "0.15.18",
+ "esbuild-linux-riscv64": "0.15.18",
+ "esbuild-linux-s390x": "0.15.18",
+ "esbuild-netbsd-64": "0.15.18",
+ "esbuild-openbsd-64": "0.15.18",
+ "esbuild-sunos-64": "0.15.18",
+ "esbuild-windows-32": "0.15.18",
+ "esbuild-windows-64": "0.15.18",
+ "esbuild-windows-arm64": "0.15.18"
+ }
+ },
+ "node_modules/esbuild-android-64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz",
+ "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-android-arm64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz",
+ "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-darwin-64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz",
+ "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-darwin-arm64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz",
+ "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-freebsd-64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz",
+ "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-freebsd-arm64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz",
+ "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-linux-32": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz",
+ "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-linux-64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz",
+ "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-linux-arm": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz",
+ "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-linux-arm64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz",
+ "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-linux-mips64le": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz",
+ "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-linux-ppc64le": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz",
+ "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-linux-riscv64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz",
+ "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-linux-s390x": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz",
+ "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-netbsd-64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz",
+ "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-openbsd-64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz",
+ "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-sunos-64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz",
+ "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-windows-32": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz",
+ "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-windows-64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz",
+ "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/esbuild-windows-arm64": {
+ "version": "0.15.18",
+ "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz",
+ "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+ "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.8",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
+ "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/postcss": {
+ "version": "8.5.1",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
+ "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.8",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.10",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+ "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-core-module": "^2.16.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "2.79.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
+ "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/vite": {
+ "version": "3.2.11",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.11.tgz",
+ "integrity": "sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.15.9",
+ "postcss": "^8.4.18",
+ "resolve": "^1.22.1",
+ "rollup": "^2.79.1"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ },
+ "peerDependencies": {
+ "@types/node": ">= 14",
+ "less": "*",
+ "sass": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.4.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ }
+ }
+ }
+ }
+}
diff --git a/tdd/wails2-root/frontend/package.json b/tdd/wails2-root/frontend/package.json
new file mode 100644
index 0000000..a1b6f8e
--- /dev/null
+++ b/tdd/wails2-root/frontend/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "frontend",
+ "private": true,
+ "version": "0.0.0",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "devDependencies": {
+ "vite": "^3.0.7"
+ }
+}
\ No newline at end of file
diff --git a/tdd/wails2-root/frontend/package.json.md5 b/tdd/wails2-root/frontend/package.json.md5
new file mode 100644
index 0000000..d4671a1
--- /dev/null
+++ b/tdd/wails2-root/frontend/package.json.md5
@@ -0,0 +1 @@
+5fbf12469d224a93954efecb5886e8a6
\ No newline at end of file
diff --git a/tdd/wails2-root/frontend/src/app.css b/tdd/wails2-root/frontend/src/app.css
new file mode 100644
index 0000000..59d06f6
--- /dev/null
+++ b/tdd/wails2-root/frontend/src/app.css
@@ -0,0 +1,54 @@
+#logo {
+ display: block;
+ width: 50%;
+ height: 50%;
+ margin: auto;
+ padding: 10% 0 0;
+ background-position: center;
+ background-repeat: no-repeat;
+ background-size: 100% 100%;
+ background-origin: content-box;
+}
+
+.result {
+ height: 20px;
+ line-height: 20px;
+ margin: 1.5rem auto;
+}
+
+.input-box .btn {
+ width: 60px;
+ height: 30px;
+ line-height: 30px;
+ border-radius: 3px;
+ border: none;
+ margin: 0 0 0 20px;
+ padding: 0 8px;
+ cursor: pointer;
+}
+
+.input-box .btn:hover {
+ background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%);
+ color: #333333;
+}
+
+.input-box .input {
+ border: none;
+ border-radius: 3px;
+ outline: none;
+ height: 30px;
+ line-height: 30px;
+ padding: 0 10px;
+ background-color: rgba(240, 240, 240, 1);
+ -webkit-font-smoothing: antialiased;
+}
+
+.input-box .input:hover {
+ border: none;
+ background-color: rgba(255, 255, 255, 1);
+}
+
+.input-box .input:focus {
+ border: none;
+ background-color: rgba(255, 255, 255, 1);
+}
\ No newline at end of file
diff --git a/tdd/wails2-root/frontend/src/assets/fonts/OFL.txt b/tdd/wails2-root/frontend/src/assets/fonts/OFL.txt
new file mode 100644
index 0000000..9cac04c
--- /dev/null
+++ b/tdd/wails2-root/frontend/src/assets/fonts/OFL.txt
@@ -0,0 +1,93 @@
+Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com),
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/tdd/wails2-root/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 b/tdd/wails2-root/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2
new file mode 100644
index 0000000..2f9cc59
Binary files /dev/null and b/tdd/wails2-root/frontend/src/assets/fonts/nunito-v16-latin-regular.woff2 differ
diff --git a/tdd/wails2-root/frontend/src/assets/images/logo-universal.png b/tdd/wails2-root/frontend/src/assets/images/logo-universal.png
new file mode 100644
index 0000000..d63303b
Binary files /dev/null and b/tdd/wails2-root/frontend/src/assets/images/logo-universal.png differ
diff --git a/tdd/wails2-root/frontend/src/main.js b/tdd/wails2-root/frontend/src/main.js
new file mode 100644
index 0000000..4ad5a2c
--- /dev/null
+++ b/tdd/wails2-root/frontend/src/main.js
@@ -0,0 +1,43 @@
+import './style.css';
+import './app.css';
+
+import logo from './assets/images/logo-universal.png';
+import {Greet} from '../wailsjs/go/main/App';
+
+document.querySelector('#app').innerHTML = `
+
+ Please enter your name below 👇
+
+
+
+
+
+`;
+document.getElementById('logo').src = logo;
+
+let nameElement = document.getElementById("name");
+nameElement.focus();
+let resultElement = document.getElementById("result");
+
+// Setup the greet function
+window.greet = function () {
+ // Get name
+ let name = nameElement.value;
+
+ // Check if the input is empty
+ if (name === "") return;
+
+ // Call App.Greet(name)
+ try {
+ Greet(name)
+ .then((result) => {
+ // Update result with data back from App.Greet()
+ resultElement.innerText = result;
+ })
+ .catch((err) => {
+ console.error(err);
+ });
+ } catch (err) {
+ console.error(err);
+ }
+};
diff --git a/tdd/wails2-root/frontend/src/style.css b/tdd/wails2-root/frontend/src/style.css
new file mode 100644
index 0000000..3940d6c
--- /dev/null
+++ b/tdd/wails2-root/frontend/src/style.css
@@ -0,0 +1,26 @@
+html {
+ background-color: rgba(27, 38, 54, 1);
+ text-align: center;
+ color: white;
+}
+
+body {
+ margin: 0;
+ color: white;
+ font-family: "Nunito", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
+ "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
+ sans-serif;
+}
+
+@font-face {
+ font-family: "Nunito";
+ font-style: normal;
+ font-weight: 400;
+ src: local(""),
+ url("assets/fonts/nunito-v16-latin-regular.woff2") format("woff2");
+}
+
+#app {
+ height: 100vh;
+ text-align: center;
+}
diff --git a/tdd/wails2-root/frontend/wailsjs/go/main/App.d.ts b/tdd/wails2-root/frontend/wailsjs/go/main/App.d.ts
new file mode 100644
index 0000000..02a3bb9
--- /dev/null
+++ b/tdd/wails2-root/frontend/wailsjs/go/main/App.d.ts
@@ -0,0 +1,4 @@
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+export function Greet(arg1:string):Promise;
diff --git a/tdd/wails2-root/frontend/wailsjs/go/main/App.js b/tdd/wails2-root/frontend/wailsjs/go/main/App.js
new file mode 100644
index 0000000..c71ae77
--- /dev/null
+++ b/tdd/wails2-root/frontend/wailsjs/go/main/App.js
@@ -0,0 +1,7 @@
+// @ts-check
+// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
+// This file is automatically generated. DO NOT EDIT
+
+export function Greet(arg1) {
+ return window['go']['main']['App']['Greet'](arg1);
+}
diff --git a/tdd/wails2-root/frontend/wailsjs/runtime/package.json b/tdd/wails2-root/frontend/wailsjs/runtime/package.json
new file mode 100644
index 0000000..1e7c8a5
--- /dev/null
+++ b/tdd/wails2-root/frontend/wailsjs/runtime/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "@wailsapp/runtime",
+ "version": "2.0.0",
+ "description": "Wails Javascript runtime library",
+ "main": "runtime.js",
+ "types": "runtime.d.ts",
+ "scripts": {
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/wailsapp/wails.git"
+ },
+ "keywords": [
+ "Wails",
+ "Javascript",
+ "Go"
+ ],
+ "author": "Lea Anthony ",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/wailsapp/wails/issues"
+ },
+ "homepage": "https://github.com/wailsapp/wails#readme"
+}
diff --git a/tdd/wails2-root/frontend/wailsjs/runtime/runtime.d.ts b/tdd/wails2-root/frontend/wailsjs/runtime/runtime.d.ts
new file mode 100644
index 0000000..94778df
--- /dev/null
+++ b/tdd/wails2-root/frontend/wailsjs/runtime/runtime.d.ts
@@ -0,0 +1,249 @@
+/*
+ _ __ _ __
+| | / /___ _(_) /____
+| | /| / / __ `/ / / ___/
+| |/ |/ / /_/ / / (__ )
+|__/|__/\__,_/_/_/____/
+The electron alternative for Go
+(c) Lea Anthony 2019-present
+*/
+
+export interface Position {
+ x: number;
+ y: number;
+}
+
+export interface Size {
+ w: number;
+ h: number;
+}
+
+export interface Screen {
+ isCurrent: boolean;
+ isPrimary: boolean;
+ width : number
+ height : number
+}
+
+// Environment information such as platform, buildtype, ...
+export interface EnvironmentInfo {
+ buildType: string;
+ platform: string;
+ arch: string;
+}
+
+// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit)
+// emits the given event. Optional data may be passed with the event.
+// This will trigger any event listeners.
+export function EventsEmit(eventName: string, ...data: any): void;
+
+// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name.
+export function EventsOn(eventName: string, callback: (...data: any) => void): () => void;
+
+// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple)
+// sets up a listener for the given event name, but will only trigger a given number times.
+export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void;
+
+// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce)
+// sets up a listener for the given event name, but will only trigger once.
+export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void;
+
+// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff)
+// unregisters the listener for the given event name.
+export function EventsOff(eventName: string, ...additionalEventNames: string[]): void;
+
+// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall)
+// unregisters all listeners.
+export function EventsOffAll(): void;
+
+// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint)
+// logs the given message as a raw message
+export function LogPrint(message: string): void;
+
+// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace)
+// logs the given message at the `trace` log level.
+export function LogTrace(message: string): void;
+
+// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug)
+// logs the given message at the `debug` log level.
+export function LogDebug(message: string): void;
+
+// [LogError](https://wails.io/docs/reference/runtime/log#logerror)
+// logs the given message at the `error` log level.
+export function LogError(message: string): void;
+
+// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal)
+// logs the given message at the `fatal` log level.
+// The application will quit after calling this method.
+export function LogFatal(message: string): void;
+
+// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo)
+// logs the given message at the `info` log level.
+export function LogInfo(message: string): void;
+
+// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning)
+// logs the given message at the `warning` log level.
+export function LogWarning(message: string): void;
+
+// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload)
+// Forces a reload by the main application as well as connected browsers.
+export function WindowReload(): void;
+
+// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp)
+// Reloads the application frontend.
+export function WindowReloadApp(): void;
+
+// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop)
+// Sets the window AlwaysOnTop or not on top.
+export function WindowSetAlwaysOnTop(b: boolean): void;
+
+// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme)
+// *Windows only*
+// Sets window theme to system default (dark/light).
+export function WindowSetSystemDefaultTheme(): void;
+
+// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme)
+// *Windows only*
+// Sets window to light theme.
+export function WindowSetLightTheme(): void;
+
+// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme)
+// *Windows only*
+// Sets window to dark theme.
+export function WindowSetDarkTheme(): void;
+
+// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter)
+// Centers the window on the monitor the window is currently on.
+export function WindowCenter(): void;
+
+// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle)
+// Sets the text in the window title bar.
+export function WindowSetTitle(title: string): void;
+
+// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen)
+// Makes the window full screen.
+export function WindowFullscreen(): void;
+
+// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen)
+// Restores the previous window dimensions and position prior to full screen.
+export function WindowUnfullscreen(): void;
+
+// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen)
+// Returns the state of the window, i.e. whether the window is in full screen mode or not.
+export function WindowIsFullscreen(): Promise;
+
+// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize)
+// Sets the width and height of the window.
+export function WindowSetSize(width: number, height: number): Promise;
+
+// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize)
+// Gets the width and height of the window.
+export function WindowGetSize(): Promise;
+
+// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize)
+// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions.
+// Setting a size of 0,0 will disable this constraint.
+export function WindowSetMaxSize(width: number, height: number): void;
+
+// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize)
+// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions.
+// Setting a size of 0,0 will disable this constraint.
+export function WindowSetMinSize(width: number, height: number): void;
+
+// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition)
+// Sets the window position relative to the monitor the window is currently on.
+export function WindowSetPosition(x: number, y: number): void;
+
+// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition)
+// Gets the window position relative to the monitor the window is currently on.
+export function WindowGetPosition(): Promise;
+
+// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide)
+// Hides the window.
+export function WindowHide(): void;
+
+// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow)
+// Shows the window, if it is currently hidden.
+export function WindowShow(): void;
+
+// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise)
+// Maximises the window to fill the screen.
+export function WindowMaximise(): void;
+
+// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise)
+// Toggles between Maximised and UnMaximised.
+export function WindowToggleMaximise(): void;
+
+// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise)
+// Restores the window to the dimensions and position prior to maximising.
+export function WindowUnmaximise(): void;
+
+// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised)
+// Returns the state of the window, i.e. whether the window is maximised or not.
+export function WindowIsMaximised(): Promise;
+
+// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise)
+// Minimises the window.
+export function WindowMinimise(): void;
+
+// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise)
+// Restores the window to the dimensions and position prior to minimising.
+export function WindowUnminimise(): void;
+
+// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised)
+// Returns the state of the window, i.e. whether the window is minimised or not.
+export function WindowIsMinimised(): Promise;
+
+// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal)
+// Returns the state of the window, i.e. whether the window is normal or not.
+export function WindowIsNormal(): Promise;
+
+// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour)
+// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels.
+export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void;
+
+// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall)
+// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system.
+export function ScreenGetAll(): Promise;
+
+// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl)
+// Opens the given URL in the system browser.
+export function BrowserOpenURL(url: string): void;
+
+// [Environment](https://wails.io/docs/reference/runtime/intro#environment)
+// Returns information about the environment
+export function Environment(): Promise;
+
+// [Quit](https://wails.io/docs/reference/runtime/intro#quit)
+// Quits the application.
+export function Quit(): void;
+
+// [Hide](https://wails.io/docs/reference/runtime/intro#hide)
+// Hides the application.
+export function Hide(): void;
+
+// [Show](https://wails.io/docs/reference/runtime/intro#show)
+// Shows the application.
+export function Show(): void;
+
+// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext)
+// Returns the current text stored on clipboard
+export function ClipboardGetText(): Promise;
+
+// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext)
+// Sets a text on the clipboard
+export function ClipboardSetText(text: string): Promise;
+
+// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop)
+// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
+export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void
+
+// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff)
+// OnFileDropOff removes the drag and drop listeners and handlers.
+export function OnFileDropOff() :void
+
+// Check if the file path resolver is available
+export function CanResolveFilePaths(): boolean;
+
+// Resolves file paths for an array of files
+export function ResolveFilePaths(files: File[]): void
\ No newline at end of file
diff --git a/tdd/wails2-root/frontend/wailsjs/runtime/runtime.js b/tdd/wails2-root/frontend/wailsjs/runtime/runtime.js
new file mode 100644
index 0000000..623397b
--- /dev/null
+++ b/tdd/wails2-root/frontend/wailsjs/runtime/runtime.js
@@ -0,0 +1,238 @@
+/*
+ _ __ _ __
+| | / /___ _(_) /____
+| | /| / / __ `/ / / ___/
+| |/ |/ / /_/ / / (__ )
+|__/|__/\__,_/_/_/____/
+The electron alternative for Go
+(c) Lea Anthony 2019-present
+*/
+
+export function LogPrint(message) {
+ window.runtime.LogPrint(message);
+}
+
+export function LogTrace(message) {
+ window.runtime.LogTrace(message);
+}
+
+export function LogDebug(message) {
+ window.runtime.LogDebug(message);
+}
+
+export function LogInfo(message) {
+ window.runtime.LogInfo(message);
+}
+
+export function LogWarning(message) {
+ window.runtime.LogWarning(message);
+}
+
+export function LogError(message) {
+ window.runtime.LogError(message);
+}
+
+export function LogFatal(message) {
+ window.runtime.LogFatal(message);
+}
+
+export function EventsOnMultiple(eventName, callback, maxCallbacks) {
+ return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks);
+}
+
+export function EventsOn(eventName, callback) {
+ return EventsOnMultiple(eventName, callback, -1);
+}
+
+export function EventsOff(eventName, ...additionalEventNames) {
+ return window.runtime.EventsOff(eventName, ...additionalEventNames);
+}
+
+export function EventsOnce(eventName, callback) {
+ return EventsOnMultiple(eventName, callback, 1);
+}
+
+export function EventsEmit(eventName) {
+ let args = [eventName].slice.call(arguments);
+ return window.runtime.EventsEmit.apply(null, args);
+}
+
+export function WindowReload() {
+ window.runtime.WindowReload();
+}
+
+export function WindowReloadApp() {
+ window.runtime.WindowReloadApp();
+}
+
+export function WindowSetAlwaysOnTop(b) {
+ window.runtime.WindowSetAlwaysOnTop(b);
+}
+
+export function WindowSetSystemDefaultTheme() {
+ window.runtime.WindowSetSystemDefaultTheme();
+}
+
+export function WindowSetLightTheme() {
+ window.runtime.WindowSetLightTheme();
+}
+
+export function WindowSetDarkTheme() {
+ window.runtime.WindowSetDarkTheme();
+}
+
+export function WindowCenter() {
+ window.runtime.WindowCenter();
+}
+
+export function WindowSetTitle(title) {
+ window.runtime.WindowSetTitle(title);
+}
+
+export function WindowFullscreen() {
+ window.runtime.WindowFullscreen();
+}
+
+export function WindowUnfullscreen() {
+ window.runtime.WindowUnfullscreen();
+}
+
+export function WindowIsFullscreen() {
+ return window.runtime.WindowIsFullscreen();
+}
+
+export function WindowGetSize() {
+ return window.runtime.WindowGetSize();
+}
+
+export function WindowSetSize(width, height) {
+ window.runtime.WindowSetSize(width, height);
+}
+
+export function WindowSetMaxSize(width, height) {
+ window.runtime.WindowSetMaxSize(width, height);
+}
+
+export function WindowSetMinSize(width, height) {
+ window.runtime.WindowSetMinSize(width, height);
+}
+
+export function WindowSetPosition(x, y) {
+ window.runtime.WindowSetPosition(x, y);
+}
+
+export function WindowGetPosition() {
+ return window.runtime.WindowGetPosition();
+}
+
+export function WindowHide() {
+ window.runtime.WindowHide();
+}
+
+export function WindowShow() {
+ window.runtime.WindowShow();
+}
+
+export function WindowMaximise() {
+ window.runtime.WindowMaximise();
+}
+
+export function WindowToggleMaximise() {
+ window.runtime.WindowToggleMaximise();
+}
+
+export function WindowUnmaximise() {
+ window.runtime.WindowUnmaximise();
+}
+
+export function WindowIsMaximised() {
+ return window.runtime.WindowIsMaximised();
+}
+
+export function WindowMinimise() {
+ window.runtime.WindowMinimise();
+}
+
+export function WindowUnminimise() {
+ window.runtime.WindowUnminimise();
+}
+
+export function WindowSetBackgroundColour(R, G, B, A) {
+ window.runtime.WindowSetBackgroundColour(R, G, B, A);
+}
+
+export function ScreenGetAll() {
+ return window.runtime.ScreenGetAll();
+}
+
+export function WindowIsMinimised() {
+ return window.runtime.WindowIsMinimised();
+}
+
+export function WindowIsNormal() {
+ return window.runtime.WindowIsNormal();
+}
+
+export function BrowserOpenURL(url) {
+ window.runtime.BrowserOpenURL(url);
+}
+
+export function Environment() {
+ return window.runtime.Environment();
+}
+
+export function Quit() {
+ window.runtime.Quit();
+}
+
+export function Hide() {
+ window.runtime.Hide();
+}
+
+export function Show() {
+ window.runtime.Show();
+}
+
+export function ClipboardGetText() {
+ return window.runtime.ClipboardGetText();
+}
+
+export function ClipboardSetText(text) {
+ return window.runtime.ClipboardSetText(text);
+}
+
+/**
+ * Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
+ *
+ * @export
+ * @callback OnFileDropCallback
+ * @param {number} x - x coordinate of the drop
+ * @param {number} y - y coordinate of the drop
+ * @param {string[]} paths - A list of file paths.
+ */
+
+/**
+ * OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
+ *
+ * @export
+ * @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
+ * @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target)
+ */
+export function OnFileDrop(callback, useDropTarget) {
+ return window.runtime.OnFileDrop(callback, useDropTarget);
+}
+
+/**
+ * OnFileDropOff removes the drag and drop listeners and handlers.
+ */
+export function OnFileDropOff() {
+ return window.runtime.OnFileDropOff();
+}
+
+export function CanResolveFilePaths() {
+ return window.runtime.CanResolveFilePaths();
+}
+
+export function ResolveFilePaths(files) {
+ return window.runtime.ResolveFilePaths(files);
+}
\ No newline at end of file
diff --git a/tdd/wails2-root/go.mod b/tdd/wails2-root/go.mod
new file mode 100644
index 0000000..9c4d3a9
--- /dev/null
+++ b/tdd/wails2-root/go.mod
@@ -0,0 +1,39 @@
+module wails
+
+go 1.23
+
+toolchain go1.23.5
+
+require github.com/wailsapp/wails/v2 v2.9.2
+
+require (
+ github.com/bep/debounce v1.2.1 // indirect
+ github.com/go-ole/go-ole v1.2.6 // indirect
+ github.com/godbus/dbus/v5 v5.1.0 // indirect
+ github.com/google/uuid v1.3.0 // indirect
+ github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e // indirect
+ github.com/labstack/echo/v4 v4.10.2 // indirect
+ github.com/labstack/gommon v0.4.0 // indirect
+ github.com/leaanthony/go-ansi-parser v1.6.0 // indirect
+ github.com/leaanthony/gosod v1.0.3 // indirect
+ github.com/leaanthony/slicer v1.6.0 // indirect
+ github.com/leaanthony/u v1.1.0 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.19 // indirect
+ github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/rivo/uniseg v0.4.4 // indirect
+ github.com/samber/lo v1.38.1 // indirect
+ github.com/tkrajina/go-reflector v0.5.6 // indirect
+ github.com/valyala/bytebufferpool v1.0.0 // indirect
+ github.com/valyala/fasttemplate v1.2.2 // indirect
+ github.com/wailsapp/go-webview2 v1.0.16 // indirect
+ github.com/wailsapp/mimetype v1.4.1 // indirect
+ golang.org/x/crypto v0.23.0 // indirect
+ golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
+ golang.org/x/net v0.25.0 // indirect
+ golang.org/x/sys v0.20.0 // indirect
+ golang.org/x/text v0.15.0 // indirect
+)
+
+// replace github.com/wailsapp/wails/v2 v2.9.2 => C:\Users\snide\go\pkg\mod
diff --git a/tdd/wails2-root/go.sum b/tdd/wails2-root/go.sum
new file mode 100644
index 0000000..6ed0576
--- /dev/null
+++ b/tdd/wails2-root/go.sum
@@ -0,0 +1,94 @@
+github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
+github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
+github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
+github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
+github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e h1:Q3+PugElBCf4PFpxhErSzU3/PY5sFL5Z6rfv4AbGAck=
+github.com/jchv/go-winloader v0.0.0-20210711035445-715c2860da7e/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
+github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
+github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
+github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
+github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
+github.com/leaanthony/debme v1.2.1 h1:9Tgwf+kjcrbMQ4WnPcEIUcQuIZYqdWftzZkBr+i/oOc=
+github.com/leaanthony/debme v1.2.1/go.mod h1:3V+sCm5tYAgQymvSOfYQ5Xx2JCr+OXiD9Jkw3otUjiA=
+github.com/leaanthony/go-ansi-parser v1.6.0 h1:T8TuMhFB6TUMIUm0oRrSbgJudTFw9csT3ZK09w0t4Pg=
+github.com/leaanthony/go-ansi-parser v1.6.0/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
+github.com/leaanthony/gosod v1.0.3 h1:Fnt+/B6NjQOVuCWOKYRREZnjGyvg+mEhd1nkkA04aTQ=
+github.com/leaanthony/gosod v1.0.3/go.mod h1:BJ2J+oHsQIyIQpnLPjnqFGTMnOZXDbvWtRCSG7jGxs4=
+github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
+github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js=
+github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=
+github.com/leaanthony/u v1.1.0 h1:2n0d2BwPVXSUq5yhe8lJPHdxevE2qK5G99PMStMZMaI=
+github.com/leaanthony/u v1.1.0/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
+github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
+github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
+github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
+github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
+github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
+github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
+github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
+github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/tkrajina/go-reflector v0.5.6 h1:hKQ0gyocG7vgMD2M3dRlYN6WBBOmdoOzJ6njQSepKdE=
+github.com/tkrajina/go-reflector v0.5.6/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
+github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
+github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/wailsapp/go-webview2 v1.0.16 h1:wffnvnkkLvhRex/aOrA3R7FP7rkvOqL/bir1br7BekU=
+github.com/wailsapp/go-webview2 v1.0.16/go.mod h1:Uk2BePfCRzttBBjFrBmqKGJd41P6QIHeV9kTgIeOZNo=
+github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
+github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
+github.com/wailsapp/wails/v2 v2.9.2 h1:Xb5YRTos1w5N7DTMyYegWaGukCP2fIaX9WF21kPPF2k=
+github.com/wailsapp/wails/v2 v2.9.2/go.mod h1:uehvlCwJSFcBq7rMCGfk4rxca67QQGsbg5Nm4m9UnBs=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
+golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
+golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200810151505-1b9f1253b3ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/tdd/wails2-root/main.go b/tdd/wails2-root/main.go
new file mode 100644
index 0000000..7a4f495
--- /dev/null
+++ b/tdd/wails2-root/main.go
@@ -0,0 +1,36 @@
+package main
+
+import (
+ "embed"
+
+ "github.com/wailsapp/wails/v2"
+ "github.com/wailsapp/wails/v2/pkg/options"
+ "github.com/wailsapp/wails/v2/pkg/options/assetserver"
+)
+
+//go:embed all:frontend/dist
+var assets embed.FS
+
+func main() {
+ // Create an instance of the app structure
+ app := NewApp()
+
+ // Create application with options
+ err := wails.Run(&options.App{
+ Title: "wails",
+ Width: 1024,
+ Height: 768,
+ AssetServer: &assetserver.Options{
+ Assets: assets,
+ },
+ BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
+ OnStartup: app.startup,
+ Bind: []interface{}{
+ app,
+ },
+ })
+
+ if err != nil {
+ println("Error:", err.Error())
+ }
+}
diff --git a/tdd/wails2-root/wails.json b/tdd/wails2-root/wails.json
new file mode 100644
index 0000000..6174bbb
--- /dev/null
+++ b/tdd/wails2-root/wails.json
@@ -0,0 +1,13 @@
+{
+ "$schema": "https://wails.io/schemas/config.v2.json",
+ "name": "wails",
+ "outputfilename": "wails",
+ "frontend:install": "npm install",
+ "frontend:build": "npm run build",
+ "frontend:dev:watcher": "npm run dev",
+ "frontend:dev:serverUrl": "auto",
+ "author": {
+ "name": "Snider",
+ "email": "snider@lt.hn"
+ }
+}