chore: update items

This commit is contained in:
Jesús Pérez 2026-01-08 21:19:01 +00:00
parent 3904d2fbc7
commit a327f59bf7
Signed by: jesus
GPG Key ID: 9F243E355E0BC939
13 changed files with 0 additions and 2077 deletions

View File

@ -1,239 +0,0 @@
# FormInquire Integration System
Dynamic form generation using Jinja2 templates rendered with `nu_plugin_tera`.
## Architecture
```
provisioning/core/forminquire/
├── templates/ # Jinja2 form templates (.j2)
│ ├── setup-wizard.form.j2
│ ├── workspace-init.form.j2
│ ├── settings-update.form.j2
│ ├── server-delete-confirm.form.j2
│ └── ...more templates
├── nulib/
│ └── forminquire.nu # Nushell integration functions
└── wrappers/
└── form.sh # Bash wrapper for FormInquire
```
## How It Works
1. **Template Rendering**: Jinja2 templates are rendered with data from config files
2. **Form Generation**: Rendered templates are saved as TOML forms in cache
3. **User Interaction**: FormInquire binary presents the form to user
4. **Result Processing**: JSON output from FormInquire is returned to calling code
```
Config Data → Template Rendering → Form Generation → FormInquire → JSON Output
(nu_plugin_tera) (cache: ~/.cache/) (interactive)
```
## Quick Examples
### Settings Update with Current Values as Defaults
```nushell
use provisioning/core/forminquire/nulib/forminquire.nu *
# Load current settings and show form with them as defaults
let result = (settings-update-form)
if $result.success {
# Process updated settings
print $"Updated: ($result.values | to json)"
}
```
### Setup Wizard
```nushell
let result = (setup-wizard-form)
if $result.success {
print "Setup configuration:"
print ($result.values | to json)
}
```
### Workspace Initialization
```nushell
let result = (workspace-init-form "my-workspace")
if $result.success {
print "Workspace created with settings:"
print ($result.values | to json)
}
```
### Server Delete Confirmation
```nushell
let confirm = (server-delete-confirm-form "web-01" "192.168.1.10" "running")
if $confirm.success {
let confirmation_text = $confirm.values.confirmation_text
let final_confirm = $confirm.values.final_confirm
if ($confirmation_text == "web-01" and $final_confirm) {
print "Deleting server..."
}
}
```
## Template Variables
All templates have access to:
### Automatic Variables (always available)
- `now_iso`: Current timestamp in ISO 8601 format
- `home_dir`: User's home directory
- `username`: Current username
- `provisioning_root`: Provisioning root directory
### Custom Variables (passed per form)
- Settings from `config.defaults.toml`
- User preferences from `~/.config/provisioning/user_config.yaml`
- Workspace configuration from workspace `config.toml`
- Any custom data passed to the form function
## Cache Management
Forms are cached at: `~/.cache/provisioning/forms/`
### Cleanup Old Forms
```nushell
let cleanup_result = (cleanup-form-cache)
print $"Cleaned up ($cleanup_result.cleaned) old form files"
```
### List Generated Forms
```nushell
list-cached-forms
```
## Template Syntax
Templates use Jinja2 syntax with macros for common form elements:
```jinja2
[items.my_field]
type = "text"
prompt = "Enter value"
default = "{{ my_variable }}"
help = "Help text here"
required = true
```
### Available Form Types
- `text`: Text input
- `select`: Dropdown selection
- `confirm`: Yes/No confirmation
- `password`: Masked password input
- `multiselect`: Multiple selection
## Available Functions
### Form Execution
- `interactive-form [name] [template] [data]` - Complete form flow
- `render-template [template_name] [data]` - Render template only
- `generate-form [form_name] [template_name] [data]` - Generate TOML form
- `run-form [form_path]` - Execute FormInquire with form
### Config Loading
- `load-user-preferences` - Load user preferences from config
- `load-workspace-config [workspace_name]` - Load workspace settings
- `load-system-defaults` - Load system defaults
- `get-form-context [workspace_name] [custom_data]` - Merged config context
### Convenience Functions
- `settings-update-form` - Update system settings
- `setup-wizard-form` - Run setup wizard
- `workspace-init-form [name]` - Initialize workspace
- `server-delete-confirm-form [name] [ip] [status]` - Delete confirmation
### Utilities
- `list-templates` - List available templates
- `list-cached-forms` - List generated forms in cache
- `cleanup-form-cache` - Remove old cached forms
## Shell Integration
Use the bash wrapper for shell scripts:
```bash
#!/bin/bash
# Generate form with Nushell
nu -c "use forminquire *; interactive-form 'my-form' 'my-template' {foo: 'bar'}" > /tmp/form.toml
# Or use form.sh wrapper directly
./provisioning/core/forminquire/wrappers/form.sh /path/to/form.toml json
```
## Performance Notes
- **First form**: ~200ms (template rendering + form generation)
- **Subsequent forms**: ~50ms (cached config loading)
- **User interaction**: Depends on FormInquire response time
- **Form cache**: Automatically cleaned after 1+ days
## Dependencies
- `forminquire` - FormInquire binary (in PATH)
- `nu_plugin_tera` - Nushell Jinja2 template plugin
- `Nushell 0.109.0+` - Core scripting language
## Error Handling
All functions return structured results:
```nushell
{
success: bool # Operation succeeded
error: string # Error message (empty if success)
form_path: string # Generated form path (if applicable)
values: record # FormInquire output values
}
```
## Adding New Forms
1. Create template in `templates/` with `.form.j2` extension
2. Create convenience function in `forminquire.nu` like `my-form-function`
3. Use in scripts: `my-form-function [args...]`
Example:
```jinja2
# templates/my-form.form.j2
[meta]
title = "My Custom Form"
[items.field1]
type = "text"
prompt = "Enter value"
default = "{{ default_value }}"
```
```nushell
# In forminquire.nu
export def my-form-function [default_value: string = ""] {
interactive-form "my-form" "my-form" {default_value: $default_value}
}
```
## Limitations
- Template rendering uses Jinja2 syntax only
- FormInquire must be in PATH
- `nu_plugin_tera` must be installed for template rendering
- Form output limited to FormInquire-supported types

View File

