Tests, licence, and the tooling to keep the repo consistent

A test suite with no dependencies beyond bash and the Python standard
library, run by one command:

  scripts/test.sh                    (or: make test)
  scripts/test.sh --windows [host]   adds the PowerShell suite over SSH

- tests/static.sh: script syntax, JSON validity, VERSION against the widget
  manifest and CHANGELOG, providers.json against the kinds, probes and checks
  the code implements (and ids that would shadow a command), qmllint and
  shellcheck when installed.
- tests/python: unit tests for cm-json.py - providers and the column contract
  bash depends on, the original three scaffolds byte for byte, every
  catalogue parser and the cache, session scan/dismiss/repair, rename,
  defaults, health, the cost guard.
- tests/cli: the CLI in a sandbox with its own HOME, CM_ROOT,
  CLAUDE_CONFIG_DIR and a file-only vault, against fake Ollama, LM Studio,
  keyed-gateway and proxy servers - preflight, presets, models, doctor, a real
  switch, sessions, and the key helper under a rename race.
- tests/windows: the same idea on a Windows host, with USERPROFILE pointed at
  a temp folder so the real install is never touched.

Also: MIT licence, CHANGELOG.md reconstructed from history, .editorconfig and
.gitattributes pinning LF everywhere (what the tree already is), and
scripts/bump-version.sh, since the version lives in two files and drifted
once before.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
smoido
2026-09-15 01:42:38 +03:00
co-authored by Claude Opus 5
parent b5824c6611
commit 51e42823d1
22 changed files with 1437 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
#!/usr/bin/env bash
# The key helper Claude Code runs on a timer in every live session.
. "$(dirname "$0")/../lib.sh"
H="$CM_ROOT/bin/claude-key-helper.sh"
helper() { OUT="$("$H" 2>&1)"; RC=$?; }
set_state anthropic
helper
expect_eq "$RC:$OUT" '0:' 'silent on anthropic'
set_state lmstudio lmstudio
helper
expect_eq "$RC:$OUT" '0:' 'silent for an inline token'
set_state lmstudio nosuch
helper
expect_rc 1 'a missing preset fails'
expect_out 'does not exist' 'and says which'
"$CM" set-key zai sk-test-0123456789abcdef >/dev/null 2>&1
set_state zai zai
helper
expect_eq "$OUT" sk-test-0123456789abcdef 'emits the vault key, and nothing else'
# Renaming the active preset while the helper loops: no fetch may see a gap.
cp "$P/lmstudio.json" "$P/racer.json"
set_state lmstudio racer
(
misses=0
end=$((SECONDS + 4))
while [ "$SECONDS" -lt "$end" ]; do
"$H" >/dev/null 2>"$SB/helper.err" || { grep -q 'does not exist' "$SB/helper.err" && misses=$((misses + 1)); }
done
echo "$misses" > "$SB/misses"
) &
loop=$!
cur=racer
for i in $(seq 1 30); do
"$CM" preset rename "$cur" "racer$i" >/dev/null 2>&1
cur="racer$i"
done
wait "$loop"
expect_eq "$(cat "$SB/misses")" 0 'no key fetch is lost to a rename'
expect_eq "$(jget "$CM_ROOT/state.json" preset)" racer30 'state ends on the last name'
finish