Commit Graph

8 Commits

Author SHA1 Message Date
a12f2416c4 v0.8.11: API-key default rail (OAuth-impersonation off, secure per-client /set-api-key) + manifest-hashing auto-update speedup
Co-Authored-By: Clover (Claude Opus 4.7) <noreply@anthropic.com>
2026-05-27 22:40:18 -07:00
578cefcc35 v0.8.6: work-box → Mac headers.log sync (tsk-2026-05-27-023)
Closes the last gap in the rate-limit-diagnosis pipeline: anthropic-ratelimit-*
headers captured on the MobaXterm work-box now flow to the Mac memory daemon
(Tier 4 Hindsight + Tier 7 mem0) automatically.

- lib/headers-sync.sh: incremental, offset-tracked, idempotent push of
  headers.log to ~/.cloverleaf/headers-<hostname>.jsonl on the Mac, riding the
  existing authenticated SSH ControlMaster. No new auth; password never in
  argv/env. No-op when nothing new; re-seed on local rotation/shrink. Fully
  graceful (no target / closed master / transport error → warn + continue;
  never crashes the session).
- /headers-sync on|off|status|target <alias>|now slash command + TAB-completion
  + /help. Config persisted to $LARRY_HOME/.env. Auto-sync fires on REPL exit.
- Security: headers.log carries only anthropic-* headers + status lines — NO
  PHI per Vera audit V7; transport reused unchanged (not weakened).

Layered cleanly on top of Clover #8's v0.8.5 (4f1ea86) — edits isolated to new
lib + help/array/trap/dispatch hunks; no overlap with the streaming parser,
retry/backoff, error-display, or phi-notice regions.