@ -1,540 +0,0 @@
#!/usr/bin/env nu
# [command]
# name = "forminquire integration"
# group = "infrastructure"
# tags = ["forminquire", "forms", "interactive", "templates"]
# version = "1.0.0"
# requires = ["nu_plugin_tera", "forminquire:1.0.0"]
# note = "Dynamic form generation using Jinja2 templates rendered with nu_plugin_tera"
# ============================================================================
# FormInquire Integration System
# Version: 1.0.0
# Purpose: Generate interactive forms dynamically from templates and config data
# ============================================================================
# Get form cache directory
def get-form-cache-dir [] : nothing -> string {
let cache_dir = (
if ($env.XDG_CACHE_HOME? | is-empty) {
$"($env.HOME)/.cache/provisioning/forms"
} else {
$"($env.XDG_CACHE_HOME)/provisioning/forms"
}
)
$cache_dir
}
# Ensure cache directory exists
def ensure-form-cache-dir [] : nothing -> string {
let cache_dir = (get-form-cache-dir)
let _mkdir_result = (do {
if not (($cache_dir | path exists)) {
^mkdir -p $cache_dir
}
} | complete)
$cache_dir
}
# Get template directory
def get-template-dir [] : nothing -> string {
let proj_root = (
if (($env.PROVISIONING_ROOT? | is-empty)) {
$"($env.HOME)/project-provisioning"
} else {
$env.PROVISIONING_ROOT
}
)
$"($proj_root)/provisioning/core/forminquire/templates"
}
# Load TOML configuration file
def load-toml-config [path: string] : nothing -> record {
let result = (do { open $path | from toml } | complete)
if ($result.exit_code == 0) {
$result.stdout
} else {
{}
}
}
# Load YAML configuration file
def load-yaml-config [path: string] : nothing -> record {
let result = (do { open $path | from yaml } | complete)
if ($result.exit_code == 0) {
$result.stdout
} else {
{}
}
}
# Render Jinja2 template with data
export def render-template [
template_name: string
data: record = {}
] : nothing -> record {
let template_dir = (get-template-dir)
let template_path = $"($template_dir)/($template_name).j2"
if not (($template_path | path exists)) {
return {
error: $"Template not found: ($template_path)"
content: ""
}
}
let template_content_result = (do { ^cat $template_path } | complete)
if ($template_content_result.exit_code != 0) {
return {
error: "Failed to read template file"
content: ""
}
}
let template_content = $template_content_result.stdout
let enriched_data = (
$data
| merge {
now_iso: (date now | format date "%Y-%m-%dT%H:%M:%SZ")
home_dir: $env.HOME
username: (whoami)
provisioning_root: (
if (($env.PROVISIONING_ROOT? | is-empty)) {
$"($env.HOME)/project-provisioning"
} else {
$env.PROVISIONING_ROOT
}
)
}
)
let render_result = (do {
tera -t $template_content --data ($enriched_data | to json)
} | complete)
if ($render_result.exit_code == 0) {
{
error: ""
content: $render_result.stdout
}
} else {
{
error: "Template rendering failed"
content: ""
}
}
}
# Generate form from template and save to cache
export def generate-form [
form_name: string
template_name: string
data: record = {}
] : nothing -> record {
let cache_dir = (ensure-form-cache-dir)
let form_path = $"($cache_dir)/($form_name).toml"
let render_result = (render-template $template_name $data)
if not (($render_result.error | is-empty)) {
return {
success: false
error: $render_result.error
form_path: ""
}
}
let write_result = (do {
$render_result.content | ^tee $form_path > /dev/null
} | complete)
if ($write_result.exit_code == 0) {
{
success: true
error: ""
form_path: $form_path
}
} else {
{
success: false
error: "Failed to write form file"
form_path: ""
}
}
}
# Execute FormInquire with generated form
export def run-form [form_path: string] : nothing -> record {
if not (($form_path | path exists)) {
return {
success: false
error: $"Form file not found: ($form_path)"
values: {}
}
}
let forminquire_result = (do {
^forminquire --from-file $form_path --output json
} | complete)
if ($forminquire_result.exit_code != 0) {
return {
success: false
error: "FormInquire execution failed"
values: {}
}
}
let parse_result = (do {
$forminquire_result.stdout | from json
} | complete)
if ($parse_result.exit_code == 0) {
{
success: true
error: ""
values: $parse_result.stdout
}
} else {
{
success: false
error: "Failed to parse FormInquire output"
values: {}
}
}
}
# Complete flow: generate form from template and run it
export def interactive-form [
form_name: string
template_name: string
data: record = {}
] : nothing -> record {
let generate_result = (generate-form $form_name $template_name $data)
if not $generate_result.success {
return {
success: false
error: $generate_result.error
form_path: ""
values: {}
}
}
let run_result = (run-form $generate_result.form_path)
{
success: $run_result.success
error: $run_result.error
form_path: $generate_result.form_path
values: $run_result.values
}
}
# Load user preferences from config
export def load-user-preferences [] : nothing -> record {
let config_path = $"($env.HOME)/.config/provisioning/user_config.yaml"
load-yaml-config $config_path
}
# Load workspace config
export def load-workspace-config [workspace_name: string] : nothing -> record {
let workspace_dir = (
if (($env.PROVISIONING_WORKSPACE? | is-empty)) {
$"($env.HOME)/workspaces/($workspace_name)"
} else {
$env.PROVISIONING_WORKSPACE
}
)
let config_file = $"($workspace_dir)/config.toml"
load-toml-config $config_file
}
# Load system defaults
export def load-system-defaults [] : nothing -> record {
let proj_root = (
if (($env.PROVISIONING_ROOT? | is-empty)) {
$"($env.HOME)/project-provisioning"
} else {
$env.PROVISIONING_ROOT
}
)
let defaults_file = $"($proj_root)/provisioning/config/config.defaults.toml"
load-toml-config $defaults_file
}
# Merge multiple config sources with priority
export def merge-config-sources [
defaults: record = {}
workspace: record = {}
user: record = {}
overrides: record = {}
] : nothing -> record {
$defaults | merge $workspace | merge $user | merge $overrides
}
# Get form context with all available data
export def get-form-context [
workspace_name: string = ""
custom_data: record = {}
] : nothing -> record {
let defaults = (load-system-defaults)
let user_prefs = (load-user-preferences)
let workspace_config = (
if (($workspace_name | is-empty)) {
{}
} else {
load-workspace-config $workspace_name
}
)
let merged = (merge-config-sources $defaults $workspace_config $user_prefs $custom_data)
$merged
}
# Settings update form - loads current settings as defaults
export def settings-update-form [] : nothing -> record {
let context = (get-form-context)
let data = {
config_source: "system defaults + user preferences"
editor: ($context.preferences.editor? // "vim")
output_format: ($context.preferences.output_format? // "yaml")
default_log_level: ($context.preferences.default_log_level? // "info")
preferred_provider: ($context.preferences.preferred_provider? // "upcloud")
confirm_delete: ($context.preferences.confirm_delete? // true)
confirm_deploy: ($context.preferences.confirm_deploy? // true)
}
interactive-form "settings-update" "settings-update" $data
}
# Setup wizard form
export def setup-wizard-form [] : nothing -> record {
let context = (get-form-context)
let data = {
system_name: ($context.system_name? // "provisioning")
admin_email: ($context.admin_email? // "")
deployment_mode: ($context.deployment_mode? // "solo")
infrastructure_provider: ($context.infrastructure_provider? // "upcloud")
cpu_cores: ($context.resources.cpu_cores? // "4")
memory_gb: ($context.resources.memory_gb? // "8")
disk_gb: ($context.resources.disk_gb? // "50")
workspace_path: ($context.workspace_path? // $"($env.HOME)/provisioning-workspace")
}
interactive-form "setup-wizard" "setup-wizard" $data
}
# Workspace init form
export def workspace-init-form [workspace_name: string = ""] : nothing -> record {
let context = (get-form-context $workspace_name)
let data = {
workspace_name: (
if (($workspace_name | is-empty)) {
"default"
} else {
$workspace_name
}
)
workspace_description: ($context.description? // "")
workspace_path: ($context.path? // $"($env.HOME)/workspaces/($workspace_name)")
default_provider: ($context.default_provider? // "upcloud")
default_region: ($context.default_region? // "")
init_git: ($context.init_git? // true)
create_example_configs: ($context.create_example_configs? // true)
setup_secrets: ($context.setup_secrets? // true)
enable_testing: ($context.enable_testing? // true)
enable_monitoring: ($context.enable_monitoring? // false)
enable_orchestrator: ($context.enable_orchestrator? // true)
}
interactive-form "workspace-init" "workspace-init" $data
}
# Server delete confirmation form
export def server-delete-confirm-form [
server_name: string
server_ip: string = ""
server_status: string = ""
] : nothing -> record {
let data = {
server_name: $server_name
server_ip: $server_ip
server_status: $server_status
}
interactive-form "server-delete-confirm" "server-delete-confirm" $data
}
# Clean up old form files from cache (older than 1 day)
export def cleanup-form-cache [] : nothing -> record {
let cache_dir = (get-form-cache-dir)
if not (($cache_dir | path exists)) {
return {cleaned: 0, error: ""}
}
let find_result = (do {
^find $cache_dir -name "*.toml" -type f -mtime +1 -delete
} | complete)
{cleaned: 0, error: ""}
}
# List available templates
export def list-templates [] : nothing -> list {
let template_dir = (get-template-dir)
if not (($template_dir | path exists)) {
return []
}
let find_result = (do {
^find $template_dir -name "*.j2" -type f
} | complete)
if ($find_result.exit_code == 0) {
$find_result.stdout
| lines
| each {|path|
let name = ($path | path basename | str replace ".j2" "")
{
name: $name
path: $path
template_file: ($path | path basename)
}
}
} else {
[]
}
}
# List generated forms in cache
export def list-cached-forms [] : nothing -> list {
let cache_dir = (ensure-form-cache-dir)
let find_result = (do {
^find $cache_dir -name "*.toml" -type f
} | complete)
if ($find_result.exit_code == 0) {
$find_result.stdout
| lines
| each {|path|
{
name: ($path | path basename)
path: $path
}
}
} else {
[]
}
}
# ============================================================================
# DELETE CONFIRMATION HELPERS
# ============================================================================
# Run server delete confirmation
export def server-delete-confirm [
server_name: string
server_ip?: string
server_status?: string
] : nothing -> record {
let context = {
server_name: $server_name
server_ip: (if ($server_ip | is-empty) { "" } else { $server_ip })
server_status: (if ($server_status | is-empty) { "running" } else { $server_status })
}
run-forminquire-form "provisioning/core/shlib/forms/infrastructure/server_delete_confirm.toml" $context
}
# Run taskserv delete confirmation
export def taskserv-delete-confirm [
taskserv_name: string
taskserv_type?: string
taskserv_server?: string
taskserv_status?: string
dependent_services?: string
] : nothing -> record {
let context = {
taskserv_name: $taskserv_name
taskserv_type: (if ($taskserv_type | is-empty) { "" } else { $taskserv_type })
taskserv_server: (if ($taskserv_server | is-empty) { "" } else { $taskserv_server })
taskserv_status: (if ($taskserv_status | is-empty) { "unknown" } else { $taskserv_status })
dependent_services: (if ($dependent_services | is-empty) { "none" } else { $dependent_services })
}
run-forminquire-form "provisioning/core/shlib/forms/infrastructure/taskserv_delete_confirm.toml" $context
}
# Run cluster delete confirmation
export def cluster-delete-confirm [
cluster_name: string
cluster_type?: string
node_count?: string
total_resources?: string
deployments_count?: string
services_count?: string
volumes_count?: string
] : nothing -> record {
let context = {
cluster_name: $cluster_name
cluster_type: (if ($cluster_type | is-empty) { "" } else { $cluster_type })
node_count: (if ($node_count | is-empty) { "unknown" } else { $node_count })
total_resources: (if ($total_resources | is-empty) { "" } else { $total_resources })
deployments_count: (if ($deployments_count | is-empty) { "0" } else { $deployments_count })
services_count: (if ($services_count | is-empty) { "0" } else { $services_count })
volumes_count: (if ($volumes_count | is-empty) { "0" } else { $volumes_count })
}
run-forminquire-form "provisioning/core/shlib/forms/infrastructure/cluster_delete_confirm.toml" $context
}
# Generic delete confirmation
export def generic-delete-confirm [
resource_type: string
resource_name: string
resource_id?: string
resource_status?: string
] : nothing -> record {
let context = {
resource_type: $resource_type
resource_name: $resource_name
resource_id: (if ($resource_id | is-empty) { "" } else { $resource_id })
resource_status: (if ($resource_status | is-empty) { "unknown" } else { $resource_status })
}
run-forminquire-form "provisioning/core/shlib/forms/infrastructure/generic_delete_confirm.toml" $context
}
# Validate delete confirmation result
export def validate-delete-confirmation [result: record] : nothing -> bool {
# Must have success = true
let success = ($result.success // false)
if not $success {
return false
}
let values = ($result.values // {})
# Must have typed "DELETE" or "DELETE CLUSTER"
let confirm_text = ($values.confirmation_text // "")
let is_confirmed = (($confirm_text == "DELETE") or ($confirm_text == "DELETE CLUSTER"))
# Must have checked final confirmation checkbox
let final_checked = ($values.final_confirm // false)
# Must have checked proceed checkbox
let proceed_checked = ($values.proceed // false)
($is_confirmed and $final_checked and $proceed_checked)
}

View File

@ -1,50 +0,0 @@
# Auto-generated delete confirmation form
# Generated: {{ now_iso }}
# Server: {{ server_name }}
[meta]
title = "Confirm Server Deletion"
description = "WARNING: This operation cannot be reversed. Please confirm carefully."
allow_cancel = true
[items.server_display]
type = "text"
prompt = "Server to Delete"
default = "{{ server_name }}"
help = "Server name (read-only for confirmation)"
read_only = true
{% if server_ip %}
[items.server_ip]
type = "text"
prompt = "Server IP Address"
default = "{{ server_ip }}"
help = "IP address (read-only for confirmation)"
read_only = true
{% endif %}
{% if server_status %}
[items.server_status]
type = "text"
prompt = "Current Status"
default = "{{ server_status }}"
help = "Current server status (read-only)"
read_only = true
{% endif %}
[items.confirmation_text]
type = "text"
prompt = "Type server name to confirm deletion"
default = ""
help = "You must type the exact server name '{{ server_name }}' to proceed"
required = true
[items.final_confirm]
type = "confirm"
prompt = "I understand this action is irreversible. Delete server?"
help = "This will permanently delete the server and all its data"
[items.backup_before_delete]
type = "confirm"
prompt = "Create backup before deletion?"
help = "Optionally create a backup of the server configuration"

View File

@ -1,73 +0,0 @@
{%- macro form_input(name, label, value="", required=false, help="") -%}
[items."{{ name }}"]
type = "text"
prompt = "{{ label }}"
default = "{{ value }}"
{% if help %}help = "{{ help }}"
{% endif %}{% if required %}required = true
{% endif %}
{%- endmacro -%}
{%- macro form_select(name, label, options=[], value="", help="") -%}
[items."{{ name }}"]
type = "select"
prompt = "{{ label }}"
options = [{% for opt in options %}"{{ opt }}"{{ "," if not loop.last }}{% endfor %}]
default = "{{ value }}"
{% if help %}help = "{{ help }}"
{% endif %}
{%- endmacro -%}
{%- macro form_confirm(name, label, help="") -%}
[items."{{ name }}"]
type = "confirm"
prompt = "{{ label }}"
{% if help %}help = "{{ help }}"
{% endif %}
{%- endmacro -%}
# Auto-generated form for settings update
# Generated: {{ now_iso }}
# Config source: {{ config_source }}
[meta]
title = "Provisioning Settings Update"
description = "Update provisioning configuration settings"
allow_cancel = true
[items.editor]
type = "text"
prompt = "Preferred Editor"
default = "{{ editor | default('vim') }}"
help = "Editor to use for file editing (vim, nano, emacs)"
[items.output_format]
type = "select"
prompt = "Default Output Format"
options = ["json", "yaml", "text", "table"]
default = "{{ output_format | default('yaml') }}"
help = "Default output format for commands"
[items.confirm_delete]
type = "confirm"
prompt = "Confirm Destructive Operations?"
help = "Require confirmation before deleting resources"
[items.confirm_deploy]
type = "confirm"
prompt = "Confirm Deployments?"
help = "Require confirmation before deploying"
[items.default_log_level]
type = "select"
prompt = "Default Log Level"
options = ["debug", "info", "warning", "error"]
default = "{{ default_log_level | default('info') }}"
help = "Default logging level"
[items.preferred_provider]
type = "select"
prompt = "Preferred Cloud Provider"
options = ["upcloud", "aws", "local"]
default = "{{ preferred_provider | default('upcloud') }}"
help = "Preferred infrastructure provider"

View File

@ -1,180 +0,0 @@
# Auto-generated form for setup wizard
# Generated: {{ now_iso }}
# This is a comprehensive 7-step setup wizard
[meta]
title = "Provisioning System Setup Wizard"
description = "Step-by-step configuration for your infrastructure provisioning system"
allow_cancel = true
# ============================================================================
# STEP 1: SYSTEM CONFIGURATION
# ============================================================================
[items.step1_header]
type = "text"
prompt = "STEP 1/7: System Configuration"
display_only = true
[items.config_path]
type = "text"
prompt = "Configuration Base Path"
default = "{{ config_path | default('/etc/provisioning') }}"
help = "Where provisioning configuration will be stored"
required = true
[items.use_defaults_path]
type = "confirm"
prompt = "Use recommended paths for your OS?"
help = "Use OS-specific default paths (recommended)"
# ============================================================================
# STEP 2: DEPLOYMENT MODE
# ============================================================================
[items.step2_header]
type = "text"
prompt = "STEP 2/7: Deployment Mode Selection"
display_only = true
[items.deployment_mode]
type = "select"
prompt = "How should platform services be deployed?"
options = ["docker-compose", "kubernetes", "systemd", "remote-ssh"]
default = "{{ deployment_mode | default('docker-compose') }}"
help = "Choose based on your infrastructure type"
required = true
# ============================================================================
# STEP 3: PROVIDER SELECTION
# ============================================================================
[items.step3_header]
type = "text"
prompt = "STEP 3/7: Infrastructure Providers"
display_only = true
[items.provider_upcloud]
type = "confirm"
prompt = "Use UpCloud as provider?"
help = "UpCloud offers affordable cloud VMs in European regions"
[items.provider_aws]
type = "confirm"
prompt = "Use AWS as provider?"
help = "Amazon Web Services - global infrastructure"
[items.provider_hetzner]
type = "confirm"
prompt = "Use Hetzner as provider?"
help = "Hetzner - German cloud provider with good pricing"
[items.provider_local]
type = "confirm"
prompt = "Use Local provider?"
help = "Local deployment - useful for development and testing"
# ============================================================================
# STEP 4: RESOURCE ALLOCATION
# ============================================================================
[items.step4_header]
type = "text"
prompt = "STEP 4/7: Resource Allocation"
display_only = true
[items.cpu_count]
type = "text"
prompt = "Number of CPUs to allocate"
default = "{{ cpu_count | default('4') }}"
help = "For cloud VMs (1-16, or more for dedicated hardware)"
required = true
[items.memory_gb]
type = "text"
prompt = "Memory in GB to allocate"
default = "{{ memory_gb | default('8') }}"
help = "RAM for provisioning system and services"
required = true
[items.disk_gb]
type = "text"
prompt = "Disk space in GB"
default = "{{ disk_gb | default('100') }}"
help = "Primary disk size for VMs or containers"
required = true
# ============================================================================
# STEP 5: SECURITY CONFIGURATION
# ============================================================================
[items.step5_header]
type = "text"
prompt = "STEP 5/7: Security Configuration"
display_only = true
[items.enable_mfa]
type = "confirm"
prompt = "Enable Multi-Factor Authentication (MFA)?"
help = "Requires TOTP or WebAuthn for sensitive operations"
[items.enable_audit_logging]
type = "confirm"
prompt = "Enable audit logging?"
help = "Log all operations for compliance and debugging"
[items.require_approval]
type = "confirm"
prompt = "Require approval for destructive operations?"
help = "Prevents accidental deletion or modification"
[items.enable_tls]
type = "confirm"
prompt = "Enable TLS encryption?"
help = "Use HTTPS for all API communications"
# ============================================================================
# STEP 6: WORKSPACE CONFIGURATION
# ============================================================================
[items.step6_header]
type = "text"
prompt = "STEP 6/7: Workspace Setup"
display_only = true
[items.create_workspace]
type = "confirm"
prompt = "Create initial workspace now?"
help = "Create a workspace for managing your infrastructure"
[items.workspace_name]
type = "text"
prompt = "Workspace name"
default = "{{ workspace_name | default('default') }}"
help = "Name for your infrastructure workspace"
[items.workspace_description]
type = "text"
prompt = "Workspace description (optional)"
default = "{{ workspace_description | default('') }}"
help = "Brief description of what this workspace manages"
# ============================================================================
# STEP 7: REVIEW & CONFIRM
# ============================================================================
[items.step7_header]
type = "text"
prompt = "STEP 7/7: Review Configuration"
display_only = true
[items.review_config]
type = "confirm"
prompt = "Review the configuration summary above and confirm?"
help = "Verify all settings before applying"
required = true
[items.final_confirm]
type = "confirm"
prompt = "I understand this is a major configuration change. Proceed?"
help = "This will create/update system configuration files"

View File

@ -1,121 +0,0 @@
# Auto-generated form for workspace initialization
# Generated: {{ now_iso }}
[meta]
title = "Initialize New Workspace"
description = "Create and configure a new provisioning workspace for managing your infrastructure"
allow_cancel = true
# ============================================================================
# WORKSPACE BASIC INFORMATION
# ============================================================================
[items.workspace_info_header]
type = "text"
prompt = "Workspace Basic Information"
display_only = true
[items.workspace_name]
type = "text"
prompt = "Workspace Name"
default = "{{ workspace_name | default('default') }}"
help = "Name for this workspace (lowercase, alphanumeric and hyphens)"
required = true
[items.workspace_description]
type = "text"
prompt = "Workspace Description"
default = "{{ workspace_description | default('') }}"
help = "Brief description of what this workspace manages"
[items.workspace_path]
type = "text"
prompt = "Workspace Directory Path"
default = "{{ workspace_path | default(home_dir + '/workspaces/default') }}"
help = "Where workspace files and configurations will be stored"
required = true
# ============================================================================
# INFRASTRUCTURE DEFAULTS
# ============================================================================
[items.infra_header]
type = "text"
prompt = "Infrastructure Configuration"
display_only = true
[items.default_provider]
type = "select"
prompt = "Default Infrastructure Provider"
options = ["upcloud", "aws", "hetzner", "local"]
default = "{{ default_provider | default('upcloud') }}"
help = "Default cloud provider for servers created in this workspace"
[items.default_region]
type = "text"
prompt = "Default Region/Zone"
default = "{{ default_region | default('') }}"
help = "Default deployment region (e.g., us-nyc1, eu-de-fra1, none for local)"
# ============================================================================
# INITIALIZATION OPTIONS
# ============================================================================
[items.init_header]
type = "text"
prompt = "Initialization Options"
display_only = true
[items.init_git]
type = "confirm"
prompt = "Initialize Git Repository?"
help = "Create git repository for infrastructure as code version control"
[items.create_example_configs]
type = "confirm"
prompt = "Create Example Configuration Files?"
help = "Generate sample server and infrastructure config files"
[items.setup_secrets]
type = "confirm"
prompt = "Setup Secrets Management?"
help = "Configure KMS encryption and secrets storage"
# ============================================================================
# WORKSPACE FEATURES
# ============================================================================
[items.features_header]
type = "text"
prompt = "Workspace Features"
display_only = true
[items.enable_testing]
type = "confirm"
prompt = "Enable Test Environment Service?"
help = "Enable Docker-based test environments for validating configurations"
[items.enable_monitoring]
type = "confirm"
prompt = "Setup Monitoring?"
help = "Configure monitoring and observability for your infrastructure"
[items.enable_orchestrator]
type = "confirm"
prompt = "Start Orchestrator Service?"
help = "Enable the orchestrator for workflow management and automation"
# ============================================================================
# CONFIRMATION
# ============================================================================
[items.confirm_header]
type = "text"
prompt = "Review and Confirm"
display_only = true
[items.confirm_creation]
type = "confirm"
prompt = "Create workspace with these settings?"
help = "This will initialize the workspace directory and apply configurations"
required = true

View File

@ -1,30 +0,0 @@
#!/bin/bash
# FormInquire wrapper for shell scripts
# Simple wrapper to execute FormInquire forms from bash/sh
set -e
FORM_FILE="${1:-}"
OUTPUT_FORMAT="${2:-json}"
# Check if form file provided
if [ -z "$FORM_FILE" ]; then
echo "Error: Form file required" >&2
echo "Usage: form.sh <form_file> [output_format]" >&2
exit 1
fi
# Check if form file exists
if [ ! -f "$FORM_FILE" ]; then
echo "Error: Form file not found: $FORM_FILE" >&2
exit 1
fi
# Check if forminquire is available
if ! command -v forminquire &> /dev/null; then
echo "Error: forminquire not found in PATH" >&2
exit 1
fi
# Execute forminquire
forminquire --from-file "$FORM_FILE" --output "$OUTPUT_FORMAT"

View File

View File

@ -1,65 +0,0 @@
#!/usr/bin/env nu
# Complete installation and registration of provisioning plugins
# Run this in a fresh Nushell session
print "Provisioning Plugins - Installation & Registration"
print "=================================================="
print ""
# Copy plugins to Nushell plugin directory
print "Step 1: Installing plugin binaries..."
print ""
let plugin_dir = ($env.HOME + "/.local/share/nushell/plugins")
# Run the registration script
let nu_path = ($env.HOME + "/.local/bin/nu" | path expand)
let register_script = ($env.PWD | path join "provisioning" "core" "plugins" "register-plugins.nu")
^$nu_path $register_script
print ""
print "Step 2: Registering plugins with Nushell..."
print ""
# Register plugins
let auth_plugin = ($env.HOME | path join ".local/share/nushell/plugins/nu_plugin_auth" | path expand)
let kms_plugin = ($env.HOME | path join ".local/share/nushell/plugins/nu_plugin_kms" | path expand)
let orch_plugin = ($env.HOME | path join ".local/share/nushell/plugins/nu_plugin_orchestrator" | path expand)
plugin add $auth_plugin
plugin add $kms_plugin
plugin add $orch_plugin
sleep 1
print ""
print "Step 3: Verifying plugin installation..."
print ""
# Verify plugins are loaded
let plugins = plugin list | where name =~ "nu_plugin_(auth|kms|orchestrator)"
if ($plugins | length) == 3 {
print "✓ All 3 plugins registered successfully!"
print ""
print "Installed plugins:"
for plugin in $plugins {
print $" ✓ ($plugin.name)"
}
} else {
print $"⚠ Expected 3 plugins, found ($plugins | length)"
print "Please run the following commands manually:"
print ""
print $"plugin add ($auth_plugin)"
print $"plugin add ($kms_plugin)"
print $"plugin add ($orch_plugin)"
}
print ""
print "✓ Installation complete!"
print ""
print "You can now use the provisioning CLI with plugin support:"
print ""
print " provisioning auth login <username>"
print " provisioning kms encrypt <data>"
print " provisioning orch status"

View File

@ -1,321 +0,0 @@
#!/usr/bin/env nu
# Install and register provisioning critical plugins
#
# This is the main user-facing script for installing the three critical
# provisioning plugins (auth, kms, orchestrator) that provide:
# - 10-50x performance improvement over HTTP API
# - OS-native keyring integration
# - Local file-based operations (no network required)
#
# Usage:
# nu install-plugins.nu # Build and install all plugins
# nu install-plugins.nu --skip-build # Register pre-built plugins only
# nu install-plugins.nu --release # Build release mode (default)
# nu install-plugins.nu --debug # Build debug mode
# nu install-plugins.nu --plugin auth # Install specific plugin only
# nu install-plugins.nu --verify # Verify after installation
const PLUGIN_DIR = "nushell-plugins"
const PROVISIONING_PLUGINS = [
"nu_plugin_auth"
"nu_plugin_kms"
"nu_plugin_orchestrator"
]
# Build a single plugin
def build-plugin [
plugin_name: string
base_dir: path
--release
]: nothing -> record {
let plugin_path = ($base_dir | path join $PLUGIN_DIR $plugin_name)
if not ($plugin_path | path exists) {
return {
name: $plugin_name
status: "not_found"
message: $"Plugin directory not found: ($plugin_path)"
}
}
let build_mode = if $release { "--release" } else { "" }
let target_dir = if $release { "release" } else { "debug" }
print $" Building ($plugin_name) \(($target_dir) mode\)..."
let start_time = (date now)
# Build the plugin
try {
cd $plugin_path
if $release {
cargo build --release
} else {
cargo build
}
cd -
let duration = ((date now) - $start_time) | into int | $in / 1_000_000_000
let binary_path = ($plugin_path | path join "target" $target_dir $plugin_name)
if ($binary_path | path exists) {
return {
name: $plugin_name
status: "built"
message: $"Build successful \(($duration | math round --precision 1)s\)"
path: $binary_path
}
} else {
return {
name: $plugin_name
status: "error"
message: "Build completed but binary not found"
}
}
} catch { |err|
cd -
return {
name: $plugin_name
status: "error"
message: $"Build failed: ($err.msg)"
}
}
}
# Register a plugin with Nushell
def register-plugin-binary [
plugin_name: string
binary_path: path
]: nothing -> record {
if not ($binary_path | path exists) {
return {
name: $plugin_name
status: "not_found"
message: $"Binary not found: ($binary_path)"
}
}
try {
plugin add $binary_path
return {
name: $plugin_name
status: "registered"
message: "Registered successfully"
path: $binary_path
}
} catch { |err|
return {
name: $plugin_name
status: "error"
message: $"Registration failed: ($err.msg)"
}
}
}
# Get binary path for a plugin
def get-binary-path [
plugin_name: string
base_dir: path
--release
]: nothing -> path {
let target_dir = if ($release) { "release" } else { "debug" }
$base_dir | path join $PLUGIN_DIR $plugin_name "target" $target_dir $plugin_name
}
# Print banner
def print-banner [] {
print ""
print "+======================================================+"
print "| Provisioning Platform - Plugin Installation |"
print "+======================================================+"
print ""
print "Installing critical plugins for optimal performance:"
print " - nu_plugin_auth: JWT auth with keyring (10x faster)"
print " - nu_plugin_kms: Multi-backend encryption (10x faster)"
print " - nu_plugin_orchestrator: Local operations (30x faster)"
print ""
}
# Print summary
def print-summary [results: list] {
let built = ($results | where status == "built" | length)
let registered = ($results | where status == "registered" | length)
let errors = ($results | where status == "error" | length)
let skipped = ($results | where status in ["not_found" "already_registered"] | length)
print ""
print "+------------------------------------------------------+"
print "| Installation Summary |"
print "+------------------------------------------------------+"
print ""
print $" Built: ($built)"
print $" Registered: ($registered)"
print $" Errors: ($errors)"
print $" Skipped: ($skipped)"
print ""
if $errors > 0 {
print "Some plugins failed to install. Check errors above."
print ""
}
}
# Main entry point
def main [
--skip-build (-s) # Skip building, only register pre-built plugins
--release (-r) # Build in release mode (default)
--debug (-d) # Build in debug mode
--plugin (-p): string # Install specific plugin only
--verify (-v) # Verify installation after completion
--quiet (-q) # Suppress output
]: nothing -> nothing {
let base_dir = ($env.PWD | path dirname) # Go up from plugins/ to core/
let use_release = not $debug
# Determine which plugins to install
let plugins_to_install = if ($plugin != null) {
if $plugin in $PROVISIONING_PLUGINS {
[$plugin]
} else if $"nu_plugin_($plugin)" in $PROVISIONING_PLUGINS {
[$"nu_plugin_($plugin)"]
} else {
print $"Error: Unknown plugin '($plugin)'"
print $"Available: ($PROVISIONING_PLUGINS | str join ', ')"
exit 1
}
} else {
$PROVISIONING_PLUGINS
}
if not $quiet {
print-banner
}
mut all_results = []
# Phase 1: Build (unless --skip-build)
if not $skip_build {
if not $quiet {
let mode = if $use_release { "release" } else { "debug" }
print $"Phase 1: Building plugins \(($mode) mode\)..."
print ""
}
for plugin_name in $plugins_to_install {
let result = (build-plugin $plugin_name $base_dir --release=$use_release)
$all_results = ($all_results | append $result)
if not $quiet {
match $result.status {
"built" => {
print $" [OK] ($result.message)"
}
"not_found" => {
print $" [SKIP] ($result.message)"
}
"error" => {
print $" [ERROR] ($result.message)"
}
_ => {}
}
}
}
if not $quiet {
print ""
}
}
# Phase 2: Register
if not $quiet {
print "Phase 2: Registering plugins with Nushell..."
print ""
}
for plugin_name in $plugins_to_install {
let binary_path = (get-binary-path $plugin_name $base_dir --release=$use_release)
if not $quiet {
print $" Registering ($plugin_name)..."
}
let result = (register-plugin-binary $plugin_name $binary_path)
$all_results = ($all_results | append $result)
if not $quiet {
match $result.status {
"registered" => {
print $" [OK] ($result.message)"
}
"not_found" => {
print $" [SKIP] ($result.message)"
}
"error" => {
print $" [ERROR] ($result.message)"
}
_ => {}
}
}
}
if not $quiet {
print-summary $all_results
}
# Phase 3: Verify (if requested)
if $verify {
if not $quiet {
print "Phase 3: Verifying installation..."
print ""
}
let registered_plugins = (plugin list)
for plugin_name in $plugins_to_install {
let is_registered = ($registered_plugins | where name == $plugin_name | length) > 0
if not $quiet {
if $is_registered {
print $" [OK] ($plugin_name) is registered"
} else {
print $" [FAIL] ($plugin_name) not found in plugin list"
}
}
}
if not $quiet {
print ""
}
}
if not $quiet {
print "Plugin commands now available:"
print ""
print " Authentication:"
print " auth login <user> [password] # Login with JWT"
print " auth logout # End session"
print " auth verify # Check token"
print " auth sessions # List sessions"
print " auth mfa enroll totp # Setup MFA"
print " auth mfa verify --code 123456 # Verify MFA"
print ""
print " Encryption (KMS):"
print " kms encrypt \"data\" --backend age # Encrypt with Age"
print " kms decrypt \$encrypted # Decrypt data"
print " kms generate-key --spec AES256 # Generate key"
print " kms status # Check KMS status"
print " kms list-backends # Available backends"
print ""
print " Orchestrator:"
print " orch status # Local status (fast)"
print " orch tasks # List tasks"
print " orch validate workflow.k # Validate KCL"
print " orch submit workflow.k # Submit workflow"
print " orch monitor <task_id> # Monitor task"
print ""
print "Verify installation with: plugin list"
print ""
}
}

View File

@ -1,93 +0,0 @@
#!/usr/bin/env nu
# Register provisioning plugins with Nushell
# Detect plugin directory
let plugin_dir = ($env.HOME + "/.local/share/nushell/plugins")
print $"Using plugin directory: ($plugin_dir)"
# Create plugin directory if it doesn't exist
if not ($plugin_dir | path exists) {
mkdir $plugin_dir
}
# Define plugins to register
let plugins = [
{
name: "nu_plugin_auth"
src: "provisioning/core/plugins/nushell-plugins/nu_plugin_auth/target/release/nu_plugin_auth"
description: "JWT authentication with system keyring"
}
{
name: "nu_plugin_kms"
src: "provisioning/core/plugins/nushell-plugins/nu_plugin_kms/target/release/nu_plugin_kms"
description: "Multi-backend KMS encryption"
}
{
name: "nu_plugin_orchestrator"
src: "provisioning/core/plugins/nushell-plugins/nu_plugin_orchestrator/target/release/nu_plugin_orchestrator"
description: "Local orchestrator operations (30x faster)"
}
]
# Copy plugins
print ""
print "Installing plugins..."
print "===================="
let result = (
$plugins
| each { |plugin|
let src = $plugin.src
let dst = ($plugin_dir + "/" + $plugin.name)
if not ($src | path exists) {
{
name: $plugin.name
success: false
message: $"Source not found at ($src)"
}
} else {
cp $src $dst
chmod +x $dst
if ($dst | path exists) {
{
name: $plugin.name
success: true
message: $"Installed to ($dst)"
}
} else {
{
name: $plugin.name
success: false
message: "Failed to copy"
}
}
}
}
)
# Print results
for item in $result {
let icon = if $item.success { "✓" } else { "✗" }
print $"($icon) ($item.name): ($item.message)"
}
let installed = ($result | where success == true | length)
let failed = ($result | where success == false | length)
print ""
print $"Results: ($installed) installed, ($failed) failed"
# Suggest next steps
if $installed > 0 {
print ""
print "Next steps:"
print "==========="
print "Run the following command in a new Nushell session:"
print ""
for plugin in $plugins {
let dst = ($plugin_dir + "/" + $plugin.name)
print $" plugin add ($dst)"
}
}

View File

@ -1,264 +0,0 @@
#!/usr/bin/env nu
# Test provisioning plugins are installed and working
#
# This script verifies that the three critical provisioning plugins
# are properly installed, registered, and functional.
#
# Usage:
# nu test-plugins.nu # Run all tests
# nu test-plugins.nu --quick # Quick registration check only
# nu test-plugins.nu --verbose # Detailed output
# nu test-plugins.nu --json # Output as JSON
const PROVISIONING_PLUGINS = [
{
name: "nu_plugin_auth"
test_command: "auth verify --local"
expected_fields: ["valid"]
description: "JWT authentication with system keyring"
}
{
name: "nu_plugin_kms"
test_command: "kms status"
expected_fields: ["backend", "available"]
description: "Multi-backend KMS encryption"
}
{
name: "nu_plugin_orchestrator"
test_command: "orch status"
expected_fields: ["running", "tasks_pending"]
description: "Local orchestrator operations"
}
]
# Check if plugin is registered
def check-registration [plugin_name: string]: nothing -> record {
let registered_plugins = (plugin list | get name?)
if ($registered_plugins == null) {
return {
name: $plugin_name
registered: false
message: "Could not query plugin list"
}
}
let is_registered = $plugin_name in $registered_plugins
{
name: $plugin_name
registered: $is_registered
message: (if $is_registered { "Registered" } else { "Not registered" })
}
}
# Test plugin functionality
def test-plugin-function [
plugin_name: string
test_command: string
expected_fields: list
]: nothing -> record {
let start_time = (date now)
try {
# Execute the test command
let result = (nu -c $test_command | from json)
let duration = ((date now) - $start_time) | into int | $in / 1_000_000
# Check if expected fields exist
let missing_fields = ($expected_fields | where { |field|
not ($field in ($result | columns))
})
if ($missing_fields | length) > 0 {
return {
name: $plugin_name
functional: false
message: $"Missing fields: ($missing_fields | str join ', ')"
duration_ms: $duration
}
}
{
name: $plugin_name
functional: true
message: "Commands working"
duration_ms: $duration
result: $result
}
} catch { |err|
let duration = ((date now) - $start_time) | into int | $in / 1_000_000
# Some commands might return errors but still work (e.g., no token)
# This is expected behavior, not a failure
if ($err.msg | str contains "not logged in") or
($err.msg | str contains "token not found") or
($err.msg | str contains "No sessions") {
return {
name: $plugin_name
functional: true
message: "Commands working (expected auth state)"
duration_ms: $duration
}
}
{
name: $plugin_name
functional: false
message: $"Error: ($err.msg)"
duration_ms: $duration
}
}
}
# Run all tests
def run-tests [
--quick: bool = false
--verbose: bool = false
]: nothing -> list {
mut results = []
for plugin in $PROVISIONING_PLUGINS {
# Registration check
let reg_result = (check-registration $plugin.name)
$results = ($results | append {
plugin: $plugin.name
test: "registration"
passed: $reg_result.registered
message: $reg_result.message
duration_ms: 0
})
if $verbose {
let status = if $reg_result.registered { "[PASS]" } else { "[FAIL]" }
print $"($status) ($plugin.name) - Registration: ($reg_result.message)"
}
# Skip functional tests if quick mode or not registered
if $quick or (not $reg_result.registered) {
continue
}
# Functional test
let func_result = (test-plugin-function $plugin.name $plugin.test_command $plugin.expected_fields)
$results = ($results | append {
plugin: $plugin.name
test: "functional"
passed: $func_result.functional
message: $func_result.message
duration_ms: $func_result.duration_ms
})
if $verbose {
let status = if $func_result.functional { "[PASS]" } else { "[FAIL]" }
print $"($status) ($plugin.name) - Functional: ($func_result.message) \(($func_result.duration_ms)ms\)"
}
}
$results
}
# Main entry point
def main [
--quick (-q) # Quick registration check only
--verbose (-v) # Detailed output
--json (-j) # Output as JSON
]: nothing -> nothing {
if not $json {
print ""
print "======================================================"
print " Provisioning Plugins Test Suite"
print "======================================================"
print ""
}
let results = (run-tests --quick=$quick --verbose=$verbose)
# Calculate summary
let total_tests = ($results | length)
let passed_tests = ($results | where passed == true | length)
let failed_tests = ($results | where passed == false | length)
# Registration summary
let reg_results = ($results | where test == "registration")
let reg_passed = ($reg_results | where passed == true | length)
let reg_total = ($reg_results | length)
# Functional summary
let func_results = ($results | where test == "functional")
let func_passed = ($func_results | where passed == true | length)
let func_total = ($func_results | length)
if $json {
# JSON output
{
total: $total_tests
passed: $passed_tests
failed: $failed_tests
registration: {
total: $reg_total
passed: $reg_passed
}
functional: {
total: $func_total
passed: $func_passed
}
results: $results
all_passed: ($failed_tests == 0)
} | to json
} else {
# Human-readable output
if not $verbose {
# Print results table
print "Test Results:"
print ""
for result in $results {
let status = if $result.passed { "[OK] " } else { "[FAIL]" }
let test_type = if $result.test == "registration" { "reg" } else { "func" }
let duration = if $result.duration_ms > 0 {
$" \(($result.duration_ms)ms\)"
} else {
""
}
print $" ($status) ($result.plugin | fill -w 25) ($test_type | fill -w 5) ($result.message)($duration)"
}
}
print ""
print "------------------------------------------------------"
print "Summary:"
print $" Registration: ($reg_passed)/($reg_total) passed"
if not $quick {
print $" Functional: ($func_passed)/($func_total) passed"
}
print $" Total: ($passed_tests)/($total_tests) passed"
print "------------------------------------------------------"
print ""
if $failed_tests == 0 {
print "All tests passed! Plugins are ready to use."
} else {
print $"($failed_tests) test\(s\) failed. Some plugins may need attention."
print ""
print "Troubleshooting:"
print " 1. Build plugins: nu install-plugins.nu"
print " 2. Register only: nu install-plugins.nu --skip-build"
print " 3. Check plugin list: plugin list"
}
print ""
}
# Exit with error code if tests failed
if $failed_tests > 0 {
exit 1
}
}
# Export for module usage
export def "provisioning-plugins test" [--quick (-q), --verbose (-v), --json (-j)] {
main --quick=$quick --verbose=$verbose --json=$json
}

View File

@ -1,101 +0,0 @@
import provisioning.version as prv_schema
# Core tools versions for provisioning system as array
# Converted from individual declarations to array of TaskservVersion items
core_versions: [prv_schema.TaskservVersion] = [
prv_schema.TaskservVersion {
name = "nushell"
version = prv_schema.Version {
current = "0.109.1"
source = "https://github.com/nushell/nushell/releases"
tags = "https://github.com/nushell/nushell/tags"
site = "https://www.nushell.sh/"
# Pinned for system stability
check_latest = False
grace_period = 86400
}
dependencies = []
detector = {
method = "command"
command = "nu -v"
pattern = r"(?P<capture0>[\d.]+\.[\d.]+)"
capture = "capture0"
}
}
prv_schema.TaskservVersion {
name = "kcl"
version = prv_schema.Version {
current = "0.11.3"
source = "https://github.com/kcl-lang/cli/releases"
tags = "https://github.com/kcl-lang/cli/tags"
site = "https://kcl-lang.io"
# Pinned for system stability
check_latest = False
grace_period = 86400
}
dependencies = []
detector = {
method = "command"
command = "kcl -v"
pattern = r"kcl\s+version\s+(?P<capture0>[\d.]+)"
capture = "capture0"
}
}
prv_schema.TaskservVersion {
name = "sops"
version = prv_schema.Version {
current = "3.10.2"
source = "https://github.com/getsops/sops/releases"
tags = "https://github.com/getsops/sops/tags"
site = "https://github.com/getsops/sops"
# Pinned for encryption compatibility
check_latest = False
grace_period = 86400
}
dependencies = ["age"]
detector = {
method = "command"
command = "sops -v"
pattern = r"sops\s+(?P<capture0>[\d.]+)"
capture = "capture0"
}
}
prv_schema.TaskservVersion {
name = "age"
version = prv_schema.Version {
current = "1.2.1"
source = "https://github.com/FiloSottile/age/releases"
tags = "https://github.com/FiloSottile/age/tags"
site = "https://github.com/FiloSottile/age"
# Pinned for encryption compatibility
check_latest = False
grace_period = 86400
}
dependencies = []
detector = {
method = "command"
command = "age --version"
pattern = r"v(?P<capture0>[\d.]+)"
capture = "capture0"
}
}
prv_schema.TaskservVersion {
name = "k9s"
version = prv_schema.Version {
current = "0.50.6"
source = "https://github.com/derailed/k9s/releases"
tags = "https://github.com/derailed/k9s/tags"
site = "https://k9scli.io/"
# Can auto-update for CLI tools
check_latest = True
grace_period = 86400
}
dependencies = []
detector = {
method = "command"
command = "k9s version"
pattern = r"Version\s+v(?P<capture0>[\d.]+)"
capture = "capture0"
}
}
]