runcastle 1.5.6 → 1.5.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/hook-client.ts CHANGED
@@ -8,9 +8,6 @@
8
8
  * consumes as context). Zero dependencies (plain `fetch`), 3s timeout (5s and
9
9
  * retried for `session-start`, see {@link postHook}). On ANY
10
10
  * error it prints `{}` and exits 0 — a hook must never break the user's session.
11
- *
12
- * One argument is not a route event: `wait-messages`, the background message
13
- * waiter of the orchestrator and of a feature's lead (see {@link waitMessages}).
14
11
  */
15
12
 
16
13
  const FETCH_TIMEOUT_MS = 3000
@@ -44,70 +41,11 @@ async function readStdin(): Promise<string> {
44
41
  })
45
42
  }
46
43
 
47
- /** The hook-client argument that runs the orchestrator's message waiter. */
48
- export const WAIT_MESSAGES_MODE = 'wait-messages'
49
-
50
- /** Longer than the server's hold, so a held poll is answered rather than cut off. */
51
- const WAIT_FETCH_TIMEOUT_MS = 40_000
52
- /** The pause after a failed poll (server restarting, network blip) before the next. */
53
- const WAIT_RETRY_MS = 3000
54
-
55
- export interface WaitMessagesDeps {
56
- fetch?: typeof fetch
57
- sleep?: (ms: number) => Promise<void>
58
- waiterId?: string
59
- }
60
-
61
- /**
62
- * `wait-messages` mode (`whole-cuts-plan-themselves` decision 20). Runs as an
63
- * orchestrate session's `asyncRewake` hook: long-polls
64
- * `GET /api/hooks/orchestrator-messages` until the server hands it lines, then
65
- * resolves exit code 2 with them joined by newlines — Claude Code wakes the
66
- * session with that output as one system reminder. `superseded` (a newer waiter
67
- * took over) and `ended` (the session is over) resolve 0 with nothing to say. A
68
- * hold that ran out polls again; a failed poll waits and retries. Never 2
69
- * without lines.
70
- */
71
- export async function waitMessages(
72
- serverUrl: string,
73
- sessionId: string | undefined,
74
- deps: WaitMessagesDeps = {},
75
- ): Promise<{ code: 0 | 2; output: string }> {
76
- if (!sessionId) return { code: 0, output: '' }
77
- const doFetch = deps.fetch ?? fetch
78
- const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)))
79
- const waiter = deps.waiterId ?? crypto.randomUUID()
80
- const url =
81
- `${serverUrl}/api/hooks/orchestrator-messages` +
82
- `?sessionId=${encodeURIComponent(sessionId)}&waiter=${encodeURIComponent(waiter)}`
83
- for (;;) {
84
- let answer: { status?: string; lines?: unknown }
85
- try {
86
- const res = await doFetch(url, { signal: AbortSignal.timeout(WAIT_FETCH_TIMEOUT_MS) })
87
- answer = (await res.json()) as typeof answer
88
- } catch {
89
- await sleep(WAIT_RETRY_MS)
90
- continue
91
- }
92
- if (answer.status === 'superseded' || answer.status === 'ended') return { code: 0, output: '' }
93
- const lines = Array.isArray(answer.lines) ? answer.lines.filter((l) => typeof l === 'string') : []
94
- if (answer.status === 'lines' && lines.length > 0) return { code: 2, output: lines.join('\n') }
95
- // Anything but a hold that ran out answered at once: never spin on it.
96
- if (answer.status !== 'empty') await sleep(WAIT_RETRY_MS)
97
- }
98
- }
99
-
100
44
  export async function main(argv: string[] = process.argv.slice(2)): Promise<void> {
101
45
  const event = argv[0] ?? ''
102
46
  const serverUrl = process.env.RUNCASTLE_SERVER_URL ?? 'http://localhost:4512'
103
47
  const sessionId = process.env.RUNCASTLE_SESSION_ID
104
48
 
105
- if (event === WAIT_MESSAGES_MODE) {
106
- const { code, output } = await waitMessages(serverUrl, sessionId)
107
- if (output) process.stderr.write(output)
108
- process.exit(code)
109
- }
110
-
111
49
  const raw = await readStdin()
112
50
  let payload: unknown
113
51
  try {