init-tables.mjs 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #!/usr/bin/env node
  2. /**
  3. * init-tables.mjs — 初始化 FmodeAgent / AgentTaskStatus / AgentDeliverable 三表
  4. *
  5. * 真连 Parse REST /schemas 建(或校验)表结构,幂等可重跑:
  6. * - 表不存在 → 创建
  7. * - 字段已存在 → 忽略(Parse schema API 幂等)
  8. * 建完逐表回读 schema 校验关键列,输出索引提示。
  9. *
  10. * 用法: node init-tables.mjs [--server <url>]
  11. * 凭据: 四级解析(见 parse-client.mjs 头注释)
  12. */
  13. import {
  14. resolveCredentials, failNoCredentials, getSchema, createSchema,
  15. } from './parse-client.mjs';
  16. const argServer = process.argv.includes('--server')
  17. ? process.argv[process.argv.indexOf('--server') + 1] : null;
  18. const cred = resolveCredentials();
  19. if (!cred) failNoCredentials();
  20. if (argServer) cred.serverURL = argServer;
  21. // 三表 schema(与 agent-status-reporter 平台侧既有结构对齐)
  22. const TABLES = {
  23. FmodeAgent: {
  24. agentId: { type: 'String' },
  25. soulSummary: { type: 'String' },
  26. containerRef: { type: 'String' },
  27. lastHeartbeat: { type: 'Date' },
  28. status: { type: 'String' },
  29. scope: { type: 'String' },
  30. },
  31. AgentTaskStatus: {
  32. agentId: { type: 'String' },
  33. taskId: { type: 'String' },
  34. taskName: { type: 'String' },
  35. status: { type: 'String' }, // ack | running | done | failed
  36. startedAt: { type: 'Date' },
  37. endedAt: { type: 'Date' },
  38. heartbeatAt: { type: 'Date' },
  39. resultNote: { type: 'String' },
  40. },
  41. AgentDeliverable: {
  42. agentId: { type: 'String' },
  43. taskId: { type: 'String' },
  44. title: { type: 'String' },
  45. project: { type: 'String' },
  46. deliverableType: { type: 'String' }, // report | code | courseware | data
  47. url: { type: 'String' },
  48. summary: { type: 'String' },
  49. deliveredAt: { type: 'Date' },
  50. },
  51. };
  52. // 查询索引提示(Parse REST 不直接建索引,平台侧 mongo 手工建;此处只提示)
  53. const INDEX_HINTS = {
  54. FmodeAgent: 'agentId',
  55. AgentTaskStatus: 'agentId + taskId 复合查询(status.mjs / progress.mjs 幂等键)',
  56. AgentDeliverable: 'agentId + taskId + deliverableType(deliver.mjs 幂等覆盖键)',
  57. };
  58. const results = [];
  59. for (const [table, fields] of Object.entries(TABLES)) {
  60. const before = await getSchema(table, cred); // eslint-disable-line no-await-in-loop
  61. if (!before) {
  62. await createSchema(table, cred, fields); // eslint-disable-line no-await-in-loop
  63. } else {
  64. await createSchema(table, cred, fields); // 幂等补列(已存在列忽略)// eslint-disable-line no-await-in-loop
  65. }
  66. // 回读校验关键列
  67. const after = await getSchema(table, cred); // eslint-disable-line no-await-in-loop
  68. const missing = Object.entries(fields)
  69. .filter(([name, spec]) => !after || !after.fields[name] || after.fields[name].type !== spec.type)
  70. .map(([name]) => name);
  71. results.push({
  72. table, created: !before, columns: Object.keys(fields).length,
  73. verified: missing.length === 0, missing,
  74. indexHint: INDEX_HINTS[table],
  75. });
  76. }
  77. console.log(JSON.stringify({
  78. ok: true,
  79. server: cred.serverURL,
  80. credentialSource: cred.source,
  81. tables: results,
  82. }, null, 2));
  83. const failed = results.filter((r) => !r.verified);
  84. if (failed.length > 0) {
  85. console.error(`[task-progress] ${failed.length} 表字段校验未通过: ${failed.map((f) => f.table).join(', ')}`);
  86. process.exit(1);
  87. }