@stagewhisper/stagewhisper 0.31.0 → 0.33.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.
@@ -1,9 +1,8 @@
1
1
  {
2
2
  "id": "stagewhisper",
3
- "kind": "channel",
4
3
  "name": "StageWhisper",
5
4
  "description": "Turn live call moments into assistant tasks via StageWhisper",
6
- "version": "0.31.0",
5
+ "version": "0.33.0",
7
6
  "channels": [
8
7
  "stagewhisper"
9
8
  ],
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "@stagewhisper/stagewhisper",
3
- "version": "0.31.0",
3
+ "version": "0.33.0",
4
4
  "type": "module",
5
5
  "description": "OpenClaw channel plugin that connects StageWhisper live calls to your AI assistant",
6
6
  "license": "MIT",
7
7
  "files": [
8
8
  "index.ts",
9
9
  "plugin-main.ts",
10
- "setup-entry.ts",
11
10
  "api.ts",
12
11
  "src",
13
12
  "openclaw.plugin.json",
@@ -22,7 +21,6 @@
22
21
  "extensions": [
23
22
  "./index.ts"
24
23
  ],
25
- "setupEntry": "./setup-entry.ts",
26
24
  "channel": {
27
25
  "id": "stagewhisper",
28
26
  "label": "StageWhisper",
package/plugin-main.ts CHANGED
@@ -1,16 +1,14 @@
1
- import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
1
+ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
2
2
  import { stagewhisperPlugin } from "./src/channel.js";
3
3
  import { setRuntime } from "./src/runtime.js";
4
4
  import { createRelayService } from "./src/service.js";
5
5
 
6
- export default defineChannelPluginEntry({
6
+ export default definePluginEntry({
7
7
  id: "stagewhisper",
8
8
  name: "StageWhisper",
9
9
  description: "Turn live call moments into assistant tasks via StageWhisper",
10
- plugin: stagewhisperPlugin,
11
- setRuntime,
12
- registerFull(api) {
13
- const service = createRelayService(api);
10
+ register(api) {
11
+ api.registerChannel({ plugin: stagewhisperPlugin });
14
12
 
15
13
  api.registerCli(
16
14
  ({ program }) => {
@@ -122,7 +120,7 @@ export default defineChannelPluginEntry({
122
120
  if (!configured) {
123
121
  console.log("\nStageWhisper: not paired\n");
124
122
  console.log(
125
- " Run: openclaw stagewhisper pair --code <CODE>\n",
123
+ " Run: openclaw stagewhisper pair --code <CODE> [--api-url <URL>]\n",
126
124
  );
127
125
  console.log(
128
126
  " Get the pairing code from StageWhisper desktop: Settings → Assistant → Generate Pairing Code\n",
@@ -155,6 +153,10 @@ export default defineChannelPluginEntry({
155
153
  { commands: ["stagewhisper"] },
156
154
  );
157
155
 
156
+ if (api.registrationMode !== "full") return;
157
+
158
+ setRuntime(api.runtime);
159
+ const service = createRelayService(api);
158
160
  api.registerService(service);
159
161
  },
160
162
  });
package/src/service.ts CHANGED
@@ -77,6 +77,32 @@ export function createRelayService(api: OpenClawPluginApi) {
77
77
  return lines.join("\n");
78
78
  }
79
79
 
80
+ function isTestTask(task: TaskPayload): boolean {
81
+ return task.action_type === "test";
82
+ }
83
+
84
+ async function updateStatus(
85
+ client: StageWhisperClient,
86
+ task: TaskPayload,
87
+ status: string,
88
+ ): Promise<void> {
89
+ if (isTestTask(task)) return;
90
+ await client.updateTaskStatus(task.id, status);
91
+ }
92
+
93
+ function extractAssistantReply(
94
+ messages: unknown[],
95
+ ): string | null {
96
+ for (let i = messages.length - 1; i >= 0; i--) {
97
+ const msg = messages[i] as Record<string, unknown> | undefined;
98
+ if (!msg) continue;
99
+ if (msg["role"] === "assistant" && typeof msg["content"] === "string") {
100
+ return msg["content"];
101
+ }
102
+ }
103
+ return null;
104
+ }
105
+
80
106
  async function handleTask(
81
107
  task: TaskPayload,
82
108
  client: StageWhisperClient,
@@ -84,7 +110,7 @@ export function createRelayService(api: OpenClawPluginApi) {
84
110
  api.logger.info(`Received task: ${task.title} (${task.id})`);
85
111
 
86
112
  try {
87
- await client.updateTaskStatus(task.id, "delivered");
113
+ await updateStatus(client, task, "delivered");
88
114
  } catch (err) {
89
115
  api.logger.warn(`Failed to mark task as delivered: ${err}`);
90
116
  }
@@ -95,23 +121,56 @@ export function createRelayService(api: OpenClawPluginApi) {
95
121
  const sessionKey = buildAgentSessionKey({
96
122
  agentId: "default",
97
123
  channel: "stagewhisper",
98
- peer: { kind: "direct", id: `sw-session-${task.session_id}` },
124
+ peer: { kind: "direct", id: `sw-task-${task.id}` },
99
125
  });
100
126
 
101
127
  const result = await api.runtime.subagent.run({
102
128
  sessionKey,
103
129
  message: messageContent,
104
- deliver: true,
130
+ deliver: false,
105
131
  idempotencyKey: randomUUID(),
106
132
  });
107
133
 
108
134
  api.logger.info(
109
135
  `Task ${task.id} dispatched to agent session (runId: ${result.runId})`,
110
136
  );
111
- await client.updateTaskStatus(task.id, "running");
137
+
138
+ try {
139
+ await updateStatus(client, task, "running");
140
+ } catch (err) {
141
+ api.logger.warn(`Failed to mark task as running: ${err}`);
142
+ }
143
+
144
+ const waitResult = await api.runtime.subagent.waitForRun({
145
+ runId: result.runId,
146
+ timeoutMs: 120_000,
147
+ });
148
+
149
+ if (waitResult.status === "ok") {
150
+ const session = await api.runtime.subagent.getSessionMessages({
151
+ sessionKey,
152
+ limit: 20,
153
+ });
154
+
155
+ const reply = extractAssistantReply(session.messages);
156
+ if (reply) {
157
+ if (!isTestTask(task)) {
158
+ await client.postReply(task.id, reply);
159
+ }
160
+ api.logger.info(`Task ${task.id} completed with reply`);
161
+ } else {
162
+ api.logger.warn(`Task ${task.id} completed but no assistant reply found`);
163
+ await updateStatus(client, task, "completed").catch(() => {});
164
+ }
165
+ } else {
166
+ api.logger.error(
167
+ `Agent run failed for task ${task.id}: ${waitResult.error}`,
168
+ );
169
+ await updateStatus(client, task, "failed").catch(() => {});
170
+ }
112
171
  } catch (err) {
113
- api.logger.error(`Failed to dispatch task to agent: ${err}`);
114
- await client.updateTaskStatus(task.id, "failed").catch(() => {});
172
+ api.logger.error(`Failed to process task ${task.id}: ${err}`);
173
+ await updateStatus(client, task, "failed").catch(() => {});
115
174
  }
116
175
  }
117
176
 
@@ -163,7 +222,9 @@ export function createRelayService(api: OpenClawPluginApi) {
163
222
 
164
223
  try {
165
224
  const task = JSON.parse(jsonStr) as TaskPayload;
166
- await handleTask(task, client);
225
+ handleTask(task, client).catch((err) => {
226
+ api.logger.error(`Unhandled error processing task: ${err}`);
227
+ });
167
228
  } catch (parseErr) {
168
229
  api.logger.warn(`Failed to parse stream event: ${parseErr}`);
169
230
  }
package/setup-entry.ts DELETED
@@ -1,4 +0,0 @@
1
- import { defineSetupPluginEntry } from "openclaw/plugin-sdk/core";
2
- import { stagewhisperPlugin } from "./src/channel.js";
3
-
4
- export default defineSetupPluginEntry(stagewhisperPlugin);