name: Vally Lint — PR Comment

# Posts results from the "Vally Lint — PR Gate" workflow.
# Runs with write permissions but never checks out PR code,
# so it is safe for fork PRs.

on:
  workflow_run:
    workflows: ["Vally Lint — PR Gate"]
    types: [completed]

permissions:
  issues: write
  pull-requests: write
  actions: read # needed to download artifacts

jobs:
  comment:
    runs-on: ubuntu-latest
    if: github.event.workflow_run.event == 'pull_request'
    steps:
      - name: Download results artifact
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
        with:
          name: vally-lint-results
          run-id: ${{ github.event.workflow_run.id }}
          github-token: ${{ github.token }}

      - name: Post PR comment with results
        uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
        with:
          script: |
            const fs = require('fs');
            const managedLabels = {
              'skill-check-warning': {
                color: 'FBCA04',
                description: 'Vally lint reported warnings'
              },
              'skill-check-error': {
                color: 'B60205',
                description: 'Vally lint reported errors'
              }
            };

            async function syncManagedLabels(issueNumber, desiredLabels) {
              const currentLabels = await github.paginate(github.rest.issues.listLabelsOnIssue, {
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: issueNumber,
                per_page: 100
              });

              const currentManagedLabels = currentLabels
                .map((label) => label.name)
                .filter((name) => Object.prototype.hasOwnProperty.call(managedLabels, name));

              const labelsToAdd = [...desiredLabels].filter((name) => !currentManagedLabels.includes(name));
              const labelsToRemove = currentManagedLabels.filter((name) => !desiredLabels.has(name));

              if (labelsToAdd.length > 0) {
                await github.rest.issues.addLabels({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  issue_number: issueNumber,
                  labels: labelsToAdd
                });
              }

              for (const name of labelsToRemove) {
                await github.rest.issues.removeLabel({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  issue_number: issueNumber,
                  name
                });
              }

              console.log(`Managed skill check labels: ${[...desiredLabels].sort().join(', ') || 'none'}`);
            }

            const prNumber = parseInt(fs.readFileSync('pr-number.txt', 'utf8').trim(), 10);
            const total = parseInt(fs.readFileSync('total.txt', 'utf8').trim(), 10);
            const exitCode = fs.readFileSync('exit-code.txt', 'utf8').trim();
            const skillCount = parseInt(fs.readFileSync('skill-count.txt', 'utf8').trim(), 10);
            const agentCount = parseInt(fs.readFileSync('agent-count.txt', 'utf8').trim(), 10);
            const totalChecked = skillCount + agentCount;

            const marker = '<!-- vally-lint-results -->';
            const rawOutput = fs.existsSync('vally-output.txt')
              ? fs.readFileSync('vally-output.txt', 'utf8')
              : '';
            const output = rawOutput.replace(/\x1b\[[0-9;]*m/g, '').trim();

            const errorCount = (output.match(/❌/g) || []).length;
            const warningCount = (output.match(/⚠/g) || []).length;
            const advisoryCount = (output.match(/ℹ/g) || []).length;
            const desiredLabels = new Set();

            if (warningCount > 0) {
              desiredLabels.add('skill-check-warning');
            }

            if (exitCode !== '0' || errorCount > 0) {
              desiredLabels.add('skill-check-error');
            }

            await syncManagedLabels(prNumber, desiredLabels);

            if (total === 0) {
              console.log('No skills/agents were checked — skipping comment.');
              return;
            }

            let verdict = '✅ All checks passed';
            if (exitCode !== '0' || errorCount > 0) {
              verdict = '⛔ Findings need attention';
            } else if (warningCount > 0 || advisoryCount > 0) {
              verdict = '⚠️ Warnings or advisories found';
            }

            const highlightedLines = output
              .split('\n')
              .map(line => line.trim())
              .filter(Boolean)
              .filter(line => !line.startsWith('###'))
              .filter(line => /^[❌⚠ℹ]/.test(line));

            const summaryLines = highlightedLines.length > 0
              ? highlightedLines.slice(0, 10)
              : output
                  .split('\n')
                  .map(line => line.trim())
                  .filter(Boolean)
                  .filter(line => !line.startsWith('###'))
                  .slice(0, 10);

            const scopeTable = [
              '| Scope | Checked |',
              '|---|---:|',
              `| Skills | ${skillCount} |`,
              `| Agents | ${agentCount} |`,
              `| Total | ${totalChecked} |`,
            ];

            const severityTable = [
              '| Severity | Count |',
              '|---|---:|',
              `| ❌ Errors | ${errorCount} |`,
              `| ⚠️ Warnings | ${warningCount} |`,
              `| ℹ️ Advisories | ${advisoryCount} |`,
            ];

            const findingsTable = summaryLines.length === 0
              ? ['_No findings were emitted by the linter._']
              : [
                  '| Level | Finding |',
                  '|---|---|',
                  ...summaryLines.map(line => {
                    const level = line.startsWith('❌')
                      ? '❌'
                      : line.startsWith('⚠')
                        ? '⚠️'
                        : line.startsWith('ℹ')
                          ? 'ℹ️'
                          : (exitCode !== '0' ? '⛔' : 'ℹ️');
                    const text = line.replace(/^[❌⚠ℹ️\s]+/, '').replace(/\|/g, '\\|');
                    return `| ${level} | ${text} |`;
                  }),
                ];

            const body = [
              marker,
              '## 🔍 Vally Lint Results',
              '',
              `**${verdict}**`,
              '',
              ...scopeTable,
              '',
              ...severityTable,
              '',
              '### Summary',
              '',
              ...findingsTable,
              '',
              '<details>',
              '<summary>Full linter output</summary>',
              '',
              '```text',
              output || 'No linter output captured.',
              '```',
              '',
              '</details>',
              '',
              exitCode !== '0'
                ? '> **Note:** Vally lint returned a non-zero exit code. Please review the findings above before merge.'
                : '',
            ].join('\n');

            // Find existing comment with our marker
            const { data: comments } = await github.rest.issues.listComments({
              owner: context.repo.owner,
              repo: context.repo.repo,
              issue_number: prNumber,
              per_page: 100,
            });

            const existing = comments.find(c => c.body.includes(marker));

            if (existing) {
              await github.rest.issues.updateComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                comment_id: existing.id,
                body,
              });
              console.log(`Updated existing comment ${existing.id}`);
            } else {
              await github.rest.issues.createComment({
                owner: context.repo.owner,
                repo: context.repo.repo,
                issue_number: prNumber,
                body,
              });
              console.log('Created new PR comment');
            }
