@gholl-studio/pier-connector 0.1.0 → 0.1.2

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +57 -24
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gholl-studio/pier-connector",
3
3
  "author": "gholl",
4
- "version": "0.1.0",
4
+ "version": "0.1.2",
5
5
  "description": "OpenClaw plugin that connects to the Pier job marketplace. Automatically fetches, executes, and reports distributed tasks for rewards.",
6
6
  "type": "module",
7
7
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -42,14 +42,15 @@ export default function register(api) {
42
42
 
43
43
  /** Connection status for the /pier command */
44
44
  let connectionStatus = 'disconnected';
45
+ const jobSubscriptions = new Map();
46
+ const jobStopTimeouts = new Map();
47
+ const activeNodeJobs = new Map();
48
+
45
49
  let jobsReceived = 0;
46
50
  let jobsCompleted = 0;
47
51
  let jobsFailed = 0;
48
52
  let connectedAt = null;
49
-
50
- /** @type {Map<string, import('@nats-io/transport-node').Subscription>} */
51
- const jobSubscriptions = new Map();
52
- const jobStopTimeouts = new Map();
53
+ let lastHeartbeatError = null;
53
54
 
54
55
  // ── resolve plugin config ──────────────────────────────────────────
55
56
 
@@ -117,8 +118,10 @@ const jobStopTimeouts = new Map();
117
118
  }
118
119
 
119
120
  const data = await resp.json();
121
+ lastHeartbeatError = null;
120
122
  return data.nats_config || null;
121
123
  } catch (err) {
124
+ lastHeartbeatError = err.message;
122
125
  logger.warn(`[pier-connector] Heartbeat failed: ${err.message}`);
123
126
  return null;
124
127
  }
@@ -148,15 +151,10 @@ const jobStopTimeouts = new Map();
148
151
  accountId: accountId ?? 'default',
149
152
  enabled: true,
150
153
  },
154
+ isConfigured: (account) => Boolean(account.nodeId && account.secretKey) || Boolean(account.privateKey),
151
155
  },
152
156
 
153
157
  setup: {
154
- checkAccountStatus: async ({ accountId }) => {
155
- if (connectionStatus === 'connected') return { status: 'connected' };
156
- if (connectionStatus === 'error') return { status: 'error', details: 'NATS connection error' };
157
- if (connectionStatus === 'connecting') return { status: 'connecting' };
158
- return { status: 'disconnected', details: connectionStatus };
159
- },
160
158
  applyAccountConfig: ({ cfg, accountId, input }) => {
161
159
  const draft = structuredClone(cfg);
162
160
  draft.channels = draft.channels || {};
@@ -188,7 +186,15 @@ const jobStopTimeouts = new Map();
188
186
  * Send a reply text back through the NATS response.
189
187
  * This is called by OpenClaw's agent after processing a job.
190
188
  */
191
- sendText: async ({ text, metadata }) => {
189
+ sendText: async (ctx) => {
190
+ const text = ctx.text;
191
+ let metadata = ctx.metadata;
192
+
193
+ if (!metadata && ctx.to) {
194
+ const toId = ctx.to.replace(/^pier:/, '');
195
+ metadata = activeNodeJobs.get(toId);
196
+ }
197
+
192
198
  const jobId = metadata?.pierJobId;
193
199
  const msg = metadata?.pierNatsMsg;
194
200
  const isRealtimeMsg = metadata?.isRealtimeMsg;
@@ -244,7 +250,7 @@ const jobStopTimeouts = new Map();
244
250
  jobSubscriptions.delete(jobId);
245
251
  jobStopTimeouts.delete(jobId);
246
252
  }
247
- }, 60000); // 60s grace period
253
+ }, 3600000); // 1 hour inactivity timeout
248
254
 
249
255
  jobStopTimeouts.set(jobId, timeout);
250
256
  }
@@ -253,6 +259,25 @@ const jobStopTimeouts = new Map();
253
259
  return { ok: true };
254
260
  },
255
261
  },
262
+
263
+ status: {
264
+ defaultRuntime: {
265
+ accountId: 'default',
266
+ running: false,
267
+ connected: false,
268
+ },
269
+ buildAccountSnapshot: ({ account }) => {
270
+ return {
271
+ accountId: account.accountId,
272
+ name: account.name,
273
+ enabled: account.enabled,
274
+ configured: Boolean(account.nodeId && account.secretKey) || Boolean(account.privateKey),
275
+ running: connectionStatus === 'connected' || connectionStatus === 'connecting',
276
+ connected: connectionStatus === 'connected' && !lastHeartbeatError,
277
+ lastError: lastHeartbeatError,
278
+ };
279
+ }
280
+ },
256
281
  };
257
282
 
258
283
  api.registerChannel({ plugin: pierChannel });
@@ -473,15 +498,18 @@ const jobStopTimeouts = new Map();
473
498
  const content = msgPayload.content;
474
499
  logger.info(`[pier-connector] 💬 Message for job ${jobId}: "${truncate(content, 40)}"`);
475
500
 
501
+ const senderCore = msgPayload.sender_id;
502
+
503
+ activeNodeJobs.set(senderCore, {
504
+ pierJobId: jobId,
505
+ isRealtimeMsg: true
506
+ });
507
+
476
508
  await api.runtime.sendIncoming({
477
509
  channelId: 'pier',
478
510
  accountId: config.accountId || 'default',
479
- senderId: `pier:${msgPayload.sender_id}`,
511
+ senderId: `pier:${senderCore}`,
480
512
  text: content,
481
- metadata: {
482
- pierJobId: jobId,
483
- isRealtimeMsg: true
484
- }
485
513
  });
486
514
  }
487
515
  } catch (err) {
@@ -537,18 +565,22 @@ const jobStopTimeouts = new Map();
537
565
  logger.info(`[pier-connector] 📥 Received job ${job.id}: "${truncate(job.task, 60)}"`);
538
566
 
539
567
  try {
568
+ const senderCore = job.meta?.sender ?? 'anonymous';
569
+
570
+ activeNodeJobs.set(senderCore, {
571
+ pierJobId: job.id,
572
+ pierNatsMsg: msg,
573
+ pierStartTime: startTime,
574
+ pierMeta: job.meta,
575
+ isRealtimeMsg: false
576
+ });
577
+
540
578
  const inbound = {
541
579
  channelId: 'pier',
542
580
  accountId: config.accountId || 'default',
543
- senderId: `pier:${job.meta?.sender ?? 'anonymous'}`,
581
+ senderId: `pier:${senderCore}`,
544
582
  text: job.task,
545
583
  assignedAgentId: config.agentId || undefined,
546
- metadata: {
547
- pierJobId: job.id,
548
- pierNatsMsg: msg,
549
- pierStartTime: startTime,
550
- pierMeta: job.meta,
551
- },
552
584
  };
553
585
 
554
586
  if (job.systemPrompt) inbound.systemPrompt = job.systemPrompt;
@@ -786,6 +818,7 @@ const jobStopTimeouts = new Map();
786
818
  `• Publish: ${config.publishSubject}`,
787
819
  `• Uptime: ${uptime}`,
788
820
  `• Jobs: ${jobsReceived} received, ${jobsCompleted} completed, ${jobsFailed} failed`,
821
+ lastHeartbeatError ? `• \x1b[31mHeartbeat Error: ${lastHeartbeatError}\x1b[0m` : `• Heartbeat: OK`,
789
822
  ].join('\n'),
790
823
  };
791
824
  },