maniflow-mission-control 0.1.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.
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # Mission Control Plugin for OpenClaw
2
+
3
+ Syncs agent lifecycle events from OpenClaw to the Mission Control dashboard (Convex backend) in real time.
4
+
5
+ ## Architecture
6
+
7
+ ### Internal Hook (HOOK.md)
8
+
9
+ - **File:** `hooks/mission-control/handler.ts`
10
+ - **Events:** `agent:bootstrap`, `gateway:startup`
11
+ - **Role:** Stores session info, reads the user prompt, sends "start" event
12
+
13
+ ### Typed Plugin Hooks (api.on)
14
+
15
+ - **File:** `src/index.ts`
16
+ - **Events:** `agent_end`, `after_tool_call`
17
+ - **Role:** Sends "end" and "progress" events with sub-second latency
18
+
19
+ ### Event Flow
20
+
21
+ ```
22
+ Agent starts -> HOOK.md agent:bootstrap -> handler.ts sends "start"
23
+ Agent uses tool -> api.on("after_tool_call") -> index.ts sends "progress"
24
+ Agent finishes -> api.on("agent_end") -> index.ts sends "end"
25
+ ```
26
+
27
+ ### Shared State
28
+
29
+ Both files coordinate via `Symbol.for()` globals:
30
+
31
+ - `mission-control:sessionInfo` — `Map<string, {agentId, sessionId}>` mapping session keys to IDs (set by handler.ts, read by index.ts)
32
+
33
+ ### Dedup
34
+
35
+ OpenClaw may fire `agent_end` twice per turn (intermediate + final message snapshot). The plugin uses a `Map<string, number>` keyed by `sessionKey → messageCount`. If `agent_end` fires again with the same message count, it's a duplicate and is skipped.
36
+
37
+ ## Configuration
38
+
39
+ | Env var | Required | Description |
40
+ |---------|----------|-------------|
41
+ | `CONVEX_URL` | Yes | Self-hosted Convex backend URL (port 443, not 8443) |
42
+
43
+ ## Requirements
44
+
45
+ - OpenClaw >= 2026.2.3 (for `api.on()` typed hooks)
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Mission Control Plugin for OpenClaw
3
+ *
4
+ * Syncs agent lifecycle events to Mission Control via authenticated HTTP
5
+ * actions on hosted Convex.
6
+ *
7
+ * Integrates with OpenClaw's infrastructure:
8
+ * - Uses registerService for background task subscriber (proper lifecycle)
9
+ * - Uses device identity for cryptographic authentication
10
+ * - Stores state in OC's state directory
11
+ *
12
+ * BYOB Mode: When MC_GATEWAY_ID is set, the plugin subscribes to Convex
13
+ * for task assignments, enabling local gateways to receive tasks without
14
+ * inbound HTTP connectivity.
15
+ */
16
+ import type { PluginApi } from "openclaw";
17
+ export default function register(api: PluginApi): void;
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAgC,MAAM,UAAU,CAAC;AA0IxE,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,SAAS,QAkC9C"}
package/dist/index.js ADDED
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Mission Control Plugin for OpenClaw
3
+ *
4
+ * Syncs agent lifecycle events to Mission Control via authenticated HTTP
5
+ * actions on hosted Convex.
6
+ *
7
+ * Integrates with OpenClaw's infrastructure:
8
+ * - Uses registerService for background task subscriber (proper lifecycle)
9
+ * - Uses device identity for cryptographic authentication
10
+ * - Stores state in OC's state directory
11
+ *
12
+ * BYOB Mode: When MC_GATEWAY_ID is set, the plugin subscribes to Convex
13
+ * for task assignments, enabling local gateways to receive tasks without
14
+ * inbound HTTP connectivity.
15
+ */
16
+ import { TaskSubscriber, bootstrapSubscriber } from "./subscriber.js";
17
+ /** Shared session info set by handler.ts on agent:bootstrap */
18
+ function getSessionInfo() {
19
+ const key = Symbol.for("mission-control:sessionInfo");
20
+ const g = globalThis;
21
+ if (!g[key]) {
22
+ g[key] = new Map();
23
+ }
24
+ return g[key];
25
+ }
26
+ async function sendToConvex(payload) {
27
+ const convexUrl = process.env.MC_CONVEX_URL;
28
+ const apiToken = process.env.MC_API_TOKEN;
29
+ if (!convexUrl || !apiToken)
30
+ return;
31
+ try {
32
+ console.log("[mission-control:typed] POST /openclaw/event", payload.action, payload.sessionKey);
33
+ const response = await fetch(`${convexUrl}/openclaw/event`, {
34
+ method: "POST",
35
+ headers: {
36
+ "Authorization": `Bearer ${apiToken}`,
37
+ "Content-Type": "application/json",
38
+ },
39
+ body: JSON.stringify(payload),
40
+ });
41
+ if (!response.ok) {
42
+ const text = await response.text().catch(() => "");
43
+ console.error("[mission-control:typed] HTTP error:", response.status, text);
44
+ return;
45
+ }
46
+ console.log("[mission-control:typed] OK:", payload.action);
47
+ }
48
+ catch (err) {
49
+ console.error("[mission-control:typed] fetch error:", err instanceof Error ? err.message : err);
50
+ }
51
+ }
52
+ /**
53
+ * Handle agent_end typed hook.
54
+ */
55
+ function handleAgentEnd(event, ctx) {
56
+ const sessionKey = ctx.sessionKey;
57
+ const agentId = ctx.agentId;
58
+ if (!sessionKey || !agentId) {
59
+ console.log("[mission-control:typed] agent_end missing sessionKey or agentId, skipping");
60
+ return;
61
+ }
62
+ const messages = event.messages;
63
+ // Extract last assistant response from messages array if available
64
+ let response = null;
65
+ if (Array.isArray(messages)) {
66
+ for (let i = messages.length - 1; i >= 0; i--) {
67
+ const msg = messages[i];
68
+ if (msg?.role === "assistant" && msg.content) {
69
+ if (Array.isArray(msg.content)) {
70
+ const textParts = msg.content
71
+ .filter((p) => p.type === "text")
72
+ .map((p) => p.text || "")
73
+ .join("\n");
74
+ if (textParts) {
75
+ response = textParts;
76
+ break;
77
+ }
78
+ }
79
+ else if (typeof msg.content === "string") {
80
+ response = msg.content;
81
+ break;
82
+ }
83
+ }
84
+ }
85
+ }
86
+ if (response && response.length > 1000) {
87
+ response = response.slice(0, 1000) + "...";
88
+ }
89
+ // Resolve runId from sessionInfo (set by handler.ts on bootstrap)
90
+ const sessionInfo = getSessionInfo();
91
+ const info = sessionInfo.get(sessionKey);
92
+ const runId = info?.sessionId ?? sessionKey;
93
+ console.log(`[mission-control:typed] agent_end for ${sessionKey} success=${event.success}`);
94
+ void sendToConvex({
95
+ runId,
96
+ action: "end",
97
+ sessionKey,
98
+ agentId,
99
+ timestamp: new Date().toISOString(),
100
+ response,
101
+ error: event.error ?? null,
102
+ eventType: "typed-hook:agent_end",
103
+ });
104
+ }
105
+ /**
106
+ * Handle after_tool_call typed hook.
107
+ */
108
+ function handleToolCall(event, ctx) {
109
+ const sessionKey = ctx.sessionKey;
110
+ const agentId = ctx.agentId;
111
+ if (!sessionKey || !agentId)
112
+ return;
113
+ const toolName = (event.toolName ?? event.name ?? "unknown");
114
+ const sessionInfo = getSessionInfo();
115
+ const info = sessionInfo.get(sessionKey);
116
+ const runId = info?.sessionId ?? sessionKey;
117
+ void sendToConvex({
118
+ runId,
119
+ action: "progress",
120
+ sessionKey,
121
+ agentId,
122
+ timestamp: new Date().toISOString(),
123
+ message: `Tool completed: ${toolName}`,
124
+ eventType: "typed-hook:after_tool_call",
125
+ });
126
+ }
127
+ export default function register(api) {
128
+ const convexUrl = process.env.MC_CONVEX_URL;
129
+ if (!convexUrl) {
130
+ api.logger.warn("mission-control: No MC_CONVEX_URL set, plugin inactive");
131
+ return;
132
+ }
133
+ api.on("agent_end", handleAgentEnd);
134
+ api.on("after_tool_call", handleToolCall);
135
+ api.logger.info({
136
+ msg: "mission-control: Typed hooks registered (agent_end, after_tool_call)",
137
+ convexUrl,
138
+ });
139
+ // BYOB Mode: Register task subscriber as OC service (proper lifecycle)
140
+ const gatewayId = process.env.MC_GATEWAY_ID;
141
+ const apiToken = process.env.MC_API_TOKEN;
142
+ if (gatewayId && apiToken) {
143
+ api.logger.info({
144
+ msg: "mission-control: BYOB mode enabled, registering task subscriber service",
145
+ gatewayId,
146
+ });
147
+ // Register as a proper OC service for lifecycle management
148
+ const subscriberService = createTaskSubscriberService(api, {
149
+ convexUrl,
150
+ apiToken,
151
+ gatewayId,
152
+ });
153
+ api.registerService(subscriberService);
154
+ }
155
+ }
156
+ /**
157
+ * Trigger an agent run via localhost loopback to /hooks/agent.
158
+ * This avoids needing OC core changes - we just POST to ourselves.
159
+ */
160
+ async function triggerAgentViaLoopback(task) {
161
+ const port = process.env.MC_GATEWAY_PORT || process.env.OPENCLAW_PORT || "18789";
162
+ const hooksToken = process.env.MC_HOOKS_TOKEN || process.env.OPENCLAW_HOOKS_TOKEN;
163
+ if (!hooksToken) {
164
+ throw new Error("MC_HOOKS_TOKEN or OPENCLAW_HOOKS_TOKEN required for loopback");
165
+ }
166
+ const url = `http://127.0.0.1:${port}/hooks/agent`;
167
+ const response = await fetch(url, {
168
+ method: "POST",
169
+ headers: {
170
+ "Authorization": `Bearer ${hooksToken}`,
171
+ "Content-Type": "application/json",
172
+ },
173
+ body: JSON.stringify({
174
+ sessionKey: task.sessionKey,
175
+ message: task.message,
176
+ agentId: task.agentId,
177
+ // Include runId in metadata so MC can correlate
178
+ metadata: { runId: task.runId },
179
+ }),
180
+ });
181
+ if (!response.ok) {
182
+ const text = await response.text().catch(() => "");
183
+ throw new Error(`Loopback trigger failed: ${response.status} ${text}`);
184
+ }
185
+ }
186
+ /**
187
+ * Create the BYOB task subscriber as an OC service.
188
+ * This integrates with OC's service lifecycle (start/stop on gateway start/stop).
189
+ */
190
+ function createTaskSubscriberService(_api, config) {
191
+ let subscriber = null;
192
+ return {
193
+ id: "mission-control-task-subscriber",
194
+ start: async (ctx) => {
195
+ ctx.logger.info("mission-control: Starting task subscriber service");
196
+ // Bootstrap: authenticate and get Convex URL
197
+ const bootstrap = await bootstrapSubscriber({
198
+ mcConvexUrl: config.convexUrl,
199
+ mcApiToken: config.apiToken,
200
+ gatewayId: config.gatewayId,
201
+ });
202
+ if (!bootstrap) {
203
+ ctx.logger.error("mission-control: Failed to bootstrap task subscriber");
204
+ return;
205
+ }
206
+ subscriber = new TaskSubscriber({
207
+ convexUrl: bootstrap.convexUrl,
208
+ gatewayId: bootstrap.gatewayId,
209
+ pollIntervalMs: 3000,
210
+ logger: {
211
+ info: (msg, data) => ctx.logger.info(`${msg} ${JSON.stringify(data ?? {})}`),
212
+ error: (msg, data) => ctx.logger.error(`${msg} ${JSON.stringify(data ?? {})}`),
213
+ warn: (msg, data) => ctx.logger.warn(`${msg} ${JSON.stringify(data ?? {})}`),
214
+ },
215
+ onTask: async (assignment) => {
216
+ ctx.logger.info(`Received task: ${assignment.taskId}`);
217
+ await triggerAgentViaLoopback({
218
+ sessionKey: assignment.sessionKey,
219
+ message: assignment.message,
220
+ agentId: assignment.agentId,
221
+ runId: assignment.runId,
222
+ });
223
+ },
224
+ });
225
+ // Start polling (runs in background)
226
+ void subscriber.start();
227
+ ctx.logger.info("mission-control: Task subscriber started");
228
+ },
229
+ stop: async (ctx) => {
230
+ if (subscriber) {
231
+ subscriber.stop();
232
+ subscriber = null;
233
+ ctx.logger.info("mission-control: Task subscriber stopped");
234
+ }
235
+ },
236
+ };
237
+ }
238
+ // Legacy startTaskSubscriber function removed - now using registerService pattern
239
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Task Subscriber for BYOB (Bring Your Own Bot)
3
+ *
4
+ * Polls Convex for pending task assignments and triggers agent runs.
5
+ * This enables local/BYOB gateways to receive tasks without requiring
6
+ * inbound HTTP connectivity.
7
+ */
8
+ interface TaskAssignment {
9
+ _id: string;
10
+ taskId: string;
11
+ message: string;
12
+ sessionKey: string;
13
+ gatewayId: string;
14
+ agentId?: string;
15
+ status: "pending" | "claimed" | "completed" | "expired";
16
+ runId?: string;
17
+ tenantId: string;
18
+ createdAt: number;
19
+ expiresAt: number;
20
+ }
21
+ export interface TaskSubscriberConfig {
22
+ convexUrl: string;
23
+ gatewayId: string;
24
+ pollIntervalMs?: number;
25
+ onTask: (assignment: TaskAssignment & {
26
+ runId: string;
27
+ }) => Promise<void>;
28
+ logger?: {
29
+ info: (msg: string, data?: Record<string, unknown>) => void;
30
+ error: (msg: string, data?: Record<string, unknown>) => void;
31
+ warn: (msg: string, data?: Record<string, unknown>) => void;
32
+ };
33
+ }
34
+ export declare class TaskSubscriber {
35
+ private client;
36
+ private gatewayId;
37
+ private pollIntervalMs;
38
+ private running;
39
+ private onTask;
40
+ private logger;
41
+ constructor(config: TaskSubscriberConfig);
42
+ start(): Promise<void>;
43
+ stop(): void;
44
+ private pollOnce;
45
+ private sleep;
46
+ }
47
+ /**
48
+ * Bootstrap the subscriber by authenticating with Convex and getting config.
49
+ */
50
+ export declare function bootstrapSubscriber(config: {
51
+ mcConvexUrl: string;
52
+ mcApiToken: string;
53
+ gatewayId: string;
54
+ }): Promise<{
55
+ convexUrl: string;
56
+ gatewayId: string;
57
+ } | null>;
58
+ export {};
59
+ //# sourceMappingURL=subscriber.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriber.d.ts","sourceRoot":"","sources":["../src/subscriber.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,UAAU,cAAc;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;IACxD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAYD,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,CAAC,UAAU,EAAE,cAAc,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;QAC5D,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;QAC7D,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;KAC7D,CAAC;CACH;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,MAAM,CAA8C;gBAEhD,MAAM,EAAE,oBAAoB;IAYlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA0B5B,IAAI,IAAI,IAAI;YAIE,QAAQ;IAiEtB,OAAO,CAAC,KAAK;CAGd;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAkC3D"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Task Subscriber for BYOB (Bring Your Own Bot)
3
+ *
4
+ * Polls Convex for pending task assignments and triggers agent runs.
5
+ * This enables local/BYOB gateways to receive tasks without requiring
6
+ * inbound HTTP connectivity.
7
+ */
8
+ import { ConvexHttpClient } from "convex/browser";
9
+ // Function references for Convex API (will be constructed at runtime)
10
+ const PENDING_FOR_GATEWAY = "taskAssignments:pendingForGateway";
11
+ const CLAIM_ASSIGNMENT = "taskAssignments:claimAssignment";
12
+ const COMPLETE_ASSIGNMENT = "taskAssignments:completeAssignment";
13
+ export class TaskSubscriber {
14
+ client;
15
+ gatewayId;
16
+ pollIntervalMs;
17
+ running = false;
18
+ onTask;
19
+ logger;
20
+ constructor(config) {
21
+ this.client = new ConvexHttpClient(config.convexUrl);
22
+ this.gatewayId = config.gatewayId;
23
+ this.pollIntervalMs = config.pollIntervalMs ?? 3000;
24
+ this.onTask = config.onTask;
25
+ this.logger = config.logger ?? {
26
+ info: (msg, data) => console.log(`[mc-subscriber] ${msg}`, data ?? ""),
27
+ error: (msg, data) => console.error(`[mc-subscriber] ${msg}`, data ?? ""),
28
+ warn: (msg, data) => console.warn(`[mc-subscriber] ${msg}`, data ?? ""),
29
+ };
30
+ }
31
+ async start() {
32
+ if (this.running) {
33
+ this.logger.warn("Subscriber already running");
34
+ return;
35
+ }
36
+ this.running = true;
37
+ this.logger.info("Starting task subscriber", {
38
+ gatewayId: this.gatewayId,
39
+ pollIntervalMs: this.pollIntervalMs,
40
+ });
41
+ while (this.running) {
42
+ try {
43
+ await this.pollOnce();
44
+ }
45
+ catch (err) {
46
+ this.logger.error("Poll error", {
47
+ error: err instanceof Error ? err.message : String(err),
48
+ });
49
+ }
50
+ await this.sleep(this.pollIntervalMs);
51
+ }
52
+ this.logger.info("Task subscriber stopped");
53
+ }
54
+ stop() {
55
+ this.running = false;
56
+ }
57
+ async pollOnce() {
58
+ // Query for pending assignments
59
+ const pending = await this.client.query(PENDING_FOR_GATEWAY, { gatewayId: this.gatewayId });
60
+ if (pending.length === 0)
61
+ return;
62
+ this.logger.info(`Found ${pending.length} pending assignment(s)`);
63
+ for (const assignment of pending) {
64
+ // Generate a unique run ID
65
+ const runId = crypto.randomUUID();
66
+ // Try to claim the assignment (atomic)
67
+ const result = await this.client.mutation(CLAIM_ASSIGNMENT, { assignmentId: assignment._id, runId });
68
+ if (!result.ok) {
69
+ this.logger.info("Assignment already claimed", {
70
+ assignmentId: assignment._id,
71
+ reason: result.reason,
72
+ });
73
+ continue;
74
+ }
75
+ this.logger.info("Claimed assignment", {
76
+ assignmentId: assignment._id,
77
+ taskId: assignment.taskId,
78
+ runId,
79
+ });
80
+ // Execute the task
81
+ try {
82
+ await this.onTask({ ...assignment, runId });
83
+ // Mark as completed
84
+ await this.client.mutation(COMPLETE_ASSIGNMENT, { assignmentId: assignment._id });
85
+ this.logger.info("Assignment completed", {
86
+ assignmentId: assignment._id,
87
+ taskId: assignment.taskId,
88
+ });
89
+ }
90
+ catch (err) {
91
+ this.logger.error("Task execution failed", {
92
+ assignmentId: assignment._id,
93
+ taskId: assignment.taskId,
94
+ error: err instanceof Error ? err.message : String(err),
95
+ });
96
+ // Still mark as completed (with error state logged)
97
+ await this.client.mutation(COMPLETE_ASSIGNMENT, { assignmentId: assignment._id }).catch(() => { });
98
+ }
99
+ }
100
+ }
101
+ sleep(ms) {
102
+ return new Promise((resolve) => setTimeout(resolve, ms));
103
+ }
104
+ }
105
+ /**
106
+ * Bootstrap the subscriber by authenticating with Convex and getting config.
107
+ */
108
+ export async function bootstrapSubscriber(config) {
109
+ try {
110
+ const response = await fetch(`${config.mcConvexUrl}/gateway/subscribe`, {
111
+ method: "POST",
112
+ headers: {
113
+ "Authorization": `Bearer ${config.mcApiToken}`,
114
+ "Content-Type": "application/json",
115
+ },
116
+ body: JSON.stringify({ gatewayId: config.gatewayId }),
117
+ });
118
+ if (!response.ok) {
119
+ const text = await response.text().catch(() => "");
120
+ console.error("[mc-subscriber] Bootstrap failed:", response.status, text);
121
+ return null;
122
+ }
123
+ const data = await response.json();
124
+ if (!data.ok) {
125
+ console.error("[mc-subscriber] Bootstrap error:", data.error);
126
+ return null;
127
+ }
128
+ return {
129
+ convexUrl: data.convexUrl,
130
+ gatewayId: data.gatewayId,
131
+ };
132
+ }
133
+ catch (err) {
134
+ console.error("[mc-subscriber] Bootstrap fetch error:", err instanceof Error ? err.message : err);
135
+ return null;
136
+ }
137
+ }
138
+ //# sourceMappingURL=subscriber.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subscriber.js","sourceRoot":"","sources":["../src/subscriber.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: mission-control
3
+ description: "Sync agent lifecycle events to Mission Control dashboard via Convex"
4
+ metadata:
5
+ {
6
+ "openclaw":
7
+ {
8
+ "emoji": "📊",
9
+ "events": ["gateway:startup", "agent:bootstrap"],
10
+ "always": true,
11
+ },
12
+ }
13
+ ---
14
+
15
+ # Mission Control Integration
16
+
17
+ Sends agent lifecycle events to the Mission Control Convex backend for real-time task tracking.
18
+ Uses authenticated HTTP requests to the hosted Convex `/openclaw/event` endpoint (Bearer token auth via MC_API_TOKEN).