Merge commit '06d0ff377173de8eaa6942ba2880930d980a0d9c'

This commit is contained in:
Alexa Amundson
2025-11-25 13:41:41 -06:00
10 changed files with 641 additions and 0 deletions

View File

@@ -35,3 +35,37 @@ jobs:
working-directory: ./bot working-directory: ./bot
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
name: Emoji Bot
on:
workflow_dispatch:
reaction:
types:
- created
permissions:
contents: read
issues: write
pull-requests: write
discussions: write
jobs:
run:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Run emoji bot
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
EMOJI_BOT_DRY_RUN: "false"
run: node bot/index.js

View File

@@ -0,0 +1,7 @@
Hey @{{actor}}, we caught your ✅ reaction and queued this item for ops.
- Added labels: {{labels}}
- Assigned: {{assignees}}
- Context: {{context}}
Thanks for keeping the signal strong! {{footer}}

7
bot/comments/close.md Normal file
View File

@@ -0,0 +1,7 @@
❌ Reaction received. Closing this out per the automation rules.
- Added labels: {{labels}}
- Assigned: {{assignees}}
- Context: {{context}}
If this was a mistake, re-open with a ✅ reaction and a quick note. {{footer}}

7
bot/comments/escalate.md Normal file
View File

@@ -0,0 +1,7 @@
⚡ Escalation triggered by @{{actor}}. Weve pulled in the right crew to swarm on this.
- Added labels: {{labels}}
- Assigned: {{assignees}}
- Context: {{context}}
Well drop updates here as we make progress. {{footer}}

7
bot/comments/help.md Normal file
View File

@@ -0,0 +1,7 @@
🛟 @{{actor}} asked for help via emoji. A support agent will take a look shortly.
- Added labels: {{labels}}
- Assigned: {{assignees}}
- Context: {{context}}
If this is urgent, drop more details and well escalate. {{footer}}

View File

