@chorus-aidlc/chorus-openclaw-plugin 0.10.0 → 0.11.1

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.
Files changed (62) hide show
  1. package/dist/connection-state.d.ts +35 -0
  2. package/dist/connection-state.d.ts.map +1 -0
  3. package/dist/connection-state.js +52 -0
  4. package/dist/connection-state.js.map +1 -0
  5. package/dist/control-handler.d.ts +73 -0
  6. package/dist/control-handler.d.ts.map +1 -0
  7. package/dist/control-handler.js +135 -0
  8. package/dist/control-handler.js.map +1 -0
  9. package/dist/daemon-client.d.ts +203 -0
  10. package/dist/daemon-client.d.ts.map +1 -0
  11. package/dist/daemon-client.js +469 -0
  12. package/dist/daemon-client.js.map +1 -0
  13. package/dist/daemon-rest-client.d.ts +86 -0
  14. package/dist/daemon-rest-client.d.ts.map +1 -0
  15. package/dist/daemon-rest-client.js +196 -0
  16. package/dist/daemon-rest-client.js.map +1 -0
  17. package/dist/event-router.d.ts +31 -6
  18. package/dist/event-router.d.ts.map +1 -1
  19. package/dist/event-router.js +58 -27
  20. package/dist/event-router.js.map +1 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +106 -7
  23. package/dist/index.js.map +1 -1
  24. package/dist/lineage.d.ts +44 -0
  25. package/dist/lineage.d.ts.map +1 -0
  26. package/dist/lineage.js +116 -0
  27. package/dist/lineage.js.map +1 -0
  28. package/dist/mcp-registration.d.ts.map +1 -1
  29. package/dist/mcp-registration.js +5 -4
  30. package/dist/mcp-registration.js.map +1 -1
  31. package/dist/sse-listener.d.ts +34 -0
  32. package/dist/sse-listener.d.ts.map +1 -1
  33. package/dist/sse-listener.js +78 -4
  34. package/dist/sse-listener.js.map +1 -1
  35. package/dist/wake.d.ts +20 -0
  36. package/dist/wake.d.ts.map +1 -1
  37. package/dist/wake.js +56 -0
  38. package/dist/wake.js.map +1 -1
  39. package/package.json +1 -1
  40. package/skills/brainstorm/SKILL.md +1 -1
  41. package/skills/chorus/SKILL.md +39 -8
  42. package/skills/code-reviewer/SKILL.md +127 -0
  43. package/skills/develop/SKILL.md +3 -1
  44. package/skills/idea/SKILL.md +1 -1
  45. package/skills/openspec-aware/SKILL.md +1 -1
  46. package/skills/proposal/SKILL.md +1 -1
  47. package/skills/proposal-reviewer/SKILL.md +1 -1
  48. package/skills/quick-dev/SKILL.md +1 -1
  49. package/skills/review/SKILL.md +5 -5
  50. package/skills/task-reviewer/SKILL.md +1 -1
  51. package/skills/yolo/SKILL.md +26 -1
  52. package/src/connection-state.ts +66 -0
  53. package/src/control-handler.ts +219 -0
  54. package/src/daemon-client.ts +622 -0
  55. package/src/daemon-rest-client.ts +312 -0
  56. package/src/event-router.ts +103 -33
  57. package/src/index.ts +113 -8
  58. package/src/lineage.ts +157 -0
  59. package/src/mcp-registration.ts +6 -19
  60. package/src/openclaw-sdk.d.ts +232 -1
  61. package/src/sse-listener.ts +117 -5
  62. package/src/wake.ts +69 -26