Co-Authored-By: Clover (Claude Opus 4.7) <noreply@anthropic.com>
2026-05-27 21:01:54 -07:00
31ffae6f36 v0.8.4: installer/updater detects HTML-sign-in-page responses and fails loud
Hardens the installer + auto-updater against the Gitea private-repo trap
(Clover #5 diagnosis): an unauthenticated raw-file read of a sign-in-gated
Gitea returns the HTML Sign-In page at HTTP 200, which `curl -fsSL` treats as
success — so the old code parsed HTML as VERSION/MANIFEST/larry.sh content and
silently aborted (or overwrote real files with HTML). This stranded a work-box
at v0.7.3 until the REQUIRE_SIGNIN_VIEW=false flip.

- New lib/fetch-safe.sh: fetch_validate URL DEST KIND [MAX_TIME]. Detects the
  HTML-login trap (DOCTYPE/<html/"Sign In - Gitea"/<title>Sign In markers, or
  text/html Content-Type) and validates content shape per file type (semver
  VERSION, path-list MANIFEST, shebang larry.sh, non-HTML .sh). On failure:
  actionable error + non-zero, target file left untouched.
- install-larry.sh (curl|bash bootstrap) and larry.sh self_update() each carry
  a byte-identical inline copy (both run before lib/ can be sourced).
- Every remote-content fetch routed through the validator: install fetch();
  agent fetch; sync_from_manifest MANIFEST + per-file; _fetch_with_fallback.
- Optional LARRY_GITEA_TOKEN / GITEA_TOKEN env var adds Authorization: token
  <PAT> for authenticated fetch against private repos. Never hardcoded/logged.
  Documented in --help + MANUAL.md.

Co-Authored-By: Clover (Claude Opus 4.7) <noreply@anthropic.com>
2026-05-27 20:28:58 -07:00
60b8f0e1c8 v0.8.2: Presidio sidecar for free-text NER (tier-5) — closes V1
The only path that closes V1 (free-text PHI gap — the dominant real-world
failure mode per Vera). Opt-in install; larry runs in v0.8.1 mode on hosts
without Presidio (MobaXterm/Cygwin per Bryan's accepted tradeoff).

New files:
- lib/phi-presidio-sidecar.py — FastAPI service on 127.0.0.1:$LARRY_PHI_PORT
  (default 41189). Presidio AnalyzerEngine + AnonymizerEngine over spaCy
  en_core_web_sm + 3 HL7-specific custom recognizers (HL7_MRN, HL7_CARET_NAME,
  HL7_PHONE_BARE). POST /redact and GET /health.
- lib/phi-sidecar.sh — lifecycle (start/stop/status/health/ensure). ensure
  is idempotent; called backgrounded from main_loop so it never blocks the
  first prompt. Honors LARRY_PHI_VENV.
- lib/phi-client.sh — bash client (phi_client_available / phi_redact_text /
  phi_redact_entities). CR-safe; 5s timeout bounds tier-5 stall.

larry.sh:
- auto_detect_phi gains tier-5: after tiers 1-4, before status summary,
  source phi-client.sh, run Presidio on a token-masked copy of the input,
  tokenize each entity through hl7-sanitize.sh tokenize-value (category
  presidio_<TYPE>) so token IDs stay stable. Honors confirm + strict modes.
  Removed the v0.7.3 early-return that skipped past tier-5 when tiers 1-4
  found nothing — pure prose now always reaches tier-5.
- Token-safe substitution: existing [[...]] tokens are pulled to sentinels,
  tier-5 value is replaced, sentinels restored — prevents the token-within-
  token corruption that naive literal-replace caused on already-tokenized
  text. Acronym guard drops HL7/clinical jargon (SSN/MRN/DOB/ADT) Presidio
  over-tags as ORGANIZATION.
- Graceful degradation: sidecar unreachable → tier-5 no-ops with a one-time
  stderr warning. /phi-sidecar slash command + completion table.

install-larry.sh:
- Probes python3 3.9+; offers to create $LARRY_HOME/phi-venv and install
  presidio + fastapi + uvicorn + en_core_web_sm. Skips silently (with a
  v0.8.1-mode note) on Cygwin/MobaXterm without python3, and on
  non-interactive pipe installs. Sets LARRY_PHI_VENV in the larry shim.

MANIFEST: three new lib files added for auto-sync.

Prototype validation (Bryan's Mac, Apple Silicon, Python 3.14):
  cold start (en_core_web_sm): ~9s   (vs ~82s if Presidio auto-grabs _lg;
                                       we pin _sm for the REPL budget)
  warm analyzer latency:       P50 20.6ms / P95 22.7ms
  end-to-end HTTP round-trip:  ~57ms warm; ~150ms first-post-startup
All comfortably under the 200ms-per-turn budget.

MobaXterm verdict: v0.8.2 is Mac/Linux-only. MobaXterm stays on v0.8.1 +
nudges, per Bryan's explicit acceptance. install-larry.sh enforces this
by platform detection; larry.sh tier-5 silently no-ops when the sidecar
is absent (which IS the MobaXterm path — no code is platform-gated).

Verification: bash -n clean on larry.sh + all 3 new lib scripts; python3
ast.parse clean on the sidecar; end-to-end tier-5 tested live against the
sidecar (pure prose, rule-pack+tier-5 combined with no token corruption,
!nophi bypass); strict-mode fail-closed abort tested; CR-taint, path-block,
and base64 round-trip batteries re-run green.

Co-Authored-By: Clover (Claude Opus 4.7) <noreply@anthropic.com>
2026-05-27 20:00:23 -07:00
9dd5821436 v0.7.5: OAuth CR-taint fix + mouse opt-in + CR-safety sweep
- Fix bash arithmetic crash on MobaXterm/Cygwin: $(date +%s) was
  returning CR-tainted values landing in $(( )) operands
- Mouse mode off by default; opt in via LARRY_MOUSE=1 or /mouse on
- Comprehensive CR-safety sweep across lib/*.sh and larry.sh — every
  command-substitution result, file read, and user input that feeds
  an arithmetic context, case dispatcher, or path/header is now
  CR-stripped at the source

New shared helper lib/cygwin-safe.sh defines three primitives:
  coerce_int VAL [DEFAULT]   — for arithmetic / integer-test operands
  strip_cr VAL               — for case patterns, regex tests, paths, headers
  read_clean VAR [PROMPT]    — read -r wrapper that strips CR pre-assign

Hardened call sites (14 files, 60+ patch points):
  - larry.sh:  status-line date/tput, 3 y/N approvals, auth menu, API key
  - lib/oauth.sh:  cmd_login + cmd_refresh date+%s captures
  - lib/nc-engine.sh:  5 y/N action prompts + find|wc arithmetic
  - lib/nc-msgs.sh:  parse_time_ms (4 date sites) + meta-TSV time + MSG_COUNT
  - lib/nc-regression.sh:  tr|wc count + hl7-diff ?-fallback arithmetic
  - lib/nc-smat-diff.sh:  A_COUNT/B_COUNT/DIFFS_TOTAL
  - lib/nc-insert-protocol.sh:  every awk-emitted line number → head/tail math
  - lib/journal.sh:  _next_seq wc -l arithmetic
  - lib/lessons.sh:  _next_id/_count + 2 y/N prompts
  - lib/hl7-sanitize.sh:  cmd_count + clear-table y/N
  - lib/ssh-helper.sh:  4 local+remote wc -c integer compares
  - lib/nc-find.sh, lib/nc-table.sh, lib/nc-document.sh, larry-rollback.sh

Reproduces the exact error Bryan hit:
  bash: ...: arithmetic syntax error: invalid arithmetic operator (error token is "")

lib/cygwin-safe.sh added to MANIFEST so it auto-syncs on next launch.

Co-Authored-By: Clover (Claude Opus 4.7) <noreply@anthropic.com>
2026-05-27 19:17:48 -07:00
8661948cf6 v0.7.0: HL7-aware tab completion + REPL mouse mode
Two REPL enhancements:

1. HL7 v2.x inline tab completion. Type a segment ID or SEG.field or
   SEG.field.component in any prompt and TAB completes against a built-in
   schema (18 segments fully fielded: MSH, PID, PV1, PV2, EVN, MSA, ERR,
   NK1, GT1, IN1, IN2, OBR, OBX, ORC, AL1, DG1, PR1, ROL; component
   breakdowns for MSH.9, PID.3, PID.5, PID.11, PV1.3, NK1.4, OBX.3, IN1.4).
   New slash commands /hl7 <SEG> and /hl7-fields <SEG.N> print schema
   without typing. Z-segments get a "site-specific" hint instead of a
   guess. Exact-match wins over prefix siblings (PID.3 completes over
   PID.30; MSH completes over MSH+MSA).

2. Mouse mode. /mouse on|off and LARRY_NO_MOUSE env kill switch enable
   bracketed-paste + SGR mouse reporting (mode 1006). Click-to-position
   cursor in the input line is intentionally NOT implemented in this
   pass — it requires per-terminal escape parsing inside bind -x which
   is not reliable across iTerm2 / macOS Terminal / MobaXterm / Cygwin
   in a single pass. Documented as terminal-dependent.

New file: lib/hl7-schema.sh (sourced; bash assoc arrays for the segment
+field+component tables, plus helpers hl7_segments / hl7_fields_for /
hl7_components_for / hl7_field_name).

MANIFEST + install-larry.sh updated to fetch the new lib file on
install/self-update.

Regression-safe: v0.6.9 status line, slash completion, @file completion,
streaming SSE, header capture, and all 37 prior slash commands are
unchanged. Added 3 new slash commands (/hl7, /hl7-fields, /mouse).

Verification: 15/15 automated checks on the three completion paths
(segment, field, component) — including mid-buffer completion and
exact-match preference.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 16:15:11 -07:00
f58bcf711f v0.6.0: secure SSH ControlMaster — password hidden from Larry-the-LLM
NEW lib/ssh-helper.sh implements the full SSH command surface:
  hosts/list                              show configured remote hosts
  add <alias> <user@host[:port]>          register a new host
  remove <alias>                          remove + clean cred + socket
  pass <alias>                            set/update password (hidden interactive)
  setup <alias>                           open long-lived ControlMaster
  close <alias>                           close ControlMaster
  status [alias]                          show open masters + cred presence
  exec <alias> <command...>               run command via master

Architecture:
  • $LARRY_HOME/.ssh-hosts.tsv      — alias \t user@host \t port (3-col)
  • $LARRY_HOME/.ssh-creds/<alias>  — raw password, mode 0600
  • $LARRY_HOME/.ssh-sockets/<alias>.sock — ControlMaster socket

The password is read from disk by sshpass via -f (file argument), so it
never lands in argv or environment. It is used ONCE to open the master;
all subsequent execs multiplex through the socket with no auth. Daily-
rotating passwords: just overwrite the cred file and re-run setup.

SLASH COMMANDS wired in larry.sh REPL: /ssh-hosts /ssh-add /ssh-remove
/ssh-pass /ssh-setup /ssh-close /ssh-status /ssh <alias> <cmd>.

LARRY TOOLS exposed to the LLM:
  ssh_status      — list aliases + open-master state
  ssh_exec        — run command on remote via the master socket
Both tool descriptions explicitly tell Larry the password is unreachable
and to ask Bryan to run /ssh-setup if a master is closed. Tool inputs
and outputs never contain the password. Output capped at max_lines
(default 500) with a "[ssh_exec: exit rc=N]" footer.

Bundle updated: MANIFEST + install-larry.sh both now include
lib/ssh-helper.sh. Auto-update will pull it on next launch.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 10:28:37 -07:00
28622ca40b v0.5.0: MANIFEST-driven self-update + OAuth code#state parsing
Self-update overhaul (no more manual reinstalls when lib/ changes):
- New MANIFEST file at repo root lists every file that should auto-sync
  (top-level scripts, agents/, lib/, VERSION, MANUAL.md).
- larry.sh self_update() reworked into two phases:
    Phase A — local sync: if $LARRY_HOME/.last-sync-version != $LARRY_VERSION,
      fetch MANIFEST and refresh every listed file. Stamps version after.
    Phase B — remote check: fetch $LARRY_BASE_URL/VERSION; if newer, pull
      larry.sh, self-replace, relaunch with LARRY_JUST_UPDATED=1 so phase B
      is skipped on the relaunch (phase A then pulls everything else).
- New LARRY_BASE_URL env var (the legacy LARRY_UPDATE_URL / LARRY_AGENTS_URL
  still work as overrides).
- Bumped LARRY_VERSION and VERSION to 0.5.0.

OAuth fix (lib/oauth.sh):
- Anthropic's callback returns the code as 'CODE#STATE' (URL fragment, not
  query). Previous prompt told users to copy "between code= and the next &"
  which produced the wrong substring; the token endpoint then returned a
  misleading 'rate_limit_error' on the malformed code.
- Now splits the pasted input on '#', verifies the returned state matches
  the one we generated, sends only CODE to the token endpoint.
- Updated user-facing prompt and error hints to describe the real format
  and explain the misleading rate_limit_error symptom.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 08:50:46 -07:00