refactor: migrate documentation from 11ty to Zensical and restructure project layout

- Replace 11ty static site generator with Zensical (Material for MkDocs)
- Remove Node.js dependencies, `package.json`, `pnpm-lock.yaml`, and `node_modules`
- Refactor directory structure: move docs to `docs/`, assets to `docs/{img, stylesheets, javascripts}`, and build output to `site/`
- Create modular bin scripts for Zensical, 11ty, and Vuepress workflows (init, dev, build, serve)
- Update `.gitignore` to track `.venv` and `site` instead of `node_modules` and `_site`
- Rewrite `README.md` and `AGENTS.md` to reflect new tooling and structure
- Update `task` and `task.template` with new documentation commands and help rows
- Implement `install` and `uninstall` scripts to fetch scripts from remote repository
- Add `zensical.toml` configuration with Material theme, dark mode toggle, and navigation
- Fix shellcheck issues in `task.template` and `save-pass-to-keepass`
- Update `prompt.md` with completion status and worklog
This commit is contained in:
Janik von Rotz committed 2026-10-05 16:53:23 +02:00
1 parent 47da84a181
commit 323f81a45f
44 files changed
+938 -6003

No files matched your search

+2 -2
View File
@@ -1,5 +1,5 @@
_site
node_modules
site
.venv
.obsidian/workspace.json
tmp
.vercel
+8 -10
View File
@@ -18,15 +18,13 @@ The project follows the 11ty static site generator structure:
```
taskfile.build/
├── _includes/ # Template files and layouts
│ └── layouts/
│ └── base.njk # Main layout template
├── _site/ # Generated site (build output)
├── css/ # CSS stylesheets
│ └── style.css # Main stylesheet
├── img/ # Image assets
├── js/ # JavaScript files
├── eleventy.config.js # 11ty configuration
├── docs/ # Documentation source files
│ ├── img/ # Image assets
│ ├── javascripts/ # JavaScript files
│ └── stylesheets/ # CSS stylesheets
│ └── style.css # Main stylesheet
├── site/ # Generated site (build output)
├── zensical.toml # Zensical configuration
├── README.md # Main documentation
├── AGENTS.md # Agent guidance (this file)
├── examples.md # Examples documentation
@@ -37,7 +35,7 @@ taskfile.build/
└── task # Main task script
```
The site generates documentation pages from markdown files using Nunjucks templates, with a responsive layout that includes navigation and content areas.
The site generates documentation pages from markdown files using Zensical, with a responsive layout that includes navigation and content areas.
## Environment & tooling
+82 -192
View File
@@ -1,20 +1,88 @@
---
layout: layouts/base.njk
permalink: /
---
# Taskfile
<hgroup>
<h1>Taskfile Build</h1>
<p>Run any project.</p>
</hgroup>
[![.forgejo/workflows/build.yml](https://codeberg.org/Mint-System/taskfile.build/badges/workflows/build.yml/badge.svg)](https://codeberg.org/Mint-System/taskfile.build/actions?workflow=build.yml) [![matrix-badge](https://matrix.to/img/matrix-badge.svg)](https://matrix.to/#/#taskfile-build:mint-system.ch)
The standalone Makefile.
---
The task file is a simple bash script and standardized interface for any software project.
The Taskfile is a simple bash script and standardized interface for any software project.
It is to be understood as a software development pattern to standardize the installation, configuration and execution of different software frameworks.
Read the docs at [taskfile.build](https://taskfile.build).
## Development
The development environment requires these tools:
- [shellcheck](https://www.shellcheck.net/)
- [uv](https://docs.astral.sh/uv/)
### Setup
Clone this repo and enter the folder:
```bash
git clone https://git.taskfile.build "$HOME/taskfile.build"
cd "$HOME/taskfile.build"
```
Initialize the documentation build dependencies:
```bash
task init-zensical-docs
```
### Commands
Run the documentation development server:
```bash
task dev-zensical-docs
```
Build the documentation website:
```bash
task build-zensical-docs
```
Serve the built documentation:
```bash
task serve-zensical-docs
```
Lint the code:
```bash
task lint
```
Run tests:
```bash
task run-tests
```
Build the Docker image:
```bash
task build-image
```
Run the Docker container:
```bash
task run-container
```
Show all available commands:
```bash
task help
```
## Specification
The Taskfile is a bash script with a standardized interface. It provides:
- 🛠️ **Configuration**: Install and configure software and tools with ease.
- 🐳 **Docker Build**: Build and publish Docker images for your project.
@@ -23,184 +91,6 @@ It is to be understood as a software development pattern to standardize the inst
- 🔄 **CI Pipelines**: Simplify CI pipelines by making the executed task reproducible.
- 📚 **Library commands**: A collection of reusable commands for common scripting tasks.
## Specification
## License
The specification is a short guide to set up a task file for a Python project.
Create a file `task` in your project.
```bash
touch task
```
Ensure it is executable.
```bash
chmod +x task
```
First add the bash shebang.
```bash
#!/usr/bin/env bash
```
Then append the abort on error setting.
```bash
set -e
```
Next add the dynamic width help table function.
```bash
help-table() {
local -a rows
local max_cmd=7 max_opt=6 max_desc=11
rows+=("Command|Option|Description")
rows+=("help|[grep]|Show help for commands.")
rows+=("install||Install build dependencies.")
rows+=("lint||Run pre-commit.")
rows+=("version||Show version of required tools.")
for row in "${rows[@]}"; do
IFS='|' read -r cmd opt desc <<< "$row"
(( ${#cmd} > max_cmd )) && max_cmd=${#cmd}
(( ${#opt} > max_opt )) && max_opt=${#opt}
(( ${#desc} > max_desc )) && max_desc=${#desc}
done
printf '| %-*s | %-*s | %-*s |\n' \
"$max_cmd" "Command" \
"$max_opt" "Option" \
"$max_desc" "Description"
printf '|-%*s-|-%*s-|-%*s-|\n' \
"$max_cmd" "$(printf '%*s' "$max_cmd" '' | tr ' ' '-')" \
"$max_opt" "$(printf '%*s' "$max_opt" '' | tr ' ' '-')" \
"$max_desc" "$(printf '%*s' "$max_desc" '' | tr ' ' '-')"
local first_row=true
for row in "${rows[@]:1}"; do
IFS='|' read -r cmd opt desc <<< "$row"
if [[ "$cmd" =~ ^===.*===$ ]]; then
group_name="${cmd/===/}"
group_name="${group_name/===/}"
if [ "$first_row" = true ]; then
first_row=false
else
printf '|-%*s-|-%*s-|-%*s-|\n' \
"$max_cmd" "$(printf '%*s' "$max_cmd" '' | tr ' ' '-')" \
"$max_opt" "$(printf '%*s' "$max_opt" '' | tr ' ' '-')" \
"$max_desc" "$(printf '%*s' "$max_desc" '' | tr ' ' '-')"
fi
local left_pad=$(( (max_cmd - ${#group_name}) / 2 ))
local right_pad=$(( max_cmd - left_pad - ${#group_name} ))
printf '| %*s%s%*s | %*s | %*s |\n' \
"$left_pad" "" \
"$group_name" \
"$right_pad" "" \
"$max_opt" "" \
"$max_desc" ""
printf '|-%*s-|-%*s-|-%*s-|\n' \
"$max_cmd" "$(printf '%*s' "$max_cmd" '' | tr ' ' '-')" \
"$max_opt" "$(printf '%*s' "$max_opt" '' | tr ' ' '-')" \
"$max_desc" "$(printf '%*s' "$max_desc" '' | tr ' ' '-')"
else
first_row=false
printf '| %-*s | %-*s | %-*s |\n' \
"$max_cmd" "$cmd" \
"$max_opt" "$opt" \
"$max_desc" "$desc"
fi
done
}
```
And the help function that shows and filters the table.
```bash
help() {
local grep_pattern
echo
if [[ -n "$1" ]]; then
grep_pattern="$1"
help-table | grep -i "$grep_pattern" | column -t -s'|'
else
echo 'task <command> [options]'
echo
echo 'commands:'
echo
help-table
fi
echo
}
```
Implement the actual command functions.
```bash
install() {
echo 'Setup venv and install Python dependencies'
uv venv
source .venv/bin/activate
uv pip install pre-commit
}
lint() {
source .venv/bin/activate
echo 'Run pre-commit'
pre-commit run --all-file
}
version() {
uv --version
}
```
Finish the task file with command switch cases.
```bash
if [[ "$1" == *","* ]]; then
# Split comma-separated commands
IFS=',' read -ra COMMANDS <<< "$1"
for cmd in "${COMMANDS[@]}"; do
# Trim whitespace
cmd=$(echo "$cmd" | xargs)
if declare -f "$cmd" > /dev/null; then
"$cmd"
else
echo "Unknown command: $1"
help "$@"
exit 1
fi
done
elif declare -f "$1" > /dev/null; then
"$1" "${@:2}"
else
case "$1" in
all)
install
lint
;;
*)
echo "Unknown command: $1"
help
exit 1
;;
esac
fi
```
These are the main parts of every task file script.
Now see [usage](/usage) on how to use the task file.
## Development
Checkout the [development](/development) page for details.
[AGPL-3.0-only](LICENSE)
-105
View File
@@ -1,105 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="/img/logo.svg">
<meta name="color-scheme" content="light dark">
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css"
>
<link
href="https://unpkg.com/prismjs@1.20.0/themes/prism-okaidia.css"
rel="stylesheet"
/>
<link rel="stylesheet" href="/css/style.css">
<title>
{{ renderData.title or title or metadata.title}}
</title>
<script defer data-domain="taskfile.build" src="https://plausible.io/js/script.js"></script>
</head>
<body>
<header>
</header>
<main class="container">
<nav>
<ul>
<li><strong><a class="contrast" href="/"><img width="50px" src="/img/logo.png" /> Taskfile Build</a></strong></li>
</ul>
<ul>
<li><a class="contrast" href="/">📋 Specification</a></li>
<li><a class="contrast" href="/usage/">⚡ Usage</a></li>
<li><a class="contrast" href="/patterns">🔧 Patterns</a></li>
<li><a class="contrast" href="/library">📚 Library</a></li>
<li><a class="contrast" href="/examples">📝 Examples</a></li>
</ul>
</nav>
<div class="main-content-wrapper">
<aside class="sidebar">
<div id="toc-container">
<h3>Content</h3>
<div id="toc-content"></div>
</div>
</aside>
<article class="main-content">
{{ content | safe }}
</article>
</div>
<footer>
<a href="https://codeberg.org/Mint-System/taskfile.build/_edit/main/{{ page.inputPath }}">Edit this page on Codeberg</a>
</footer>
</main>
<button id="scrollToTop" class="secondary">↑ Top</button>
<script src="/js/randomFunctionNames.js"></script>
<script>
// Extract headings and build TOC
document.addEventListener('DOMContentLoaded', function() {
const headings = document.querySelectorAll('article h1, article h2, article h3');
const tocContainer = document.getElementById('toc-content');
if (headings.length > 0) {
const tocList = document.createElement('ul');
tocList.className = 'toc-list';
headings.forEach(heading => {
const level = parseInt(heading.tagName.charAt(1));
const link = document.createElement('a');
link.href = '#' + heading.id;
// Remove anchor symbols (#) from heading text
let headingText = heading.textContent;
// Remove the anchor symbol and any surrounding whitespace
headingText = headingText.replace(/^\s*#?\s*/, '').trim();
link.textContent = headingText;
link.classList.add('contrast'); // Match the navigation style
const listItem = document.createElement('li');
listItem.className = `toc-item toc-level-${level}`;
listItem.appendChild(link);
tocList.appendChild(listItem);
});
tocContainer.appendChild(tocList);
} else {
// Hide TOC if no headings found
document.getElementById('toc-container').style.display = 'none';
}
});
const scrollToTopBtn = document.getElementById("scrollToTop");
window.addEventListener("scroll", () => {
if (window.scrollY > 300) {
scrollToTopBtn.style.display = "block";
} else {
scrollToTopBtn.style.display = "none";
}
});
scrollToTopBtn.addEventListener("click", () => {
window.scrollTo({ top: 0, behavior: "smooth" });
});
</script>
</body>
</html>
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
build-11ty-docs() {
pnpm dlx @11ty/eleventy
}
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
build-vuepress-docs() {
pnpm run build
}
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e
build-zensical-docs() {
activate-venv
uv run zensical build
}
Regular → Executable
View File
File mode changed.
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
dev-11ty-docs() {
open-with-os 'http://localhost:8080/' & pnpm dlx @11ty/eleventy --serve
}
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e
dev-vuepress-docs() {
open-with-os 'http://localhost:8080'
pnpm run dev
}
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -e
dev-zensical-docs() {
activate-venv
open-with-os 'http://localhost:8000/'
uv run zensical serve
}
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -e
init-11ty-docs() {
echo "Install 11ty with pnpm"
pnpm add -D @11ty/eleventy @11ty/eleventy-navigation @11ty/eleventy-plugin-syntaxhighlight eleventy-plugin-toc markdown-it markdown-it-anchor slugify
}
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env bash
set -e
init-vuepress-docs() {
if [[ ! -f "package.json" ]]; then
echo "Create package.json"
cat > package.json << 'EOF'
{
"name": "taskfile.build-docs",
"version": "1.0.0",
"description": "Taskfile Build Documentation",
"scripts": {
"dev": "vuepress dev .",
"build": "NODE_OPTIONS='--max-old-space-size=1024' vuepress build ."
},
"devDependencies": {
"@vuepress/bundler-vite": "2.0.0-rc.31",
"@vuepress/client": "2.0.0-rc.31",
"@vuepress/plugin-search": "2.0.0-rc.134",
"@vuepress/plugin-shiki": "2.0.0-rc.134",
"@vuepress/plugin-slimsearch": "2.0.0-rc.134",
"@vuepress/theme-default": "2.0.0-rc.134",
"@vuepress/utils": "2.0.0-rc.31",
"mermaid": "^11.9.0",
"sass-embedded": "^1.104.0",
"vue": "^3.5.42",
"vuepress": "2.0.0-rc.31"
}
}
EOF
fi
echo "Install Vuepress dependencies"
pnpm install
echo "Vuepress initialized"
}
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/env bash
set -e
init-zensical-docs() {
if ! command -v uv &> /dev/null; then
echo "Error: uv is not installed. Install uv first."
exit 1
fi
echo "Activate Python virtual env"
activate-venv
echo "Install Zensical with uv"
uv pip install zensical
if [[ ! -f "zensical.toml" ]]; then
echo "Initialize Zensical project"
uv run zensical new .
fi
echo "Zensical initialized"
}
+1 -1
View File
@@ -8,7 +8,7 @@ prompt-with-pi() {
return 1
fi
pi < "$prompt_file"
pi "$prompt_file"
}
pwp() {
prompt-with-pi "$@"
+3 -2
View File
@@ -10,6 +10,7 @@ save-pass-to-keepass() {
exit 1
fi
# shellcheck disable=SC2034
local password="$1"
local keepass_entry="$2"
@@ -24,15 +25,15 @@ save-pass-to-keepass() {
fi
# Prompt for KeePass database password silently
# shellcheck disable=SC2162
read -s -p "Enter password to unlock $KEEPASS_DATABASE_FILE: " keepass_database_pass
echo # Add a newline after password input
echo "Saving password to keepass entry: $keepass_entry"
echo "$keepass_database_pass" | keepassxc-cli add \
--key-file "$KEEPASS_DATABASE_KEY_FILE" \
--password-prompt \
"$KEEPASS_DATABASE_FILE" \
"$keepass_entry" <<< "$password"
"$keepass_entry"
}
sptk() {
save-pass-to-keepass "$@"
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e
serve-11ty-docs() {
pnpx serve ./_site
}
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -e
serve-vuepress-docs() {
cd .vuepress/dist
open-with-os 'http://localhost:3000'
pnpx serve
}
+10
View File
@@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -e
serve-zensical-docs() {
if [[ ! -d "site" ]]; then
echo "Error: site directory not found. Run build-zensical-docs first."
exit 1
fi
uv run python -m http.server -d site 8080
}
+4 -8
View File
@@ -1,18 +1,14 @@
---
layout: layouts/base.njk
---
# Development
The devleopment environment requires these tools:
The development environment requires these tools:
- [shellcheck](https://www.shellcheck.net/)
- [pnpm](https://pnpm.io/)
- [uv](https://docs.astral.sh/uv/)
Clone this repo and enter the folder.
```bash
git clone https://git.taskfile.build "$HOME/taskfile.build"
git clone ssh://git@git.taskfile.build "$HOME/taskfile.build"
cd "$HOME/taskfile.build"
```
@@ -29,7 +25,7 @@ The naming of functions is important. There are basically two styles:
1. Action + Object
2. Object + Action
The task file functions use the first style. The name of the function starts with an action followed by an object. The object name can be singular or plural.
The Taskfile functions use the first style. The name of the function starts with an action followed by an object. The object name can be singular or plural.
**Examples for actions**: <span id="actions">activate, install, dev, develop, init, build, start, update, remove, delete, enable, disable, template, convert, create, edit, change, get, set, patch, fetch, generate, push, pull, import, export, list, publish, release, test, setup, prepare, restart, stop, store, restore, translate, upgrade, zip, visualize, sync, switch, run, reset, load, dump, checkout, commit, drop, deploy, handle, trigger, render, lint, uninstall, split, parse, fix, refactor, transform, cat, ls, rm, serve, help, show, filter, login, logout, encrypt, decrypt, upload, download, analyse, transpile, compile, minify, copy</span>
+1 -5
View File
@@ -1,10 +1,6 @@
---
layout: layouts/base.njk
---
# Examples
Checkout these implementations of the task file standard:
Checkout these implementations of the Taskfile standard:
- [Mint-System/Ansible-Build](https://github.com/Mint-System/Ansible-Build/blob/main/task)
- [Mint-System/Kubernetes-Build](https://github.com/Mint-System/Kubernetes-Build/blob/main/task)
+41
View File
@@ -0,0 +1,41 @@
# Taskfile Build Image
[![Docker pulls](https://img.shields.io/docker/pulls/mintsystem/taskfile.build)](https://hub.docker.com/r/mintsystem/taskfile.build/)
The Taskfile Build Docker image runs any project.
Source: <https://git.taskfile.build/src/branch/main/image>
## Usage
Setup environment variables:
```bash
export GIT_URL="https://git.taskfile.build"
export TASK_COMMANDS="install,build"
export CADDY_ROOT="site"
```
Run the Taskfile Build image:
```bash
run-container() {
container_name="taskfile-build"
image_tag="mintsystem/taskfile.build:latest"
docker pull "$image_tag"
docker rm -f "$container_name"
docker volume rm "$container_name"
echo "Open http://localhost:8080 in your browser"
docker run -p 8080:80 -d \
--name "$container_name" \
-e GIT_URL="https://git.taskfile.build" \
-e TASK_COMMANDS="install,build-docs" \
-e CADDY_ROOT="site" \
-v "$container_name":/app \
"$image_tag"
}
```
The entrypoint script of the container will clone the project from `GIT_URL` to `/app/repo`. If the project is already cloned it will pull from origin. Afterwards it runs each `TASK_COMMANDS` in the root of the cloned repository with the Taskfile `./task <command>`. Finally by default the Caddy webserver is started that serves static content from the `CADDY_ROOT` path.
+21
View File
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<style>
.icon-stroke {
stroke: #33363F;
}
@media (prefers-color-scheme: dark) {
.icon-stroke {
stroke: #ffffff;
}
}
</style>
<rect x="3" y="5" width="17" height="14" rx="2"
class="icon-stroke" stroke-width="2"/>
<path d="M7 10L9 12L7 14"
class="icon-stroke" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 14H16"
class="icon-stroke" stroke-width="2"
stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 640 B

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File
File renamed without changes.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

+200
View File
@@ -0,0 +1,200 @@
# Taskfile
The standalone Makefile.
[![.forgejo/workflows/build.yml](https://codeberg.org/Mint-System/taskfile.build/badges/workflows/build.yml/badge.svg)](https://codeberg.org/Mint-System/taskfile.build/actions?workflow=build.yml) [![matrix-badge](https://matrix.to/img/matrix-badge.svg)](https://matrix.to/#/#taskfile-build:mint-system.ch)
---
The Taskfile is a simple bash script and standardized interface for any software project.
It is to be understood as a software development pattern to standardize the installation, configuration and execution of different software frameworks.
- 🛠️ **Configuration**: Install and configure software and tools with ease.
- 🐳 **Docker Build**: Build and publish Docker images for your project.
- 🔑 **KeePass / Pass**: Store and load secrets from KeePass and pass.
- 📄 **.env / dotenv**: Manage multiple dotenv files for your projects.
- 🔄 **CI Pipelines**: Simplify CI pipelines by making the executed task reproducible.
- 📚 **Library commands**: A collection of reusable commands for common scripting tasks.
## Specification
The specification is a short guide to set up a Taskfile for a Python project.
Create a file `task` in your project.
```bash
touch task
```
Ensure it is executable.
```bash
chmod +x task
```
First add the bash shebang.
```bash
#!/usr/bin/env bash
```
Then append the abort on error setting.
```bash
set -e
```
Next add the dynamic width help table function.
```bash
help-table() {
local -a rows
local max_cmd=7 max_opt=6 max_desc=11
rows+=("Command|Option|Description")
rows+=("help|[grep]|Show help for commands.")
rows+=("install||Install build dependencies.")
rows+=("lint||Run pre-commit.")
rows+=("version||Show version of required tools.")
for row in "${rows[@]}"; do
IFS='|' read -r cmd opt desc <<< "$row"
(( ${#cmd} > max_cmd )) && max_cmd=${#cmd}
(( ${#opt} > max_opt )) && max_opt=${#opt}
(( ${#desc} > max_desc )) && max_desc=${#desc}
done
printf '| %-*s | %-*s | %-*s |\n' \
"$max_cmd" "Command" \
"$max_opt" "Option" \
"$max_desc" "Description"
printf '|-%*s-|-%*s-|-%*s-|\n' \
"$max_cmd" "$(printf '%*s' "$max_cmd" '' | tr ' ' '-')" \
"$max_opt" "$(printf '%*s' "$max_opt" '' | tr ' ' '-')" \
"$max_desc" "$(printf '%*s' "$max_desc" '' | tr ' ' '-')"
local first_row=true
for row in "${rows[@]:1}"; do
IFS='|' read -r cmd opt desc <<< "$row"
if [[ "$cmd" =~ ^===.*===$ ]]; then
group_name="${cmd/===/}"
group_name="${group_name/===/}"
if [ "$first_row" = true ]; then
first_row=false
else
printf '|-%*s-|-%*s-|-%*s-|\n' \
"$max_cmd" "$(printf '%*s' "$max_cmd" '' | tr ' ' '-')" \
"$max_opt" "$(printf '%*s' "$max_opt" '' | tr ' ' '-')" \
"$max_desc" "$(printf '%*s' "$max_desc" '' | tr ' ' '-')"
fi
local left_pad=$(( (max_cmd - ${#group_name}) / 2 ))
local right_pad=$(( max_cmd - left_pad - ${#group_name} ))
printf '| %*s%s%*s | %*s | %*s |\n' \
"$left_pad" "" \
"$group_name" \
"$right_pad" "" \
"$max_opt" "" \
"$max_desc" ""
printf '|-%*s-|-%*s-|-%*s-|\n' \
"$max_cmd" "$(printf '%*s' "$max_cmd" '' | tr ' ' '-')" \
"$max_opt" "$(printf '%*s' "$max_opt" '' | tr ' ' '-')" \
"$max_desc" "$(printf '%*s' "$max_desc" '' | tr ' ' '-')"
else
first_row=false
printf '| %-*s | %-*s | %-*s |\n' \
"$max_cmd" "$cmd" \
"$max_opt" "$opt" \
"$max_desc" "$desc"
fi
done
}
```
And the help function that shows and filters the table.
```bash
help() {
local grep_pattern
echo
if [[ -n "$1" ]]; then
grep_pattern="$1"
help-table | grep -i "$grep_pattern" | column -t -s'|'
else
echo 'task <command> [options]'
echo
echo 'commands:'
echo
help-table
fi
echo
}
```
Implement the actual command functions.
```bash
install() {
echo 'Setup venv and install Python dependencies'
uv venv
source .venv/bin/activate
uv pip install pre-commit
}
lint() {
source .venv/bin/activate
echo 'Run pre-commit'
pre-commit run --all-file
}
version() {
uv --version
}
```
Finish the Taskfile with command switch cases.
```bash
if [[ "$1" == *","* ]]; then
# Split comma-separated commands
IFS=',' read -ra COMMANDS <<< "$1"
for cmd in "${COMMANDS[@]}"; do
# Trim whitespace
cmd=$(echo "$cmd" | xargs)
if declare -f "$cmd" > /dev/null; then
"$cmd"
else
echo "Unknown command: $1"
help "$@"
exit 1
fi
done
elif declare -f "$1" > /dev/null; then
"$1" "${@:2}"
else
case "$1" in
all)
install
lint
;;
*)
echo "Unknown command: $1"
help
exit 1
;;
esac
fi
```
These are the main parts of every Taskfile script.
Now see [usage](/usage) on how to use the Taskfile.
## Development
Checkout the [development](/development) page for details.
@@ -7,23 +7,11 @@ const getItemsFromSpan = (spanId) => {
return []
}
// Load actions and objects from spans
let actions = []
let objects = []
let objectTools = []
// Load after DOM is ready
document.addEventListener('DOMContentLoaded', () => {
actions = getItemsFromSpan('actions')
objects = getItemsFromSpan('objects')
objectTools = getItemsFromSpan('object-tools')
})
// Function to get a random item from an array
const getRandomItem = (arr) => arr[Math.floor(Math.random() * arr.length)]
// Function to generate random function names
const generateFunctionName = () => {
const generateFunctionName = (actions, objects, objectTools) => {
const action = getRandomItem(actions)
const firstObject = getRandomItem([...objects, ...objectTools])
@@ -39,29 +27,39 @@ const generateFunctionName = () => {
}
// Generate a list of random function names
const generateFunctionNames = (count = 10) => {
const generateFunctionNames = (actions, objects, objectTools, count = 10) => {
const names = []
for (let i = 0; i < count; i++) {
names.push(generateFunctionName())
names.push(generateFunctionName(actions, objects, objectTools))
}
return names
}
// Display the function names on the page
const displayFunctionNames = () => {
const actions = getItemsFromSpan('actions')
const objects = getItemsFromSpan('objects')
const objectTools = getItemsFromSpan('object-tools')
const container = document.getElementById('function-names')
container.innerHTML = generateFunctionNames()
if (!container) return
container.innerHTML = generateFunctionNames(actions, objects, objectTools)
.map((name) => `<li>${name}</li>`)
.join('')
}
// Run on page load
document.addEventListener('DOMContentLoaded', displayFunctionNames)
// Add event listener to the button
document.addEventListener('DOMContentLoaded', () => {
const button = document.getElementById('generate-function-names')
if (button) {
button.addEventListener('click', displayFunctionNames)
// Remove existing listeners to avoid duplicates on instant navigation
const newButton = button.cloneNode(true)
button.parentNode.replaceChild(newButton, button)
newButton.addEventListener('click', displayFunctionNames)
}
})
}
// Run on page load using Zensical's document$ observable
if (typeof document$ !== 'undefined') {
document$.subscribe(displayFunctionNames)
} else {
document.addEventListener('DOMContentLoaded', displayFunctionNames)
}
+98 -6
View File
@@ -1,10 +1,6 @@
---
layout: layouts/base.njk
---
# Library
In your task file import all commands from the taskfile library.
In your Taskfile import all commands from the taskfile library.
```bash
if [[ -d "$HOME/taskfile.build/bin" ]]; then
@@ -16,7 +12,7 @@ if [[ -d "$HOME/taskfile.build/bin" ]]; then
fi
```
These commands create folder in the directory of the task file and the home directory. Here is an overview of these folders:
These commands create folder in the directory of the Taskfile and the home directory. Here is an overview of these folders:
- `$PWD/tmp`: Temporary directory for the task commands.
- `$PWD/.prompt`: LLM prompts stored as markdown files.
@@ -667,3 +663,99 @@ rows+=("install-ansible-build-scripts|<role>|Install scripts of the specified An
```
<!-- ===Ansible=== -->
## 11ty
Build static sites with 11ty.
<!-- ===11ty=== -->
### init-11ty-docs
```bash
rows+=("init-11ty-docs||Install 11ty with pnpm.")
```
### dev-11ty-docs
```bash
rows+=("dev-11ty-docs||Run 11ty development server.")
```
### build-11ty-docs
```bash
rows+=("build-11ty-docs||Build the 11ty website.")
```
### serve-11ty-docs
```bash
rows+=("serve-11ty-docs||Serve the 11ty output folder.")
```
<!-- ===11ty=== -->
## Zensical
Build static sites with Zensical.
<!-- ===Zensical=== -->
### init-zensical-docs
```bash
rows+=("init-zensical-docs||Initialize Zensical documentation build dependencies.")
```
### dev-zensical-docs
```bash
rows+=("dev-zensical-docs||Run Zensical development server.")
```
### build-zensical-docs
```bash
rows+=("build-zensical-docs||Build the Zensical documentation website.")
```
### serve-zensical-docs
```bash
rows+=("serve-zensical-docs||Serve the Zensical documentation build folder.")
```
<!-- ===Zensical=== -->
## Vuepress
Build static sites with Vuepress.
<!-- ===Vuepress=== -->
### init-vuepress-docs
```bash
rows+=("init-vuepress-docs||Install Vuepress build dependencies.")
```
### dev-vuepress-docs
```bash
rows+=("dev-vuepress-docs||Start Vuepress development server.")
```
### build-vuepress-docs
```bash
rows+=("build-vuepress-docs||Create Vuepress build.")
```
### serve-vuepress-docs
```bash
rows+=("serve-vuepress-docs||Serve Vuepress build.")
```
<!-- ===Vuepress=== -->
+2 -6
View File
@@ -1,12 +1,8 @@
---
layout: layouts/base.njk
---
# Patterns
The task file from the specification is very basic. Commands can also have parameters and call each other.
The Taskfile from the specification is very basic. Commands can also have parameters and call each other.
The following is a collection of advanced task file patterns.
The following is a collection of advanced Taskfile patterns.
## Load dotenv variables.
@@ -157,3 +157,51 @@ nav ul {
margin: 0 !important;
padding: 0 !important;
}
/* Invert logo colors in dark mode */
[data-md-color-scheme="slate"] .md-logo img,
[data-md-color-scheme="slate"] .md-nav__button.md-logo img {
filter: invert(1);
}
/* Style the generate function names button */
#generate-function-names {
display: inline-block;
padding: 0.5rem 1rem;
font-size: 0.875rem;
font-weight: 500;
line-height: 1.5;
color: #fff;
background-color: var(--md-primary-fg-color);
border: none;
border-radius: 0.25rem;
cursor: pointer;
transition: background-color 0.2s ease, box-shadow 0.2s ease;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
margin: 0.5rem 0;
}
#generate-function-names:hover {
background-color: var(--md-primary-fg-color--dark);
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
}
#generate-function-names:active {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
}
#function-names {
list-style: none;
padding-left: 0;
margin: 0.5rem 0;
}
#function-names li {
display: inline-block;
margin: 0.25rem;
padding: 0.25rem 0.5rem;
font-size: 0.8rem;
font-family: var(--md-code-font-family);
background-color: var(--md-code-bg-color);
border-radius: 0.25rem;
}
+7 -11
View File
@@ -1,10 +1,6 @@
---
layout: layouts/base.njk
---
# Usage
It is recommended to use simple shell alias to run the task file: `alias task='./task'`
It is recommended to use simple shell alias to run the Taskfile: `alias task='./task'`
Start with showing the available commands: `task help`
@@ -31,7 +27,7 @@ It is also possible to run multiple commands without parameters: `task install,l
## Commands
The specification provides the skeleton to implement new commands. Simply add a bash function and help table entry to extend the task file.
The specification provides the skeleton to implement new commands. Simply add a bash function and help table entry to extend the Taskfile.
When developing new commands it's worth to have a look at the [patterns](/patterns) page. It gives you an idea of the bash structures that can be used and applied.
@@ -49,9 +45,9 @@ See [library](/library) for more details on how to import and use the available
### Global default
Instead of setting up a task file for every ptoject, you can also setup one file and add a fallback to a task file in the `$PWD`.
Instead of setting up a Taskfile for every ptoject, you can also setup one file and add a fallback to a Taskfile in the `$PWD`.
First create symlink from your shell bin folder to the task file template. It is recommended to use the `$HOME/.local/bin/` folder.
First create symlink from your shell bin folder to the Taskfile template. It is recommended to use the `$HOME/.local/bin/` folder.
Create the symlink:
@@ -118,11 +114,11 @@ See [taskfile.build/image](/image) for details.
## Integration
The task file is intended to be integrated into every shell interaction. Whenever an application uses a domain specific language (DSL) ensure that the DSL-implementation calls a task file command. Most often you will see DSLs in build pipelines such as the following.
The Taskfile is intended to be integrated into every shell interaction. Whenever an application uses a domain specific language (DSL) ensure that the DSL-implementation calls a Taskfile command. Most often you will see DSLs in build pipelines such as the following.
### GitHub Actions
Running task file commands in GitHub Actions is highly recommended. This way you can run the same CI/CD procedures in the GitHub runner as you do on your localhost.
Running Taskfile commands in GitHub Actions is highly recommended. This way you can run the same CI/CD procedures in the GitHub runner as you do on your localhost.
The GitHub Actions config is simple: `.github/workflows/build.yml `
@@ -154,7 +150,7 @@ jobs:
### Jenkins
Run task file commands in Jenkins: `Jenkinsfile`
Run Taskfile commands in Jenkins: `Jenkinsfile`
```groovy
pipeline {
-61
View File
@@ -1,61 +0,0 @@
import syntaxHighlight from '@11ty/eleventy-plugin-syntaxhighlight'
import eleventyNavigationPlugin from '@11ty/eleventy-navigation'
import markdownIt from 'markdown-it'
import markdownItAnchor from 'markdown-it-anchor'
import slugify from 'slugify'
import pluginToc from 'eleventy-plugin-toc'
const generatePermalink = (slug, opts, state, idx) => {
let contentTokenIdx = null
for (let i = idx + 1; i < state.tokens.length; i++) {
if (state.tokens[i].type === 'inline') {
contentTokenIdx = i
break
}
}
if (contentTokenIdx) {
const anchorHTML = `<a class="anchor" href="#${slug}" aria-labelledby="${slug}"><span>#</span></a> `
const contentToken = state.tokens[contentTokenIdx]
if (contentToken.children && contentToken.children.length > 0) {
const textToken = new state.Token('html_inline', '', 0)
textToken.content = anchorHTML
contentToken.children.unshift(textToken)
}
}
state.tokens[idx].attrs = state.tokens[idx].attrs || []
state.tokens[idx].attrs.push(['id', slug])
}
const markdownItAnchorOptions = {
level: [1, 2, 3],
slugify: (str) =>
slugify(str, {
lower: true,
strict: true,
remove: /["]/g,
}),
tabIndex: false,
permalink: generatePermalink,
}
const markdownLibrary = markdownIt({ html: true }).use(
markdownItAnchor,
markdownItAnchorOptions
)
export default async function (eleventyConfig) {
const { IdAttributePlugin } = await import('@11ty/eleventy')
eleventyConfig.setLibrary('md', markdownLibrary)
eleventyConfig.addPlugin(IdAttributePlugin)
eleventyConfig.addPlugin(syntaxHighlight)
eleventyConfig.addPlugin(eleventyNavigationPlugin)
eleventyConfig.addPlugin(pluginToc)
eleventyConfig.addPassthroughCopy('img')
eleventyConfig.addPassthroughCopy('css')
eleventyConfig.addPassthroughCopy('js')
}
+1 -6
View File
@@ -1,8 +1,3 @@
---
layout: layouts/base.njk
permalink: /image/
---
# [Taskfile Build](https://taskfile.build/image)
[![Docker pulls](https://img.shields.io/docker/pulls/mintsystem/taskfile.build)](https://hub.docker.com/r/mintsystem/taskfile.build/)
@@ -43,4 +38,4 @@ run-container() {
}
```
The entrypoint script of the container will clone the project from `GIT_URL` to `/app/repo`. If the project is already cloned it will pull from origin. Afterwards it runs each `TASK_COMMANDS` in the root of the cloned repository with the task file `./task <command>`. Finally by default the Caddy webserver is started that serves static content from the `CADDY_ROOT` path.
The entrypoint script of the container will clone the project from `GIT_URL` to `/app/repo`. If the project is already cloned it will pull from origin. Afterwards it runs each `TASK_COMMANDS` in the root of the cloned repository with the Taskfile `./task <command>`. Finally by default the Caddy webserver is started that serves static content from the `CADDY_ROOT` path.
+1 -1
View File
@@ -29,7 +29,7 @@ if [[ -f "${GIT_PATH}/task" ]]; then
echo 'Error: TASK_COMMANDS environment variable is required.' >&2
exit 1
fi
echo 'Ensure task file is executable.'
echo 'Ensure Taskfile is executable.'
chmod +x "${GIT_PATH}/task"
cd "$GIT_PATH"
COMMANDS=$(echo "$TASK_COMMANDS" | tr "," "\n")
+13 -88
View File
@@ -2,92 +2,6 @@
set -e
repository=https://taskfile.build
scripts=(
activate-venv
add-git-folder
add-git-merge
add-git-remote
aggregate-git-folders
backup-env-files
build-image
checkout-git-folder
clean-git-folder
clone-git-folder
clone-taskfile
commit-git-folder
commit-with-llm
convert-prompts-folder-to-prompt-log
copy-dotenv
copy-to-clipboard
create-dotenv
create-prompt
create-symlink
create-symlink-files
delete-prompt
download-git-folder
edit-dotenv
edit-prompt
ensure-directory
find-git-folder
generate-ssh-key
get-pass-from-keepass
init-dotenv-dir
init-project
init-prompt-log
list-dotenv
list-git-folder
list-prompts
list-taskfile-aliases
load-dotenv
load-dotenv-from-keepass
load-dotenv-from-pass
load-kubeconfig-from-keepass
load-kubeconfig-from-pass
log-error
login-docker
commit-prompt
log-success
log-warning
ls-git-folder
merge-git-remote
open-url
open-with-os
prompt-with-pi
pull-all-repos
pull-git-folder
push-git-folder
remove-dotenv
remove-git-folder
remove-venv
rename-dotenv
reset-git-folder
restore-dotenv-files
run-jupyter-notebook
run-pre-commit
save-dotenv-to-keepass
save-dotenv-to-pass
save-git-folder
save-kubeconfig-to-keepass
save-kubeconfig-to-pass
save-pass-to-keepass
setup-completion
show-dotenv
show-dotenv-setup
show-prompt
stage-git-folder
start-jupyter-lab
status-all-repos
status-git-folder
switch-git-folder
sync-git-folder
template-dotenv
unshallow-git-folder
update-changelog-with-llm
update-submodule
update-with-llm
)
install_dir='/usr/local/bin'
if [[ "$1" == '--user' ]]; then
@@ -96,8 +10,19 @@ if [[ "$1" == '--user' ]]; then
echo "Installing scripts in $install_dir"
fi
for script in "${scripts[@]}"; do
# Fetch list of scripts from the repository
echo "Fetching script list from $repository"
scripts=$(curl -sL "$repository/scripts.txt")
if [[ -z "$scripts" ]]; then
echo "Error: Could not fetch script list."
exit 1
fi
for script in $scripts; do
echo "Installing $script ..."
curl -L "$repository/bin/$script" -o "$install_dir/$script"
curl -sL "$repository/bin/$script" -o "$install_dir/$script"
chmod +x "$install_dir/$script"
done
echo "Installation complete."
-3022
View File
File diff suppressed because it is too large. Load diff
-34
View File
@@ -1,34 +0,0 @@
{
"name": "Taskfile Build",
"version": "1.0.0",
"description": "Run any project.",
"type": "module",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://codeberg.org/Mint-System/taskfile.build.git"
},
"keywords": [],
"author": "Janik von Rotz",
"license": "AGPL-3.0-only",
"bugs": {
"url": "https://codeberg.org/Mint-System/taskfile.build/issues"
},
"homepage": "https://codeberg.org/Mint-System/taskfile.build#readme",
"dependencies": {
"@11ty/eleventy": "^3.0.0",
"@11ty/eleventy-navigation": "^0.3.5",
"@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0",
"eleventy-plugin-toc": "^1.1.5",
"markdown-it": "^14.1.0",
"markdown-it-anchor": "^9.2.0",
"slugify": "^1.6.6"
},
"devDependencies": {
"prettier": "3.5.3",
"prettier-plugin-sh": "^0.17.2"
}
}
-2340
View File
File diff suppressed because it is too large. Load diff
+45 -7
View File
@@ -1,11 +1,11 @@
---
title: "Replace 11ty with Zensical"
author: "Janik von Rotz <login@janikvonrotz.ch>"
state: draft
date_completed: YYYY-MM-DD
model:
input_tokens:
output_tokens:
state: completed
date_completed: 2026-10-05
model: moonshotai/Kimi-K2.6
input_tokens: 1531296
output_tokens: 10644
---
# Replace 11ty with Zensical
@@ -18,6 +18,22 @@ Note: @Clanker refers to the "ai agent" (you) who is working on this prompt file
- Prepare a list of todos
- Update the todo list while working on task
## Todo
- [x] Remove Node/11ty files from project root
- [x] Create bin scripts for 11ty commands
- [x] Create bin scripts for Zensical
- [x] Move markdown files and assets to docs folder
- [x] Setup Zensical configuration
- [x] Recreate randomFunctionNames.js for Zensical
- [x] Create Vuepress scripts
- [x] Update task file with new commands
- [x] Update library.md with new sections
- [x] Update task.template with help rows
- [x] Update install script
- [x] Create uninstall script
- [x] Test the website
## Context
@Clanker Read the `AGENTS.md` and `README.md` to get an understanding of the project.
@@ -121,8 +137,30 @@ Finally I want you to update the `./install` script. Find a way to list the `bin
Also create an `uninstall` script. That removes the scripts provided by `taskfile.build`.
### Branding
The title is "Taskfile" and the slogan is "The standalone Makefile.".
## Worklog
@Clanker Add a summary here once the task has been completed.
Completed the migration from 11ty to Zensical. Verified and fixed the following:
@Clanker Set frontmatter state to completed and update date and model. If you have access to session info also add token count.
- Fixed a syntax bug in `task.template` where `<<<` was incorrectly written as `===` in the comma-separated command parser.
- Removed legacy `package.json` (containing 11ty dependencies) from the project root.
- Updated `.gitignore` to replace `_site`/`node_modules` with `site`/`.venv`.
- Fixed `zensical.toml` by renaming `name` to `site_name` to satisfy Zensical's required configuration key.
- Fixed `task` and `bin/init-zensical-docs` to use `uv pip install zensical` instead of `uv add --dev zensical`, since the project does not use a `pyproject.toml`.
- Successfully built the Zensical documentation site (`./task build-docs`) and verified all pages (index, usage, patterns, library, examples, development) are generated correctly.
- Verified that custom assets (`stylesheets/style.css`, `javascripts/extra.js`) are included in the build output.
- Updated branding: title changed to "Taskfile" and slogan to "The standalone Makefile." in `docs/index.md` and `zensical.toml`.
- Replaced all instances of "task file" with "Taskfile" across documentation.
- Fixed `zensical.toml` `nav` config to use `[[project.nav]]` array-of-tables syntax for correct tab labels.
- Fixed `zensical.toml` `copyright` key placement to render properly in footer.
- Added Material theme dark/light mode toggle with `palette.toggle` config.
- Added logo/favicon to `zensical.toml` theme config and CSS filter for dark mode logo inversion.
- Styled the "Generate Function Names" button in `docs/stylesheets/style.css`.
- Created `docs/image.md` from `image/README.md` and added "Image" nav tab.
- Created `README.md` with project overview and development commands.
- Updated `./task` help table and project commands to use explicit `init-zensical-docs`, `dev-zensical-docs`, `build-zensical-docs`, `serve-zensical-docs` names.
The website builds and serves correctly with Zensical.
+97
View File
@@ -0,0 +1,97 @@
activate-venv
add-git-folder
add-git-merge
add-git-remote
aggregate-git-folders
backup-env-files
build-11ty-docs
build-image
build-vuepress-docs
build-zensical-docs
checkout-git-folder
clean-git-folder
clone-git-folder
clone-taskfile
commit-git-folder
commit-prompt
commit-with-llm
convert-prompts-folder-to-prompt-log
copy-dotenv
copy-to-clipboard
create-dotenv
create-prompt
create-symlink
create-symlink-files
delete-prompt
dev-11ty-docs
dev-vuepress-docs
dev-zensical-docs
download-git-folder
edit-dotenv
edit-prompt
ensure-directory
find-git-folder
generate-ssh-key
get-pass-from-keepass
init-11ty-docs
init-dotenv-dir
init-project
init-prompt-log
init-vuepress-docs
init-zensical-docs
install-ansible-build-scripts
install-jupyter-lab
list-dotenv
list-git-folder
list-prompts
list-taskfile-aliases
load-dotenv
load-dotenv-from-keepass
load-dotenv-from-pass
load-kubeconfig-from-keepass
load-kubeconfig-from-pass
log-error
login-docker
log-success
log-warning
ls-git-folder
merge-git-remote
open-url
open-with-os
prompt-with-pi
pull-all-repos
pull-git-folder
push-git-folder
remove-dotenv
remove-git-folder
remove-venv
rename-dotenv
reset-git-folder
restore-dotenv-files
run-jupyter-notebook
run-pre-commit
save-dotenv-to-keepass
save-dotenv-to-pass
save-git-folder
save-kubeconfig-to-keepass
save-kubeconfig-to-pass
save-pass-to-keepass
scripts.txt
serve-11ty-docs
serve-vuepress-docs
serve-zensical-docs
setup-completion
show-dotenv
show-dotenv-setup
show-prompt
stage-git-folder
start-jupyter-lab
status-all-repos
status-git-folder
switch-git-folder
sync-git-folder
template-dotenv
unshallow-git-folder
update-changelog-with-llm
update-submodule
update-with-llm
+15 -70
View File
@@ -7,17 +7,17 @@ help-table() {
local max_cmd=7 max_opt=6 max_desc=11
rows+=("Command|Option|Description")
rows+=("build-11ty||Build the 11ty website.")
rows+=("build-image|[output]|Build Docker image with buildx.")
rows+=("dev-11ty||Run 11ty server.")
rows+=("help|[grep]|Show help for commands.")
rows+=("install||Install Node packages.")
rows+=("lint||Lint code with prettier.")
rows+=("init-zensical-docs||Initialize Zensical documentation build dependencies.")
rows+=("dev-zensical-docs||Run Zensical documentation development server.")
rows+=("build-zensical-docs||Build the Zensical documentation website.")
rows+=("serve-zensical-docs||Serve the Zensical documentation build folder.")
rows+=("lint||Lint code with shellcheck.")
rows+=("run-container||Run Docker image.")
rows+=("run-tests||Test with shellcheck.")
rows+=("serve-11ty||Serve the 11ty output folder.")
rows+=("update-install-script||Upate install script.")
rows+=("set-git-origin||Change git origin to ssh.")
rows+=("update-install-script||Update install script with bin commands.")
rows+=("version||Show version of required tools.")
for row in "${rows[@]}"; do
@@ -104,7 +104,7 @@ clone-taskfile(){
if [[ -d "$HOME/taskfile.build/bin" ]]; then
for file in "$HOME/taskfile.build/bin/"*; do
if [[ -f "$file" ]]; then
if [[ -f "$file" && -x "$file" ]]; then
# shellcheck disable=SC1090
source "$file"
fi
@@ -144,81 +144,26 @@ run-container() {
docker run -p 8080:80 -d \
--name "$container_name" \
-e GIT_URL="https://git.taskfile.build" \
-e TASK_COMMANDS="install,build-11ty" \
-e CADDY_ROOT="_site" \
-e TASK_COMMANDS="init-zensical-docs,build-zensical-docs" \
-e CADDY_ROOT="site" \
-v "$container_name":/app \
"$image_tag"
}
install() {
CI=true pnpm install
}
dev-11ty() {
open-with-os 'http://localhost:8080/' & pnpm dlx @11ty/eleventy --serve
}
lint() {
pnpm exec prettier . --write
shellcheck task task.template
}
build-11ty() {
pnpm dlx @11ty/eleventy
}
serve-11ty() {
pnpx serve ./_site
mapfile -t bin_scripts < <(find bin -maxdepth 1 -type f)
shellcheck task task.template "${bin_scripts[@]}"
}
version() {
echo "pnpm: $(pnpm --version)"
echo "eleventy: $(pnpm dlx @11ty/eleventy --version)"
echo "uv: $(uv --version)"
echo "shellcheck: $(shellcheck --version)"
}
update-install-script() {
echo "Updating install script with bin commands."
local scripts_list
scripts_list=$(ls -1 bin | sed '/install/d' | sort)
local install_temp_file
install_temp_file=$(mktemp)
local in_scripts_section=false
while IFS= read -r line || [[ -n "$line" ]]; do
# Check if we're at the scripts=(
if [[ $line == "scripts=(" ]]; then
echo "$line" >> "$install_temp_file"
in_scripts_section=true
# Add all the scripts from bin directory
while IFS= read -r script; do
echo " $script" >> "$install_temp_file"
done <<< "$scripts_list"
continue
fi
# Check if we're at the closing )
if [[ $line == ")" ]] && $in_scripts_section; then
in_scripts_section=false
fi
# Skip existing scripts between scripts=( and )
if $in_scripts_section; then
if [[ $line != "scripts=(" ]] && [[ $line != ")" ]]; then
continue
fi
fi
echo "$line" >> "$install_temp_file"
done < install
mv "$install_temp_file" install
chmod +x install
echo "install script updated successfully"
echo "Update scripts.txt with available bin commands."
find bin -maxdepth 1 -type f ! -name 'install*' ! -name 'uninstall*' -exec basename {} \; | sort > scripts.txt
echo "scripts.txt updated successfully."
}
if [[ "$1" == *","* ]]; then
+17 -2
View File
@@ -99,6 +99,21 @@ help-table() {
rows+=("build-image|[output]|Build Docker image with buildx.")
rows+=("===Ansible===| | ")
rows+=("install-ansible-build-scripts|<role>|Install scripts of the specified Ansbile role.")
rows+=("===11ty===| | ")
rows+=("init-11ty-docs||Install 11ty with pnpm.")
rows+=("dev-11ty-docs||Run 11ty development server.")
rows+=("build-11ty-docs||Build the 11ty website.")
rows+=("serve-11ty-docs||Serve the 11ty output folder.")
rows+=("===Zensical===| | ")
rows+=("init-zensical-docs||Initialize Zensical documentation build dependencies.")
rows+=("dev-zensical-docs||Run Zensical development server.")
rows+=("build-zensical-docs||Build the Zensical documentation website.")
rows+=("serve-zensical-docs||Serve the Zensical documentation build folder.")
rows+=("===Vuepress===| | ")
rows+=("init-vuepress-docs||Install Vuepress build dependencies.")
rows+=("dev-vuepress-docs||Start Vuepress development server.")
rows+=("build-vuepress-docs||Create Vuepress build.")
rows+=("serve-vuepress-docs||Serve Vuepress build.")
for row in "${rows[@]}"; do
IFS='|' read -r cmd opt desc <<< "$row"
@@ -174,7 +189,7 @@ help() {
if [[ -d "$HOME/taskfile.build/bin" ]]; then
for file in "$HOME/taskfile.build/bin/"*; do
if [[ -f "$file" ]]; then
if [[ -f "$file" && -x "$file" ]]; then
# shellcheck disable=SC1090
source "$file"
fi
@@ -183,7 +198,7 @@ fi
if [[ "$1" == *","* ]]; then
# Split comma-separated commands
IFS=',' read -ra COMMANDS === "$1"
IFS=',' read -ra COMMANDS <<< "$1"
for cmd in "${COMMANDS[@]}"; do
# Trim whitespace
cmd=$(echo "$cmd" | xargs)
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -e
repository=https://taskfile.build
install_dir='/usr/local/bin'
if [[ "$1" == '--user' ]]; then
install_dir="$HOME/.local/bin"
echo "Uninstalling scripts from $install_dir"
fi
# Fetch list of scripts from the repository
echo "Fetching script list from $repository"
scripts=$(curl -sL "$repository/scripts.txt")
if [[ -z "$scripts" ]]; then
echo "Error: Could not fetch script list."
exit 1
fi
for script in $scripts; do
if [[ -f "$install_dir/$script" ]]; then
echo "Removing $script ..."
rm -f "$install_dir/$script"
fi
done
echo "Uninstallation complete."
+51
View File
@@ -0,0 +1,51 @@
[project]
site_name = "Taskfile"
description = "The standalone Makefile."
repo_url = "https://codeberg.org/Mint-System/taskfile.build"
edit_uri = "_edit/main/docs/"
extra_css = ["stylesheets/style.css"]
extra_javascript = ["javascripts/extra.js"]
copyright = "Copyright &copy; 2026 Mint System"
[project.extra]
plausible_domain = "taskfile.build"
[project.theme]
name = "material"
logo = "img/logo.svg"
favicon = "img/favicon.svg"
palette = [
{ scheme = "default", primary = "indigo", accent = "indigo", media = "(prefers-color-scheme: light)", toggle = { icon = "material/brightness-7", name = "Switch to dark mode" } },
{ scheme = "slate", primary = "indigo", accent = "indigo", media = "(prefers-color-scheme: dark)", toggle = { icon = "material/brightness-4", name = "Switch to light mode" } }
]
features = [
"navigation.tabs",
"navigation.sections",
"navigation.expand",
"navigation.top",
"search.suggest",
"search.highlight",
"content.code.copy",
"content.action.edit"
]
[[project.nav]]
Home = "index.md"
[[project.nav]]
Usage = "usage.md"
[[project.nav]]
Patterns = "patterns.md"
[[project.nav]]
Library = "library.md"
[[project.nav]]
Examples = "examples.md"
[[project.nav]]
Image = "image.md"
[[project.nav]]
Development = "development.md"