From 9f5059ed07834ca21ec9777a946ffd3129c0761b Mon Sep 17 00:00:00 2001 From: Julian Lechner Date: Fri, 18 Sep 2026 17:25:33 +0200 Subject: [PATCH] feat(instructions): add client overlays --- scripts/commands/add-instruction.ps1 | 23 +++++++++++++++ scripts/commands/add-instruction.sh | 42 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 scripts/commands/add-instruction.ps1 create mode 100644 scripts/commands/add-instruction.sh diff --git a/scripts/commands/add-instruction.ps1 b/scripts/commands/add-instruction.ps1 new file mode 100644 index 0000000..0a43f99 --- /dev/null +++ b/scripts/commands/add-instruction.ps1 @@ -0,0 +1,23 @@ +[CmdletBinding()] +param( + [ValidateSet('Codex','Claude','Both')][string]$Client, + [AllowEmptyString()][string]$Instruction, + [string]$HomePath = [Environment]::GetFolderPath('UserProfile') +) +$ErrorActionPreference = 'Stop' +$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent +. (Join-Path $root 'scripts/lib/install-targets.ps1') + +if (-not $Client) { $Client = Read-InstallClient -Client $Client } +if (-not $PSBoundParameters.ContainsKey('Instruction')) { $Instruction = Read-Host 'Instruction' } +if ([string]::IsNullOrWhiteSpace($Instruction) -or $Instruction.Length -gt 65536) { throw 'Instruction must contain between 1 and 65536 characters.' } +if (-not [System.IO.Path]::IsPathRooted($HomePath)) { throw 'HomePath must be absolute.' } + +$directory = Join-Path $HomePath '.my-ai-configuration/instructions' +New-Item -ItemType Directory -Path $directory -Force | Out-Null +foreach ($target in $(if ($Client -eq 'Both') { @('codex','claude') } else { @($Client.ToLowerInvariant()) })) { + $path = Join-Path $directory "$target.md" + $prefix = if ((Test-Path -LiteralPath $path) -and (Get-Item -LiteralPath $path).Length -gt 0 -and -not (Get-Content -LiteralPath $path -Raw).EndsWith([Environment]::NewLine)) { [Environment]::NewLine } else { '' } + [System.IO.File]::AppendAllText($path, $prefix + $Instruction.TrimEnd() + [Environment]::NewLine, [System.Text.UTF8Encoding]::new($false)) + Write-Output "Instruction added for $target." +} diff --git a/scripts/commands/add-instruction.sh b/scripts/commands/add-instruction.sh new file mode 100644 index 0000000..2d3ae26 --- /dev/null +++ b/scripts/commands/add-instruction.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -euo pipefail + +client= +instruction= +home_path=${HOME:?HOME is required} +while [ $# -gt 0 ]; do + case "$1" in + --client) client=${2:?--client requires a value}; shift 2 ;; + --instruction) instruction=${2:?--instruction requires a value}; shift 2 ;; + --home) home_path=${2:?--home requires a value}; shift 2 ;; + *) printf 'Unknown argument: %s\n' "$1" >&2; exit 1 ;; + esac +done + +case "$client" in + codex|Codex) targets=(codex) ;; + claude|Claude) targets=(claude) ;; + both|Both) targets=(codex claude) ;; + '') + read -r -p 'Select client (codex, claude, or both) ' client + case "$client" in + codex|Codex) targets=(codex) ;; + claude|Claude) targets=(claude) ;; + both|Both) targets=(codex claude) ;; + *) printf 'Unknown --client value: %s\n' "$client" >&2; exit 1 ;; + esac + ;; + *) printf 'Unknown --client value: %s\n' "$client" >&2; exit 1 ;; +esac +if [ -z "$instruction" ]; then read -r -p 'Instruction ' instruction; fi +if [ -z "${instruction//[[:space:]]/}" ] || [ ${#instruction} -gt 65536 ]; then printf 'Instruction must contain between 1 and 65536 characters.\n' >&2; exit 1; fi +case "$home_path" in /*|[A-Za-z]:[\\/]*) ;; *) printf 'Home path must be absolute.\n' >&2; exit 1 ;; esac + +directory="$home_path/.my-ai-configuration/instructions" +mkdir -p -- "$directory" +for target in "${targets[@]}"; do + path="$directory/$target.md" + [ ! -s "$path" ] || [ "$(tail -c 1 -- "$path" | wc -l)" -eq 1 ] || printf '\n' >> "$path" + printf '%s\n' "$instruction" >> "$path" + printf 'Instruction added for %s.\n' "$target" +done