← Files Voice Notify for CodexARCHIVED FILE
.github/workflows/ci.yml
7.82 KB · Oct 2, 2026 · 00:29 UTC
name: CI
on:
push:
pull_request:
permissions:
contents: read
jobs:
validate:
strategy:
matrix:
os:
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Unit tests
run: python -m unittest discover -s tests -v
- name: Package and WAV validation
run: python scripts/validate_package.py
- name: Deterministic release ZIP validation
run: >-
python scripts/build_release.py --check-only
--sha256-output "${{ runner.temp }}/release-sha256.txt"
- name: Upload deterministic release digest
uses: actions/upload-artifact@v7
with:
name: release-digest-${{ matrix.os }}
path: ${{ runner.temp }}/release-sha256.txt
if-no-files-found: error
retention-days: 1
- name: macOS first-time setup smoke test
if: runner.os == 'macOS'
shell: bash
run: |
set -euo pipefail
SKILL_DIR="$PWD/skills/voice-notify-settings"
PLUGIN_ROOT="$(cd "$SKILL_DIR/../.." && pwd)"
SETTINGS_SCRIPT="$PLUGIN_ROOT/scripts/voice_notify_config.sh"
HOOK_SCRIPT="$PLUGIN_ROOT/hooks/play_notify.sh"
/bin/sh -n "$SETTINGS_SCRIPT"
/bin/sh -n "$HOOK_SCRIPT"
FAKE_CODEX="$RUNNER_TEMP/codex"
printf '#!/bin/sh\necho "codex-cli 0.145.0"\n' > "$FAKE_CODEX"
chmod +x "$FAKE_CODEX"
REJECTED_CONFIG="$RUNNER_TEMP/rejected-settings.json"
export CODEX_VOICE_NOTIFY_CONFIG="$REJECTED_CONFIG"
set +e
/bin/sh "$SETTINGS_SCRIPT" setup \
--voice male \
--language en \
--codex-command /bin/echo \
--skip-audio-test
REJECTED_STATUS=$?
set -e
if [ "$REJECTED_STATUS" -ne 3 ] || [ -e "$REJECTED_CONFIG" ]; then
echo "Rejected Codex executables must return 3 without saving settings." >&2
exit 1
fi
export CODEX_VOICE_NOTIFY_CONFIG="$RUNNER_TEMP/settings.json"
/bin/sh "$SETTINGS_SCRIPT" setup \
--voice male \
--language ja \
--codex-command "$FAKE_CODEX" \
--skip-audio-test
test "$(/usr/bin/plutil -extract voice raw "$CODEX_VOICE_NOTIFY_CONFIG")" = "male"
test "$(/usr/bin/plutil -extract language raw "$CODEX_VOICE_NOTIFY_CONFIG")" = "ja"
test "$(/usr/bin/plutil -extract events.PreToolUse raw "$CODEX_VOICE_NOTIFY_CONFIG")" = "false"
SHOWN_SETTINGS="$RUNNER_TEMP/shown-settings.json"
/bin/sh "$SETTINGS_SCRIPT" show > "$SHOWN_SETTINGS"
test "$(/usr/bin/plutil -extract voice raw "$SHOWN_SETTINGS")" = "male"
/bin/sh "$SETTINGS_SCRIPT" setup \
--voice female \
--language ko \
--codex-command "$FAKE_CODEX" \
--open-hooks \
--dry-run
export PLUGIN_ROOT
export PLUGIN_DATA="$RUNNER_TEMP/codex-voice-notify"
export CODEX_VOICE_NOTIFY_NO_PLAY=1
for LOCALE in ru zh-CN; do
/bin/sh "$SETTINGS_SCRIPT" set --language "$LOCALE"
test "$(/usr/bin/plutil -extract language raw "$CODEX_VOICE_NOTIFY_CONFIG")" = "$LOCALE"
/bin/sh "$SETTINGS_SCRIPT" test \
--event Stop --language "$LOCALE" --dry-run
printf '%s' '{"hook_event_name":"Stop","prompt":"PRIVATE_SENTINEL"}' |
/bin/sh "$HOOK_SCRIPT"
done
- name: Windows settings script smoke test
if: runner.os == 'Windows'
shell: powershell
run: |
$SkillDir = Join-Path (Get-Location).Path "skills\voice-notify-settings"
$PluginRoot = [IO.Path]::GetFullPath((Join-Path $SkillDir "..\.."))
$FakeCodex = Join-Path $env:RUNNER_TEMP "codex.cmd"
Set-Content -LiteralPath $FakeCodex -Encoding ASCII -Value '@echo codex-cli 0.145.0'
$RejectedConfig = Join-Path $env:RUNNER_TEMP "rejected-settings.json"
$env:CODEX_VOICE_NOTIFY_CONFIG = $RejectedConfig
powershell.exe -NoProfile -ExecutionPolicy Bypass `
-File "$PluginRoot\scripts\voice_notify_config.ps1" `
setup -Voice male -Language en -CodexCommand $env:ComSpec -SkipAudioTest
if ($LASTEXITCODE -ne 3 -or (Test-Path -LiteralPath $RejectedConfig)) {
throw "Rejected Codex executables must return 3 without saving settings."
}
$env:CODEX_VOICE_NOTIFY_CONFIG = Join-Path $env:RUNNER_TEMP "settings.json"
$Settings = & "$PluginRoot\scripts\voice_notify_config.ps1" show | ConvertFrom-Json
if ($Settings.events.PreToolUse -ne $false -or
$Settings.events.PostToolUse -ne $false) {
throw "Tool lifecycle notifications must default to disabled."
}
powershell.exe -NoProfile -ExecutionPolicy Bypass `
-File "$PluginRoot\scripts\voice_notify_config.ps1" `
setup -Voice male -Language ja -CodexCommand $FakeCodex -SkipAudioTest
powershell.exe -NoProfile -ExecutionPolicy Bypass `
-File "$PluginRoot\scripts\voice_notify_config.ps1" `
setup -Voice female -Language ko -CodexCommand $FakeCodex -OpenHooks -DryRun
$env:PLUGIN_ROOT = (Get-Location).Path
$env:PLUGIN_DATA = Join-Path $env:RUNNER_TEMP "codex-voice-notify"
$env:CODEX_VOICE_NOTIFY_NO_PLAY = "1"
$HookInput = '{"hook_event_name":"Stop","prompt":"PRIVATE_SENTINEL"}'
$LocaleCases = @(
@{ Input = "ru"; Expected = "ru" },
@{ Input = "zh-cn"; Expected = "zh-CN" }
)
foreach ($LocaleCase in $LocaleCases) {
& "$PluginRoot\scripts\voice_notify_config.ps1" set `
-Language $LocaleCase.Input
if ($LASTEXITCODE -ne 0) {
throw "Windows set smoke test failed for $($LocaleCase.Input)."
}
$SavedSettings = `
& "$PluginRoot\scripts\voice_notify_config.ps1" show | ConvertFrom-Json
if ($SavedSettings.language -cne $LocaleCase.Expected) {
throw "Expected canonical locale $($LocaleCase.Expected), got $($SavedSettings.language)."
}
& "$PluginRoot\scripts\voice_notify_config.ps1" test `
-Event Stop -Language $LocaleCase.Input -DryRun
if ($LASTEXITCODE -ne 0) {
throw "Windows test smoke test failed for $($LocaleCase.Input)."
}
$HookInput |
powershell.exe -NoLogo -NoProfile -NonInteractive `
-ExecutionPolicy Bypass `
-File "$PluginRoot\hooks\play_notify.ps1"
if ($LASTEXITCODE -ne 0) {
throw "Windows hook smoke test failed for $($LocaleCase.Input) with exit code $LASTEXITCODE."
}
}
compare-release-digests:
name: compare release digests
needs: validate
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v8
with:
pattern: release-digest-*
path: release-digests
- name: Require identical macOS and Windows ZIP digests
shell: bash
run: |
set -euo pipefail
MACOS_DIGEST="$(tr -d '\r\n' < release-digests/release-digest-macos-latest/release-sha256.txt)"
WINDOWS_DIGEST="$(tr -d '\r\n' < release-digests/release-digest-windows-latest/release-sha256.txt)"
[[ "$MACOS_DIGEST" =~ ^[0-9a-f]{64}$ ]]
[[ "$WINDOWS_DIGEST" =~ ^[0-9a-f]{64}$ ]]
if [[ "$MACOS_DIGEST" != "$WINDOWS_DIGEST" ]]; then
echo "macOS ZIP SHA-256: $MACOS_DIGEST" >&2
echo "Windows ZIP SHA-256: $WINDOWS_DIGEST" >&2
exit 1
fi
echo "Cross-platform ZIP SHA-256: $MACOS_DIGEST"
SHA-256: 354722fd1ca40981c13f8a1d352fde9f32c7d547158155931a31683ff0f3e948