verify-default-upload.mjs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #!/usr/bin/env node
  2. /**
  3. * 验收:容器是否**默认**自动上云(提示词不含任何上传暗示)
  4. *
  5. * 判定三条:
  6. * ① 回复里自动带出 https://s3.fmode.cn 链接
  7. * ② 成果表自动多一条记录
  8. * ③ 过程缓存没有被误传(成果数不应暴涨)
  9. */
  10. import { readFileSync } from 'node:fs';
  11. import { homedir } from 'node:os';
  12. import { join } from 'node:path';
  13. const F = 'https://server.fmode.cn/api/functions';
  14. const TARGET = 'agent-node-lj-test';
  15. const WAIT_MS = 420_000;
  16. const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
  17. const t = JSON.parse(readFileSync(join(homedir(), '.fmode/config/user.json'), 'utf8'))?.sessionToken;
  18. async function callFn(id, params) {
  19. const r = await fetch(F, { method: 'POST', headers: { 'Content-Type': 'application/json' },
  20. body: JSON.stringify({ id, token: t, params }) });
  21. return r.json();
  22. }
  23. async function provision(id) {
  24. const j = await callFn('RP5Ht55NeX', { agentId: id });
  25. return j.result ?? j;
  26. }
  27. async function countDeliverables() {
  28. const d = await callFn('lfYlgU7SkK', { action: 'list', agentId: TARGET, limit: 200 });
  29. const list = d.deliverables ?? d.result?.deliverables ?? [];
  30. return list.length;
  31. }
  32. /* 🔴 全程不出现:上传 / 云盘 / S3 / 链接 / URL / 成果 / 分享 */
  33. const PROMPT = `帮我写一份这周的工作周报,用 Markdown,分成「本周完成」「下周计划」「风险」三块。`;
  34. async function main() {
  35. const before = await countDeliverables();
  36. console.log('测试前成果数:', before);
  37. const prov = await provision(TARGET);
  38. const agent = await provision(TARGET);
  39. const mx = await import('matrix-js-sdk');
  40. const c = mx.createClient({ baseUrl: prov.homeserver, accessToken: prov.accessToken, userId: prov.userMxId });
  41. const room = (await c.createRoom({ invite: [agent.agentMxId], name: `accept-${Date.now()}`, preset: mx.Preset.TrustedPrivateChat })).room_id;
  42. const hs = prov.homeserver.replace(/\/$/, '');
  43. const auth = { Authorization: `Bearer ${prov.accessToken}` };
  44. for (let i = 0; i < 30; i++) {
  45. await sleep(3000);
  46. const r = await fetch(`${hs}/_matrix/client/v3/rooms/${encodeURIComponent(room)}/joined_members`, { headers: auth }).catch(() => null);
  47. const j = r ? await r.json().catch(() => ({})) : {};
  48. if ((j.joined ?? {})[agent.agentMxId]) break;
  49. }
  50. console.log('\n=== 提示词(无任何上传暗示)===');
  51. console.log(PROMPT);
  52. const sent = await c.sendEvent(room, 'm.room.message', { msgtype: 'm.text', body: PROMPT, 'm.mentions': { user_ids: [agent.agentMxId] } });
  53. const seen = new Set([sent.event_id]);
  54. const deadline = Date.now() + WAIT_MS;
  55. const texts = [];
  56. let finished = false;
  57. while (Date.now() < deadline) {
  58. await sleep(8000);
  59. try {
  60. const r = await fetch(`${hs}/_matrix/client/v3/rooms/${encodeURIComponent(room)}/messages?dir=b&limit=50`, { headers: auth });
  61. const j = await r.json();
  62. let hasUrl = false;
  63. for (const ev of (j.chunk ?? []).reverse()) {
  64. if (ev.type !== 'm.room.message' || seen.has(ev.event_id) || ev.sender === prov.userMxId) continue;
  65. seen.add(ev.event_id);
  66. const b = String(ev.content?.body ?? '');
  67. texts.push(b);
  68. if (/https:\/\/s3\.fmode\.cn/.test(b)) hasUrl = true;
  69. }
  70. if (hasUrl) { finished = true; break; }
  71. } catch { /* 轮询抖动 */ }
  72. }
  73. const all = texts.join('\n');
  74. console.log('\n=== 最后一条正文 ===');
  75. const prose = texts.filter((b) => !/^[*·•]?\s*(🐍|💻|🔎|📖|✍️)/.test(b.trim()));
  76. console.log((prose[prose.length - 1] ?? '(无)').slice(0, 1500));
  77. await sleep(8000); // 等成果表写入
  78. const after = await countDeliverables();
  79. console.log('\n=== 验收判定 ===');
  80. const r1 = /https:\/\/s3\.fmode\.cn/.test(all);
  81. console.log(`① 回复自动带 https 链接 : ${r1 ? '✅ 是' : '❌ 否'}`);
  82. console.log(`② 成果表新增 : ${after - before} 条(${before} → ${after})${after > before ? '✅' : '❌'}`);
  83. console.log(`③ 未误传过程缓存 : ${after - before <= 2 ? '✅ 未暴涨' : `⚠️ 新增 ${after - before} 条,可能误传`}`);
  84. console.log(`④ 正文是否残留本地路径 : ${/\/opt\/data\//.test(prose.join('\n')) ? '⚠️ 是' : '✅ 否'}`);
  85. console.log(`\n总判定: ${r1 && after > before ? '✅ 通过 —— 默认上云已生效' : '❌ 未通过'}`);
  86. c.stopClient();
  87. }
  88. main().catch((e) => { console.error('失败:', e.message); process.exit(1); });