rentabots-sdk 1.7.26 → 1.7.29

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/dist/index.js CHANGED
@@ -71,7 +71,7 @@ exports.MessageSchema = zod_1.z.object({
71
71
  })
72
72
  });
73
73
  // --- CORE SDK ENGINE ---
74
- let SDK_VERSION = '1.7.26'; // fallback when package.json is unavailable
74
+ let SDK_VERSION = '1.7.29'; // fallback when package.json is unavailable
75
75
  try {
76
76
  const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
77
77
  SDK_VERSION = pkg.version;
package/init.js CHANGED
@@ -148,6 +148,13 @@ async function main() {
148
148
  queen.workers.delete(job.id);
149
149
  try { fs.unlinkSync(jobDataPath); } catch {}
150
150
  await pushLog('WARN', 'Worker exited for mission ' + job.id + ' (code=' + code + ', signal=' + (signal || 'none') + ')');
151
+
152
+ if (code === 42 && queen.activeMissions.has(job.id) && !queen.workers.has(job.id)) {
153
+ await pushLog('INFO', 'Worker requested controlled restart for ' + job.id + '; respawning...');
154
+ setTimeout(() => {
155
+ spawnMissionWorker(job, 'controlled-restart').catch(() => {});
156
+ }, 1200);
157
+ }
151
158
  });
152
159
 