@@ -42,3 +42,210 @@ if (reaction) {
} else { } else {
console.log("💬 Comment ignored — no emoji trigger detected."); console.log("💬 Comment ignored — no emoji trigger detected.");
} }
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');
const core = require('@actions/core');
const github = require('@actions/github');
function loadYaml(filePath) {
const absolutePath = path.resolve(filePath);
const fileContents = fs.readFileSync(absolutePath, 'utf8');
return yaml.load(fileContents);
}
function resolveTemplate(config, templateKey) {
const templateMap = config?.defaults?.templates || {};
const resolvedPath = templateMap[templateKey] || templateKey;
return path.resolve(resolvedPath);
}
function renderTemplate(content, context) {
return content.replace(/{{(.*?)}}/g, (_, key) => {
const trimmed = key.trim();
return Object.prototype.hasOwnProperty.call(context, trimmed)
? context[trimmed]
: '';
});
}
function mapLabels(labelKeys, defaults) {
const labelMap = defaults?.labels || {};
return (labelKeys || []).map((key) => labelMap[key] || key);
}
function parseArgs(argv) {
const args = { eventPath: null, dryRunOverride: null };
for (let i = 0; i < argv.length; i += 1) {
const arg = argv[i];
if (arg === '--event') {
args.eventPath = argv[i + 1];
i += 1;
}
if (arg === '--dry-run') {
args.dryRunOverride = true;
}
if (arg === '--execute') {
args.dryRunOverride = false;
}
}
return args;
}
function loadEventPayload(eventPathFromArgs) {
const explicitPath = eventPathFromArgs || process.env.GITHUB_EVENT_PATH;
if (!explicitPath) {
return github.context.payload;
}
const absolutePath = path.resolve(explicitPath);
const payload = fs.readFileSync(absolutePath, 'utf8');
return JSON.parse(payload);
}
function resolveTargetNumber(payload) {
if (payload.issue?.number) return payload.issue.number;
if (payload.pull_request?.number) return payload.pull_request.number;
if (payload.comment?.issue_url) {
const parts = payload.comment.issue_url.split('/');
return Number(parts[parts.length - 1]);
}
return null;
}
function buildContext(payload, config, reactionDefinition) {
const labels = mapLabels(reactionDefinition.addLabels, config.defaults);
const assignees = reactionDefinition.assign || [];
const footer = config.defaults?.commentFooter || '';
return {
labels: labels.length ? labels.join(', ') : 'none',
assignees: assignees.length ? assignees.join(', ') : 'none',
footer,
};
}
async function applyActions({
octokit,
owner,
repo,
issueNumber,
reactionDefinition,
labels,
assignees,
dryRun,
}) {
if (labels.length) {
if (dryRun) {
core.info(`[dry-run] Would add labels ${labels.join(', ')} to ${owner}/${repo}#${issueNumber}`);
} else {
await octokit.rest.issues.addLabels({ owner, repo, issue_number: issueNumber, labels });
}
}
if (assignees.length) {
if (dryRun) {
core.info(`[dry-run] Would assign ${assignees.join(', ')} to ${owner}/${repo}#${issueNumber}`);
} else {
await octokit.rest.issues.addAssignees({ owner, repo, issue_number: issueNumber, assignees });
}
}
if (reactionDefinition.close) {
if (dryRun) {
core.info(`[dry-run] Would close ${owner}/${repo}#${issueNumber}`);
} else {
await octokit.rest.issues.update({ owner, repo, issue_number: issueNumber, state: 'closed' });
}
}
}
function buildCommentBody(templatePath, context) {
const templateContent = fs.readFileSync(templatePath, 'utf8');
return renderTemplate(templateContent, context);
}
async function postComment({ octokit, owner, repo, issueNumber, body, dryRun }) {
if (dryRun) {
core.info(`[dry-run] Would post comment to ${owner}/${repo}#${issueNumber}:\n${body}`);
return;
}
await octokit.rest.issues.createComment({ owner, repo, issue_number: issueNumber, body });
}
async function run() {
const config = loadYaml('emoji-bot-config.yml');
const args = parseArgs(process.argv.slice(2));
const payload = loadEventPayload(args.eventPath);
const reaction = payload.reaction?.content;
if (!reaction) {
core.info('No reaction found in payload. Exiting.');
return;
}
const eventName = process.env.GITHUB_EVENT_NAME || 'local';
const targetNumber = resolveTargetNumber(payload);
if (!targetNumber) {
core.info('Could not resolve target issue or pull request number. Exiting.');
return;
}
const reactionDefinition = config.reactions?.[reaction];
if (!reactionDefinition) {
core.info(`Reaction ${reaction} is not configured. Exiting.`);
return;
}
const owner = payload.repository?.owner?.login || github.context.repo.owner;
const repo = payload.repository?.name || github.context.repo.repo;
const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
const octokit = token ? github.getOctokit(token) : null;
const dryRunEnv = process.env.EMOJI_BOT_DRY_RUN;
const configDefault = Boolean(config.defaults?.dryRun);
const dryRun = typeof args.dryRunOverride === 'boolean'
? args.dryRunOverride
: typeof dryRunEnv === 'string'
? dryRunEnv.toLowerCase() !== 'false'
: configDefault;
const templatePath = resolveTemplate(config, reactionDefinition.template);
const labels = mapLabels(reactionDefinition.addLabels, config.defaults);
const assignees = reactionDefinition.assign || [];
const context = buildContext(payload, config, reactionDefinition);
const renderedContext = {
...context,
actor: payload.sender?.login || 'unknown',
context: `${owner}/${repo}#${targetNumber} (${eventName})`,
};
const body = buildCommentBody(templatePath, renderedContext);
if (!octokit) {
core.warning('GITHUB_TOKEN was not provided; running in dry-run mode.');
}
const client = octokit || github.getOctokit('');
await applyActions({
octokit: client,
owner,
repo,
issueNumber: targetNumber,
reactionDefinition,
labels,
assignees,
dryRun: dryRun || !token,
});
await postComment({
octokit: client,
owner,
repo,
issueNumber: targetNumber,
body,
dryRun: dryRun || !token,
});
}
run().catch((error) => {
core.setFailed(error.message);
});

38
docs/emoji-bot-spec.txt Normal file
View File

@@ -0,0 +1,38 @@
Emoji Bot Spec (v0.1)
====================
Summary
-------
A GitHub Action that listens for reaction events and routes work using emojis.
Each emoji maps to a declarative rule set defined in `emoji-bot-config.yml` and
uses markdown templates in `bot/comments/` for replies.
Events
------
- `reaction.created` on issues, PRs, and comments
- Manual `workflow_dispatch` trigger for smoke testing
Config
------
- `defaults.dryRun` toggles between logging and performing mutations
- `defaults.templates` maps logical names to comment markdown files
- `reactions` keys are emoji strings with actions: `addLabels`, `assign`, `close`, `template`, `note`
- `defaults.labels` stores reusable label names to avoid duplication
Actions
-------
For each matched reaction:
- Apply `addLabels` using the canonical labels map
- Assign `assign` usernames
- Render the configured template with `actor`, `labels`, `assignees`, `context`, and `footer`
- If `close` is true, close the issue or pull request
Local Testing
-------------
- Run `node bot/index.js --event <path-to-sample-event.json> --dry-run`
- Use `npm test` for the rest of the repo if needed; the bot is dependency-light
Notes
-----
- The bot relies on `@actions/github` and the built-in `GITHUB_TOKEN`
- Templates include a footer marker so duplicate comments are easy to find

