|
| 1 | +// Export reviewable coverage worksheets; this is not a test or a second registry. |
| 2 | +import { readFile, mkdir, writeFile } from 'node:fs/promises'; |
| 3 | +import { dirname, resolve } from 'node:path'; |
| 4 | +import { fileURLToPath } from 'node:url'; |
| 5 | + |
| 6 | +const root = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); |
| 7 | +const args = process.argv.slice(2); |
| 8 | +if (args.length !== 2 || args[0] !== '--output') { |
| 9 | + throw new Error('Usage: node scripts/diagnostics/export-communications-matrix.mjs --output <new-directory>'); |
| 10 | +} |
| 11 | +const output = resolve(args[1]); |
| 12 | +const registry = JSON.parse(await readFile(resolve(root, |
| 13 | + 'src/crates/contracts/product-domains/src/generated/remote-surface-registry.json'), 'utf8')); |
| 14 | +if (registry.schemaVersion !== 1 || !Array.isArray(registry.operations)) { |
| 15 | + throw new Error('Unsupported Product Operation Registry shape'); |
| 16 | +} |
| 17 | +const source = await readFile(resolve(root, |
| 18 | + 'src/crates/services/services-integrations/src/remote_connect.rs'), 'utf8'); |
| 19 | +const commandBody = source.match(/pub enum RemoteCommand \{\n([\s\S]*?)\n\}/)?.[1]; |
| 20 | +if (!commandBody) throw new Error('RemoteCommand enum was not found'); |
| 21 | +const commands = [...commandBody.matchAll(/^ ([A-Z]\w*)\s*(?:,|\{)/gm)] |
| 22 | + .map((match) => match[1].replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase()); |
| 23 | +if (commands.length === 0 || new Set(commands).size !== commands.length) { |
| 24 | + throw new Error('RemoteCommand inventory is empty or contains duplicates'); |
| 25 | +} |
| 26 | +const guide = await readFile(resolve(root, 'docs/development/communications-e2e.zh-CN.md'), 'utf8'); |
| 27 | +const cases = [...guide.matchAll(/^\| ((?:ENV|RLY|SSH|MOB|BOT|PEER|DSP|COMBO|EXT)-\d+) \| ([^\n]+) \| ([^\n]+) \|$/gm)] |
| 28 | + .map((match) => [match[1], match[2], match[3]]); |
| 29 | +if (cases.length === 0 || new Set(cases.map(([id]) => id)).size !== cases.length) { |
| 30 | + throw new Error('Manual case inventory is empty or contains duplicate ids'); |
| 31 | +} |
| 32 | +const csv = (rows) => rows.map((row) => row.map((cell) => |
| 33 | + `"${String(cell ?? '').replaceAll('"', '""')}"`).join(',')).join('\n') + '\n'; |
| 34 | +// A fresh directory prevents a rerun from erasing manually recorded evidence. |
| 35 | +await mkdir(output, { recursive: false }); |
| 36 | +await writeFile(resolve(output, 'product-operations.csv'), csv([ |
| 37 | + ['operation', 'remote_workspace_policy', 'peer_policy', 'cli_peer_policy', 'cli_reason', |
| 38 | + 'ssh_result', 'desktop_peer_result', 'cli_peer_result', 'composition_result', 'evidence'], |
| 39 | + ...registry.operations.map((op) => [op.id, op.remoteWorkspace, op.peer.kind, op.cliPeer.kind, |
| 40 | + op.cliPeer.reason, 'NOT_RUN', 'NOT_RUN', 'NOT_RUN', 'NOT_RUN', '']), |
| 41 | +])); |
| 42 | +await writeFile(resolve(output, 'remote-commands.csv'), csv([ |
| 43 | + ['command', 'room_mobile_result', 'account_mobile_result', 'feishu_result', |
| 44 | + 'telegram_result', 'weixin_result', 'peer_result', 'evidence'], |
| 45 | + ...commands.map((command) => [command, ...Array(6).fill('NOT_RUN'), '']), |
| 46 | +])); |
| 47 | +await writeFile(resolve(output, 'manual-cases.csv'), csv([ |
| 48 | + ['case_id', 'steps', 'expected', 'environment', 'result', 'evidence', 'issue'], |
| 49 | + ...cases.map(([id, steps, expected]) => [id, steps, expected, '', 'NOT_RUN', '', '']), |
| 50 | +])); |
| 51 | +const inventory = { |
| 52 | + registryDigest: registry.digest, |
| 53 | + productOperations: registry.operations.length, |
| 54 | + remoteCommands: commands.length, |
| 55 | + manualCases: cases.length, |
| 56 | + note: 'Inventory only. NOT_RUN is not coverage. Preserve environment and evidence per execution.', |
| 57 | +}; |
| 58 | +await writeFile(resolve(output, 'inventory.json'), JSON.stringify(inventory, null, 2) + '\n'); |
| 59 | +console.log(JSON.stringify(inventory, null, 2)); |
0 commit comments