feat: race-free on-wake messages and explicit restart CLI

Decouple container restart from config updates — config CLI ops now only
write to the DB; restart is a separate `ncl groups restart` command with
--rebuild and --message flags. Add on_wake column to messages_in so wake
messages are only picked up by a fresh container's first poll, preventing
dying containers from stealing them during the SIGTERM grace window.
killContainer accepts an onExit callback for race-free respawn. Agent-
called restart auto-scopes to the calling session.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
gavrielc
2026-05-09 19:02:15 +03:00
parent 08698da0d2
commit be3a8a97c6
12 changed files with 381 additions and 61 deletions

View File

@@ -49,7 +49,7 @@ function getMaxMessagesPerPrompt(): number {
* sees the prior context it missed. Host's countDueMessages gates waking on
* trigger=1 separately (see src/db/session-db.ts).
*/
export function getPendingMessages(): MessageInRow[] {
export function getPendingMessages(isFirstPoll = false): MessageInRow[] {
const inbound = openInboundDb();
const outbound = getOutboundDb();
@@ -59,10 +59,11 @@ export function getPendingMessages(): MessageInRow[] {
`SELECT * FROM messages_in
WHERE status = 'pending'
AND (process_after IS NULL OR datetime(process_after) <= datetime('now'))
AND (on_wake = 0 OR ?1 = 1)
ORDER BY seq DESC
LIMIT ?`,
LIMIT ?2`,
)
.all(getMaxMessagesPerPrompt()) as MessageInRow[];
.all(isFirstPoll ? 1 : 0, getMaxMessagesPerPrompt()) as MessageInRow[];
if (pending.length === 0) return [];