View File

@@ -28,3 +28,59 @@ guardian_agent: "@guardian-agent"
# Optional: Default GitHub Project ID to update # Optional: Default GitHub Project ID to update
default_project_id: 12345678 # Example: 12345678 default_project_id: 12345678 # Example: 12345678
# High-level configuration for the emoji-driven automation bot.
# Each reaction entry maps an emoji to the actions the bot should perform.
meta:
name: emoji-bot
description: GitHub-native visual automation powered by reactions.
maintainers:
- ops-team
- automation-guild
defaults:
dryRun: true
commentFooter: "<!-- emoji-bot -->"
templates:
acknowledge: bot/comments/acknowledge.md
help: bot/comments/help.md
close: bot/comments/close.md
escalate: bot/comments/escalate.md
labels:
acknowledged: "status: acknowledged"
needsHelp: "needs: support"
closed: "status: closed"
reactions:
"✅":
template: acknowledge
addLabels:
- acknowledged
assign:
- ops-team
note: Mark work as acknowledged by operations.
"🛟":
template: help
addLabels:
- needsHelp
assign:
- automation-guild
note: Route the conversation to a support agent.
"❌":
template: close
addLabels:
- closed
close: true
note: Close items that are explicitly rejected.
"⚡":
template: escalate
addLabels:
- acknowledged
- "priority: high"
assign:
- ops-team
- automation-guild
note: Escalate urgent work to both groups.

275
package-lock.json generated
View File