@@ -0,0 +1,469 @@
1
+ // packages/openclaw-plugin/src/daemon-client.ts
2
+ // The OpenClaw in-process host's bidirectional daemon behavior — the in-process
3
+ // analog of the chorus CLI host (cli/waker.mjs + cli/daemon.mjs), re-mapped from a
4
+ // spawned `claude` subprocess to a single `runtime.agent.runEmbeddedAgent(...)` call.
5
+ //
6
+ // Re-mapping table (verified against ../openclaw, 2026-06-20):
7
+ // | Concern | CLI host | this client |
8
+ // | run an agent | spawn `claude` subprocess | runEmbeddedAgent(params) in-process |
9
+ // | observe messages | parse stream-json lines | onAssistantMessageStart/onBlockReply |
10
+ // | | | /onToolResult callbacks (params.ts) |
11
+ // | mid-run interrupt | SIGINT→SIGKILL the proc group | AbortController.abort() → abortSignal |
12
+ // | crash vs user-abort | non-zero exit code | promise rejects / result.meta.aborted|
13
+ // | resume same session | `claude --resume <directIdea>` | sessionKey from business key → |
14
+ // | | | getSessionEntry resolves sessionId |
15
+ // The server-facing payloads are IDENTICAL across hosts (that is why they live in the
16
+ // shared daemon-rest-client). This module owns only the host-side concerns: the
17
+ // run wrapper, the abort/execution registries, the transcript content filter, the
18
+ // session mapping, and the at-most-once turn dispatch.
19
+ //
20
+ // VERIFIED runEmbeddedAgent surface (../openclaw):
21
+ // - abortSignal?: AbortSignal params.ts:167
22
+ // - onAssistantMessageStart?: () => void|Promise<void> params.ts:190 (ZERO-arg)
23
+ // - onBlockReply?: (BlockReplyPayload{text?,isReasoning?}) params.ts:191 / payloads.ts:1-11
24
+ // - onToolResult?: (ReplyPayload) params.ts:201 (tool internals — NOT transcript)
25
+ // - onReasoningStream?: (...) params.ts:195 (thinking — NOT transcript)
26
+ // - result.meta.aborted?: boolean types.ts:140 (user-abort marker)
27
+ // - getSessionEntry({sessionKey,agentId}) → SessionEntry? store.ts:210
28
+ // - resolveSessionFilePath(sessionId, entry?, opts?) paths.ts:267
29
+ const NOOP_LOGGER = { info() { }, warn() { }, error() { } };
30
+ /** Resource kinds the server's DaemonExecution accepts (mirrors waker.mjs). */
31
+ const EXECUTION_ENTITY_TYPES = new Set(["task", "idea", "proposal", "document", "daemon_session"]);
32
+ /**
33
+ * Extract finalized assistant VISIBLE text from an `onBlockReply` payload, or null to
34
+ * skip. Mirrors the CLI host's stream-json filter (upload-hooks.mjs
35
+ * `extractTranscriptText`): keep only finalized assistant text; DROP reasoning/thinking
36
+ * (`isReasoning`) — verified the flag exists at ../openclaw/src/agents/
37
+ * embedded-agent-payloads.ts:7 and is set true for reasoning blocks
38
+ * (embedded-agent-subscribe.handlers.messages.ts:915). Tool internals never reach here
39
+ * (they arrive on `onToolResult`, which the client does not post). Never throws.
40
+ */
41
+ export function extractBlockReplyText(payload) {
42
+ if (!payload || typeof payload !== "object")
43
+ return null;
44
+ // Reasoning/thinking blocks are internal — not user-visible transcript.
45
+ if (payload.isReasoning)
46
+ return null;
47
+ const text = typeof payload.text === "string" ? payload.text : "";
48
+ if (!text.trim())
49
+ return null;
50
+ return { role: "assistant", text };
51
+ }
52
+ /**
53
+ * The OpenClaw in-process daemon client. One instance per plugin process; the entry
54
+ * injects the shared REST client + the host run-context resolver + the re-dispatch
55
+ * hook, and wires this client's `controlHooks` into the control handler.
56
+ */
57
+ export class OpenClawDaemonClient {
58
+ restClient;
59
+ resolveRunContext;
60
+ redispatch;
61
+ buildTurnPrompt;
62
+ logger;
63
+ /** AbortController per in-flight run, keyed `entityType:entityUuid`. */
64
+ aborts = new Map();
65
+ /** Execution snapshot source — one entry per running/queued resource. */
66
+ executions = new Map();
67
+ /**
68
+ * At-most-once turn dedup, keyed `turn:<uuid>`. Shared by the live deliver_turn
69
+ * path and the reconnect backfill so a turn observed by either runs at most once
70
+ * (mirrors the CLI host's `seen` set; backfill.mjs).
71
+ */
72
+ seenTurns = new Set();
73
+ runCounter = 0;
74
+ constructor(opts) {
75
+ this.restClient = opts.restClient;
76
+ this.resolveRunContext = opts.resolveRunContext;
77
+ this.redispatch = opts.redispatch;
78
+ this.buildTurnPrompt = opts.buildTurnPrompt;
79
+ this.logger = opts.logger ?? NOOP_LOGGER;
80
+ }
81
+ // ---------------------------------------------------------------------------
82
+ // Control hooks — wired into the T3 control handler (ControlBehaviorHooks).
83
+ // ---------------------------------------------------------------------------
84
+ /**
85
+ * The behavior hooks the control handler routes verified commands to. The handler
86
+ * owns the double-check (own connection + held entity); these implement the actual
87
+ * abort / re-dispatch / pending-turns-sweep.
88
+ */
89
+ get controlHooks() {
90
+ return {
91
+ isEntityRunning: (entityType, entityUuid) => this.aborts.has(execKey(entityType, entityUuid)),
92
+ onInterrupt: (entityType, entityUuid) => this.interrupt(entityType, entityUuid),
93
+ onResume: (entityType, entityUuid) => this.resume(entityType, entityUuid),
94
+ onDeliverTurn: (turnUuid) => {
95
+ // Fire-and-forget: the control handler is synchronous; the sweep is async.
96
+ void this.deliverTurn(turnUuid);
97
+ },
98
+ };
99
+ }
100
+ /**
101
+ * Abort the matching in-flight run (true mid-run stop via abortSignal) and mark it
102
+ * `interrupting` so the run's settle path reports reason=user (not crash). No-op when
103
+ * no run is registered (the handler's Check 2 already gates this, but we re-check so a
104
+ * direct caller is safe). Never throws.
105
+ */
106
+ interrupt(entityType, entityUuid) {
107
+ const key = execKey(entityType, entityUuid);
108
+ const entry = this.aborts.get(key);
109
+ if (!entry) {
110
+ this.logger.info(`[Chorus] interrupt: no in-flight run for ${key}; ignoring`);
111
+ return;
112
+ }
113
+ entry.interrupting = true;
114
+ try {
115
+ entry.controller.abort();
116
+ this.logger.info(`[Chorus] interrupt: aborted in-flight run for ${key}`);
117
+ }
118
+ catch (err) {
119
+ this.logger.warn(`[Chorus] interrupt: abort() failed for ${key}: ${err}`);
120
+ }
121
+ }
122
+ /**
123
+ * Re-dispatch a wake for the entity to continue the SAME session (the run is gone;
124
+ * resolveRunContext re-derives the same sessionKey → getSessionEntry resolves the
125
+ * existing sessionId). The control handler has no prompt; we synthesize a minimal
126
+ * resume prompt. Continues under the same business key (directIdea/entity).
127
+ */
128
+ resume(entityType, entityUuid) {
129
+ this.logger.info(`[Chorus] resume: re-dispatching wake for ${entityType}:${entityUuid}`);
130
+ this.redispatch({
131
+ prompt: `[Chorus] Your previous run for this ${entityType} was interrupted by a human and is now being resumed. ` +
132
+ `Continue where you left off (entityType: ${entityType}, entityUuid: ${entityUuid}).`,
133
+ contextKey: `chorus:resume:${entityUuid}`,
134
+ entityType,
135
+ entityUuid,
136
+ });
137
+ }
138
+ /**
139
+ * Read connection-scoped pending turns and run the unstarted human_instruction turn.
140
+ * With a `turnUuid` run PRECISELY that one (live deliver_turn); without one sweep all
141
+ * (reconnect backfill). Idempotent via the shared `seenTurns` set keyed `turn:<uuid>`.
142
+ * Never throws into the caller. Mirrors backfill.mjs `backfillPendingTurns`.
143
+ */
144
+ async deliverTurn(onlyTurnUuid) {
145
+ const result = await this.restClient.readPendingTurns();
146
+ if (!result.ok || !result.data) {
147
+ // Nothing to read yet (skipped) or a logged failure — nothing to dispatch.
148
+ return;
149
+ }
150
+ let dispatched = 0;
151
+ for (const turn of result.data.turns) {
152
+ if (!turn || typeof turn.turnUuid !== "string")
153
+ continue;
154
+ // Single-turn precision: when a uuid was announced, run ONLY it.
155
+ if (onlyTurnUuid && turn.turnUuid !== onlyTurnUuid)
156
+ continue;
157
+ const seenKey = `turn:${turn.turnUuid}`;
158
+ if (this.seenTurns.has(seenKey))
159
+ continue;
160
+ this.seenTurns.add(seenKey);
161
+ dispatched++;
162
+ // Reconstruct the execution entity DIRECTLY from the turn's own ids (mirrors
163
+ // cli/event-router.mjs dispatchPendingTurn): an idea-anchored conversation
164
+ // reports against the real idea (`idea:<directIdeaUuid>`), an ad-hoc conversation
165
+ // against itself (`daemon_session:<sessionId>`). entityType MUST be set — without
166
+ // it entityOf() returns null, so the run reports no execution row (invisible in
167
+ // the UI) and registers no AbortController (uninterruptible). entityUuid aligns
168
+ // with the session business key so the report anchor, the OpenClaw session, and
169
+ // the per-session UI match key are all the same value.
170
+ const directIdeaUuid = typeof turn.directIdeaUuid === "string" ? turn.directIdeaUuid : null;
171
+ this.redispatch({
172
+ prompt: this.buildTurnPrompt(turn),
173
+ contextKey: `chorus:deliver_turn:${turn.turnUuid}`,
174
+ entityType: directIdeaUuid ? "idea" : "daemon_session",
175
+ entityUuid: directIdeaUuid ?? turn.sessionId,
176
+ directIdeaUuid,
177
+ turnUuid: turn.turnUuid,
178
+ });
179
+ }
180
+ if (dispatched > 0) {
181
+ const scope = onlyTurnUuid ? `turn ${onlyTurnUuid}` : `${dispatched} pending turn(s)`;
182
+ this.logger.info(`[Chorus] deliver: re-derived ${scope} from the turn table`);
183
+ }
184
+ }
185
+ /** Reconnect backfill: full connection-scoped pending-turns sweep (no single-turn filter). */
186
+ async onReconnect() {
187
+ await this.deliverTurn();
188
+ }
189
+ // ---------------------------------------------------------------------------
190
+ // The wake run wrapper.
191
+ // ---------------------------------------------------------------------------
192
+ /**
193
+ * Run one wake via runEmbeddedAgent with full daemon reporting. Never throws — a
194
+ * wake failure is logged + reported (crash), never propagated (the SSE service must
195
+ * stay alive). Fire-and-forget from the caller's perspective; returns a promise the
196
+ * tests can await.
197
+ *
198
+ * Lifecycle (mirrors waker.mjs):
199
+ * 1. resolve run context (drop on null);
200
+ * 2. derive sessionKey from the business key → getSessionEntry → sessionId/sessionFile;
201
+ * 3. register the AbortController + mark the execution running → turnAdvance(running)
202
+ * + execution-state snapshot;
203
+ * 4. run with transcript callbacks (onBlockReply → post {role:"assistant", text});
204
+ * 5. on settle → turnAdvance(ended) + snapshot; classify interrupt(user) vs crash;
205
+ * 6. finally → deregister the controller + drop the execution row + snapshot.
206
+ */
207
+ async runWake(req) {
208
+ const { prompt, contextKey } = req;
209
+ const entity = entityOf(req);
210
+ const key = entity ? execKey(entity.entityType, entity.entityUuid) : null;
211
+ const rootIdeaUuid = req.rootIdeaUuid ?? null;
212
+ // Session anchor = the business key: directIdeaUuid when present, else the entity
213
+ // uuid (quick task / standalone doc / ad-hoc daemon_session). This is the `sessionId`
214
+ // used in ALL reports (turn-advance/transcript) — NOT the OpenClaw sessionKey, which
215
+ // is the agent's queue key. Two distinct identifiers (see deriveSessionId / sessionKey).
216
+ const reportSessionId = deriveSessionId(req);
217
+ if (!reportSessionId) {
218
+ this.logger.warn(`[Chorus] Wake DROPPED — no session id (no directIdea/entity) for contextKey=${contextKey}`);
219
+ return;
220
+ }
221
+ let ctx;
222
+ try {
223
+ ctx = this.resolveRunContext();
224
+ }
225
+ catch (err) {
226
+ this.logger.warn(`[Chorus] Wake DROPPED — run-context resolution failed (${contextKey}): ${err}`);
227
+ return;
228
+ }
229
+ if (!ctx) {
230
+ this.logger.warn(`[Chorus] Wake DROPPED — no resolvable session/agent runtime on this host (${contextKey}).`);
231
+ return;
232
+ }
233
+ // Resolve the EXISTING session for the business key so the wake continues the same
234
+ // conversation (resume / deliver_turn re-enter it). The OpenClaw sessionKey is
235
+ // derived deterministically from the business key, so a later resume re-derives the
236
+ // same key and getSessionEntry returns the same sessionId/sessionFile.
237
+ const sessionKey = deriveSessionKey(reportSessionId, ctx.sessionKey);
238
+ let sessionId;
239
+ let sessionFile;
240
+ try {
241
+ const sessionEntry = ctx.agent.session.getSessionEntry({ sessionKey, agentId: ctx.agentId });
242
+ // No existing OpenClaw session for this key (the FIRST wake on the business key):
243
+ // open a NEW session whose id is the business key itself. The business key
244
+ // (directIdeaUuid / entityUuid / ad-hoc sessionId) is always a uuid, which
245
+ // satisfies OpenClaw's SAFE_SESSION_ID_RE (`^[a-z0-9][a-z0-9._-]{0,127}$`).
246
+ // The run id (`nextRunId`) is NOT a valid session id — it embeds the colon-laden
247
+ // contextKey, which `resolveSessionFilePath` rejects with "Invalid session ID" —
248
+ // so it must never be used as the session id. Reusing the business key here also
249
+ // keeps continuity: a later resume re-derives the SAME sessionKey, and once this
250
+ // first run has persisted the session, getSessionEntry returns this same id.
251
+ sessionId = sessionEntry?.sessionId ?? reportSessionId;
252
+ sessionFile = ctx.agent.session.resolveSessionFilePath(sessionId, sessionEntry?.sessionFile ? { sessionFile: sessionEntry.sessionFile } : undefined, { agentId: ctx.agentId });
253
+ }
254
+ catch (err) {
255
+ this.logger.warn(`[Chorus] Wake DROPPED — session resolution failed (${contextKey}): ${err}`);
256
+ return;
257
+ }
258
+ const controller = new AbortController();
259
+ const abortEntry = { controller, interrupting: false };
260
+ if (key)
261
+ this.aborts.set(key, abortEntry);
262
+ // Mark RUNNING + report turn-advance(running) + execution snapshot.
263
+ if (entity && key) {
264
+ this.executions.set(key, {
265
+ entityType: entity.entityType,
266
+ entityUuid: entity.entityUuid,
267
+ rootIdeaUuid,
268
+ status: "running",
269
+ startedAt: new Date().toISOString(),
270
+ });
271
+ this.emitExecutionSnapshot();
272
+ }
273
+ let advancedToRunning = false;
274
+ await this.advanceTurn(reportSessionId, "running", entity);
275
+ advancedToRunning = true;
276
+ const runId = this.nextRunId(contextKey);
277
+ this.logger.info(`[Chorus] Waking agent via embedded run (sessionKey=${sessionKey}, sessionId=${reportSessionId}, ` +
278
+ `model=${ctx.modelRef ? `${ctx.modelRef.provider}/${ctx.modelRef.model}` : "host-default"}, contextKey=${contextKey})`);
279
+ let aborted = false;
280
+ let crashed = false;
281
+ try {
282
+ const result = await ctx.agent.runEmbeddedAgent({
283
+ sessionId,
284
+ sessionKey,
285
+ agentId: ctx.agentId,
286
+ trigger: "manual",
287
+ sessionFile,
288
+ ...(ctx.agentDir ? { agentDir: ctx.agentDir } : {}),
289
+ workspaceDir: ctx.workspaceDir,
290
+ config: ctx.config,
291
+ prompt,
292
+ timeoutMs: ctx.timeoutMs,
293
+ runId,
294
+ disableMessageTool: true,
295
+ abortSignal: controller.signal,
296
+ // Streaming transcript: post ONLY finalized assistant visible text. Reasoning
297
+ // (onReasoningStream / isReasoning blocks) and tool internals (onToolResult) are
298
+ // intentionally NOT posted (match the CLI host's stream-json filter).
299
+ onBlockReply: (payload) => {
300
+ const msg = extractBlockReplyText(payload);
301
+ if (msg)
302
+ void this.postTranscript(reportSessionId, [msg]);
303
+ },
304
+ ...(ctx.modelRef ? { provider: ctx.modelRef.provider, model: ctx.modelRef.model } : {}),
305
+ });
306
+ // result.meta.aborted distinguishes a clean abort from a normal completion
307
+ // (types.ts:140). An abort flagged here OR an interrupt requested → user-abort.
308
+ aborted = result?.meta?.aborted === true || abortEntry.interrupting;
309
+ }
310
+ catch (err) {
311
+ // The run rejected. If an interrupt was requested, it's a user abort; otherwise
312
+ // it's an unexpected crash.
313
+ if (abortEntry.interrupting || controller.signal.aborted) {
314
+ aborted = true;
315
+ }
316
+ else {
317
+ crashed = true;
318
+ }
319
+ this.logger.warn(`[Chorus] Wake turn ${crashed ? "crashed" : "aborted"} (sessionId=${reportSessionId}, ${contextKey}): ` +
320
+ `${err instanceof Error ? err.message : String(err)}`);
321
+ }
322
+ finally {
323
+ // Deregister FIRST so a stale controller can never abort a later run for the
324
+ // same entity (spec: "A settled run deregisters its controller").
325
+ if (key)
326
+ this.aborts.delete(key);
327
+ }
328
+ // Turn lifecycle: advance running→ended regardless of outcome (a turn ends whether
329
+ // clean, aborted, or crashed). Guarded on advancedToRunning so a never-started wake
330
+ // never attempts an illegal pending→ended transition.
331
+ if (advancedToRunning) {
332
+ await this.advanceTurn(reportSessionId, "ended", entity);
333
+ }
334
+ // Interrupt-vs-crash reporting (entity-keyed — only for a reportable resource).
335
+ if (entity) {
336
+ if (aborted) {
337
+ await this.report(entity, "user");
338
+ }
339
+ else if (crashed) {
340
+ await this.report(entity, "crash");
341
+ }
342
+ // A clean completion reports nothing (mirrors waker.mjs).
343
+ }
344
+ // Drop the execution row + emit a fresh snapshot (absence == ended server-side).
345
+ if (key && this.executions.delete(key)) {
346
+ this.emitExecutionSnapshot();
347
+ }
348
+ this.logger.info(`[Chorus] Wake complete (sessionId=${reportSessionId}, contextKey=${contextKey}, ` +
349
+ `outcome=${aborted ? "interrupted" : crashed ? "crashed" : "completed"})`);
350
+ }
351
+ /**
352
+ * Mark a resource QUEUED and emit a snapshot. Called before a wake actually runs
353
+ * (e.g. when it sits behind a same-session run) so the server sees it waiting. The
354
+ * running transition in `runWake` overwrites it. Never throws.
355
+ */
356
+ markQueued(req) {
357
+ const entity = entityOf(req);
358
+ if (!entity)
359
+ return;
360
+ const key = execKey(entity.entityType, entity.entityUuid);
361
+ const existing = this.executions.get(key);
362
+ // Don't downgrade a running resource to queued if a duplicate dispatch arrives.
363
+ if (existing && existing.status === "running")
364
+ return;
365
+ this.executions.set(key, {
366
+ entityType: entity.entityType,
367
+ entityUuid: entity.entityUuid,
368
+ rootIdeaUuid: req.rootIdeaUuid ?? null,
369
+ status: "queued",
370
+ startedAt: existing?.startedAt ?? null,
371
+ });
372
+ this.emitExecutionSnapshot();
373
+ }
374
+ // ---------------------------------------------------------------------------
375
+ // Internal reporting helpers — never throw into the wake path.
376
+ // ---------------------------------------------------------------------------
377
+ buildExecutionSnapshot() {
378
+ return [...this.executions.values()].map((e) => ({
379
+ entityType: e.entityType,
380
+ entityUuid: e.entityUuid,
381
+ rootIdeaUuid: e.rootIdeaUuid,
382
+ status: e.status,
383
+ startedAt: e.startedAt,
384
+ }));
385
+ }
386
+ /** Fire-and-forget execution-state snapshot. Never throws. */
387
+ emitExecutionSnapshot() {
388
+ void this.restClient.executionState({ executions: this.buildExecutionSnapshot() });
389
+ }
390
+ async advanceTurn(sessionId, status, entity) {
391
+ try {
392
+ await this.restClient.turnAdvance({
393
+ sessionId,
394
+ status,
395
+ entityType: entity?.entityType ?? null,
396
+ entityUuid: entity?.entityUuid ?? null,
397
+ });
398
+ }
399
+ catch (err) {
400
+ this.logger.warn(`[Chorus] advanceTurn failed for session ${sessionId} → ${status}: ${err}`);
401
+ }
402
+ }
403
+ async postTranscript(sessionId, messages) {
404
+ try {
405
+ await this.restClient.transcript({ sessionId, messages });
406
+ }
407
+ catch (err) {
408
+ this.logger.warn(`[Chorus] transcript post failed for session ${sessionId}: ${err}`);
409
+ }
410
+ }
411
+ async report(entity, reason) {
412
+ try {
413
+ await this.restClient.reportInterrupt({
414
+ entityType: entity.entityType,
415
+ entityUuid: entity.entityUuid,
416
+ reason,
417
+ });
418
+ }
419
+ catch (err) {
420
+ this.logger.warn(`[Chorus] reportInterrupt failed for ${entity.entityType}:${entity.entityUuid} (${reason}): ${err}`);
421
+ }
422
+ }
423
+ nextRunId(contextKey) {
424
+ this.runCounter += 1;
425
+ return `chorus-wake-${this.runCounter}-${contextKey}`;
426
+ }
427
+ }
428
+ // ---------------------------------------------------------------------------
429
+ // Pure helpers (exported for unit testing).
430
+ // ---------------------------------------------------------------------------
431
+ /** Registry key for an entity. */
432
+ export function execKey(entityType, entityUuid) {
433
+ return `${entityType}:${entityUuid}`;
434
+ }
435
+ /**
436
+ * The reportable resource for a wake — `{ entityType, entityUuid }` — or null when it
437
+ * has no recognized target (mirrors waker.mjs `#entityOf`).
438
+ */
439
+ export function entityOf(req) {
440
+ const { entityType, entityUuid } = req;
441
+ if (typeof entityType === "string" &&
442
+ typeof entityUuid === "string" &&
443
+ entityUuid.length > 0 &&
444
+ EXECUTION_ENTITY_TYPES.has(entityType)) {
445
+ return { entityType, entityUuid };
446
+ }
447
+ return null;
448
+ }
449
+ /**
450
+ * The session BUSINESS KEY used in all reports (turn-advance/transcript): the
451
+ * directIdeaUuid when the entity has an idea ancestor, else the entity uuid. Mirrors
452
+ * the CLI host's `sessionId = directIdeaUuid ?? notification.entityUuid` (waker.mjs:286).
453
+ */
454
+ export function deriveSessionId(req) {
455
+ return req.directIdeaUuid ?? req.entityUuid ?? null;
456
+ }
457
+ /**
458
+ * Derive the deterministic OpenClaw `sessionKey` for a wake from its business key. The
459
+ * OpenClaw session store is keyed by `sessionKey` (the agent queue key), NOT by the
460
+ * Chorus business id — so to make `resume`/`deliver_turn` continue the SAME OpenClaw
461
+ * session we must derive the SAME key from the SAME business id every time. We namespace
462
+ * the business id under the host's main-agent key so a Chorus wake gets its own stable
463
+ * lane that re-resolves identically across runs (the in-process analog of
464
+ * `claude --resume <directIdeaUuid>`, where the disk transcript is the stable anchor).
465
+ */
466
+ export function deriveSessionKey(businessKey, mainSessionKey) {
467
+ return `${mainSessionKey}:chorus:${businessKey}`;
468
+ }
469
+ //# sourceMappingURL=daemon-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-client.js","sourceRoot":"","sources":["../src/daemon-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ export interface DaemonRestLogger {
2
+ info: (msg: string) => void;
3
+ warn: (msg: string) => void;
4
+ error: (msg: string) => void;
5
+ }
6
+ /** A single transcript message — only `role` + visible `text` (no internals). */
7
+ export interface DaemonTranscriptMessage {
8
+ role: "user" | "assistant";
9
+ text: string;
10
+ }
11
+ /** One execution-snapshot row, in the server's exact `execution-state` shape. */
12
+ export interface DaemonExecutionRow {
13
+ entityType: string;
14
+ entityUuid: string;
15
+ rootIdeaUuid: string | null;
16
+ status: "running" | "queued";
17
+ startedAt: string | null;
18
+ }
19
+ /** One unstarted (pending) turn read back from the turn table. */
20
+ export interface DaemonPendingTurn {
21
+ turnUuid: string;
22
+ sessionId: string;
23
+ directIdeaUuid: string | null;
24
+ trigger: string;
25
+ promptText: string | null;
26
+ }
27
+ /**
28
+ * Structured result of every client call. Mirrors the CLI client's
29
+ * `DaemonRestResult`: `ok` is true only on a 2xx (and, for reads, a well-formed
30
+ * body); `error` carries the (also-logged) failure cause; `skipped` marks an
31
+ * intentional non-call (e.g. no connection uuid yet); `data` holds parsed read
32
+ * payloads.
33
+ */
34
+ export interface DaemonRestResult<TData = unknown> {
35
+ ok: boolean;
36
+ status: number | null;
37
+ error?: string;
38
+ skipped?: boolean;
39
+ data?: TData;
40
+ }
41
+ export interface CreateDaemonRestClientOptions {
42
+ /** Chorus base URL (a trailing slash is normalized away). */
43
+ url: string;
44
+ /** `cho_` agent API key for Bearer auth. */
45
+ apiKey: string;
46
+ /**
47
+ * The daemon's registered connection uuid (learned from the SSE handshake),
48
+ * read LAZILY on every call so construction order does not matter. The
49
+ * connection-scoped operations (turnAdvance, executionState, reportInterrupt,
50
+ * readPendingTurns) require it; a null value skips the call (logged where the
51
+ * skip is unexpected, silent where it is a normal early state).
52
+ */
53
+ getConnectionUuid?: () => string | null;
54
+ /** Injectable for tests (defaults to global fetch). */
55
+ fetchImpl?: typeof fetch;
56
+ logger?: DaemonRestLogger;
57
+ }
58
+ export interface DaemonRestClient {
59
+ turnAdvance(p: {
60
+ sessionId: string;
61
+ status: "running" | "ended";
62
+ entityType?: string | null;
63
+ entityUuid?: string | null;
64
+ }): Promise<DaemonRestResult>;
65
+ transcript(p: {
66
+ sessionId: string;
67
+ messages: DaemonTranscriptMessage[];
68
+ }): Promise<DaemonRestResult>;
69
+ executionState(p: {
70
+ executions: DaemonExecutionRow[];
71
+ }): Promise<DaemonRestResult>;
72
+ reportInterrupt(p: {
73
+ entityType: string;
74
+ entityUuid: string;
75
+ reason: "user" | "crash";
76
+ }): Promise<DaemonRestResult>;
77
+ readPendingTurns(): Promise<DaemonRestResult<{
78
+ turns: DaemonPendingTurn[];
79
+ }>>;
80
+ }
81
+ /**
82
+ * Build the shared daemon REST client. Inputs are entirely host-agnostic, which is
83
+ * exactly why the same surface serves both daemon hosts.
84
+ */
85
+ export declare function createDaemonRestClient(opts: CreateDaemonRestClientOptions): DaemonRestClient;
86
+ //# sourceMappingURL=daemon-rest-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-rest-client.d.ts","sourceRoot":"","sources":["../src/daemon-rest-client.ts"],"names":[],"mappings":"AA2CA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAID,iFAAiF;AACjF,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,iFAAiF;AACjF,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,kEAAkE;AAClE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB,CAAC,KAAK,GAAG,OAAO;IAC/C,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,KAAK,CAAC;CACd;AAED,MAAM,WAAW,6BAA6B;IAC5C,6DAA6D;IAC7D,GAAG,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACxC,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,CAAC,EAAE;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;QAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC9B,UAAU,CAAC,CAAC,EAAE;QACZ,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,uBAAuB,EAAE,CAAC;KACrC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC9B,cAAc,CAAC,CAAC,EAAE;QAAE,UAAU,EAAE,kBAAkB,EAAE,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACnF,eAAe,CAAC,CAAC,EAAE;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;KAC1B,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC9B,gBAAgB,IAAI,OAAO,CAAC,gBAAgB,CAAC;QAAE,KAAK,EAAE,iBAAiB,EAAE,CAAA;KAAE,CAAC,CAAC,CAAC;CAC/E;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,6BAA6B,GAAG,gBAAgB,CAmL5F"}