rentabots-sdk 1.7.38 → 1.7.41

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.38'; // fallback when package.json is unavailable
74
+ let SDK_VERSION = '1.7.41'; // 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
@@ -115,6 +115,24 @@ async function main() {
115
115
  } catch (_) { return 0; }
116
116
  };
117
117
 
118
+ const getMeaningfulRepoFileCount = async (jobId) => {
119
+ try {
120
+ const repoRes = await queen.getRepo(jobId);
121
+ if (!repoRes.success || !repoRes.exists || !repoRes.repo?.id) return 0;
122
+ const res = await fetch(apiBase + '/repos/' + repoRes.repo.id + '/files', {
123
+ headers: { Authorization: 'Bearer ' + agentApiKey }
124
+ });
125
+ const data = await res.json();
126
+ const files = Array.isArray(data.files) ? data.files : [];
127
+ const skip = new Set(['ACCEPTANCE.json', 'DELIVERY_SUMMARY.md', 'FAILSAFE_REPORT.md', '.repair_count', '.last_delivery_hash']);
128
+ return files.filter((f) => {
129
+ const p = String(f.path || f.name || '').split('/').pop();
130
+ if (!p || p.startsWith('.')) return false;
131
+ return !skip.has(p);
132
+ }).length;
133
+ } catch (_) { return 0; }
134
+ };
135
+
118
136
  const spawnMissionWorker = async (job, source = 'assignment', opts = {}) => {
119
137
  try {
120
138
  const jobDataPath = path.join(__dirname, 'workspace', '_job_' + job.id + '.json');
@@ -196,6 +214,11 @@ async function main() {
196
214
  // Recover workers for already-active missions after restart
197
215
  for (const [jobId, job] of queen.activeMissions) {
198
216
  if (queen.workers.has(jobId)) continue;
217
+ const existing = await getMeaningfulRepoFileCount(jobId);
218
+ if (existing > 0) {
219
+ await pushLog('INFO', 'Recovery skip for ' + jobId + ': found ' + existing + ' existing deliverable file(s). Waiting for human update.');
220
+ continue;
221
+ }
199
222
  await spawnMissionWorker(job, 'recovery');
200
223
  }
201
224
 
@@ -234,21 +257,27 @@ async function main() {
234
257
  fs.writeFileSync(markerPath, JSON.stringify({ at: Date.now(), content: msg.content || '' }));
235
258
  } catch (_) {}
236
259
 
237
- const replyPrompt = JSON.stringify([
238
- 'You are mission assistant. Reply briefly to the human and confirm implementation has started.',
239
- 'Return only the reply message text.',
240
- 'HUMAN MESSAGE: ' + (msg.content || ''),
241
- 'MISSION TITLE: ' + (job.title || ''),
242
- ].join('\n'));
243
- let autoReply = '🧠 Got it. I am applying your instruction now and will deliver updated output shortly.';
244
- for (const c of ['openclaw sessions spawn --task ' + replyPrompt, 'openclaw sessions_spawn --task ' + replyPrompt]) {
245
- const r = await queen.execute(msg.jobId, c, { timeout: 120000, shell: true });
246
- const out = (r.output || '').trim();
247
- if (r.exitCode === 0 && out && !/unknown command|usage: openclaw/i.test(out)) { autoReply = out.slice(-500); break; }
248
- if (!/unknown command/i.test(out)) break;
249
- }
260
+ // Immediate human ack so chat never feels ignored
261
+ await queen.sendMessage(msg.jobId, '🧠 Got it applying your instruction now.');
262
+
263
+ try {
264
+ const replyPrompt = JSON.stringify([
265
+ 'You are mission assistant. Reply briefly to the human and confirm what will be changed next.',
266
+ 'Return only one short reply message text.',
267
+ 'HUMAN MESSAGE: ' + (msg.content || ''),
268
+ 'MISSION TITLE: ' + (job.title || ''),
269
+ ].join('\\n'));
270
+ for (const c of ['openclaw sessions spawn --task ' + replyPrompt, 'openclaw sessions_spawn --task ' + replyPrompt]) {
271
+ const r = await queen.execute(msg.jobId, c, { timeout: 45000, shell: true });
272
+ const out = (r.output || '').trim();
273
+ if (r.exitCode === 0 && out && !/unknown command|usage: openclaw/i.test(out)) {
274
+ await queen.sendMessage(msg.jobId, out.slice(-500));
275
+ break;
276
+ }
277
+ if (!/unknown command/i.test(out)) break;
278
+ }
279
+ } catch (_) {}
250
280
 
251
- await queen.sendMessage(msg.jobId, autoReply);
252
281
  await spawnMissionWorker(job, 'human-followup', { watchAfterClarification: true, baselineFiles });
253
282
  });
254
283
 
package/init_templates.js CHANGED
@@ -43,7 +43,7 @@ async function main() {
43
43
  const notifyOwner = async (message, data = null) => {
44
44
  try {
45
45
  if (!agentId || !agentApiKey) return;
46
- await fetch(\`${apiBase}/agents/\${agentId}/notify\`, {
46
+ await fetch(\`\${apiBase}/agents/\${agentId}/notify\`, {
47
47
  method: 'POST',
48
48
  headers: {
49
49
  'Content-Type': 'application/json',
@@ -57,7 +57,7 @@ async function main() {
57
57
  const pushLog = async (level, message) => {
58
58
  try {
59
59
  if (!agentId || !agentApiKey) return;
60
- await fetch(\`${apiBase}/agents/\${agentId}/logs\`, {
60
+ await fetch(\`\${apiBase}/agents/\${agentId}/logs\`, {
61
61
  method: 'POST',
62
62
  headers: {
63
63
  'Content-Type': 'application/json',
@@ -84,6 +84,24 @@ async function main() {
84
84
  } catch (_) { return 0; }
85
85
  };
86
86
 
87
+ const getMeaningfulRepoFileCount = async (jobId) => {
88
+ try {
89
+ const repoRes = await queen.getRepo(jobId);
90
+ if (!repoRes.success || !repoRes.exists || !repoRes.repo?.id) return 0;
91
+ const res = await fetch(apiBase + '/repos/' + repoRes.repo.id + '/files', {
92
+ headers: { Authorization: 'Bearer ' + agentApiKey }
93
+ });
94
+ const data = await res.json();
95
+ const files = Array.isArray(data.files) ? data.files : [];
96
+ const skip = new Set(['ACCEPTANCE.json', 'DELIVERY_SUMMARY.md', 'FAILSAFE_REPORT.md', '.repair_count', '.last_delivery_hash']);
97
+ return files.filter((f) => {
98
+ const p = String(f.path || f.name || '').split('/').pop();
99
+ if (!p || p.startsWith('.')) return false;
100
+ return !skip.has(p);
101
+ }).length;
102
+ } catch (_) { return 0; }
103
+ };
104
+
87
105
  const spawnMissionWorker = async (job, source = 'assignment', opts = {}) => {
88
106
  try {
89
107
  const jobDataPath = path.join(__dirname, 'workspace', '_job_' + job.id + '.json');
@@ -165,6 +183,11 @@ async function main() {
165
183
  // Recover workers for already-active missions after restart
166
184
  for (const [jobId, job] of queen.activeMissions) {
167
185
  if (queen.workers.has(jobId)) continue;
186
+ const existing = await getMeaningfulRepoFileCount(jobId);
187
+ if (existing > 0) {
188
+ await pushLog('INFO', 'Recovery skip for ' + jobId + ': found ' + existing + ' existing deliverable file(s). Waiting for human update.');
189
+ continue;
190
+ }
168
191
  await spawnMissionWorker(job, 'recovery');
169
192
  }
170
193
 
@@ -203,21 +226,27 @@ async function main() {
203
226
  fs.writeFileSync(markerPath, JSON.stringify({ at: Date.now(), content: msg.content || '' }));
204
227
  } catch (_) {}
205
228
 
206
- const replyPrompt = JSON.stringify([
207
- 'You are mission assistant. Reply briefly to the human and confirm implementation has started.',
208
- 'Return only the reply message text.',
209
- 'HUMAN MESSAGE: ' + (msg.content || ''),
210
- 'MISSION TITLE: ' + (job.title || ''),
211
- ].join('\n'));
212
- let autoReply = '🧠 Got it. I am applying your instruction now and will deliver updated output shortly.';
213
- for (const c of ['openclaw sessions spawn --task ' + replyPrompt, 'openclaw sessions_spawn --task ' + replyPrompt]) {
214
- const r = await queen.execute(msg.jobId, c, { timeout: 120000, shell: true });
215
- const out = (r.output || '').trim();
216
- if (r.exitCode === 0 && out && !/unknown command|usage: openclaw/i.test(out)) { autoReply = out.slice(-500); break; }
217
- if (!/unknown command/i.test(out)) break;
218
- }
229
+ // Immediate human ack so chat never feels ignored
230
+ await queen.sendMessage(msg.jobId, '🧠 Got it applying your instruction now.');
231
+
232
+ try {
233
+ const replyPrompt = JSON.stringify([
234
+ 'You are mission assistant. Reply briefly to the human and confirm what will be changed next.',
235
+ 'Return only one short reply message text.',
236
+ 'HUMAN MESSAGE: ' + (msg.content || ''),
237
+ 'MISSION TITLE: ' + (job.title || ''),
238
+ ].join('\\n'));
239
+ for (const c of ['openclaw sessions spawn --task ' + replyPrompt, 'openclaw sessions_spawn --task ' + replyPrompt]) {
240
+ const r = await queen.execute(msg.jobId, c, { timeout: 45000, shell: true });
241
+ const out = (r.output || '').trim();
242
+ if (r.exitCode === 0 && out && !/unknown command|usage: openclaw/i.test(out)) {
243
+ await queen.sendMessage(msg.jobId, out.slice(-500));
244
+ break;
245
+ }
246
+ if (!/unknown command/i.test(out)) break;
247
+ }
248
+ } catch (_) {}
219
249
 
220
- await queen.sendMessage(msg.jobId, autoReply);
221
250
  await spawnMissionWorker(job, 'human-followup', { watchAfterClarification: true, baselineFiles });
222
251
  });
223
252
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rentabots-sdk",
3
- "version": "1.7.38",
3
+ "version": "1.7.41",
4
4
  "description": "Official SDK for RentaBots AI Agent Marketplace",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",