@@ -9,10 +9,13 @@
"version": "1.0.0", "version": "1.0.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@actions/core": "^1.11.1",
"@actions/github": "^6.0.1",
"bullmq": "^5.64.1", "bullmq": "^5.64.1",
"express": "^5.1.0", "express": "^5.1.0",
"fastify": "^5.6.2", "fastify": "^5.6.2",
"ioredis": "^5.8.2", "ioredis": "^5.8.2",
"js-yaml": "^4.1.0",
"node-cron": "^4.2.1", "node-cron": "^4.2.1",
"react": "^19.2.0", "react": "^19.2.0",
"react-dom": "^19.2.0", "react-dom": "^19.2.0",
@@ -42,6 +45,56 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@actions/core": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz",
"integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==",
"license": "MIT",
"dependencies": {
"@actions/exec": "^1.1.1",
"@actions/http-client": "^2.0.1"
}
},
"node_modules/@actions/exec": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
"license": "MIT",
"dependencies": {
"@actions/io": "^1.0.1"
}
},
"node_modules/@actions/github": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-6.0.1.tgz",
"integrity": "sha512-xbZVcaqD4XnQAe35qSQqskb3SqIAfRyLBrHMd/8TuL7hJSz2QtbDwnNM8zWx4zO5l2fnGtseNE3MbEvD7BxVMw==",
"license": "MIT",
"dependencies": {
"@actions/http-client": "^2.2.0",
"@octokit/core": "^5.0.1",
"@octokit/plugin-paginate-rest": "^9.2.2",
"@octokit/plugin-rest-endpoint-methods": "^10.4.0",
"@octokit/request": "^8.4.1",
"@octokit/request-error": "^5.1.1",
"undici": "^5.28.5"
}
},
"node_modules/@actions/http-client": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz",
"integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==",
"license": "MIT",
"dependencies": {
"tunnel": "^0.0.6",
"undici": "^5.25.4"
}
},
"node_modules/@actions/io": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==",
"license": "MIT"
},
"node_modules/@adobe/css-tools": { "node_modules/@adobe/css-tools": {
"version": "4.4.4", "version": "4.4.4",
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz",
@@ -1028,6 +1081,15 @@
"fast-uri": "^3.0.0" "fast-uri": "^3.0.0"
} }
}, },
"node_modules/@fastify/busboy": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
"license": "MIT",
"engines": {
"node": ">=14"
}
},
"node_modules/@fastify/error": { "node_modules/@fastify/error": {
"version": "4.2.0", "version": "4.2.0",
"resolved": "https://registry.npmjs.org/@fastify/error/-/error-4.2.0.tgz", "resolved": "https://registry.npmjs.org/@fastify/error/-/error-4.2.0.tgz",
@@ -1287,6 +1349,164 @@
"url": "https://paulmillr.com/funding/" "url": "https://paulmillr.com/funding/"
} }
}, },
"node_modules/@octokit/auth-token": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
"integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==",
"license": "MIT",
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/core": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz",
"integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==",
"license": "MIT",
"dependencies": {
"@octokit/auth-token": "^4.0.0",
"@octokit/graphql": "^7.1.0",
"@octokit/request": "^8.4.1",
"@octokit/request-error": "^5.1.1",
"@octokit/types": "^13.0.0",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/endpoint": {
"version": "9.0.6",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz",
"integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^13.1.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/graphql": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz",
"integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==",
"license": "MIT",
"dependencies": {
"@octokit/request": "^8.4.1",
"@octokit/types": "^13.0.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/openapi-types": {
"version": "24.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
"license": "MIT"
},
"node_modules/@octokit/plugin-paginate-rest": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz",
"integrity": "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^12.6.0"
},
"engines": {
"node": ">= 18"
},
"peerDependencies": {
"@octokit/core": "5"
}
},
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
"license": "MIT"
},
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
"version": "12.6.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
"license": "MIT",
"dependencies": {
"@octokit/openapi-types": "^20.0.0"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "10.4.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz",
"integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^12.6.0"
},
"engines": {
"node": ">= 18"
},
"peerDependencies": {
"@octokit/core": "5"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
"license": "MIT"
},
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": {
"version": "12.6.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
"license": "MIT",
"dependencies": {
"@octokit/openapi-types": "^20.0.0"
}
},
"node_modules/@octokit/request": {
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz",
"integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==",
"license": "MIT",
"dependencies": {
"@octokit/endpoint": "^9.0.6",
"@octokit/request-error": "^5.1.1",
"@octokit/types": "^13.1.0",
"universal-user-agent": "^6.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/request-error": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz",
"integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^13.1.0",
"deprecation": "^2.0.0",
"once": "^1.4.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/@octokit/types": {
"version": "13.10.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
"license": "MIT",
"dependencies": {
"@octokit/openapi-types": "^24.2.0"
}
},
"node_modules/@paralleldrive/cuid2": { "node_modules/@paralleldrive/cuid2": {
"version": "2.3.1", "version": "2.3.1",
"resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz", "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.3.1.tgz",
@@ -2234,6 +2454,12 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"license": "Python-2.0"
},
"node_modules/aria-query": { "node_modules/aria-query": {
"version": "5.3.0", "version": "5.3.0",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
@@ -2297,6 +2523,12 @@
"baseline-browser-mapping": "dist/cli.js" "baseline-browser-mapping": "dist/cli.js"
} }
}, },
"node_modules/before-after-hook": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==",
"license": "Apache-2.0"
},
"node_modules/bidi-js": { "node_modules/bidi-js": {
"version": "1.0.3", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
@@ -2659,6 +2891,12 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
"license": "ISC"
},
"node_modules/dequal": { "node_modules/dequal": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
@@ -3451,6 +3689,18 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/js-yaml": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
"integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/jsdom": { "node_modules/jsdom": {
"version": "27.2.0", "version": "27.2.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.2.0.tgz", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.2.0.tgz",
@@ -4824,6 +5074,13 @@
}, },
"optionalDependencies": { "optionalDependencies": {
"fsevents": "~2.3.3" "fsevents": "~2.3.3"
"node_modules/tunnel": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
"license": "MIT",
"engines": {
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
} }
}, },
"node_modules/type-is": { "node_modules/type-is": {
@@ -4854,6 +5111,18 @@
"node": ">=14.17" "node": ">=14.17"
} }
}, },
"node_modules/undici": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
"license": "MIT",
"dependencies": {
"@fastify/busboy": "^2.0.0"
},
"engines": {
"node": ">=14.0"
}
},
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "7.16.0", "version": "7.16.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
@@ -4861,6 +5130,12 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/universal-user-agent": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==",
"license": "ISC"
},
"node_modules/unpipe": { "node_modules/unpipe": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",

View File

@@ -14,10 +14,13 @@
"license": "ISC", "license": "ISC",
"type": "commonjs", "type": "commonjs",
"dependencies": { "dependencies": {
"@actions/core": "^1.11.1",
"@actions/github": "^6.0.1",
"bullmq": "^5.64.1", "bullmq": "^5.64.1",
"express": "^5.1.0", "express": "^5.1.0",
"fastify": "^5.6.2", "fastify": "^5.6.2",
"ioredis": "^5.8.2", "ioredis": "^5.8.2",
"js-yaml": "^4.1.0",
"node-cron": "^4.2.1", "node-cron": "^4.2.1",
"react": "^19.2.0", "react": "^19.2.0",
"react-dom": "^19.2.0", "react-dom": "^19.2.0",