feat(main): trigger-watcher — file-based input injection for harness scripts - #24
Merged
Conversation
…scripts Drop a JSON trigger file into ~/.switchboard/triggers/<uuid>.json to send a command (e.g. /compact) into any open PTY session. Optional idle-wait polls session._cliBusy (the OSC-title spinner flag) before writing, so the harness can safely call /compact without racing mid-response output. - trigger-watcher.js: watches triggers dir, processes JSON files, writes result to processed/<uuid>.result.json, deletes the trigger on done. - main.js: wires start() after startScheduler with getPtyForSession and isSessionBusy closures over activeSessions. - test/trigger-watcher.test.js: 6 node:test cases (happy path, unknown session, malformed JSON, missing field, idle-wait flip, idle timeout). - .ai/contexts/trigger-watcher.md: context doc. - .ai/contexts/README.md: table entry.
- C1: lstatSync size guard — reject trigger files > 64 KB before readFileSync - C2: lstatSync isFile() — reject symlinks and non-regular files - W1: SyntaxError retry — wait 50 ms and re-read once before failing on partial writes - W2: command length cap — reject commands > 4 KB - W3: control char sanitization — reject \r \n \0 \x1b in command - W4: concurrency cap — queue triggers when > 8 in-flight; simple semaphore via waitQueue - W5: session-exit during wait:idle — check getPtyForSession on each poll tick - W6: tests for C1, C2, W1 retry-then-fail, W2, W3, W4 (12 concurrent), W5, PTY throw, dedup, I4 - I1: atomic result write — write to .tmp then renameSync to final path - I3: wrap trigger-watcher start() in try/catch in main.js boot path - I4: NaN guard on parseInt(SWITCHBOARD_TRIGGER_IDLE_TIMEOUT_MS) — fall back to default
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a file-based trigger mechanism so harness scripts can inject keyboard input into any open Switchboard PTY session without requiring Electron IPC.
trigger-watcher.js— new module (exportsstart(ctx)). Watches~/.switchboard/triggers/for*.jsonfiles, validates shape, optionally waits for the session to go idle, writescommand + '\r'into the PTY, and leaves a result file inprocessed/.main.js— wirestrigger-watcher.start()right afterstartScheduler, passing closures overactiveSessionsto exposegetPtyForSessionandisSessionBusy.test/trigger-watcher.test.js— 6node:testcases: happy path, unknown session, malformed JSON, missing field, idle-wait flip, idle-timeout..ai/contexts/trigger-watcher.md— context doc for future agents.~/.skaleet-ai/conventions/how-to/switchboard-trigger.md— harness-author convention doc (outside repo, not in this PR diff).Contract
Drop a file at
~/.switchboard/triggers/<uuid>.json:{ "sessionId": "abc-123", "command": "/compact", "wait": "idle" }Result appears at
~/.switchboard/triggers/processed/<uuid>.result.json:{ "ok": true, "sessionId": "abc-123", "command": "/compact", "sent_at": "...", "waited_ms": 320 }Bash one-liner
Full
switchboard_sendbash function in~/.skaleet-ai/conventions/how-to/switchboard-trigger.md.Context doc
.ai/contexts/trigger-watcher.md— covers public surface, invariants, non-obvious behaviors (OSC-title busy detection,inFlightdedup), and the change-also checklist.Test plan
task check(lint + tests): 70 pass / 0 fail, 0 new lint errorscommandfield: result ok:falsewait:"idle"— busy flips to idle after 150 ms: write happens,waited_ms >= 100wait:"idle"timeout (200 ms): result ok:false, no PTY write