refactor(scripts): organize script entry points

This commit is contained in:
fraujulian committed 2026-09-18 11:35:38 +02:00
1 parent 793eee5b61
commit 11c2b6dfcb
41 files changed
+102 -101

No files matched your search

@@ -11,7 +11,7 @@ from pathlib import Path
CLAUDE_TOP_LEVEL = {"permissions", "sandbox", "env", "statusLine", "hooks"}
CLAUDE_PERMISSION_KEYS = {"defaultMode", "allow", "deny"}
CLAUDE_SANDBOX_KEYS = {"enabled", "allowUnsandboxedCommands"}
CLAUDE_SANDBOX_KEYS = {"enabled", "allowUnsandboxedCommands", "failIfUnavailable"}
CLAUDE_STATUS_LINE_KEYS = {"type", "command"}
CLAUDE_HOOK_KEYS = {"type", "command", "timeout"}
CLAUDE_PERMISSION_MODES = {"acceptEdits", "auto", "bypassPermissions", "default", "dontAsk", "plan"}
@@ -40,8 +40,8 @@ def validate_claude(path: Path) -> None:
if not isinstance(permissions.get(key), list) or not all(isinstance(item, str) for item in permissions[key]):
fail(f"permissions.{key} must be an array of strings")
sandbox = require_keys(settings.get("sandbox"), CLAUDE_SANDBOX_KEYS, "sandbox")
if sandbox.get("enabled") is not True or sandbox.get("allowUnsandboxedCommands") is not False:
fail("sandbox must be enabled without unsandboxed command retries")
if sandbox.get("enabled") is not True or sandbox.get("allowUnsandboxedCommands") is not False or sandbox.get("failIfUnavailable") is not True:
fail("sandbox must be enabled, fail closed, and disallow unsandboxed command retries")
env = settings.get("env")
if not isinstance(env, dict) or not all(isinstance(key, str) and isinstance(value, str) for key, value in env.items()):
fail("env must be an object of string values")
@@ -1,7 +1,7 @@
[CmdletBinding()]
param([switch]$Summary)
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$shared = Join-Path $root 'shared'
$output = Join-Path $root 'generated'
$pluginManifest = Join-Path $root 'adapters/plugins.tsv'
@@ -202,7 +202,7 @@ foreach ($shell in @('powershell','bash')) {
$tomlPath = Join-Path $output "codex-$shell/config.toml"
$settingsPath = Join-Path $output "claude-$shell/settings.json"
& python (Join-Path $root 'scripts/validate-config.py') $tomlPath $settingsPath
& python (Join-Path $root 'scripts/checks/validate-config.py') $tomlPath $settingsPath
if ($LASTEXITCODE -ne 0) { throw "Generated configuration validation failed for $shell." }
Test-CodexSchema $tomlPath
}
+3 -3
View File
@@ -8,7 +8,7 @@ while [ $# -gt 0 ]; do
esac
done
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
shared="$root/shared"
output="$root/generated"
plugin_manifest="$root/adapters/plugins.tsv"
@@ -85,7 +85,7 @@ quote_toml() {
printf '"%s"' "$value"
}
session_output=$(bash "$shared/hooks/scripts/test-session-config.sh" "$root") || { printf '%s\n' "$session_output" >&2; exit 1; }
session_output=$(bash "$shared/hooks/scripts/tests/test-session-config.sh" "$root") || { printf '%s\n' "$session_output" >&2; exit 1; }
if [ "$summary" = true ]; then
printf '%s\n' "$session_output" | sed '/^PASS session configuration$/d'
else
@@ -213,7 +213,7 @@ done
toml_path="$output/codex-$shell/config.toml"
settings_path="$output/claude-$shell/settings.json"
python3 "$root/scripts/validate-config.py" "$toml_path" "$settings_path"
python3 "$root/scripts/checks/validate-config.py" "$toml_path" "$settings_path"
if command -v codex >/dev/null; then
schema_home=$(mktemp -d)
cp "$toml_path" "$schema_home/config.toml"
File renamed without changes.
File renamed without changes.
@@ -1,8 +1,8 @@
[CmdletBinding()]
param([switch]$Summary)
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
. (Join-Path $PSScriptRoot 'lib/manifest.ps1')
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
. (Join-Path $root 'scripts/lib/manifest.ps1')
$homePath = [Environment]::GetFolderPath('UserProfile')
$script:fail = $false
$script:checkCount = 0
+1 -1
View File
@@ -9,7 +9,7 @@ while [ $# -gt 0 ]; do
esac
done
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
. "$root/scripts/lib/manifest.sh"
home_path=${HOME:?HOME is required}
failed=false
@@ -6,13 +6,13 @@ param(
[switch]$Summary
)
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
. (Join-Path $PSScriptRoot 'lib/plugins.ps1')
. (Join-Path $PSScriptRoot 'lib/manifest.ps1')
. (Join-Path $PSScriptRoot 'lib/install-targets.ps1')
. (Join-Path $PSScriptRoot 'lib/selection-state.ps1')
. (Join-Path $PSScriptRoot 'lib/install-options.ps1')
. (Join-Path $PSScriptRoot 'lib/semantic-retrieval.ps1')
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
. (Join-Path $root 'scripts/lib/plugins.ps1')
. (Join-Path $root 'scripts/lib/manifest.ps1')
. (Join-Path $root 'scripts/lib/install-targets.ps1')
. (Join-Path $root 'scripts/lib/selection-state.ps1')
. (Join-Path $root 'scripts/lib/install-options.ps1')
. (Join-Path $root 'scripts/lib/semantic-retrieval.ps1')
$Shell = Read-InstallShell -Shell $Shell
$shell = $Shell.ToLowerInvariant()
@@ -26,7 +26,7 @@ if (-not $DryRun -and (Test-AnyManifestPresent (Get-InstallDestinations -HomePat
$options = Read-InstallOptions -HomePath $homePath -RepositoryRoot $root -Client $Client -DryRun:$DryRun
$reinstallViaNpm = Read-CliReinstallOption -Client $Client -DryRun:$DryRun
$buildScript = Join-Path $PSScriptRoot 'build.ps1'
$buildScript = Join-Path $root 'scripts/commands/build.ps1'
& $buildScript -Summary:$Summary
if (-not $?) { throw 'Build failed. Installation was not started.' }
$generated = Join-Path $root 'generated'
+2 -2
View File
@@ -15,7 +15,7 @@ while [ $# -gt 0 ]; do
esac
done
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
. "$root/scripts/lib/plugins.sh"
. "$root/scripts/lib/manifest.sh"
. "$root/scripts/lib/install-targets.sh"
@@ -40,7 +40,7 @@ reinstall_via_npm=$(read_cli_reinstall_option "$client" "$dry_run")
build_args=()
[ "$summary" = false ] || build_args+=(--summary)
bash "$root/scripts/build.sh" "${build_args[@]}"
bash "$root/scripts/commands/build.sh" "${build_args[@]}"
generated="$root/generated"
[ -d "$generated" ] || { printf 'Generated output is missing after a successful build.\n' >&2; exit 1; }
@@ -1,7 +1,7 @@
[CmdletBinding()]
param([switch]$Summary)
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$generated = Join-Path $root 'generated'
if (-not (Test-Path (Join-Path $generated 'claude-bash/CLAUDE.md'))) { throw 'Generated output is missing; run build first.' }
function Measure-Tree([string]$path) {
@@ -30,7 +30,7 @@ if ($old) {
}
}
if ($Summary) { Write-Output 'Prompt Budget'; foreach ($row in $rows | Select-Object -First 2) { $limits = $baselineValues[$row.Name]; $base = if($limits){$limits[0]}else{'-'}; $absolute = if($limits){$limits[1]}else{'-'}; Write-Output ('{0,-28} {1,8} bytes baseline {2} relative 115% absolute {3}' -f $row.Name,$row.Bytes,$base,$absolute) }; $rows | Select-Object -Skip 2 | ForEach-Object { Write-Output ('{0,-28} {1,8} bytes {2,6} tokens' -f $_.Name,$_.Bytes,$_.Tokens) } } else { $rows | ForEach-Object { Write-Output ('{0}: {1} bytes / {2} tokens' -f $_.Name,$_.Bytes,$_.Tokens) } }
& python (Join-Path $PSScriptRoot 'lib/prompt-inventory.py') --home ([Environment]::GetFolderPath('UserProfile'))
& python (Join-Path $root 'scripts/lib/prompt-inventory.py') --home ([Environment]::GetFolderPath('UserProfile'))
if ($LASTEXITCODE -ne 0) { throw 'Prompt inventory failed.' }
if ($fail) { exit 1 }
exit 0
+1 -1
View File
@@ -2,7 +2,7 @@
set -euo pipefail
summary=false
for arg in "$@"; do case "$arg" in --summary) summary=true;; *) printf 'Unknown argument: %s\n' "$arg" >&2; exit 1;; esac; done
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
generated="$root/generated"
[ -f "$generated/claude-bash/CLAUDE.md" ] || { printf 'Generated output is missing; run build first.\n' >&2; exit 1; }
bytes() { wc -c < "$1" | tr -d ' '; }
@@ -1,7 +1,7 @@
[CmdletBinding()]
param([switch]$Force,[switch]$Summary)
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$cacheDir = Join-Path $root '.ai-session'
$cachePath = Join-Path $cacheDir 'repository-context.json'
$safeRoot = $root.Replace('\','/')
+1 -1
View File
@@ -2,7 +2,7 @@
set -euo pipefail
force=false; summary=false
for arg in "$@"; do case "$arg" in --force) force=true;; --summary) summary=true;; *) printf 'Unknown argument: %s\n' "$arg" >&2; exit 1;; esac; done
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd); cache_dir="$root/.ai-session"; cache_path="$cache_dir/repository-context.json"
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd); cache_dir="$root/.ai-session"; cache_path="$cache_dir/repository-context.json"
head=$(git -c "safe.directory=$root" -C "$root" rev-parse HEAD 2>/dev/null || true); key_input=$head
while IFS= read -r file; do key_input+="\n$file:$(sha256sum "$file" | awk '{print $1}')"; done < <(find "$root" -type f \( -name AI-Instructions.md -o -path '*/adapters/*' \) ! -path '*/generated/*' ! -path '*/.git/*' ! -path '*/.ai-session/*' | sort)
key=$(printf '%s' "$key_input" | sha256sum | awk '{print $1}')
@@ -12,7 +12,7 @@ param(
[switch]$Reset
)
$ErrorActionPreference = 'Stop'
$helper = Join-Path (Split-Path $PSScriptRoot -Parent) 'shared/hooks/scripts/session-state.py'
$helper = Join-Path (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) 'shared/hooks/scripts/session-state.py'
$values = @{ workspace = $Workspace }
$fields = @{ Goal = 'goal'; Decisions = 'decisions'; ChangedFiles = 'changed'; Verified = 'verified'; Pending = 'open'; Risks = 'risks' }
foreach ($parameter in $fields.Keys) {
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
arguments=()
if [ "${AI_TASK_GOAL+x}" = x ]; then arguments+=(--goal "$AI_TASK_GOAL"); fi
python3 "$root/shared/hooks/scripts/session-state.py" "${arguments[@]}" "$@"
@@ -2,7 +2,7 @@
param([ValidateSet('record','summary','rotate')][string]$Action='record',[string]$Event,[string]$Agent,[string]$Role,[Nullable[int]]$DurationMs,[Nullable[int]]$ToolCalls,[string]$CommandClass,[Nullable[int64]]$Bytes,[Nullable[int]]$Count,[Nullable[int]]$HandoffBytes,[Nullable[int]]$FilesRead,[Nullable[int]]$FilesChanged,[string]$Outcome,[Nullable[int]]$InputTokens,[Nullable[int]]$CachedTokens,[Nullable[int]]$OutputTokens,[Nullable[int]]$ReasoningTokens)
$ErrorActionPreference = 'Stop'; if ($env:AI_CONFIG_TELEMETRY -eq '0') { exit 0 }
try {
$root = Split-Path $PSScriptRoot -Parent; $dir = Join-Path $root '.ai-session'; $path = Join-Path $dir 'telemetry.jsonl'; New-Item $dir -ItemType Directory -Force | Out-Null
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent; $dir = Join-Path $root '.ai-session'; $path = Join-Path $dir 'telemetry.jsonl'; New-Item $dir -ItemType Directory -Force | Out-Null
if ($Action -eq 'rotate') { if (Test-Path $path) { Move-Item $path ($path + '.1') -Force }; exit 0 }
if ($Action -eq 'summary') { if (-not (Test-Path $path)) { Write-Output 'Telemetry: no events'; exit 0 }; $events=@(Get-Content $path | ForEach-Object { try { $_ | ConvertFrom-Json } catch {} }); Write-Output ('Telemetry: {0} events' -f $events.Count); foreach($group in @($events | Where-Object role | Group-Object role | Sort-Object Name)){ $inputs=@($group.Group|Where-Object tokenUsage|ForEach-Object {$_.tokenUsage.input}|Where-Object {$_ -is [int] -or $_ -is [long]}|Sort-Object); $median=if($inputs.Count){$inputs[[int][Math]::Floor($inputs.Count/2)]}else{'-'}; Write-Output ('{0}: runs {1} findings {2} median input {3}' -f $group.Name,$group.Count,@($group.Group|Where-Object outcome -eq findings).Count,$median)}; exit 0 }
if ([string]::IsNullOrWhiteSpace($Event)) { throw 'Event is required.' }
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
[ "${AI_CONFIG_TELEMETRY:-1}" = 0 ] && exit 0
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd); dir="$root/.ai-session"; path="$dir/telemetry.jsonl"; mkdir -p "$dir"
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd); dir="$root/.ai-session"; path="$dir/telemetry.jsonl"; mkdir -p "$dir"
action=${1:-record}; shift || true
case "$action" in
rotate) [ -f "$path" ] && mv -f "$path" "$path.1"; exit 0;;
@@ -6,11 +6,11 @@ param(
[switch]$Summary
)
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
. (Join-Path $PSScriptRoot 'lib/plugins.ps1')
. (Join-Path $PSScriptRoot 'lib/manifest.ps1')
. (Join-Path $PSScriptRoot 'lib/install-targets.ps1')
. (Join-Path $PSScriptRoot 'lib/semantic-retrieval.ps1')
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
. (Join-Path $root 'scripts/lib/plugins.ps1')
. (Join-Path $root 'scripts/lib/manifest.ps1')
. (Join-Path $root 'scripts/lib/install-targets.ps1')
. (Join-Path $root 'scripts/lib/semantic-retrieval.ps1')
$Client = Read-InstallClient -Client $Client
$homePath = [Environment]::GetFolderPath('UserProfile')
@@ -15,7 +15,7 @@ while [ $# -gt 0 ]; do
esac
done
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
. "$root/scripts/lib/plugins.sh"
. "$root/scripts/lib/manifest.sh"
. "$root/scripts/lib/install-targets.sh"
@@ -7,13 +7,13 @@ param(
[switch]$Summary
)
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
. (Join-Path $PSScriptRoot 'lib/plugins.ps1')
. (Join-Path $PSScriptRoot 'lib/manifest.ps1')
. (Join-Path $PSScriptRoot 'lib/install-targets.ps1')
. (Join-Path $PSScriptRoot 'lib/selection-state.ps1')
. (Join-Path $PSScriptRoot 'lib/install-options.ps1')
. (Join-Path $PSScriptRoot 'lib/semantic-retrieval.ps1')
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
. (Join-Path $root 'scripts/lib/plugins.ps1')
. (Join-Path $root 'scripts/lib/manifest.ps1')
. (Join-Path $root 'scripts/lib/install-targets.ps1')
. (Join-Path $root 'scripts/lib/selection-state.ps1')
. (Join-Path $root 'scripts/lib/install-options.ps1')
. (Join-Path $root 'scripts/lib/semantic-retrieval.ps1')
$homePath = [Environment]::GetFolderPath('UserProfile')
if ($Quick) {
@@ -32,7 +32,7 @@ if (-not $DryRun -and -not (Test-AllManifestsPresent (Get-InstallDestinations -H
$options = if ($Quick) { $saved } else { Read-InstallOptions -HomePath $homePath -RepositoryRoot $root -Client $Client -DryRun:$DryRun }
$buildScript = Join-Path $PSScriptRoot 'build.ps1'
$buildScript = Join-Path $root 'scripts/commands/build.ps1'
& $buildScript -Summary:$Summary
if (-not $?) { throw 'Build failed. Update was not started.' }
$generated = Join-Path $root 'generated'
+2 -2
View File
@@ -17,7 +17,7 @@ while [ $# -gt 0 ]; do
esac
done
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
. "$root/scripts/lib/plugins.sh"
. "$root/scripts/lib/manifest.sh"
. "$root/scripts/lib/install-targets.sh"
@@ -45,7 +45,7 @@ if [ "$quick" = false ]; then read_install_options; fi
build_args=()
[ "$summary" = false ] || build_args+=(--summary)
bash "$root/scripts/build.sh" "${build_args[@]}"
bash "$root/scripts/commands/build.sh" "${build_args[@]}"
generated="$root/generated"
[ -d "$generated" ] || { printf 'Generated output is missing after a successful build.\n' >&2; exit 1; }
@@ -1,7 +1,7 @@
[CmdletBinding()]
param([switch]$Summary)
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$work = Join-Path ([System.IO.Path]::GetTempPath()) ("ai-config-build-validation-" + [Guid]::NewGuid())
New-Item $work -ItemType Directory -Force | Out-Null
@@ -18,14 +18,14 @@ function Test-BuildFails([string]$Label, [scriptblock]$Mutate) {
$copy = New-RepoCopy
& $Mutate $copy
$failed = $false
try { & (Join-Path $copy 'scripts/build.ps1') 2>&1 | Out-Null }
try { & (Join-Path $copy 'scripts/commands/build.ps1') 2>&1 | Out-Null }
catch { $failed = $true }
Remove-Item $copy -Recurse -Force -ErrorAction SilentlyContinue
if (-not $failed) { throw "Expected build to fail for case '$Label' but it succeeded." }
}
$baseline = New-RepoCopy
& (Join-Path $baseline 'scripts/build.ps1') -Summary | Out-Null
& (Join-Path $baseline 'scripts/commands/build.ps1') -Summary | Out-Null
Test-BuildFails 'invalid Claude settings.json' {
param($copy)
+3 -3
View File
@@ -8,7 +8,7 @@ while [ $# -gt 0 ]; do
esac
done
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
work=$(mktemp -d)
cleanup() { rm -rf -- "$work"; }
trap cleanup EXIT
@@ -24,7 +24,7 @@ test_build_fails() {
local label=$1 mutate_fn=$2 copy
copy=$(new_repo_copy)
"$mutate_fn" "$copy"
if bash "$copy/scripts/build.sh" >/dev/null 2>&1; then
if bash "$copy/scripts/commands/build.sh" >/dev/null 2>&1; then
printf 'Expected build to fail for case "%s" but it succeeded.\n' "$label" >&2
exit 1
fi
@@ -32,7 +32,7 @@ test_build_fails() {
}
baseline=$(new_repo_copy)
bash "$baseline/scripts/build.sh" --summary >/dev/null
bash "$baseline/scripts/commands/build.sh" --summary >/dev/null
mutate_invalid_json() {
printf '} this is not json {' >> "$1/adapters/claude/config/settings.json"
@@ -1,9 +1,9 @@
[CmdletBinding()]
param([switch]$Summary)
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
. (Join-Path $PSScriptRoot 'lib/manifest.ps1')
. (Join-Path $PSScriptRoot 'lib/install-targets.ps1')
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
. (Join-Path $root 'scripts/lib/manifest.ps1')
. (Join-Path $root 'scripts/lib/install-targets.ps1')
$work = Join-Path ([System.IO.Path]::GetTempPath()) ("ai-config-install-guard-test-" + [Guid]::NewGuid())
try {
+1 -1
View File
@@ -8,7 +8,7 @@ while [ $# -gt 0 ]; do
esac
done
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
. "$root/scripts/lib/manifest.sh"
. "$root/scripts/lib/install-targets.sh"
@@ -9,7 +9,7 @@ import tomllib
import unittest
ROOT = Path(__file__).resolve().parent.parent
ROOT = Path(__file__).resolve().parent.parent.parent
SPEC = importlib.util.spec_from_file_location('install_options', ROOT / 'scripts/lib/install-options.py')
OPTIONS = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(OPTIONS)
@@ -172,19 +172,19 @@ class ManagedExtensionTests(unittest.TestCase):
self.manager(dry_run=True, summary=True).sync([plugin(), skill()], ['codex'], {'Example', 'Humanizer'})
self.assertEqual('EXTENSIONS: reconciliation complete (dry run)\n', output.getvalue())
def test_qmd_installs_once_and_registers_codex_mcp(self):
def test_qmd_installs_once_as_a_cli_without_registering_mcp(self):
entry = dict(name='QMD', codex_method='qmd', codex_source='@tobilu/qmd', codex_skill='qmd', codex_plugin='-', codex_marketplace='-', claude_plugin='qmd@qmd', claude_marketplace='tobi/qmd')
self.manager().sync([entry], ['codex'], {'QMD'})
self.assertEqual([['npm', 'install', '--global', '@tobilu/qmd'], ['codex', 'mcp', 'add', 'qmd', '--', 'qmd', 'mcp']], self.commands)
self.assertEqual([['npm', 'install', '--global', '@tobilu/qmd']], self.commands)
self.manager().sync([], ['codex'], set())
self.assertEqual(['codex', 'mcp', 'remove', 'qmd'], self.commands[-1])
self.assertEqual(['npm', 'uninstall', '--global', '@tobilu/qmd'], self.commands[-1])
def test_qmd_installs_once_for_both_clients(self):
entry = dict(name='QMD', codex_method='qmd', codex_source='@tobilu/qmd', codex_skill='qmd', codex_plugin='-', codex_marketplace='-', claude_plugin='qmd@qmd', claude_marketplace='tobi/qmd')
self.manager().sync([entry], ['claude', 'codex'], {'QMD'})
self.assertEqual(1, self.commands.count(['npm', 'install', '--global', '@tobilu/qmd']))
self.assertIn(['claude', 'plugin', 'install', 'qmd@qmd', '--scope', 'user'], self.commands)
self.assertIn(['codex', 'mcp', 'add', 'qmd', '--', 'qmd', 'mcp'], self.commands)
self.assertNotIn(['codex', 'mcp', 'add', 'qmd', '--', 'qmd', 'mcp'], self.commands)
def test_foreign_empty_directory_survives_skill_removal(self):
self.manager().sync([skill()], ['codex'], {'Humanizer'})
@@ -1,9 +1,9 @@
[CmdletBinding()]
param([switch]$Summary)
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
. (Join-Path $PSScriptRoot 'lib/manifest.ps1')
. (Join-Path $PSScriptRoot 'lib/install-targets.ps1')
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
. (Join-Path $root 'scripts/lib/manifest.ps1')
. (Join-Path $root 'scripts/lib/install-targets.ps1')
$work = Join-Path ([System.IO.Path]::GetTempPath()) ("ai-config-manifest-test-" + [Guid]::NewGuid())
New-Item $work -ItemType Directory -Force | Out-Null
+1 -1
View File
@@ -8,7 +8,7 @@ while [ $# -gt 0 ]; do
esac
done
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
. "$root/scripts/lib/manifest.sh"
. "$root/scripts/lib/install-targets.sh"
@@ -1,8 +1,9 @@
[CmdletBinding()]
param([switch]$Summary)
$ErrorActionPreference = 'Stop'
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
function Write-Host { param($Object) if (-not $Summary) { Microsoft.PowerShell.Utility\Write-Host $Object } }
. (Join-Path $PSScriptRoot 'lib/plugins.ps1')
. (Join-Path $root 'scripts/lib/plugins.ps1')
$script:answers = [System.Collections.Generic.Queue[string]]::new()
$script:answers.Enqueue('1')
@@ -43,22 +44,22 @@ $null = Get-InstalledPlugins -Client Codex -HomePath 'C:/temporary profile'
if ($observedCodexHome -ne (Join-Path 'C:/temporary profile' '.codex') -or $observedProfile -ne 'C:/temporary profile') { throw 'Plugin inspection must use the requested user home.' }
if ($env:CODEX_HOME -ne $previousCodexHome -or $env:USERPROFILE -ne $previousProfile) { throw 'Plugin inspection must restore the process environment.' }
$script:answers.Enqueue('done')
$selection = Select-ConfiguredPlugins -RepositoryRoot (Split-Path $PSScriptRoot -Parent) -Client Codex -Mode Update
$selection = Select-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -Mode Update
if (@($selection.Selected | Where-Object { $_.codex_method -eq 'plugin' }).Count -ne 5) { throw 'All installed Codex plugins must start checked when updating.' }
$script:answers.Enqueue('4')
$script:answers.Enqueue('done')
$selection = Select-ConfiguredPlugins -RepositoryRoot (Split-Path $PSScriptRoot -Parent) -Client Codex -Mode Update
$selection = Select-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -Mode Update
if (@($selection.Deselected | Where-Object { $_.name -eq 'Context7' }).Count -ne 1) { throw 'Only the explicitly unchecked installed plugin must be deselected.' }
$script:managedArguments = @()
function python { $script:managedArguments = @($args); $global:LASTEXITCODE = 0 }
$entry = [pscustomobject]@{ name = 'Test'; codex_method = 'plugin'; codex_marketplace = '-'; codex_plugin = 'test@market' }
Sync-ConfiguredPlugins -RepositoryRoot (Split-Path $PSScriptRoot -Parent) -Client Codex -HomePath 'C:/temporary home' -Update -Summary -Entries @($entry)
Sync-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -HomePath 'C:/temporary home' -Update -Summary -Entries @($entry)
if ($managedArguments -notcontains 'sync' -or $managedArguments -notcontains '--update' -or $managedArguments -notcontains 'Test' -or $managedArguments -notcontains 'C:/temporary home') { throw 'Managed reconciliation must receive selection, home, and update mode.' }
Sync-ConfiguredPlugins -RepositoryRoot (Split-Path $PSScriptRoot -Parent) -Client Codex -Entries @()
Sync-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Codex -Entries @()
if ($managedArguments[-1] -ne '--selected') { throw 'Empty selection must reach reconciliation for managed cleanup.' }
function Get-InstalledPlugins { throw 'Empty selection must not query installed plugins.' }
function Invoke-PluginCommand { throw 'Empty selection must not run plugin commands.' }
Install-ConfiguredPlugins -RepositoryRoot (Split-Path $PSScriptRoot -Parent) -Client Both -Entries @()
Install-ConfiguredPlugins -RepositoryRoot (Split-Path (Split-Path $PSScriptRoot -Parent) -Parent) -Client Both -Entries @()
Uninstall-DeselectedPlugins -Client Both -Entries @()
if ($Summary) { Write-Output 'Tests: PASS | plugin selection' } else { Write-Output 'PASS plugin toggle selection: toggle and confirm' }
+1 -1
View File
@@ -8,7 +8,7 @@ while [ $# -gt 0 ]; do
esac
done
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
. "$root/scripts/lib/plugins.sh"
# shellcheck disable=SC2034
File renamed without changes.
File renamed without changes.
@@ -8,7 +8,7 @@ import tempfile
import unittest
ROOT = Path(__file__).resolve().parent.parent
ROOT = Path(__file__).resolve().parent.parent.parent
HELPER = ROOT / 'scripts/lib/selection-state.py'
@@ -112,7 +112,7 @@ class SelectionTests(unittest.TestCase):
env=environment, capture_output=True, text=True, timeout=10)
self.assertEqual(save.returncode, 0, save.stdout + save.stderr)
original = self.path.read_bytes()
source = (ROOT / 'scripts/update.ps1').read_text(encoding='utf-8-sig')
source = (ROOT / 'scripts/commands/update.ps1').read_text(encoding='utf-8-sig')
source = source.replace("[Environment]::GetFolderPath('UserProfile')", '$env:TEST_SELECTION_HOME')
with tempfile.NamedTemporaryFile(mode='w', suffix='.tmp.ps1', dir=ROOT / 'scripts',
encoding='utf-8', delete=False) as stream:
@@ -148,7 +148,7 @@ class SelectionTests(unittest.TestCase):
self.assertEqual(save.returncode, 0, save.stdout + save.stderr)
original = self.path.read_bytes()
environment = dict(os.environ, HOME=self.home.as_posix())
result = subprocess.run([shell, str(ROOT / 'scripts/update.sh'), '--quick', '--dry-run'],
result = subprocess.run([shell, str(ROOT / 'scripts/commands/update.sh'), '--quick', '--dry-run'],
env=environment, stdin=subprocess.DEVNULL, capture_output=True, text=True, timeout=90)
self.assertEqual(result.returncode, 0, result.stdout + result.stderr)
self.assertNotIn('Select plugins', result.stdout)
+2 -2
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
set -euo pipefail
case "${1:-}" in ''|--summary) ;; *) printf 'Unknown argument: %s\n' "$1" >&2; exit 1 ;; esac
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
python3 "$root/scripts/test-quick-update.py"
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
python3 "$root/scripts/tests/test-quick-update.py"
printf 'Tests: PASS | quick update selection\n'
@@ -11,7 +11,7 @@ import unittest
from unittest.mock import patch
ROOT = Path(__file__).resolve().parent.parent
ROOT = Path(__file__).resolve().parent.parent.parent
SPEC = importlib.util.spec_from_file_location('retrieval_server', ROOT / 'shared/retrieval/server.py')
MODULE = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(MODULE)
@@ -9,7 +9,7 @@ import unittest
from unittest.mock import patch
ROOT = Path(__file__).resolve().parent.parent
ROOT = Path(__file__).resolve().parent.parent.parent
SPEC = importlib.util.spec_from_file_location('semantic_retrieval', ROOT / 'scripts/lib/semantic-retrieval.py')
MODULE = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(MODULE)
@@ -8,7 +8,7 @@ import tempfile
import unittest
ROOT = Path(__file__).resolve().parent.parent
ROOT = Path(__file__).resolve().parent.parent.parent
SHELLS = [
('powershell', shutil.which('powershell') or shutil.which('pwsh')),
('bash', str(Path(os.environ.get('ProgramFiles', 'C:/Program Files')) / 'Git/bin/bash.exe')
@@ -88,16 +88,16 @@ class SessionStateHookTests(unittest.TestCase):
if shell == 'powershell':
prefix = [executable, '-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command']
commands = [
'& ./scripts/session-state.ps1 -Workspace $env:TASK_WORKSPACE -Goal $env:TASK_GOAL -Decisions @("keep", "line two") -Pending @("check")',
'& ./scripts/session-state.ps1 -Workspace $env:TASK_WORKSPACE -Verified @("passed")',
'& ./scripts/session-state.ps1 -Workspace $env:TASK_WORKSPACE -Pointer',
'& ./scripts/commands/session-state.ps1 -Workspace $env:TASK_WORKSPACE -Goal $env:TASK_GOAL -Decisions @("keep", "line two") -Pending @("check")',
'& ./scripts/commands/session-state.ps1 -Workspace $env:TASK_WORKSPACE -Verified @("passed")',
'& ./scripts/commands/session-state.ps1 -Workspace $env:TASK_WORKSPACE -Pointer',
]
else:
prefix = [executable, '-c']
commands = [
'bash ./scripts/session-state.sh --workspace "$TASK_WORKSPACE" --goal "$TASK_GOAL" --decisions keep "line two" --open check',
'bash ./scripts/session-state.sh --workspace "$TASK_WORKSPACE" --verified passed',
'bash ./scripts/session-state.sh --workspace "$TASK_WORKSPACE" --pointer',
'bash ./scripts/commands/session-state.sh --workspace "$TASK_WORKSPACE" --goal "$TASK_GOAL" --decisions keep "line two" --open check',
'bash ./scripts/commands/session-state.sh --workspace "$TASK_WORKSPACE" --verified passed',
'bash ./scripts/commands/session-state.sh --workspace "$TASK_WORKSPACE" --pointer',
]
for command in commands:
result = subprocess.run(prefix + [command], cwd=repository, capture_output=True,
@@ -1,13 +1,13 @@
[CmdletBinding()]
param([switch]$Summary)
$ErrorActionPreference = 'Stop'
$root = Split-Path $PSScriptRoot -Parent
$root = Split-Path (Split-Path $PSScriptRoot -Parent) -Parent
$powerShellHook = Get-Content -LiteralPath (Join-Path $root 'shared/hooks/flashbang.ps1') -Raw
$bashHook = Get-Content -LiteralPath (Join-Path $root 'shared/hooks/flashbang.sh') -Raw
if ($powerShellHook -notmatch '\$HoldMs\s*=\s*250' -or $powerShellHook -notmatch '\$FadeMs\s*=\s*250' -or ([regex]::Matches($bashHook, 'default=250').Count -lt 2)) { throw 'Flashbang defaults must total 500 milliseconds on PowerShell and Bash.' }
$statusInput = '{"model":{"display_name":"Test Model"},"effort":{"level":"high"},"workspace":{"current_dir":"' + $root.Replace('\','\\') + '","repo":{"name":"TestRepo"}},"context_window":{"context_window_size":200000,"used_percentage":8.5,"total_input_tokens":15500,"total_output_tokens":1200}}'
$branch = & git -C $root branch --show-current
$buildSummaryOutput = & (Join-Path $root 'scripts/build.ps1') -Summary
$buildSummaryOutput = & (Join-Path $root 'scripts/commands/build.ps1') -Summary
if (@($buildSummaryOutput | Where-Object { $_ -eq 'Build: PASS | 4 packages' }).Count -ne 1) { throw "build.ps1 -Summary must still print the PASS line: $($buildSummaryOutput -join '; ')" }
$statusOutput = ($statusInput | & (Join-Path $root 'shared/statusline/statusline.ps1')) -join "`n"
$plainStatusOutput = [regex]::Replace($statusOutput, [char]27 + '\[[0-9;]*m', '')
@@ -48,7 +48,7 @@ foreach ($shell in @('powershell','bash')) {
throw "Claude finish hook is incorrect in $package"
} elseif ($content -notmatch '"defaultMode"\s*:\s*"auto"') {
throw "Claude auto permission mode is missing in $package"
} elseif (-not $settings.sandbox.enabled -or $settings.sandbox.allowUnsandboxedCommands -ne $false) {
} elseif (-not $settings.sandbox.enabled -or $settings.sandbox.allowUnsandboxedCommands -ne $false -or $settings.sandbox.failIfUnavailable -ne $true) {
throw "Claude strict sandbox is missing in $package"
} elseif (-not (Test-Path -LiteralPath (Join-Path $package "statusline/statusline.$(if ($shell -eq 'powershell') { 'ps1' } else { 'sh' })")) -or $settings.statusLine.command -notmatch "statusline\.$(if ($shell -eq 'powershell') { 'ps1' } else { 'sh' })") {
throw "Claude status line is incorrect in $package"
@@ -70,17 +70,17 @@ foreach ($shellSelection in @('1','2')) {
$script:answers.Enqueue($shellSelection)
$script:answers.Enqueue($clientSelection)
function Read-Host { param($Prompt) $answers.Dequeue() }
$output = & "$PSScriptRoot/install.ps1" -DryRun 6>$null
$output = & (Join-Path $root 'scripts/commands/install.ps1') -DryRun 6>$null
if ($output -notcontains 'PASS install dry-run') { throw 'Dry-run did not finish.' }
$shell = if ($shellSelection -eq '1') { 'powershell' } else { 'bash' }
if (($output -join "`n") -notmatch "-$shell") { throw 'Incorrect selected package.' }
}
}
$doctorSummaryOutput = & (Join-Path $root 'scripts/doctor.ps1') -Summary
$doctorSummaryOutput = & (Join-Path $root 'scripts/commands/doctor.ps1') -Summary
if (@($doctorSummaryOutput | Where-Object { $_ -match '^PASS ' }).Count -ne 0) { throw 'Doctor summary mode must not print individual PASS lines.' }
if (@($doctorSummaryOutput | Where-Object { $_ -match '^Doctor: PASS \| \d+ checks$' }).Count -ne 1) { throw "Doctor summary mode must print one 'Doctor: PASS | N checks' line: $($doctorSummaryOutput -join '; ')" }
foreach ($entryPoint in @('install','update')) {
$preview = @(& "$PSScriptRoot/$entryPoint.ps1" -Summary -DryRun -Client Both -Shell PowerShell)
$preview = @(& (Join-Path $root "scripts/commands/$entryPoint.ps1") -Summary -DryRun -Client Both -Shell PowerShell)
if ($preview -match '^(SOURCE|CREATE|UPDATE|UNCHANGED|BACKUP|DRYRUN|PASS) ') { throw "$entryPoint summary leaked per-item output." }
if (@($preview | Where-Object { $_ -match ('^' + $entryPoint + ': PASS') }).Count -ne 1) { throw "$entryPoint summary is missing." }
}
+6 -6
View File
@@ -7,12 +7,12 @@ while [ $# -gt 0 ]; do
*) printf 'Unknown argument: %s\n' "$1" >&2; exit 1 ;;
esac
done
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
grep -Eq '\$HoldMs[[:space:]]*=[[:space:]]*250' "$root/shared/hooks/flashbang.ps1"
grep -Eq '\$FadeMs[[:space:]]*=[[:space:]]*250' "$root/shared/hooks/flashbang.ps1"
[ "$(grep -c 'default=250' "$root/shared/hooks/flashbang.sh")" -ge 2 ]
branch=$(git -C "$root" branch --show-current)
build_summary_output=$(bash "$root/scripts/build.sh" --summary)
build_summary_output=$(bash "$root/scripts/commands/build.sh" --summary)
if ! printf '%s\n' "$build_summary_output" | grep -qx 'Build: PASS | 4 packages'; then
printf 'build.sh --summary must still print the PASS line: %s\n' "$build_summary_output" >&2
exit 1
@@ -65,7 +65,7 @@ for shell in powershell bash; do
! grep -q 'flashbang-if-input' "$package/$file"
! grep -q '"async"[[:space:]]*:[[:space:]]*true' "$package/$file"
grep -q '"defaultMode"[[:space:]]*:[[:space:]]*"auto"' "$package/$file"
python3 -c 'import json,sys; settings=json.load(open(sys.argv[1], encoding="utf-8-sig")); assert settings["sandbox"] == {"enabled": True, "allowUnsandboxedCommands": False}' "$package/$file"
python3 -c 'import json,sys; settings=json.load(open(sys.argv[1], encoding="utf-8-sig")); assert settings["sandbox"] == {"enabled": True, "allowUnsandboxedCommands": False, "failIfUnavailable": True}' "$package/$file"
statusline_extension='sh'
[ "$shell" != powershell ] || statusline_extension=ps1
test -f "$package/statusline/statusline.$statusline_extension"
@@ -100,7 +100,7 @@ for shell in powershell bash; do
done
for shell_selection in 1 2; do
for client_selection in 1 2 3; do
output=$(printf '%s\n%s\n' "$shell_selection" "$client_selection" | bash "$root/scripts/install.sh" --dry-run 2>&1) || { printf '%s\n' "$output" >&2; exit 1; }
output=$(printf '%s\n%s\n' "$shell_selection" "$client_selection" | bash "$root/scripts/commands/install.sh" --dry-run 2>&1) || { printf '%s\n' "$output" >&2; exit 1; }
printf '%s\n' "$output" | grep -E 'WARN|FAIL|WARNING|ERROR' || true
[[ "$output" == *'PASS install dry-run'* ]]
shell=powershell
@@ -108,7 +108,7 @@ for shell_selection in 1 2; do
[[ "$output" == *"-$shell"* ]]
done
done
doctor_summary_output=$(bash "$root/scripts/doctor.sh" --summary)
doctor_summary_output=$(bash "$root/scripts/commands/doctor.sh" --summary)
if printf '%s\n' "$doctor_summary_output" | grep -q '^PASS '; then
printf 'Doctor summary mode must not print individual PASS lines.\n' >&2
exit 1
@@ -118,7 +118,7 @@ if ! printf '%s\n' "$doctor_summary_output" | grep -Eq '^Doctor: PASS \| [0-9]+
exit 1
fi
for entry_point in install update; do
preview=$(bash "$root/scripts/$entry_point.sh" --summary --dry-run --client both --shell bash)
preview=$(bash "$root/scripts/commands/$entry_point.sh" --summary --dry-run --client both --shell bash)
if printf '%s\n' "$preview" | grep -Eq '^(SOURCE|CREATE|UPDATE|UNCHANGED|BACKUP|DRYRUN|PASS) '; then
printf '%s summary leaked per-item output.\n' "$entry_point" >&2
exit 1
@@ -7,7 +7,7 @@ import tempfile
import unittest
ROOT = Path(__file__).resolve().parent.parent
ROOT = Path(__file__).resolve().parent.parent.parent
class TelemetryTests(unittest.TestCase):
@@ -17,9 +17,9 @@ class TelemetryTests(unittest.TestCase):
self.skipTest('Bash unavailable')
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
script = root / 'scripts/telemetry.sh'
script = root / 'scripts/commands/telemetry.sh'
script.parent.mkdir()
shutil.copy(ROOT / 'scripts/telemetry.sh', script)
shutil.copy(ROOT / 'scripts/commands/telemetry.sh', script)
env = dict(os.environ, AI_CONFIG_TELEMETRY='1')
result = subprocess.run([bash, str(script), 'record', 'subagent-stop', '--role', 'reviewer', '--filesRead', '3', '--outcome', 'findings'], env=env, capture_output=True, text=True)
self.assertEqual(result.returncode, 0, result.stderr)