_dispatch_node_shell.cjs 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. // opencode shell dispatch v2: tolerates lost POST response (B-101), polls /api/shell for new id, auto-kills leftovers
  2. const BASE = process.env.BASE;
  3. const CMD = process.env.CMD;
  4. const AUTH = 'Basic ' + Buffer.from('opencode:' + (process.env.OPENCODE_SERVER_PASSWORD || 'IwinTrue@123')).toString('base64');
  5. const capMs = parseInt(process.env.CAP_MS || '300000', 10);
  6. const H = { 'Authorization': AUTH, 'Content-Type': 'application/json' };
  7. async function j(url, opt) {
  8. try {
  9. const r = await fetch(url, Object.assign({ headers: H }, opt));
  10. const t = await r.text();
  11. try { return { status: r.status, json: JSON.parse(t) }; } catch { return { status: r.status, text: t }; }
  12. } catch (e) { return { status: 0, err: e.message }; }
  13. }
  14. const sleep = ms => new Promise(r => setTimeout(r, ms));
  15. async function listShells() {
  16. const r = await j(BASE + '/api/shell');
  17. return ((r.json && r.json.data) || []).map(x => x.id);
  18. }
  19. async function main() {
  20. const before = new Set(await listShells());
  21. console.log('PRE', before.size);
  22. const cr = await j(BASE + '/api/session', { method: 'POST', body: JSON.stringify({ title: "r112-" + Date.now(), model: { id: "deepseek3.2", providerID: "axon" }, projectID: process.env.PROJECT_ID }) });
  23. const sid = (cr.json && cr.json.data && cr.json.data.id) || '';
  24. console.log('SID', sid || JSON.stringify(cr).slice(0, 150));
  25. if (!sid) throw new Error('no session');
  26. j(BASE + '/api/session/' + sid + '/shell', { method: 'POST', body: JSON.stringify({ command: CMD }) })
  27. .then(r => console.log('CREATE_STATUS', r.status)).catch(e => console.log('CREATE_ERR', e.message));
  28. let id = null;
  29. for (let i = 0; i < 20 && !id; i++) {
  30. await sleep(2000);
  31. const now = await listShells();
  32. const fresh = now.filter(x => !before.has(x));
  33. if (fresh.length) id = fresh[fresh.length - 1];
  34. }
  35. console.log('SHELL_ID', id || 'NONE');
  36. if (!id) throw new Error('shell not created');
  37. const t0 = Date.now();
  38. let last = '';
  39. while (Date.now() - t0 < capMs) {
  40. await sleep(5000);
  41. const st = await j(BASE + '/api/shell/' + id);
  42. const d = (st.json && st.json.data) || {};
  43. const s = d.status || '?';
  44. if (s !== last) { console.log('STATUS', s, Math.round((Date.now() - t0) / 1000) + 's'); last = s; }
  45. if (s && s !== 'running') {
  46. const out = await j(BASE + '/api/shell/' + id + '/output');
  47. console.log('OUT_BEGIN');
  48. console.log(((out.json && out.json.data && out.json.data.output) || out.text || '').slice(-6000));
  49. console.log('OUT_END');
  50. return;
  51. }
  52. }
  53. console.log('TIMEOUT', capMs);
  54. }
  55. main().catch(e => { console.error('ERR', e.message); process.exit(1); });