153
160
  worker.on('error', async (err) => {
@@ -245,7 +252,8 @@ const job = JSON.parse(fs.readFileSync(jobDataPath, 'utf8'));
245
252
 
246
253
  function inferContract(job) {
247
254
  const text = ((job.title || '') + ' ' + (job.description || '')).toLowerCase();
248
- const adapter = text.includes('api') ? 'api' : text.includes('csv') || text.includes('dataset') || text.includes('etl') ? 'data' : text.includes('landing page') || text.includes('frontend') || text.includes('ui') || text.includes('web') ? 'web' : text.includes('docs') || text.includes('documentation') ? 'docs' : 'script';
255
+ const hasApiWord = /(^|[^a-z0-9])api([^a-z0-9]|$)/i.test(text) || /endpoint|rest\b|graphql\b/.test(text);
256
+ const adapter = hasApiWord ? 'api' : text.includes('csv') || text.includes('dataset') || text.includes('etl') ? 'data' : text.includes('landing page') || text.includes('frontend') || text.includes('ui') || text.includes('web') ? 'web' : text.includes('docs') || text.includes('documentation') ? 'docs' : 'script';
249
257
  const contract = {
250
258
  adapter,
251
259
  taskType: adapter,
@@ -456,7 +464,13 @@ async function main() {
456
464
  issues.push('whitespace cleanup requirement not reflected in output');
457
465
  }
458
466
  for (const d of contract.deliverables || []) {
459
- if (!hasFile((f) => f.toLowerCase() === String(d).toLowerCase())) {
467
+ const dl = String(d).toLowerCase();
468
+ let ok = false;
469
+ if (dl === 'readme.md') ok = hasFile((f) => /^readme(\..+)?\.md$/i.test(f) || /^readme\.md$/i.test(f));
470
+ else if (dl === 'solution.py') ok = hasFile((f) => f.toLowerCase().endsWith('.py'));
471
+ else if (dl === 'openapi-or-endpoint-docs.md') ok = hasFile((f) => /openapi|endpoint|api.*doc/i.test(f));
472
+ else ok = hasFile((f) => f.toLowerCase() === dl);
473
+ if (!ok) {
460
474
  issues.push('missing contract deliverable: ' + d);
461
475
  }
462
476
  }
@@ -497,8 +511,43 @@ async function main() {
497
511
 
498
512
  if (issues.length > 0) {
499
513
  await agent.setProgress(job.id, 70);
500
- await agent.sendMessage(job.id, '⚠️ Contract QA failed: ' + issues.slice(0, 4).join('; ') + '. Revising now.');
501
- return;
514
+ await agent.sendMessage(job.id, '⚠️ Contract QA failed: ' + issues.slice(0, 4).join('; ') + '. Running targeted OpenClaw repair pass now.');
515
+
516
+ const repairPath = path.join(workDir, '.repair_count');
517
+ let repairCount = 0;
518
+ try { repairCount = Number(fs.readFileSync(repairPath, 'utf8') || '0'); } catch (_) {}
519
+ repairCount += 1;
520
+ fs.writeFileSync(repairPath, String(repairCount));
521
+
522
+ if (repairCount > 6) {
523
+ await agent.sendMessage(job.id, '🚨 OpenClaw repair limit reached. Please send one concrete clarification so I can continue with a precise fix.');
524
+ return;
525
+ }
526
+
527
+ const repairPrompt = [
528
+ 'Repair the existing workspace to satisfy missing deterministic gates.',
529
+ 'Do not explain. Edit files now and finish.',
530
+ 'MISSING GATES:',
531
+ ...issues.map(i => '- ' + i),
532
+ '',
533
+ 'MISSION TITLE: ' + job.title,
534
+ 'MISSION DESCRIPTION: ' + job.description,
535
+ ].join('\n');
536
+
537
+ const repairArg = JSON.stringify(repairPrompt);
538
+ const repairCmds = [
539
+ 'openclaw sessions spawn --task ' + repairArg,
540
+ 'openclaw sessions_spawn --task ' + repairArg,
541
+ ];
542
+ for (const rcmd of repairCmds) {
543
+ const r = await agent.execute(job.id, rcmd, { timeout: 900000, shell: true });
544
+ const out = (r.output || '').toLowerCase();
545
+ const pseudo = out.includes('usage: openclaw') || out.includes('unknown command') || out.includes('pass --to');
546
+ if (r.exitCode === 0 && !pseudo) break;
547
+ }
548
+
549
+ await agent.sendMessage(job.id, '🔁 OpenClaw repair pass complete. Re-queueing worker validation pass now.');
550
+ process.exit(42);
502
551
  }
503
552
 
504
553
  if (fallbackGenerated) {
@@ -614,28 +663,29 @@ async function main() {
614
663
  const snippet = lastOutput.slice(-500) || 'No output captured';
615
664
  console.error("Worker Error:", snippet);
616
665
 
617
- // Fail-safe: keep user informed + attach diagnostic report + fallback draft
666
+ const failPath = path.join(workDir, '.openclaw_fail_count');
667
+ let fails = 0;
668
+ try { fails = Number(fs.readFileSync(failPath, 'utf8') || '0'); } catch (_) {}
669
+ fails += 1;
670
+ fs.writeFileSync(failPath, String(fails));
671
+
672
+ if (fails <= 5) {
673
+ await agent.setProgress(job.id, 25);
674
+ await agent.sendMessage(job.id, '⚠️ OpenClaw run failed (attempt ' + fails + '). Re-queueing OpenClaw-only retry...');
675
+ await new Promise(r => setTimeout(r, 5000));
676
+ process.exit(42);
677
+ }
678
+
679
+ // Fail-safe report only after OpenClaw retry budget exhausted
618
680
  await agent.setProgress(job.id, 25);
619
- await agent.sendMessage(job.id, "⚠️ OpenClaw run failed. Switching to backup adapter mode now so you don't wait idle.");
681
+ await agent.sendMessage(job.id, "🚨 OpenClaw execution repeatedly failed. Please send one concrete clarification and I will continue immediately.");
620
682
 
621
683
  try {
622
- generateAdapterFallbackFiles(workDir, job, contract);
623
-
624
684
  const repoRes = await agent.getRepo(job.id);
625
685
  if (!repoRes.success || !repoRes.exists) {
626
686
  await agent.createRepo(job.id, 'mission-recovery-' + job.id.slice(0, 8));
627
687
  }
628
688
 
629
- // Upload fallback draft artifacts first
630
- const fallbackFiles = fs.readdirSync(workDir).filter((f) => fs.statSync(path.join(workDir, f)).isFile());
631
- for (const f of fallbackFiles) {
632
- try {
633
- const full = path.join(workDir, f);
634
- const content = fs.readFileSync(full, 'utf8');
635
- await agent.uploadRepoFile(job.id, f, content, false);
636
- } catch (_) {}
637
- }
638
-
639
689
  const report = [
640
690
  '# FAILSAFE_REPORT',
641
691
  '',
package/init_templates.js CHANGED
@@ -117,6 +117,13 @@ async function main() {
117
117
  queen.workers.delete(job.id);
118
118
  try { fs.unlinkSync(jobDataPath); } catch {}
119
119
  await pushLog('WARN', 'Worker exited for mission ' + job.id + ' (code=' + code + ', signal=' + (signal || 'none') + ')');
120
+
121
+ if (code === 42 && queen.activeMissions.has(job.id) && !queen.workers.has(job.id)) {
122
+ await pushLog('INFO', 'Worker requested controlled restart for ' + job.id + '; respawning...');
123
+ setTimeout(() => {
124
+ spawnMissionWorker(job, 'controlled-restart').catch(() => {});
125
+ }, 1200);
126
+ }
120
127
  });
121
128
 
122
129
  worker.on('error', async (err) => {
@@ -221,7 +228,8 @@ const job = JSON.parse(fs.readFileSync(jobDataPath, 'utf8'));
221
228
 
222
229
  function inferContract(job) {
223
230
  const text = ((job.title || '') + ' ' + (job.description || '')).toLowerCase();
224
- const adapter = text.includes('api') ? 'api' : text.includes('csv') || text.includes('dataset') || text.includes('etl') ? 'data' : text.includes('landing page') || text.includes('frontend') || text.includes('ui') || text.includes('web') ? 'web' : text.includes('docs') || text.includes('documentation') ? 'docs' : 'script';
231
+ const hasApiWord = /(^|[^a-z0-9])api([^a-z0-9]|$)/i.test(text) || /endpoint|rest\b|graphql\b/.test(text);
232
+ const adapter = hasApiWord ? 'api' : text.includes('csv') || text.includes('dataset') || text.includes('etl') ? 'data' : text.includes('landing page') || text.includes('frontend') || text.includes('ui') || text.includes('web') ? 'web' : text.includes('docs') || text.includes('documentation') ? 'docs' : 'script';
225
233
  const contract = {
226
234
  adapter,
227
235
  taskType: adapter,
@@ -441,7 +449,13 @@ async function main() {
441
449
  issues.push('whitespace cleanup requirement not reflected in output');
442
450
  }
443
451
  for (const d of contract.deliverables || []) {
444
- if (!hasFile((f) => f.toLowerCase() === String(d).toLowerCase())) {
452
+ const dl = String(d).toLowerCase();
453
+ let ok = false;
454
+ if (dl === 'readme.md') ok = hasFile((f) => /^readme(\..+)?\.md$/i.test(f) || /^readme\.md$/i.test(f));
455
+ else if (dl === 'solution.py') ok = hasFile((f) => f.toLowerCase().endsWith('.py'));
456
+ else if (dl === 'openapi-or-endpoint-docs.md') ok = hasFile((f) => /openapi|endpoint|api.*doc/i.test(f));
457
+ else ok = hasFile((f) => f.toLowerCase() === dl);
458
+ if (!ok) {
445
459
  issues.push('missing contract deliverable: ' + d);
446
460
  }
447
461
  }
@@ -482,8 +496,43 @@ async function main() {
482
496
 
483
497
  if (issues.length > 0) {
484
498
  await agent.setProgress(job.id, 70);
485
- await agent.sendMessage(job.id, '⚠️ Contract QA failed: ' + issues.slice(0, 4).join('; ') + '. Revising now.');
486
- return;
499
+ await agent.sendMessage(job.id, '⚠️ Contract QA failed: ' + issues.slice(0, 4).join('; ') + '. Running targeted OpenClaw repair pass now.');
500
+
501
+ const repairPath = path.join(workDir, '.repair_count');
502
+ let repairCount = 0;
503
+ try { repairCount = Number(fs.readFileSync(repairPath, 'utf8') || '0'); } catch (_) {}
504
+ repairCount += 1;
505
+ fs.writeFileSync(repairPath, String(repairCount));
506
+
507
+ if (repairCount > 6) {
508
+ await agent.sendMessage(job.id, '🚨 OpenClaw repair limit reached. Please send one concrete clarification so I can continue with a precise fix.');
509
+ return;
510
+ }
511
+
512
+ const repairPrompt = [
513
+ 'Repair the existing workspace to satisfy missing deterministic gates.',
514
+ 'Do not explain. Edit files now and finish.',
515
+ 'MISSING GATES:',
516
+ ...issues.map(i => '- ' + i),
517
+ '',
518
+ 'MISSION TITLE: ' + job.title,
519
+ 'MISSION DESCRIPTION: ' + job.description,
520
+ ].join('\n');
521
+
522
+ const repairArg = JSON.stringify(repairPrompt);
523
+ const repairCmds = [
524
+ 'openclaw sessions spawn --task ' + repairArg,
525
+ 'openclaw sessions_spawn --task ' + repairArg,
526
+ ];
527
+ for (const rcmd of repairCmds) {
528
+ const r = await agent.execute(job.id, rcmd, { timeout: 900000, shell: true });
529
+ const out = (r.output || '').toLowerCase();
530
+ const pseudo = out.includes('usage: openclaw') || out.includes('unknown command') || out.includes('pass --to');
531
+ if (r.exitCode === 0 && !pseudo) break;
532
+ }
533
+
534
+ await agent.sendMessage(job.id, '🔁 OpenClaw repair pass complete. Re-queueing worker validation pass now.');
535
+ process.exit(42);
487
536
  }
488
537
 
489
538
  if (fallbackGenerated) {
@@ -599,28 +648,29 @@ async function main() {
599
648
  const snippet = lastOutput.slice(-500) || 'No output captured';
600
649
  console.error("Worker Error:", snippet);
601
650
 
602
- // Fail-safe: keep user informed + attach diagnostic report + fallback draft
651
+ const failPath = path.join(workDir, '.openclaw_fail_count');
652
+ let fails = 0;
653
+ try { fails = Number(fs.readFileSync(failPath, 'utf8') || '0'); } catch (_) {}
654
+ fails += 1;
655
+ fs.writeFileSync(failPath, String(fails));
656
+
657
+ if (fails <= 5) {
658
+ await agent.setProgress(job.id, 25);
659
+ await agent.sendMessage(job.id, '⚠️ OpenClaw run failed (attempt ' + fails + '). Re-queueing OpenClaw-only retry...');
660
+ await new Promise(r => setTimeout(r, 5000));
661
+ process.exit(42);
662
+ }
663
+
664
+ // Fail-safe report only after OpenClaw retry budget exhausted
603
665
  await agent.setProgress(job.id, 25);
604
- await agent.sendMessage(job.id, "⚠️ OpenClaw run failed. Switching to backup adapter mode now so you don't wait idle.");
666
+ await agent.sendMessage(job.id, "🚨 OpenClaw execution repeatedly failed. Please send one concrete clarification and I will continue immediately.");
605
667
 
606
668
  try {
607
- generateAdapterFallbackFiles(workDir, job, contract);
608
-
609
669
  const repoRes = await agent.getRepo(job.id);
610
670
  if (!repoRes.success || !repoRes.exists) {
611
671
  await agent.createRepo(job.id, 'mission-recovery-' + job.id.slice(0, 8));
612
672
  }
613
673
 
614
- // Upload fallback draft artifacts first
615
- const fallbackFiles = fs.readdirSync(workDir).filter((f) => fs.statSync(path.join(workDir, f)).isFile());
616
- for (const f of fallbackFiles) {
617
- try {
618
- const full = path.join(workDir, f);
619
- const content = fs.readFileSync(full, 'utf8');
620
- await agent.uploadRepoFile(job.id, f, content, false);
621
- } catch (_) {}
622
- }
623
-
624
674
  const report = [
625
675
  '# FAILSAFE_REPORT',
626
676
  '',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rentabots-sdk",
3
- "version": "1.7.26",
3
+ "version": "1.7.29",
4
4
  "description": "Official SDK for RentaBots AI Agent Marketplace",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",