I have now found a solution to my woes, in the form of SleepWatcher from Bernhardt Baehr, which is licensed under the GNU GPL. To make the magic happen, you download and install both the daemon itself and the StartupItem as described in the included instructions. Read the man page for SleepWatcher so you get a feel for its capabilities.
By default, SleepWatcher runs in daemon mode, and executes /etc/rc.wakeup and /etc/rc.sleep just after your Mac wakes, or just before it sleeps. These scripts look for currently logged-in users and execute scripts called ~/.wakeup and ~/.sleep if they exist. So far so good. Now to add the auto-sleep after my preferred idle time. The StartupItem is stored in /Library -> StartupItems -> SleepWatcher -> SleepWatcher, and this file sets the options for the daemon when that starts:
StartService ()
{
ConsoleMessage "Starting Sleep Watcher"
/usr/local/sbin/sleepwatcher -d -V -s /etc/rc.sleep -w /etc/rc.wakeup
/etc/rc.wakeup
return 0
}
So the simple change is to edit this file (you need your Administrator password) to include the -t (timeout) and -i (idle command) options. Usefully, SleepWatcher can call itself, and it has a 'sleep now' option, -n.
Note that the -t option is given in tenths of a second, so as I like to sleep after 20 minutes, I set this to 12000. My version looks like this (the user/local/sbin... line has been split in two for a narrower display here; enter it as one long line):
StartService ()
{
ConsoleMessage "Starting Sleep Watcher"
/usr/local/sbin/sleepwatcher -d -V -s /etc/rc.sleep -w /etc/rc.wakeup
-t 12000 -i "/usr/local/sbin/sleepwatcher -n"
/etc/rc.wakeup
return 0
}
Other ways of using SleepWatcher could include setting the -f (config file) option to point to a separate location in the StartupItem, then you can add commands to the config file rather than editing the StartupItem to make changes. Or you might arrange to run sleepwatcher commands from your login account to set things up differently for various users. Note that the last logged-in user to set options wins in this case, as there is only one daemon running for the whole system!
[robg adds: SleepWatcher has been covered here before a few times, being put to different uses.]

