@jiggai/recipes 0.4.65 → 0.4.68

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/index.ts CHANGED
@@ -243,7 +243,6 @@ const recipesPlugin = {
243
243
  };
244
244
 
245
245
  api.on("message_received" as never, approvalReplyHandler as never, { priority: 50 } as unknown as { priority: number });
246
- api.on("message:received" as never, approvalReplyHandler as never, { priority: 50 } as unknown as { priority: number });
247
246
 
248
247
 
249
248
  // On plugin load, ensure multi-agent config has an explicit agents.list with main at top.
@@ -2,7 +2,7 @@
2
2
  "id": "recipes",
3
3
  "name": "Recipes",
4
4
  "description": "Markdown recipes that scaffold agents and teams (workspace-local).",
5
- "version": "0.4.65",
5
+ "version": "0.4.68",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jiggai/recipes",
3
- "version": "0.4.65",
3
+ "version": "0.4.68",
4
4
  "description": "ClawRecipes plugin for OpenClaw (markdown recipes -> scaffold agents/teams)",
5
5
  "main": "index.ts",
6
6
  "type": "commonjs",
@@ -1,4 +1,5 @@
1
1
  import fs from 'node:fs/promises';
2
+ import os from 'node:os';
2
3
  import path from 'node:path';
3
4
  import crypto from 'node:crypto';
4
5
  import type { OpenClawPluginApi } from 'openclaw/plugin-sdk';
@@ -598,6 +599,7 @@ export async function runWorkflowWorkerTick(api: OpenClawPluginApi, opts: {
598
599
  const lockInfo = {
599
600
  workerId,
600
601
  pid: process.pid,
602
+ host: os.hostname(),
601
603
  taskId: task.id,
602
604
  claimedAt: claimedAtIso,
603
605
  ttlMs: DEFAULT_LOCK_TTL_MS,
@@ -614,7 +616,7 @@ export async function runWorkflowWorkerTick(api: OpenClawPluginApi, opts: {
614
616
  let unlocked = false;
615
617
  try {
616
618
  const raw = await readTextFile(lockPath);
617
- const parsed = JSON.parse(raw) as { claimedAt?: string; ttlMs?: number; expiresAt?: string };
619
+ const parsed = JSON.parse(raw) as { claimedAt?: string; ttlMs?: number; expiresAt?: string; host?: string; pid?: number };
618
620
 
619
621
  const expiresAtMs = parsed?.expiresAt ? Date.parse(String(parsed.expiresAt)) : NaN;
620
622
  const claimedAtMs = parsed?.claimedAt ? Date.parse(String(parsed.claimedAt)) : NaN;
@@ -635,7 +637,34 @@ export async function runWorkflowWorkerTick(api: OpenClawPluginApi, opts: {
635
637
  : NaN;
636
638
 
637
639
  const stale = Number.isFinite(effectiveExpiryMs) && Date.now() > effectiveExpiryMs;
638
- if (stale) {
640
+
641
+ // Same-host PID liveness check. If the lock recorded a host that
642
+ // matches ours and a pid that is no longer alive, the holder
643
+ // crashed or was killed; reclaim now instead of waiting out the
644
+ // full TTL (which can be tens of minutes for long LLM nodes).
645
+ //
646
+ // Cross-host locks are NEVER reclaimed via PID check — a remote
647
+ // PID may collide with a live local PID and produce a false
648
+ // "alive" reading, but we'd rather under-reclaim than steal a
649
+ // legitimately-held lock from another machine.
650
+ //
651
+ // Locks lacking host or pid (older format) skip this branch and
652
+ // fall through to TTL-only behavior.
653
+ let dead = false;
654
+ const sameHost = typeof parsed?.host === 'string' && parsed.host === os.hostname();
655
+ const lockPid = typeof parsed?.pid === 'number' && Number.isFinite(parsed.pid) ? parsed.pid : NaN;
656
+ if (sameHost && Number.isFinite(lockPid) && lockPid > 0) {
657
+ try {
658
+ process.kill(lockPid, 0);
659
+ // Process exists; treat lock as held.
660
+ } catch (err) {
661
+ if ((err as NodeJS.ErrnoException)?.code === 'ESRCH') dead = true;
662
+ // EPERM means the process exists but we can't signal it (e.g.,
663
+ // owned by another user); fall through to TTL-only behavior.
664
+ }
665
+ }
666
+
667
+ if (stale || dead) {
639
668
  await fs.unlink(lockPath);
640
669
  unlocked = true;
641
670
  }