@chorus-aidlc/chorus-openclaw-plugin 0.5.3 → 0.11.0

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 (61) 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 +37 -6
  42. package/skills/develop/SKILL.md +1 -1
  43. package/skills/idea/SKILL.md +18 -3
  44. package/skills/openspec-aware/SKILL.md +1 -1
  45. package/skills/proposal/SKILL.md +1 -1
  46. package/skills/proposal-reviewer/SKILL.md +1 -1
  47. package/skills/quick-dev/SKILL.md +1 -1
  48. package/skills/review/SKILL.md +1 -1
  49. package/skills/task-reviewer/SKILL.md +1 -1
  50. package/skills/yolo/SKILL.md +1 -1
  51. package/src/connection-state.ts +66 -0
  52. package/src/control-handler.ts +219 -0
  53. package/src/daemon-client.ts +622 -0
  54. package/src/daemon-rest-client.ts +312 -0
  55. package/src/event-router.ts +103 -33
  56. package/src/index.ts +113 -8
  57. package/src/lineage.ts +157 -0
  58. package/src/mcp-registration.ts +6 -19
  59. package/src/openclaw-sdk.d.ts +232 -1
  60. package/src/sse-listener.ts +117 -5
  61. package/src/wake.ts +69 -26
@@ -0,0 +1,35 @@
1
+ /**
2
+ * A read accessor for the live connection identity. This is the exact shape the
3
+ * shared `daemon-rest-client` (`getConnectionUuid?: () => string|null`) and the
4
+ * control handler consume, so a single `ConnectionState` instance can be passed
5
+ * to both.
6
+ */
7
+ export interface ConnectionStateReader {
8
+ /** The connection uuid this stream registered as, or null before handshake. */
9
+ getConnectionUuid: () => string | null;
10
+ }
11
+ /**
12
+ * Mutable connection identity. One instance per plugin process; the SSE
13
+ * listener's `onConnectionId` writes it, the rest client + control handler read
14
+ * it. Not a singleton export — the entry owns the instance and injects it — so
15
+ * tests can construct an isolated state per case.
16
+ */
17
+ export declare class ConnectionState implements ConnectionStateReader {
18
+ private connectionUuid;
19
+ /** The current connection identity, or null before the first handshake. */
20
+ getConnectionUuid(): string | null;
21
+ /**
22
+ * Record (or refresh) the connection identity. Called from the SSE listener's
23
+ * `onConnectionId` on every `connection_registered` event, so a reconnect that
24
+ * registers a new DaemonConnection overwrites the previous uuid rather than
25
+ * leaving a stale one that could mis-route a control command.
26
+ */
27
+ setConnectionUuid(connectionUuid: string): void;
28
+ /**
29
+ * Forget the connection identity (e.g. on a clean disconnect). After this,
30
+ * `getConnectionUuid()` returns null so the control handler's double-check
31
+ * treats every command as "not ours" until a fresh handshake re-registers.
32
+ */
33
+ clear(): void;
34
+ }
35
+ //# sourceMappingURL=connection-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-state.d.ts","sourceRoot":"","sources":["../src/connection-state.ts"],"names":[],"mappings":"AAsBA;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IACpC,+EAA+E;IAC/E,iBAAiB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CACxC;AAED;;;;;GAKG;AACH,qBAAa,eAAgB,YAAW,qBAAqB;IAC3D,OAAO,CAAC,cAAc,CAAuB;IAE7C,2EAA2E;IAC3E,iBAAiB,IAAI,MAAM,GAAG,IAAI;IAIlC;;;;;OAKG;IACH,iBAAiB,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI;IAI/C;;;;OAIG;IACH,KAAK,IAAI,IAAI;CAGd"}
@@ -0,0 +1,52 @@
1
+ // packages/openclaw-plugin/src/connection-state.ts
2
+ // Holds the live DaemonConnection identity for this OpenClaw plugin process —
3
+ // the `connectionUuid` the server assigns post-handshake and reports via the
4
+ // `connection_registered` SSE data event (see api/events/notifications/route.ts).
5
+ //
6
+ // WHY A DEDICATED MODULE: the connectionUuid is captured in ONE place (the SSE
7
+ // listener, via onConnectionId) but READ in several (the daemon REST client to
8
+ // attribute execution-state / turn-advance, and the control handler to do its
9
+ // `targetConnectionUuid === my uuid` double-check). Threading it through every
10
+ // constructor would couple those modules to the listener's lifecycle; instead
11
+ // the listener writes it here and the consumers read it through a stable
12
+ // `getConnectionUuid()` accessor — the same accessor shape the shared
13
+ // `daemon-rest-client` already expects (`getConnectionUuid?: () => string|null`).
14
+ //
15
+ // The value is refreshed on every `connection_registered` (so a reconnect that
16
+ // registers a NEW DaemonConnection overwrites the stale uuid), and is the single
17
+ // source of truth for "which connection am I" across the plugin.
18
+ //
19
+ // This mirrors the CLI host's `SseListener.connectionUuid` field
20
+ // (cli/sse-listener.mjs), lifted into a module so the OpenClaw plugin's separate
21
+ // modules can share one identity without a circular import on the listener.
22
+ /**
23
+ * Mutable connection identity. One instance per plugin process; the SSE
24
+ * listener's `onConnectionId` writes it, the rest client + control handler read
25
+ * it. Not a singleton export — the entry owns the instance and injects it — so
26
+ * tests can construct an isolated state per case.
27
+ */
28
+ export class ConnectionState {
29
+ connectionUuid = null;
30
+ /** The current connection identity, or null before the first handshake. */
31
+ getConnectionUuid() {
32
+ return this.connectionUuid;
33
+ }
34
+ /**
35
+ * Record (or refresh) the connection identity. Called from the SSE listener's
36
+ * `onConnectionId` on every `connection_registered` event, so a reconnect that
37
+ * registers a new DaemonConnection overwrites the previous uuid rather than
38
+ * leaving a stale one that could mis-route a control command.
39
+ */
40
+ setConnectionUuid(connectionUuid) {
41
+ this.connectionUuid = connectionUuid;
42
+ }
43
+ /**
44
+ * Forget the connection identity (e.g. on a clean disconnect). After this,
45
+ * `getConnectionUuid()` returns null so the control handler's double-check
46
+ * treats every command as "not ours" until a fresh handshake re-registers.
47
+ */
48
+ clear() {
49
+ this.connectionUuid = null;
50
+ }
51
+ }
52
+ //# sourceMappingURL=connection-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-state.js","sourceRoot":"","sources":["../src/connection-state.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,8EAA8E;AAC9E,6EAA6E;AAC7E,kFAAkF;AAClF,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,8EAA8E;AAC9E,+EAA+E;AAC/E,8EAA8E;AAC9E,yEAAyE;AACzE,sEAAsE;AACtE,kFAAkF;AAClF,EAAE;AACF,+EAA+E;AAC/E,iFAAiF;AACjF,iEAAiE;AACjE,EAAE;AACF,iEAAiE;AACjE,iFAAiF;AACjF,4EAA4E;AAa5E;;;;;GAKG;AACH,MAAM,OAAO,eAAe;IAClB,cAAc,GAAkB,IAAI,CAAC;IAE7C,2EAA2E;IAC3E,iBAAiB;QACf,OAAO,IAAI,CAAC,cAAc,CAAC;IAC7B,CAAC;IAED;;;;;OAKG;IACH,iBAAiB,CAAC,cAAsB;QACtC,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC;IACvC,CAAC;IAED;;;;OAIG;IACH,KAAK;QACH,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;IAC7B,CAAC;CACF"}
@@ -0,0 +1,73 @@
1
+ import type { ConnectionStateReader } from "./connection-state.js";
2
+ /**
3
+ * The control event shape the server publishes on `control:{connectionUuid}` and
4
+ * forwards verbatim as a `type:"control"` SSE data event. Mirrors the server's
5
+ * `ControlEvent` (src/lib/event-bus.ts). `entityType`/`entityUuid` are present for
6
+ * `interrupt`/`resume`; `turnUuid` is present only for `deliver_turn`.
7
+ */
8
+ export interface ControlEvent {
9
+ type: string;
10
+ command?: string;
11
+ targetConnectionUuid?: string;
12
+ entityType?: string;
13
+ entityUuid?: string;
14
+ turnUuid?: string;
15
+ }
16
+ /**
17
+ * Injected behavior hooks. These are the seams the openclaw-daemon-client task
18
+ * (T4) fills with the real abort / re-dispatch / pending-turns-sweep. This task
19
+ * (T3) only ROUTES verified commands to them — it does not implement the
20
+ * behaviors. All hooks are optional so a partially-wired host (or a test) can
21
+ * verify routing without every behavior present.
22
+ */
23
+ export interface ControlBehaviorHooks {
24
+ /**
25
+ * Whether this plugin currently holds a RUNNING embedded-agent run for the
26
+ * entity — the OpenClaw analog of the CLI host's "execution registry holds a
27
+ * running child" check. Gates `interrupt` (Check 2). Defaults to "nothing is
28
+ * running" (always false) when absent, so an interrupt with no registry is a
29
+ * safe no-op rather than a blind abort.
30
+ */
31
+ isEntityRunning?: (entityType: string, entityUuid: string) => boolean;
32
+ /**
33
+ * Abort the matching in-flight run for the entity (true mid-run stop via the
34
+ * run's AbortController). Invoked only after BOTH checks pass. (T4)
35
+ */
36
+ onInterrupt?: (entityType: string, entityUuid: string) => void;
37
+ /**
38
+ * Re-dispatch the entity's wake to continue the same session — the synthetic
39
+ * "resume" wake. Invoked after Check 1 only (no running-entity requirement —
40
+ * the run is gone). (T4)
41
+ */
42
+ onResume?: (entityType: string, entityUuid: string) => void;
43
+ /**
44
+ * Run the connection-scoped pending turn(s). With a `turnUuid` (origin-only
45
+ * live delivery) run PRECISELY that one turn; without one (older server /
46
+ * reconnect) sweep all pending turns. Invoked after Check 1 only. (T4)
47
+ */
48
+ onDeliverTurn?: (turnUuid?: string) => void;
49
+ }
50
+ export interface ControlHandlerOptions {
51
+ /** Live connection identity (connection-state). Provides Check 1's "my uuid". */
52
+ connectionState: ConnectionStateReader;
53
+ /** Injected behavior hooks (filled by T4). */
54
+ hooks: ControlBehaviorHooks;
55
+ logger: {
56
+ info: (msg: string) => void;
57
+ warn: (msg: string) => void;
58
+ error: (msg: string) => void;
59
+ };
60
+ }
61
+ /**
62
+ * Build the `onControl(event)` callback the SSE listener invokes for a
63
+ * `type:"control"` event. The returned function is synchronous and non-throwing:
64
+ * it performs the double-check and routes to the (injected) behavior hook,
65
+ * returning immediately so the SSE consumer never blocks.
66
+ *
67
+ * A control event NEVER enqueues a wake or spawns a run for the control event
68
+ * itself — that structural guarantee is owned by the SSE listener fork (the
69
+ * control event never reaches `onEvent` / the wake router) and reinforced here
70
+ * by routing ONLY to the abort/resume/deliver hooks, never to the wake path.
71
+ */
72
+ export declare function createControlHandler(opts: ControlHandlerOptions): (event: ControlEvent) => void;
73
+ //# sourceMappingURL=control-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-handler.d.ts","sourceRoot":"","sources":["../src/control-handler.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAEnE;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAK3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;IAEtE;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAE/D;;;;OAIG;IACH,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAE5D;;;;OAIG;IACH,aAAa,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7C;AAED,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,eAAe,EAAE,qBAAqB,CAAC;IACvC,8CAA8C;IAC9C,KAAK,EAAE,oBAAoB,CAAC;IAC5B,MAAM,EAAE;QAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACpG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,qBAAqB,GAAG,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAqG/F"}
@@ -0,0 +1,135 @@
1
+ // packages/openclaw-plugin/src/control-handler.ts
2
+ // OpenClaw-host handler for reverse (server→daemon) control commands — the
3
+ // in-process analog of cli/control-handler.mjs. The SSE listener forks a
4
+ // `type:"control"` SSE event here (NOT to the wake router — see sse-listener.ts),
5
+ // so a control command can NEVER spawn a new embedded-agent run for the control
6
+ // event itself. This module is the ROUTING + DOUBLE-CHECK layer only; the actual
7
+ // abort / re-dispatch / pending-turns-sweep BEHAVIORS are injected (filled by the
8
+ // openclaw-daemon-client task, T4).
9
+ //
10
+ // The single safety property this module enforces is the DOUBLE-CHECK, identical
11
+ // to the CLI host (cli/control-handler.mjs): act ONLY when —
12
+ // Check 1 (every command): event.targetConnectionUuid === this plugin's OWN
13
+ // registered connectionUuid (from connection-state). On mismatch — a
14
+ // stale/recycled uuid, another connection's command, or a handshake not
15
+ // yet complete — IGNORE + LOG. This is what stops a recycled connection
16
+ // uuid from aborting the wrong run (Tech Design "Risks": mis-kill after
17
+ // a reconnect).
18
+ // Check 2 (interrupt only): the injected `isEntityRunning(entityType, entityUuid)`
19
+ // predicate returns true — i.e. this plugin currently holds a running
20
+ // embedded-agent run for that entity. (In the CLI host this is "the
21
+ // execution registry holds a running child"; here it is an injected
22
+ // predicate the daemon client backs with its AbortController registry.)
23
+ // On mismatch — only queued, never ran, or already finished — IGNORE + LOG.
24
+ //
25
+ // `resume` and `deliver_turn` carry NO running-entity requirement (mirroring the
26
+ // CLI host): the run for a resumed entity is already gone, and a `deliver_turn`
27
+ // resolves its turn by uuid from the persisted turn table. They only require
28
+ // Check 1.
29
+ //
30
+ // The three verbs route to injected behavior hooks (the seams T4 plugs into):
31
+ // - interrupt → onInterrupt(entityType, entityUuid)
32
+ // - resume → onResume(entityType, entityUuid)
33
+ // - deliver_turn → onDeliverTurn(turnUuid?) (turnUuid present = precise single
34
+ // turn; absent = older server, full connection sweep fallback)
35
+ //
36
+ // Non-throwing: a control event must NEVER crash the SSE loop, so the whole body
37
+ // is wrapped in a try/catch backstop and the hooks' own throws are caught + logged
38
+ // (memory: no-silent-errors — every ignore/failure is logged, never swallowed).
39
+ /**
40
+ * Build the `onControl(event)` callback the SSE listener invokes for a
41
+ * `type:"control"` event. The returned function is synchronous and non-throwing:
42
+ * it performs the double-check and routes to the (injected) behavior hook,
43
+ * returning immediately so the SSE consumer never blocks.
44
+ *
45
+ * A control event NEVER enqueues a wake or spawns a run for the control event
46
+ * itself — that structural guarantee is owned by the SSE listener fork (the
47
+ * control event never reaches `onEvent` / the wake router) and reinforced here
48
+ * by routing ONLY to the abort/resume/deliver hooks, never to the wake path.
49
+ */
50
+ export function createControlHandler(opts) {
51
+ const { connectionState, hooks, logger } = opts;
52
+ const isEntityRunning = hooks.isEntityRunning ?? (() => false);
53
+ return function onControl(event) {
54
+ try {
55
+ if (!event || event.type !== "control") {
56
+ logger.warn(`[Chorus] control-handler received non-control event; ignoring`);
57
+ return;
58
+ }
59
+ if (event.command !== "interrupt" &&
60
+ event.command !== "resume" &&
61
+ event.command !== "deliver_turn") {
62
+ // Forward-compatible: the wire enum may grow. Unknown command → ignore + log.
63
+ logger.warn(`[Chorus] control command "${event.command}" not supported; ignoring`);
64
+ return;
65
+ }
66
+ const { command, targetConnectionUuid, entityType, entityUuid } = event;
67
+ // --- Check 1: connection-uuid match (applies to EVERY command) ---
68
+ const myConnectionUuid = connectionState.getConnectionUuid();
69
+ if (!myConnectionUuid || targetConnectionUuid !== myConnectionUuid) {
70
+ // Not ours (stale/recycled uuid, another connection, or handshake not yet
71
+ // complete). Ignore — never abort/resume/deliver for a command that isn't ours.
72
+ logger.info(`[Chorus] control: ignoring ${command} for connection ${targetConnectionUuid} ` +
73
+ `(this plugin is ${myConnectionUuid ?? "<unregistered>"})`);
74
+ return;
75
+ }
76
+ // --- deliver_turn: origin-only live delivery. No entity on the wire (the
77
+ // turn is read by uuid) and NO running-entity requirement (mirrors
78
+ // resume). With a turnUuid, run PRECISELY that turn; without one (older
79
+ // server), the hook falls back to a full connection sweep. ---
80
+ if (command === "deliver_turn") {
81
+ const turnUuid = typeof event.turnUuid === "string" ? event.turnUuid : undefined;
82
+ logger.info(`[Chorus] control: deliver_turn for connection ${targetConnectionUuid} ` +
83
+ (turnUuid ? `(turn ${turnUuid})` : "(no turnUuid — full sweep fallback)"));
84
+ try {
85
+ hooks.onDeliverTurn?.(turnUuid);
86
+ }
87
+ catch (err) {
88
+ logger.warn(`[Chorus] control: deliver_turn hook failed: ${err}`);
89
+ }
90
+ return;
91
+ }
92
+ // interrupt / resume both target a specific entity — require both fields.
93
+ if (typeof entityType !== "string" || typeof entityUuid !== "string") {
94
+ logger.warn(`[Chorus] control: ${command} missing entityType/entityUuid; ignoring`);
95
+ return;
96
+ }
97
+ // --- resume: re-dispatch the wake for this entity. No running-entity check —
98
+ // the run is gone (it was interrupted); the wake path re-enters the same
99
+ // session. Check 1 already passed. ---
100
+ if (command === "resume") {
101
+ logger.info(`[Chorus] control: resuming ${entityType}:${entityUuid} (re-dispatch wake)`);
102
+ try {
103
+ hooks.onResume?.(entityType, entityUuid);
104
+ }
105
+ catch (err) {
106
+ logger.warn(`[Chorus] control: resume re-dispatch failed for ${entityType}:${entityUuid}: ${err}`);
107
+ }
108
+ return;
109
+ }
110
+ // --- interrupt path: Check 2 — this plugin must hold a RUNNING run for the
111
+ // entity. The injected predicate is backed by the daemon client's
112
+ // AbortController registry (T4). ---
113
+ if (!isEntityRunning(entityType, entityUuid)) {
114
+ // Either we never ran this entity, it's only queued, or the run already
115
+ // finished (race: interrupt arrived after completion). Safe no-op.
116
+ logger.info(`[Chorus] control: no running embedded-agent run for ${entityType}:${entityUuid} ` +
117
+ `on this plugin; ignoring interrupt`);
118
+ return;
119
+ }
120
+ // --- Both checks passed: route to the abort hook (true mid-run stop). ---
121
+ logger.info(`[Chorus] control: interrupting running run for ${entityType}:${entityUuid}`);
122
+ try {
123
+ hooks.onInterrupt?.(entityType, entityUuid);
124
+ }
125
+ catch (err) {
126
+ logger.warn(`[Chorus] control: interrupt hook failed for ${entityType}:${entityUuid}: ${err}`);
127
+ }
128
+ }
129
+ catch (err) {
130
+ // Absolute backstop — a control event must never crash the SSE loop.
131
+ logger.error(`[Chorus] control-handler unexpected error: ${err}`);
132
+ }
133
+ };
134
+ }
135
+ //# sourceMappingURL=control-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control-handler.js","sourceRoot":"","sources":["../src/control-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,203 @@
1
+ import type { OpenClawRuntimeAgent, OpenClawBlockReplyPayload } from "openclaw/plugin-sdk/plugin-entry";
2
+ import type { DaemonRestClient, DaemonTranscriptMessage, DaemonPendingTurn } from "./daemon-rest-client.js";
3
+ export interface DaemonClientLogger {
4
+ info: (msg: string) => void;
5
+ warn: (msg: string) => void;
6
+ error: (msg: string) => void;
7
+ }
8
+ /**
9
+ * The host knobs the run needs, resolved per-wake by the entry/wake layer. These are
10
+ * the OpenClaw runtime-derived values (workspace dir, timeout, model, …) that wake.ts
11
+ * already knows how to resolve from `api.config`. The daemon client takes them as a
12
+ * resolver so it never reaches into `api` directly (keeps it host-API-agnostic + testable).
13
+ */
14
+ export interface WakeRunContext {
15
+ /** The `runtime.agent` surface to run the turn with. */
16
+ agent: OpenClawRuntimeAgent;
17
+ /** The OpenClaw session key for this wake's main agent (e.g. `agent:main:main`). */
18
+ sessionKey: string;
19
+ /** The resolved default agent id (session/workspace resolvers are agent-scoped). */
20
+ agentId: string;
21
+ /** The opaque `api.config` snapshot passed through to runEmbeddedAgent. */
22
+ config: unknown;
23
+ /** Resolved agent workspace dir. */
24
+ workspaceDir: string;
25
+ /** Resolved agent dir (optional — omitted when the host has none). */
26
+ agentDir?: string;
27
+ /** Resolved per-agent timeout. */
28
+ timeoutMs: number;
29
+ /** Resolved `{ provider, model }` override, or null to use the host default. */
30
+ modelRef: {
31
+ provider: string;
32
+ model: string;
33
+ } | null;
34
+ }
35
+ /**
36
+ * Per-wake attribution + prompt. `entityType`/`entityUuid` identify the resource the
37
+ * execution row keys on; `directIdeaUuid`/`rootIdeaUuid` come from the lineage resolve
38
+ * (the two-id contract: directIdea = session anchor, rootIdea = snapshot attribution).
39
+ * `contextKey` is the router's dedupe/log key. `turnUuid` is set for a delivered turn.
40
+ */
41
+ export interface WakeRequest {
42
+ prompt: string;
43
+ contextKey: string;
44
+ entityType?: string | null;
45
+ entityUuid?: string | null;
46
+ directIdeaUuid?: string | null;
47
+ rootIdeaUuid?: string | null;
48
+ /** When this wake runs a specific pending turn (deliver_turn / backfill). */
49
+ turnUuid?: string | null;
50
+ }
51
+ export interface OpenClawDaemonClientOptions {
52
+ /** The shared REST client (turnAdvance/transcript/executionState/reportInterrupt/readPendingTurns). */
53
+ restClient: DaemonRestClient;
54
+ /**
55
+ * Resolve the host run context for a wake (workspace/timeout/model/agent/session
56
+ * key). Returns null when the wake must be DROPPED (no resolvable session/agent on
57
+ * this host) — mirrors wake.ts's graceful-drop. Errors thrown here are caught.
58
+ */
59
+ resolveRunContext: () => WakeRunContext | null;
60
+ /**
61
+ * Re-dispatch a wake for an entity (the synthetic resume / pending-turn path). Built
62
+ * by the entry from the router so a resume / delivered turn rides the SAME wake path
63
+ * (continuing the same session). Receives the full WakeRequest.
64
+ */
65
+ redispatch: (req: WakeRequest) => void;
66
+ /**
67
+ * Read this connection's unstarted (pending) turns and feed each to `redispatch`.
68
+ * The client owns the seen-set dedup + the optional single-turn filter; the entry
69
+ * just provides the prompt builder via `buildTurnPrompt`.
70
+ */
71
+ buildTurnPrompt: (turn: DaemonPendingTurn) => string;
72
+ logger?: DaemonClientLogger;
73
+ }
74
+ /**
75
+ * Extract finalized assistant VISIBLE text from an `onBlockReply` payload, or null to
76
+ * skip. Mirrors the CLI host's stream-json filter (upload-hooks.mjs
77
+ * `extractTranscriptText`): keep only finalized assistant text; DROP reasoning/thinking
78
+ * (`isReasoning`) — verified the flag exists at ../openclaw/src/agents/
79
+ * embedded-agent-payloads.ts:7 and is set true for reasoning blocks
80
+ * (embedded-agent-subscribe.handlers.messages.ts:915). Tool internals never reach here
81
+ * (they arrive on `onToolResult`, which the client does not post). Never throws.
82
+ */
83
+ export declare function extractBlockReplyText(payload: OpenClawBlockReplyPayload | undefined | null): DaemonTranscriptMessage | null;
84
+ /**
85
+ * The OpenClaw in-process daemon client. One instance per plugin process; the entry
86
+ * injects the shared REST client + the host run-context resolver + the re-dispatch
87
+ * hook, and wires this client's `controlHooks` into the control handler.
88
+ */
89
+ export declare class OpenClawDaemonClient {
90
+ private readonly restClient;
91
+ private readonly resolveRunContext;
92
+ private readonly redispatch;
93
+ private readonly buildTurnPrompt;
94
+ private readonly logger;
95
+ /** AbortController per in-flight run, keyed `entityType:entityUuid`. */
96
+ private readonly aborts;
97
+ /** Execution snapshot source — one entry per running/queued resource. */
98
+ private readonly executions;
99
+ /**
100
+ * At-most-once turn dedup, keyed `turn:<uuid>`. Shared by the live deliver_turn
101
+ * path and the reconnect backfill so a turn observed by either runs at most once
102
+ * (mirrors the CLI host's `seen` set; backfill.mjs).
103
+ */
104
+ private readonly seenTurns;
105
+ private runCounter;
106
+ constructor(opts: OpenClawDaemonClientOptions);
107
+ /**
108
+ * The behavior hooks the control handler routes verified commands to. The handler
109
+ * owns the double-check (own connection + held entity); these implement the actual
110
+ * abort / re-dispatch / pending-turns-sweep.
111
+ */
112
+ get controlHooks(): {
113
+ isEntityRunning: (entityType: string, entityUuid: string) => boolean;
114
+ onInterrupt: (entityType: string, entityUuid: string) => void;
115
+ onResume: (entityType: string, entityUuid: string) => void;
116
+ onDeliverTurn: (turnUuid?: string) => void;
117
+ };
118
+ /**
119
+ * Abort the matching in-flight run (true mid-run stop via abortSignal) and mark it
120
+ * `interrupting` so the run's settle path reports reason=user (not crash). No-op when
121
+ * no run is registered (the handler's Check 2 already gates this, but we re-check so a
122
+ * direct caller is safe). Never throws.
123
+ */
124
+ interrupt(entityType: string, entityUuid: string): void;
125
+ /**
126
+ * Re-dispatch a wake for the entity to continue the SAME session (the run is gone;
127
+ * resolveRunContext re-derives the same sessionKey → getSessionEntry resolves the
128
+ * existing sessionId). The control handler has no prompt; we synthesize a minimal
129
+ * resume prompt. Continues under the same business key (directIdea/entity).
130
+ */
131
+ resume(entityType: string, entityUuid: string): void;
132
+ /**
133
+ * Read connection-scoped pending turns and run the unstarted human_instruction turn.
134
+ * With a `turnUuid` run PRECISELY that one (live deliver_turn); without one sweep all
135
+ * (reconnect backfill). Idempotent via the shared `seenTurns` set keyed `turn:<uuid>`.
136
+ * Never throws into the caller. Mirrors backfill.mjs `backfillPendingTurns`.
137
+ */
138
+ deliverTurn(onlyTurnUuid?: string): Promise<void>;
139
+ /** Reconnect backfill: full connection-scoped pending-turns sweep (no single-turn filter). */
140
+ onReconnect(): Promise<void>;
141
+ /**
142
+ * Run one wake via runEmbeddedAgent with full daemon reporting. Never throws — a
143
+ * wake failure is logged + reported (crash), never propagated (the SSE service must
144
+ * stay alive). Fire-and-forget from the caller's perspective; returns a promise the
145
+ * tests can await.
146
+ *
147
+ * Lifecycle (mirrors waker.mjs):
148
+ * 1. resolve run context (drop on null);
149
+ * 2. derive sessionKey from the business key → getSessionEntry → sessionId/sessionFile;
150
+ * 3. register the AbortController + mark the execution running → turnAdvance(running)
151
+ * + execution-state snapshot;
152
+ * 4. run with transcript callbacks (onBlockReply → post {role:"assistant", text});
153
+ * 5. on settle → turnAdvance(ended) + snapshot; classify interrupt(user) vs crash;
154
+ * 6. finally → deregister the controller + drop the execution row + snapshot.
155
+ */
156
+ runWake(req: WakeRequest): Promise<void>;
157
+ /**
158
+ * Mark a resource QUEUED and emit a snapshot. Called before a wake actually runs
159
+ * (e.g. when it sits behind a same-session run) so the server sees it waiting. The
160
+ * running transition in `runWake` overwrites it. Never throws.
161
+ */
162
+ markQueued(req: WakeRequest): void;
163
+ private buildExecutionSnapshot;
164
+ /** Fire-and-forget execution-state snapshot. Never throws. */
165
+ private emitExecutionSnapshot;
166
+ private advanceTurn;
167
+ private postTranscript;
168
+ private report;
169
+ private nextRunId;
170
+ }
171
+ /** Registry key for an entity. */
172
+ export declare function execKey(entityType: string, entityUuid: string): string;
173
+ /**
174
+ * The reportable resource for a wake — `{ entityType, entityUuid }` — or null when it
175
+ * has no recognized target (mirrors waker.mjs `#entityOf`).
176
+ */
177
+ export declare function entityOf(req: {
178
+ entityType?: string | null;
179
+ entityUuid?: string | null;
180
+ }): {
181
+ entityType: string;
182
+ entityUuid: string;
183
+ } | null;
184
+ /**
185
+ * The session BUSINESS KEY used in all reports (turn-advance/transcript): the
186
+ * directIdeaUuid when the entity has an idea ancestor, else the entity uuid. Mirrors
187
+ * the CLI host's `sessionId = directIdeaUuid ?? notification.entityUuid` (waker.mjs:286).
188
+ */
189
+ export declare function deriveSessionId(req: {
190
+ directIdeaUuid?: string | null;
191
+ entityUuid?: string | null;
192
+ }): string | null;
193
+ /**
194
+ * Derive the deterministic OpenClaw `sessionKey` for a wake from its business key. The
195
+ * OpenClaw session store is keyed by `sessionKey` (the agent queue key), NOT by the
196
+ * Chorus business id — so to make `resume`/`deliver_turn` continue the SAME OpenClaw
197
+ * session we must derive the SAME key from the SAME business id every time. We namespace
198
+ * the business id under the host's main-agent key so a Chorus wake gets its own stable
199
+ * lane that re-resolves identically across runs (the in-process analog of
200
+ * `claude --resume <directIdeaUuid>`, where the disk transcript is the stable anchor).
201
+ */
202
+ export declare function deriveSessionKey(businessKey: string, mainSessionKey: string): string;
203
+ //# sourceMappingURL=daemon-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-client.d.ts","sourceRoot":"","sources":["../src/daemon-client.ts"],"names":[],"mappings":"AA6BA,OAAO,KAAK,EACV,oBAAoB,EACpB,yBAAyB,EAC1B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EACV,gBAAgB,EAEhB,uBAAuB,EACvB,iBAAiB,EAClB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,kBAAkB;IACjC,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;AAOD;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,wDAAwD;IACxD,KAAK,EAAE,oBAAoB,CAAC;IAC5B,oFAAoF;IACpF,UAAU,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,MAAM,EAAE,OAAO,CAAC;IAChB,oCAAoC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,QAAQ,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CACtD;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAgBD,MAAM,WAAW,2BAA2B;IAC1C,uGAAuG;IACvG,UAAU,EAAE,gBAAgB,CAAC;IAC7B;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,cAAc,GAAG,IAAI,CAAC;IAC/C;;;;OAIG;IACH,UAAU,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,CAAC;IACvC;;;;OAIG;IACH,eAAe,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,MAAM,CAAC;IACrD,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,yBAAyB,GAAG,SAAS,GAAG,IAAI,GACpD,uBAAuB,GAAG,IAAI,CAOhC;AAED;;;;GAIG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmB;IAC9C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAmD;IACrF,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA4C;IACvE,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAiD;IACjF,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAE5C,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IACxD,yEAAyE;IACzE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqC;IAChE;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAE/C,OAAO,CAAC,UAAU,CAAK;gBAEX,IAAI,EAAE,2BAA2B;IAY7C;;;;OAIG;IACH,IAAI,YAAY,IAAI;QAClB,eAAe,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC;QACrE,WAAW,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;QAC9D,QAAQ,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;QAC3D,aAAa,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;KAC5C,CAUA;IAED;;;;;OAKG;IACH,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAgBvD;;;;;OAKG;IACH,MAAM,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAYpD;;;;;OAKG;IACG,WAAW,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwCvD,8FAA8F;IACxF,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAQlC;;;;;;;;;;;;;;OAcG;IACG,OAAO,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAgK9C;;;;OAIG;IACH,UAAU,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI;IAqBlC,OAAO,CAAC,sBAAsB;IAU9B,8DAA8D;IAC9D,OAAO,CAAC,qBAAqB;YAIf,WAAW;YAiBX,cAAc;YAQd,MAAM;IAiBpB,OAAO,CAAC,SAAS;CAIlB;AAMD,kCAAkC;AAClC,wBAAgB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE;IAC5B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,GAAG;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAWpD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE;IACnC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,GAAG,MAAM,GAAG,IAAI,CAEhB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,CAEpF"}