contacts: extract into standalone skill, add himalaya wrapper for all email sends

Refactors the contacts system from being embedded in cal_tool.py into a
standalone contacts skill that serves as the single source of truth for
recipient validation across all outbound email paths.

- New skills/contacts/ skill: list, add, delete, resolve commands
- New skills/himalaya/scripts/himalaya.sh wrapper: validates To/Cc/Bcc
  recipients against contacts for message send, template send, and
  message write commands; passes everything else through unchanged
- cal_tool.py now delegates to contacts.py resolve instead of inline logic
- TOOLS.md updated: agent should use himalaya wrapper, not raw himalaya
This commit is contained in:
Yanxin Lu
2026-03-31 11:12:08 -07:00
parent cd1ee050ed
commit f05a84d8ca
10 changed files with 703 additions and 314 deletions

View File

@@ -6,6 +6,7 @@ End-to-end tests for contacts, send, reply, todo, calendar sync, and local calen
```bash
SKILL_DIR=~/.openclaw/workspace/skills/calendar
CONTACTS_DIR=~/.openclaw/workspace/skills/contacts
# Use a date 3 days from now for test events
TEST_DATE=$(date -d "+3 days" +%Y-%m-%d)
@@ -19,19 +20,19 @@ Set up test contacts needed for send tests.
```bash
# Add a contact with a single email
$SKILL_DIR/scripts/calendar.sh contact add --name "测试用户" --email "mail@luyx.org"
$CONTACTS_DIR/scripts/contacts.sh add --name "测试用户" --email "mail@luyx.org"
# List contacts
$SKILL_DIR/scripts/calendar.sh contact list
$CONTACTS_DIR/scripts/contacts.sh list
# Add a contact with typed email and nickname
$SKILL_DIR/scripts/calendar.sh contact add --name "测试多邮箱" --email "work@example.com" --type work --nickname "多邮箱"
$CONTACTS_DIR/scripts/contacts.sh add --name "测试多邮箱" --email "work@example.com" --type work --nickname "多邮箱"
# Add a second email to the same contact
$SKILL_DIR/scripts/calendar.sh contact add --name "测试多邮箱" --email "home@example.com" --type home
$CONTACTS_DIR/scripts/contacts.sh add --name "测试多邮箱" --email "home@example.com" --type home
# List again — should show both emails
$SKILL_DIR/scripts/calendar.sh contact list
$CONTACTS_DIR/scripts/contacts.sh list
```
**Verify:**
@@ -105,13 +106,13 @@ $SKILL_DIR/scripts/calendar.sh send \
```bash
# Delete the multi-email test contact
$SKILL_DIR/scripts/calendar.sh contact delete --name "测试多邮箱"
$CONTACTS_DIR/scripts/contacts.sh delete --name "测试多邮箱"
# Verify it's gone
$SKILL_DIR/scripts/calendar.sh contact list
$CONTACTS_DIR/scripts/contacts.sh list
# Delete by nickname — should fail (contact already deleted)
$SKILL_DIR/scripts/calendar.sh contact delete --name "多邮箱"
$CONTACTS_DIR/scripts/contacts.sh delete --name "多邮箱"
```
**Verify:**
@@ -621,6 +622,6 @@ todo list
| SMTP rate limit / EOF error | Too many sends too fast. Wait 10+ seconds between sends (Migadu limit) |
| Events disappeared after cleanup | **Never use `rm *.ics`** on calendar dirs. Use `event delete --match` instead |
| Recurring series deleted when cancelling one date | Use `--date YYYY-MM-DD` to add EXDATE, not bare `event delete` (which requires `--all` for recurring) |
| `send` rejects email address | Address not in contacts. Add with `contact add` first (separate from send) |
| `send` rejects email address | Address not in contacts. Add with `contacts.sh add` first (separate from send) |
| `send` says "has multiple emails" | Contact has work+home emails. Use `name:type` syntax (e.g. `小橘子:work`) |
| Contacts dir empty after sync | Check vdirsyncer CardDAV pair is configured for `contacts/default/` |