@nicnocquee/dataqueue 1.36.0 → 1.37.0-beta.20260315151704
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ai/docs-content.json +10 -10
- package/dist/cli.cjs +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/package.json +4 -2
- package/src/install-mcp-command.test.ts +1 -1
- package/src/install-mcp-command.ts +1 -1
package/ai/docs-content.json
CHANGED
|
@@ -63,43 +63,43 @@
|
|
|
63
63
|
"slug": "cli",
|
|
64
64
|
"title": "CLI",
|
|
65
65
|
"description": "Command-line tools for managing DataQueue migrations, project scaffolding, and AI integrations.",
|
|
66
|
-
"content": "DataQueue ships a CLI tool called `dataqueue-cli` that you can run directly with `npx`:\n\n```bash\nnpx dataqueue
|
|
66
|
+
"content": "DataQueue ships a CLI tool called `dataqueue-cli` that you can run directly with `npx`:\n\n```bash\nnpx @nicnocquee/dataqueue <command> [options]\n```\n\n## Commands\n\n| Command | Description |\n| --------------------------------------- | ------------------------------------------------- |\n| [`migrate`](/cli/migrate) | Run PostgreSQL database migrations |\n| [`init`](/cli/init) | Scaffold a Next.js project for DataQueue |\n| [`install-skills`](/cli/install-skills) | Install AI skill files for coding assistants |\n| [`install-rules`](/cli/install-rules) | Install agent rule sets for AI clients |\n| [`install-mcp`](/cli/install-mcp) | Configure the DataQueue MCP server for AI clients |\n| [`mcp`](/cli/mcp) | Start the DataQueue MCP server over stdio |\n\n## Usage\n\nRunning `dataqueue-cli` without a command (or with an unrecognized command) prints the help output:\n\n```\nUsage:\n dataqueue-cli migrate [--envPath <path>] [-s <schema> | --schema <schema>]\n dataqueue-cli init\n dataqueue-cli install-skills\n dataqueue-cli install-rules\n dataqueue-cli install-mcp\n dataqueue-cli mcp\n\nOptions for migrate:\n --envPath <path> Path to a .env file to load environment variables\n -s, --schema <schema> Set the schema to use\n\nAI tooling commands:\n install-skills Install DataQueue skill files for AI assistants\n install-rules Install DataQueue agent rules for AI clients\n install-mcp Configure the DataQueue MCP server for AI clients\n mcp Start the DataQueue MCP server (stdio)\n```"
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
"slug": "cli/init",
|
|
70
70
|
"title": "init",
|
|
71
71
|
"description": "Scaffold a Next.js project for DataQueue with a single command.",
|
|
72
|
-
"content": "Scaffolds your Next.js project with everything needed to start using DataQueue — API routes, a job queue singleton, a cron script, and all required dependencies.\n\n```bash\nnpx dataqueue
|
|
72
|
+
"content": "Scaffolds your Next.js project with everything needed to start using DataQueue — API routes, a job queue singleton, a cron script, and all required dependencies.\n\n```bash\nnpx @nicnocquee/dataqueue init\n```\n\n## What It Does\n\nThe `init` command auto-detects your project structure (App Router vs Pages Router, `src/` directory vs root) and creates the following:\n\n### Files Created\n\n| File | Purpose |\n| ----------------------------------------------- | ------------------------------------------------------ |\n| `app/api/dataqueue/manage/[[...task]]/route.ts` | API route for queue management (App Router) |\n| `pages/api/dataqueue/manage/[[...task]].ts` | API route for queue management (Pages Router) |\n| `lib/dataqueue/queue.ts` | Job queue singleton with a sample `send_email` handler |\n| `cron.sh` | Shell script for local development cron jobs |\n\n> **Note:** Only the API route matching your detected router is created. Existing files\n are never overwritten.\n\n### Dependencies Added\n\n**Production:**\n\n- `@nicnocquee/dataqueue`\n- `@nicnocquee/dataqueue-dashboard`\n- `@nicnocquee/dataqueue-react`\n\n**Development:**\n\n- `dotenv-cli`\n- `ts-node`\n- `node-pg-migrate`\n\n### Scripts Added\n\n| Script | Command |\n| ------------------- | ----------------------------------------------- |\n| `cron` | `bash cron.sh` |\n| `migrate-dataqueue` | `dotenv -e .env.local -- dataqueue-cli migrate` |\n\n## After Running\n\n1. Install the newly added dependencies:\n\n```bash\nnpm install\n```\n\n2. Set up your environment variables in `.env.local`:\n\n```bash\nPG_DATAQUEUE_DATABASE=postgresql://user:password@localhost:5432/mydb\nCRON_SECRET=your-secret-here\n```\n\n3. Run database migrations:\n\n```bash\nnpm run migrate-dataqueue\n```\n\n4. Start your Next.js dev server and the cron script:\n\n```bash\nnpm run dev\nnpm run cron\n```\n\n## Requirements\n\n- Must be run in a Next.js project directory (looks for `next` in `package.json` dependencies)\n- Must have either an `app/` or `pages/` directory"
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
75
|
"slug": "cli/install-mcp",
|
|
76
76
|
"title": "install-mcp",
|
|
77
77
|
"description": "Configure the DataQueue MCP server for AI coding clients.",
|
|
78
|
-
"content": "Configures the DataQueue [MCP](https://modelcontextprotocol.io/) (Model Context Protocol) server in your AI client's configuration. This gives your AI assistant direct access to DataQueue documentation.\n\n```bash\nnpx dataqueue
|
|
78
|
+
"content": "Configures the DataQueue [MCP](https://modelcontextprotocol.io/) (Model Context Protocol) server in your AI client's configuration. This gives your AI assistant direct access to DataQueue documentation.\n\n```bash\nnpx @nicnocquee/dataqueue install-mcp\n```\n\n## Interactive Prompt\n\nThe command prompts you to select your AI client:\n\n```\nDataQueue MCP Server Installer\n\nSelect your AI client:\n\n 1) Cursor\n 2) Claude Code\n 3) VS Code (Copilot)\n 4) Windsurf\n\nEnter choice (1-4):\n```\n\n## What It Configures\n\nThe installer adds a `\"dataqueue\"` server entry to your client's MCP config file:\n\n```json\n{\n \"mcpServers\": {\n \"dataqueue\": {\n \"command\": \"npx\",\n \"args\": [\"dataqueue-cli\", \"mcp\"]\n }\n }\n}\n```\n\nIf the config file already exists, the `dataqueue` entry is merged in without affecting other servers.\n\n## Install Locations\n\n| Client | Config File |\n| ----------------- | ------------------------------------- |\n| Cursor | `.cursor/mcp.json` |\n| Claude Code | `.mcp.json` |\n| VS Code (Copilot) | `.vscode/mcp.json` |\n| Windsurf | `~/.codeium/windsurf/mcp_config.json` |\n\n> **Note:** After installing, your AI client will automatically start the MCP server when\n needed. See the [`mcp`](/cli/mcp) command for details on what the server\n exposes."
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
"slug": "cli/install-rules",
|
|
82
82
|
"title": "install-rules",
|
|
83
83
|
"description": "Install DataQueue agent rules for AI coding clients.",
|
|
84
|
-
"content": "Installs comprehensive DataQueue rule sets into your AI client's configuration. Rules give AI assistants detailed guidance for generating correct DataQueue code.\n\n```bash\nnpx dataqueue
|
|
84
|
+
"content": "Installs comprehensive DataQueue rule sets into your AI client's configuration. Rules give AI assistants detailed guidance for generating correct DataQueue code.\n\n```bash\nnpx @nicnocquee/dataqueue install-rules\n```\n\n## Interactive Prompt\n\nThe command prompts you to select your AI client:\n\n```\nDataQueue Agent Rules Installer\n\nSelect your AI client:\n\n 1) Cursor\n 2) Claude Code\n 3) AGENTS.md (Codex, Jules, OpenCode)\n 4) GitHub Copilot\n 5) Windsurf\n\nEnter choice (1-5):\n```\n\n## Rules Installed\n\nThree rule files are installed, covering the full surface area of DataQueue:\n\n| Rule File | What It Covers |\n| -------------------- | ------------------------------------------------------------- |\n| `basic.md` | Core API — initialization, adding jobs, processing, handlers |\n| `advanced.md` | Advanced features — waits, cron, tokens, cancellation, events |\n| `react-dashboard.md` | React SDK and Dashboard components |\n\n## Install Locations\n\n| Client | Installs To |\n| -------------- | -------------------------------------------------------------------------------------------------------------------------- |\n| Cursor | `.cursor/rules/dataqueue-basic.mdc`, `.cursor/rules/dataqueue-advanced.mdc`, `.cursor/rules/dataqueue-react-dashboard.mdc` |\n| Claude Code | `CLAUDE.md` (appended between markers) |\n| AGENTS.md | `AGENTS.md` (appended between markers) |\n| GitHub Copilot | `.github/copilot-instructions.md` (appended between markers) |\n| Windsurf | `CONVENTIONS.md` (appended between markers) |\n\n> **Note:** For Cursor, each rule file is written separately. For all other clients, the\n rules are combined and appended to a single file between `<!-- DATAQUEUE\n RULES START -->` and `<!-- DATAQUEUE RULES END -->` markers.\n Re-running the command updates the content between the markers without\n duplicating it."
|
|
85
85
|
},
|
|
86
86
|
{
|
|
87
87
|
"slug": "cli/install-skills",
|
|
88
88
|
"title": "install-skills",
|
|
89
89
|
"description": "Install DataQueue skill files for AI coding assistants.",
|
|
90
|
-
"content": "Copies DataQueue skill files (`SKILL.md`) into your AI coding assistant's skills directory. Skills teach AI assistants DataQueue patterns and best practices.\n\n```bash\nnpx dataqueue
|
|
90
|
+
"content": "Copies DataQueue skill files (`SKILL.md`) into your AI coding assistant's skills directory. Skills teach AI assistants DataQueue patterns and best practices.\n\n```bash\nnpx @nicnocquee/dataqueue install-skills\n```\n\n## Skills Installed\n\n| Skill | What It Covers |\n| -------------------- | ------------------------------------------------------------------ |\n| `dataqueue-core` | Core patterns — initialization, adding jobs, processing, handlers |\n| `dataqueue-advanced` | Advanced features — waits, cron jobs, tokens, cancellation, events |\n| `dataqueue-react` | React SDK and Dashboard integration |\n\n## Auto-Detection\n\nThe command automatically detects which AI tools are present by checking for their config directories:\n\n| AI Tool | Detected By | Skills Installed To |\n| -------------- | ----------- | ------------------- |\n| Cursor | `.cursor/` | `.cursor/skills/` |\n| Claude Code | `.claude/` | `.claude/skills/` |\n| GitHub Copilot | `.github/` | `.github/skills/` |\n\nIf no AI tool directories are detected, it defaults to `.cursor/skills/`.\n\n## Example Output\n\n```\nInstalling skills for Cursor...\n ✓ dataqueue-core\n ✓ dataqueue-advanced\n ✓ dataqueue-react\n\nDone! Installed 3 skill(s) for Cursor.\n```"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
"slug": "cli/mcp",
|
|
94
94
|
"title": "mcp",
|
|
95
95
|
"description": "Start the DataQueue MCP server for AI-powered documentation access.",
|
|
96
|
-
"content": "Starts the DataQueue MCP (Model Context Protocol) server over stdio. This server gives AI coding assistants live access to the full DataQueue documentation.\n\n```bash\nnpx dataqueue
|
|
96
|
+
"content": "Starts the DataQueue MCP (Model Context Protocol) server over stdio. This server gives AI coding assistants live access to the full DataQueue documentation.\n\n```bash\nnpx @nicnocquee/dataqueue mcp\n```\n\n> **Note:** You typically don't run this command directly. Use\n [`install-mcp`](/cli/install-mcp) to configure your AI client, which will\n start the server automatically.\n\n## Tools Exposed\n\nThe MCP server exposes three tools that AI assistants can call:\n\n| Tool | Description |\n| ---------------- | ------------------------------------------------------------------------------ |\n| `list-doc-pages` | Lists all available documentation pages with titles and descriptions |\n| `get-doc-page` | Fetches a specific page by slug (e.g., `\"usage/add-job\"` or `\"api/job-queue\"`) |\n| `search-docs` | Full-text search across all documentation pages with term matching |\n\n## Resources\n\nThe server also exposes a resource:\n\n| URI | Description |\n| ---------------------- | ------------------------------------------------------- |\n| `dataqueue://llms.txt` | Machine-readable DataQueue overview for LLM consumption |\n\n## How It Works\n\nThe server loads a bundled `docs-content.json` file containing all DataQueue documentation pages. Search uses simple term matching across page titles, descriptions, and content, returning the top 5 results with relevant excerpts.\n\nCommunication happens over stdio using the [Model Context Protocol](https://modelcontextprotocol.io/), so it works with any MCP-compatible client."
|
|
97
97
|
},
|
|
98
98
|
{
|
|
99
99
|
"slug": "cli/migrate",
|
|
100
100
|
"title": "migrate",
|
|
101
101
|
"description": "Run PostgreSQL database migrations for DataQueue.",
|
|
102
|
-
"content": "Runs the DataQueue database migrations against your PostgreSQL database using [node-pg-migrate](https://github.com/salsita/node-pg-migrate).\n\n```bash\nnpx dataqueue
|
|
102
|
+
"content": "Runs the DataQueue database migrations against your PostgreSQL database using [node-pg-migrate](https://github.com/salsita/node-pg-migrate).\n\n```bash\nnpx @nicnocquee/dataqueue migrate [options]\n```\n\n## Options\n\n| Option | Description |\n| ----------------------- | ------------------------------------------------------------------------------ |\n| `--envPath <path>` | Path to a `.env` file to load environment variables from |\n| `-s, --schema <schema>` | PostgreSQL schema to use. Automatically creates the schema if it doesn't exist |\n\n## Environment Variables\n\nThe migration reads the connection string from the `PG_DATAQUEUE_DATABASE` environment variable. You can set it directly or load it from a `.env` file using `--envPath`.\n\n## Examples\n\nRun migrations using environment variables already set in your shell:\n\n```bash\nnpx @nicnocquee/dataqueue migrate\n```\n\nLoad environment variables from a specific `.env` file:\n\n```bash\nnpx @nicnocquee/dataqueue migrate --envPath .env.local\n```\n\nRun migrations in a custom PostgreSQL schema:\n\n```bash\nnpx @nicnocquee/dataqueue migrate --schema my_schema\n```\n\nCombine both options:\n\n```bash\nnpx @nicnocquee/dataqueue migrate --envPath .env.local --schema my_schema\n```\n\n## How It Works\n\nUnder the hood, `dataqueue-cli migrate` runs:\n\n```bash\nnpx node-pg-migrate up \\\n -t dataqueuedev_migrations \\\n -d PG_DATAQUEUE_DATABASE \\\n -m <bundled-migrations-dir> \\\n [--envPath <path>] \\\n [-s <schema> --create-schema]\n```\n\nThe migrations directory is bundled with the `@nicnocquee/dataqueue` package, so you don't need to manage migration files yourself.\n\n> **Note:** This command is only needed for the PostgreSQL backend. The Redis backend\n requires no migrations."
|
|
103
103
|
},
|
|
104
104
|
{
|
|
105
105
|
"slug": "example",
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
"slug": "usage/building-with-ai",
|
|
148
148
|
"title": "Building with AI",
|
|
149
149
|
"description": "Tools and resources for building DataQueue projects with AI coding assistants.",
|
|
150
|
-
"content": "We provide multiple tools to help AI coding assistants write correct DataQueue code. Use one or all of them for the best developer experience.\n\n## Quick Setup\n\n### 1. Install Skills\n\nPortable instruction sets that teach any AI coding assistant DataQueue best practices.\n\n```bash\nnpx dataqueue
|
|
150
|
+
"content": "We provide multiple tools to help AI coding assistants write correct DataQueue code. Use one or all of them for the best developer experience.\n\n## Quick Setup\n\n### 1. Install Skills\n\nPortable instruction sets that teach any AI coding assistant DataQueue best practices.\n\n```bash\nnpx @nicnocquee/dataqueue install-skills\n```\n\nSkills are installed as `SKILL.md` files into your AI tool's skills directory (`.cursor/skills/`, `.claude/skills/`, etc.). They cover core patterns, advanced features (waits, cron, tokens), and React/Dashboard integration.\n\n### 2. Install Agent Rules\n\nComprehensive rule sets installed directly into your AI client's config files.\n\n```bash\nnpx @nicnocquee/dataqueue install-rules\n```\n\nThe installer prompts you to choose your AI client and writes rules to the appropriate location:\n\n| Client | Installs to |\n| -------------- | --------------------------------- |\n| Cursor | `.cursor/rules/dataqueue-*.mdc` |\n| Claude Code | `CLAUDE.md` |\n| AGENTS.md | `AGENTS.md` |\n| GitHub Copilot | `.github/copilot-instructions.md` |\n| Windsurf | `CONVENTIONS.md` |\n\n### 3. Install MCP Server\n\nGive your AI assistant direct access to DataQueue documentation — search docs, fetch specific pages, and list all available topics.\n\n```bash\nnpx @nicnocquee/dataqueue install-mcp\n```\n\nThe installer prompts you to choose your AI client and writes the MCP config to the appropriate location. Currently supported clients:\n\n| Client | Installs to |\n| ----------------- | ------------------------------------- |\n| Cursor | `.cursor/mcp.json` |\n| Claude Code | `.mcp.json` |\n| VS Code (Copilot) | `.vscode/mcp.json` |\n| Windsurf | `~/.codeium/windsurf/mcp_config.json` |\n\nThe MCP server runs via `npx @nicnocquee/dataqueue mcp` and communicates over stdio. It exposes three tools:\n\n| Tool | Description |\n| ---------------- | ---------------------------------------- |\n| `search-docs` | Full-text search across all doc pages |\n| `get-doc-page` | Fetch a specific doc page by slug |\n| `list-doc-pages` | List all available doc pages with titles |\n\n## Skills vs Agent Rules vs MCP\n\n| | **Skills** | **Agent Rules** | **MCP Server** |\n| :---------------- | :----------------------------------- | :------------------------------------- | :------------------------------------- |\n| **What it does** | Drops skill files into your project | Installs rule sets into client config | Runs a live server your AI connects to |\n| **Installs to** | `.cursor/skills/`, `.claude/skills/` | `.cursor/rules/`, `CLAUDE.md`, etc. | `.cursor/mcp.json`, `.mcp.json`, etc. |\n| **Best for** | Teaching patterns and best practices | Comprehensive code generation guidance | Live documentation search |\n| **Works offline** | Yes | Yes | Yes (runs locally) |\n\n**Recommendation:** Install all three. Skills and Agent Rules teach your AI _how_ to write code. The MCP Server lets it _look up_ the docs when it needs specifics.\n\n## llms.txt\n\nWe publish machine-readable documentation for LLM consumption:\n\n- [docs.dataqueue.dev/llms.txt](https://docs.dataqueue.dev/llms.txt) — concise overview\n- [docs.dataqueue.dev/llms-full.txt](https://docs.dataqueue.dev/llms-full.txt) — full documentation\n\nThese follow the [llms.txt standard](https://llmstxt.org) and can be fed directly into any LLM context window.\n\n## Project-Level Context Snippet\n\nIf you prefer a lightweight approach, paste this snippet into a context file at the root of your project:\n\n| File | Read by |\n| :-------------------------------- | :---------------------------- |\n| `CLAUDE.md` | Claude Code |\n| `AGENTS.md` | OpenAI Codex, Jules, OpenCode |\n| `.cursor/rules/*.md` | Cursor |\n| `.github/copilot-instructions.md` | GitHub Copilot |\n| `CONVENTIONS.md` | Windsurf, Cline, and others |\n\n```markdown\n# DataQueue rules\n\n## Imports\n\nAlways import from `@nicnocquee/dataqueue`.\n\n## PayloadMap pattern\n\nDefine a type map of job types to payload shapes for full type safety:\n\n\\`\\`\\`ts\ntype JobPayloadMap = {\nsend_email: { to: string; subject: string; body: string };\n};\n\\`\\`\\`\n\n## Initialization (singleton)\n\nNever call initJobQueue per request — use a module-level singleton:\n\n\\`\\`\\`ts\nimport { initJobQueue } from '@nicnocquee/dataqueue';\nlet queue: ReturnType<typeof initJobQueue<JobPayloadMap>> | null = null;\nexport const getJobQueue = () => {\nif (!queue) {\nqueue = initJobQueue<JobPayloadMap>({\ndatabaseConfig: { connectionString: process.env.PG_DATAQUEUE_DATABASE },\n});\n}\nreturn queue;\n};\n\\`\\`\\`\n\n## Handler pattern\n\nType handlers as `JobHandlers<PayloadMap>` — TypeScript enforces a handler for every job type.\n\n## Processing\n\n- Serverless: `processor.start()` (one-shot)\n- Long-running: `processor.startInBackground()` + `stopAndDrain()` on SIGTERM\n\n## Common mistakes\n\n1. Creating initJobQueue per request (creates a DB pool each time)\n2. Missing handler for a job type (fails with NoHandler)\n3. Not checking signal.aborted in long handlers\n4. Forgetting dead-letter routing for critical jobs — set `deadLetterJobType` so exhausted failures are inspectable/replayable\n5. Forgetting reclaimStuckJobs() — crashed workers leave jobs stuck\n6. Skipping migrations (PostgreSQL requires `dataqueue-cli migrate`)\n```"
|
|
151
151
|
},
|
|
152
152
|
{
|
|
153
153
|
"slug": "usage/cancel-jobs",
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
"slug": "usage/cron-jobs",
|
|
166
166
|
"title": "Cron Jobs (Recurring Schedules)",
|
|
167
167
|
"description": "Define recurring jobs that automatically enqueue on a cron schedule.",
|
|
168
|
-
"content": "DataQueue supports recurring cron schedules. Define a schedule with a cron expression, and the processor will **automatically enqueue** job instances before each batch — no extra code required.\n\n## Add a Cron Schedule\n\n```typescript title=\"@/app/api/cron-schedules/route.ts\"\nimport { NextRequest, NextResponse } from 'next/server';\nimport { getJobQueue } from '@/lib/queue';\n\nexport async function POST(request: NextRequest) {\n const jobQueue = getJobQueue();const id = await jobQueue.addCronJob({\n scheduleName: 'daily-report', // must be unique!\n cronExpression: '0 9 * * *', // every day at 9:00 AM\n jobType: 'generate_report',\n payload: { reportId: 'daily', userId: 'system' },\n timezone: 'America/New_York', // default: 'UTC'\n });\n return NextResponse.json({ id });\n}\n```\n\n### Options\n\n| Option | Type | Default | Description |\n| ---------------- | ---------- | ---------- | -------------------------------------------------- |\n| `scheduleName` | `string` | _required_ | Unique name for the schedule |\n| `cronExpression` | `string` | _required_ | Standard 5-field cron expression |\n| `jobType` | `string` | _required_ | Job type from your PayloadMap |\n| `payload` | `object` | _required_ | Payload for each job instance |\n| `timezone` | `string` | `'UTC'` | IANA timezone for cron evaluation |\n| `allowOverlap` | `boolean` | `false` | Allow new instance while previous is still running |\n| `maxAttempts` | `number` | `3` | Max retry attempts per job instance |\n| `priority` | `number` | `0` | Priority for each job instance |\n| `timeoutMs` | `number` | — | Timeout per job instance |\n| `tags` | `string[]` | — | Tags for each job instance |\n\n## Automatic Enqueueing\n\nWhen you call `processor.start()` or `processor.startInBackground()`, DataQueue automatically checks all active cron schedules and enqueues jobs whose next run time has passed — **before** processing the batch.\n\n```typescript title=\"@/app/api/cron/process/route.ts\"\nimport { NextRequest, NextResponse } from 'next/server';\nimport { getJobQueue, jobHandlers } from '@/lib/queue';\n\nexport async function GET(request: NextRequest) {\n const authHeader = request.headers.get('authorization');\n if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n const jobQueue = getJobQueue();// Cron jobs are automatically enqueued before each batch\n const processor = jobQueue.createProcessor(jobHandlers, {\n batchSize: 10,\n concurrency: 3,\n });\n const processed = await processor.start();\n\n return NextResponse.json({ processed });\n}\n```\n\n### Vercel Cron Example\n\n```json title=\"vercel.json\"\n{\n \"crons\": [\n {\n \"path\": \"/api/cron/process\",\n \"schedule\": \"* * * * *\"\n }\n ]\n}\n```\n\n### Manual Trigger\n\nIf you need to enqueue due cron jobs outside the processor (e.g., in tests or one-off scripts), you can still call `enqueueDueCronJobs()` directly:\n\n```typescript\nconst enqueued = await jobQueue.enqueueDueCronJobs();\n```\n\n## Overlap Protection\n\nBy default, `allowOverlap` is `false`. This means if a previous job instance from the same schedule is still **pending**, **processing**, or **waiting**, a new instance will **not** be enqueued — even if the cron expression says it's time.\n\n```typescript\n// Allow overlapping instances (e.g., for idempotent jobs)\nawait jobQueue.addCronJob({\n scheduleName: 'heartbeat',\n cronExpression: '* * * * *',\n jobType: 'send_email',\n payload: { to: 'admin@example.com', subject: 'heartbeat', body: 'ping' },allowOverlap: true,\n});\n```\n\n## Manage Schedules\n\n### Pause and Resume\n\n```typescript\n// Pause — skipped during automatic enqueueing\nawait jobQueue.pauseCronJob(scheduleId);\n\n// Resume\nawait jobQueue.resumeCronJob(scheduleId);\n```\n\n### Edit a Schedule\n\n```typescript\nawait jobQueue.editCronJob(scheduleId, {\n cronExpression: '0 */2 * * *', // change to every 2 hours\n payload: { reportId: 'bi-hourly', userId: 'system' },\n});\n```\n\nWhen `cronExpression` or `timezone` changes, `nextRunAt` is automatically recalculated.\n\n### Remove a Schedule\n\n```typescript\n// Deletes the schedule definition. Already-enqueued jobs are not cancelled.\nawait jobQueue.removeCronJob(scheduleId);\n```\n\n### List and Query\n\n```typescript\n// List all schedules\nconst all = await jobQueue.listCronJobs();\n\n// List only active / paused\nconst active = await jobQueue.listCronJobs('active');\nconst paused = await jobQueue.listCronJobs('paused');\n\n// Get by ID or name\nconst byId = await jobQueue.getCronJob(id);\nconst byName = await jobQueue.getCronJobByName('daily-report');\n```\n\n## Database Migration\n\nThe cron feature requires the `cron_schedules` table. Run the DataQueue migrations to create it:\n\n```bash\nnpx dataqueue
|
|
168
|
+
"content": "DataQueue supports recurring cron schedules. Define a schedule with a cron expression, and the processor will **automatically enqueue** job instances before each batch — no extra code required.\n\n## Add a Cron Schedule\n\n```typescript title=\"@/app/api/cron-schedules/route.ts\"\nimport { NextRequest, NextResponse } from 'next/server';\nimport { getJobQueue } from '@/lib/queue';\n\nexport async function POST(request: NextRequest) {\n const jobQueue = getJobQueue();const id = await jobQueue.addCronJob({\n scheduleName: 'daily-report', // must be unique!\n cronExpression: '0 9 * * *', // every day at 9:00 AM\n jobType: 'generate_report',\n payload: { reportId: 'daily', userId: 'system' },\n timezone: 'America/New_York', // default: 'UTC'\n });\n return NextResponse.json({ id });\n}\n```\n\n### Options\n\n| Option | Type | Default | Description |\n| ---------------- | ---------- | ---------- | -------------------------------------------------- |\n| `scheduleName` | `string` | _required_ | Unique name for the schedule |\n| `cronExpression` | `string` | _required_ | Standard 5-field cron expression |\n| `jobType` | `string` | _required_ | Job type from your PayloadMap |\n| `payload` | `object` | _required_ | Payload for each job instance |\n| `timezone` | `string` | `'UTC'` | IANA timezone for cron evaluation |\n| `allowOverlap` | `boolean` | `false` | Allow new instance while previous is still running |\n| `maxAttempts` | `number` | `3` | Max retry attempts per job instance |\n| `priority` | `number` | `0` | Priority for each job instance |\n| `timeoutMs` | `number` | — | Timeout per job instance |\n| `tags` | `string[]` | — | Tags for each job instance |\n\n## Automatic Enqueueing\n\nWhen you call `processor.start()` or `processor.startInBackground()`, DataQueue automatically checks all active cron schedules and enqueues jobs whose next run time has passed — **before** processing the batch.\n\n```typescript title=\"@/app/api/cron/process/route.ts\"\nimport { NextRequest, NextResponse } from 'next/server';\nimport { getJobQueue, jobHandlers } from '@/lib/queue';\n\nexport async function GET(request: NextRequest) {\n const authHeader = request.headers.get('authorization');\n if (authHeader !== `Bearer ${process.env.CRON_SECRET}`) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\n }\n\n const jobQueue = getJobQueue();// Cron jobs are automatically enqueued before each batch\n const processor = jobQueue.createProcessor(jobHandlers, {\n batchSize: 10,\n concurrency: 3,\n });\n const processed = await processor.start();\n\n return NextResponse.json({ processed });\n}\n```\n\n### Vercel Cron Example\n\n```json title=\"vercel.json\"\n{\n \"crons\": [\n {\n \"path\": \"/api/cron/process\",\n \"schedule\": \"* * * * *\"\n }\n ]\n}\n```\n\n### Manual Trigger\n\nIf you need to enqueue due cron jobs outside the processor (e.g., in tests or one-off scripts), you can still call `enqueueDueCronJobs()` directly:\n\n```typescript\nconst enqueued = await jobQueue.enqueueDueCronJobs();\n```\n\n## Overlap Protection\n\nBy default, `allowOverlap` is `false`. This means if a previous job instance from the same schedule is still **pending**, **processing**, or **waiting**, a new instance will **not** be enqueued — even if the cron expression says it's time.\n\n```typescript\n// Allow overlapping instances (e.g., for idempotent jobs)\nawait jobQueue.addCronJob({\n scheduleName: 'heartbeat',\n cronExpression: '* * * * *',\n jobType: 'send_email',\n payload: { to: 'admin@example.com', subject: 'heartbeat', body: 'ping' },allowOverlap: true,\n});\n```\n\n## Manage Schedules\n\n### Pause and Resume\n\n```typescript\n// Pause — skipped during automatic enqueueing\nawait jobQueue.pauseCronJob(scheduleId);\n\n// Resume\nawait jobQueue.resumeCronJob(scheduleId);\n```\n\n### Edit a Schedule\n\n```typescript\nawait jobQueue.editCronJob(scheduleId, {\n cronExpression: '0 */2 * * *', // change to every 2 hours\n payload: { reportId: 'bi-hourly', userId: 'system' },\n});\n```\n\nWhen `cronExpression` or `timezone` changes, `nextRunAt` is automatically recalculated.\n\n### Remove a Schedule\n\n```typescript\n// Deletes the schedule definition. Already-enqueued jobs are not cancelled.\nawait jobQueue.removeCronJob(scheduleId);\n```\n\n### List and Query\n\n```typescript\n// List all schedules\nconst all = await jobQueue.listCronJobs();\n\n// List only active / paused\nconst active = await jobQueue.listCronJobs('active');\nconst paused = await jobQueue.listCronJobs('paused');\n\n// Get by ID or name\nconst byId = await jobQueue.getCronJob(id);\nconst byName = await jobQueue.getCronJobByName('daily-report');\n```\n\n## Database Migration\n\nThe cron feature requires the `cron_schedules` table. Run the DataQueue migrations to create it:\n\n```bash\nnpx @nicnocquee/dataqueue migrate up\n```\n\nIf you're already using DataQueue, just run migrations again — the new table will be added alongside existing ones."
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
171
|
"slug": "usage/dashboard",
|
|
@@ -261,7 +261,7 @@
|
|
|
261
261
|
"slug": "usage/quick-start",
|
|
262
262
|
"title": "Quick Start",
|
|
263
263
|
"description": "Get started with DataQueue",
|
|
264
|
-
"content": "In this docs, we'll use a Next.js with App Router project which is deployed to Vercel as an example.\n\n## Next.js Shortcut\n\nIf you're using Next.js, you can scaffold everything — API routes, a job queue singleton, a cron script, and all dependencies — with a single command:\n\n```bash\nnpx dataqueue
|
|
264
|
+
"content": "In this docs, we'll use a Next.js with App Router project which is deployed to Vercel as an example.\n\n## Next.js Shortcut\n\nIf you're using Next.js, you can scaffold everything — API routes, a job queue singleton, a cron script, and all dependencies — with a single command:\n\n```bash\nnpx @nicnocquee/dataqueue init\n```\n\nThe command auto-detects your project structure (App Router vs Pages Router, `src/` directory vs root) and creates all the files you need. See the [`init` CLI reference](/cli/init) for full details.\n\nIf you prefer to set things up manually, follow the steps below.\n\n## PostgreSQL Backend\n\n1. [Run migrations before deploying your app](/usage/database-migration)\n2. [Define job handlers](/usage/job-handlers)\n3. [Initialize the job queue](/usage/init-queue)\n4. [Add a job](/usage/add-job)\n5. Create three API routes to [process jobs](/usage/process-jobs), [reclaim stuck jobs](/usage/reclaim-jobs), and [cleanup old jobs](/usage/cleanup-jobs)\n6. [Call those API routes periodically](/usage/process-jobs#triggering-the-processor-via-cron) via a cron service (like Vercel cron) or a small script like [this one](https://github.com/nicnocquee/dataqueue/blob/main/apps/demo/cron.sh) during development.\n\n## Redis Backend\n\n1. [Install `ioredis`](/intro/install)\n2. [Define job handlers](/usage/job-handlers)\n3. [Initialize the job queue with Redis config](/usage/init-queue#redis)\n4. [Add a job](/usage/add-job)\n5. Create three API routes to [process jobs](/usage/process-jobs), [reclaim stuck jobs](/usage/reclaim-jobs), and [cleanup old jobs](/usage/cleanup-jobs)\n6. [Call those API routes periodically](/usage/process-jobs#triggering-the-processor-via-cron) via a cron service (like Vercel cron) or a small script like [this one](https://github.com/nicnocquee/dataqueue/blob/main/apps/demo/cron.sh) during development.\n\n> **Note:** The Redis backend requires **no database migrations**. Just install `ioredis`,\n configure the connection, and you're ready to go.\n\n## Long-Running Server\n\nIf you're running a persistent server (Express, Fastify, plain Node.js, etc.) instead of a serverless environment, the setup is slightly different:\n\n1. [Run migrations](/usage/database-migration) (PostgreSQL) or [install `ioredis`](/intro/install) (Redis)\n2. [Define job handlers](/usage/job-handlers)\n3. [Initialize the job queue](/usage/init-queue)\n4. Start the processor in the background with `startInBackground()`\n5. Start the [background supervisor](/usage/long-running-server#background-supervisor) with `createSupervisor()` to automate maintenance (reclaim stuck jobs, cleanup old data)\n6. Handle `SIGTERM`/`SIGINT` for graceful shutdown with `stopAndDrain()`\n\nSee [Long-Running Server](/usage/long-running-server) for a complete walkthrough and full example."
|
|
265
265
|
},
|
|
266
266
|
{
|
|
267
267
|
"slug": "usage/react-sdk",
|
package/dist/cli.cjs
CHANGED
|
@@ -929,7 +929,7 @@ Installing MCP config for ${client.label}...`);
|
|
|
929
929
|
existsSync: existsSync2,
|
|
930
930
|
log
|
|
931
931
|
});
|
|
932
|
-
log("\nDone! The MCP server will run via: npx dataqueue
|
|
932
|
+
log("\nDone! The MCP server will run via: npx @nicnocquee/dataqueue mcp");
|
|
933
933
|
} catch (err) {
|
|
934
934
|
error("Failed to install MCP config:", err);
|
|
935
935
|
exit(1);
|
package/dist/cli.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/init-command.ts","../src/install-skills-command.ts","../src/install-rules-command.ts","../src/install-mcp-command.ts","../src/mcp-server.ts","../src/cli.ts"],"names":["readFileSync","writeFileSync","existsSync","mkdirSync","chmodSync","path","__filename","fileURLToPath","__dirname","fs","client","readline","McpServer","z","StdioServerTransport","spawnSync","loadDotenv"],"mappings":"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","file":"cli.cjs","sourcesContent":["import {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n} from 'fs';\nimport path from 'path';\n\ntype JsonObject = Record<string, unknown>;\ntype JsonMap = Record<string, string>;\n\nconst DEPENDENCIES_TO_ADD = [\n '@nicnocquee/dataqueue',\n '@nicnocquee/dataqueue-dashboard',\n '@nicnocquee/dataqueue-react',\n] as const;\n\nconst DEV_DEPENDENCIES_TO_ADD = [\n 'dotenv-cli',\n 'ts-node',\n 'node-pg-migrate',\n] as const;\n\nconst SCRIPTS_TO_ADD = {\n cron: 'bash cron.sh',\n 'migrate-dataqueue': 'dotenv -e .env.local -- dataqueue-cli migrate',\n} as const;\n\n/**\n * App router endpoint template for queue management.\n */\nexport const APP_ROUTER_ROUTE_TEMPLATE = `/**\n * This end point is used to manage the job queue.\n * It supports the following tasks:\n * - reclaim: Reclaim stuck jobs\n * - cleanup: Cleanup old jobs\n * - process: Process jobs\n *\n * Example usage with default values (reclaim stuck jobs for 10 minutes, cleanup old jobs for 30 days, and process jobs with batch size 3, concurrency 2, and verbose true):\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\"\n *\n * Example usage with custom values:\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"maxProcessingTimeMinutes\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"daysToKeep\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"batchSize\": 5, \"concurrency\": 3, \"verbose\": false, \"workerId\": \"custom-worker-id\"}' -H \"Content-Type: application/json\"\n *\n * During development, you can run the following script to run the cron jobs continuously in the background:\n * pnpm cron\n */\nimport { getJobQueue, jobHandlers } from '@/lib/dataqueue/queue';\nimport { NextResponse } from 'next/server';\n\nexport async function POST(\n request: Request,\n { params }: { params: Promise<{ task: string[] }> },\n) {\n const { task } = await params;\n const authHeader = request.headers.get('authorization');\n if (authHeader !== \\`Bearer \\${process.env.CRON_SECRET}\\`) {\n return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });\n }\n\n if (!task || task.length === 0) {\n return NextResponse.json({ message: 'Task is required' }, { status: 400 });\n }\n\n const supportedTasks = ['reclaim', 'cleanup', 'process'];\n const theTask = task[0];\n if (!supportedTasks.includes(theTask)) {\n return NextResponse.json(\n { message: 'Task not supported' },\n { status: 400 },\n );\n }\n\n try {\n const jobQueue = getJobQueue();\n\n if (theTask === 'reclaim') {\n let maxProcessingTimeMinutes = 10;\n try {\n const body = await request.json();\n maxProcessingTimeMinutes = body.maxProcessingTimeMinutes || 10;\n } catch {\n // ignore parsing error and use default value\n }\n const reclaimed = await jobQueue.reclaimStuckJobs(\n maxProcessingTimeMinutes,\n );\n console.log(\\`Reclaimed \\${reclaimed} stuck jobs\\`);\n return NextResponse.json({\n message: \\`Stuck jobs reclaimed: \\${reclaimed} with maxProcessingTimeMinutes: \\${maxProcessingTimeMinutes}\\`,\n reclaimed,\n });\n }\n\n if (theTask === 'cleanup') {\n let daysToKeep = 30;\n try {\n const body = await request.json();\n daysToKeep = body.daysToKeep || 30;\n } catch {\n // ignore parsing error and use default value\n }\n const deleted = await jobQueue.cleanupOldJobs(daysToKeep);\n console.log(\\`Deleted \\${deleted} old jobs\\`);\n return NextResponse.json({\n message: \\`Old jobs cleaned up: \\${deleted} with daysToKeep: \\${daysToKeep}\\`,\n deleted,\n });\n }\n\n if (theTask === 'process') {\n let batchSize = 3;\n let concurrency = 2;\n let verbose = true;\n let workerId = \\`manage-\\${theTask}-\\${Date.now()}\\`;\n try {\n const body = await request.json();\n batchSize = body.batchSize || 3;\n concurrency = body.concurrency || 2;\n verbose = body.verbose || true;\n workerId = body.workerId || \\`manage-\\${theTask}-\\${Date.now()}\\`;\n } catch {\n // ignore parsing error and use default value\n }\n const processor = jobQueue.createProcessor(jobHandlers, {\n workerId,\n batchSize,\n concurrency,\n verbose,\n });\n const processed = await processor.start();\n\n return NextResponse.json({\n message: \\`Jobs processed: \\${processed} with workerId: \\${workerId}, batchSize: \\${batchSize}, concurrency: \\${concurrency}, and verbose: \\${verbose}\\`,\n processed,\n });\n }\n\n return NextResponse.json(\n { message: 'Task not supported' },\n { status: 400 },\n );\n } catch (error) {\n console.error('Error processing jobs:', error);\n return NextResponse.json(\n { message: 'Failed to process jobs' },\n { status: 500 },\n );\n }\n}\n`;\n\n/**\n * Pages router endpoint template for queue management.\n */\nexport const PAGES_ROUTER_ROUTE_TEMPLATE = `/**\n * This end point is used to manage the job queue.\n * It supports the following tasks:\n * - reclaim: Reclaim stuck jobs\n * - cleanup: Cleanup old jobs\n * - process: Process jobs\n *\n * Example usage with default values (reclaim stuck jobs for 10 minutes, cleanup old jobs for 30 days, and process jobs with batch size 3, concurrency 2, and verbose true):\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\"\n *\n * Example usage with custom values:\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"maxProcessingTimeMinutes\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"daysToKeep\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"batchSize\": 5, \"concurrency\": 3, \"verbose\": false, \"workerId\": \"custom-worker-id\"}' -H \"Content-Type: application/json\"\n *\n * During development, you can run the following script to run the cron jobs continuously in the background:\n * pnpm cron\n */\nimport type { NextApiRequest, NextApiResponse } from 'next';\nimport { getJobQueue, jobHandlers } from '@/lib/dataqueue/queue';\n\ntype ResponseBody = {\n message: string;\n reclaimed?: number;\n deleted?: number;\n processed?: number;\n};\n\nexport default async function handler(\n req: NextApiRequest,\n res: NextApiResponse<ResponseBody>,\n) {\n if (req.method !== 'POST') {\n res.setHeader('Allow', 'POST');\n return res.status(405).json({ message: 'Method not allowed' });\n }\n\n const authHeader = req.headers.authorization;\n if (authHeader !== \\`Bearer \\${process.env.CRON_SECRET}\\`) {\n return res.status(401).json({ message: 'Unauthorized' });\n }\n\n const task = req.query.task;\n const taskArray = Array.isArray(task) ? task : task ? [task] : [];\n if (!taskArray.length) {\n return res.status(400).json({ message: 'Task is required' });\n }\n\n const supportedTasks = ['reclaim', 'cleanup', 'process'];\n const theTask = taskArray[0];\n if (!supportedTasks.includes(theTask)) {\n return res.status(400).json({ message: 'Task not supported' });\n }\n\n try {\n const jobQueue = getJobQueue();\n const body = typeof req.body === 'object' && req.body ? req.body : {};\n\n if (theTask === 'reclaim') {\n const maxProcessingTimeMinutes = body.maxProcessingTimeMinutes || 10;\n const reclaimed = await jobQueue.reclaimStuckJobs(maxProcessingTimeMinutes);\n console.log(\\`Reclaimed \\${reclaimed} stuck jobs\\`);\n return res.status(200).json({\n message: \\`Stuck jobs reclaimed: \\${reclaimed} with maxProcessingTimeMinutes: \\${maxProcessingTimeMinutes}\\`,\n reclaimed,\n });\n }\n\n if (theTask === 'cleanup') {\n const daysToKeep = body.daysToKeep || 30;\n const deleted = await jobQueue.cleanupOldJobs(daysToKeep);\n console.log(\\`Deleted \\${deleted} old jobs\\`);\n return res.status(200).json({\n message: \\`Old jobs cleaned up: \\${deleted} with daysToKeep: \\${daysToKeep}\\`,\n deleted,\n });\n }\n\n const batchSize = body.batchSize || 3;\n const concurrency = body.concurrency || 2;\n const verbose = body.verbose || true;\n const workerId = body.workerId || \\`manage-\\${theTask}-\\${Date.now()}\\`;\n const processor = jobQueue.createProcessor(jobHandlers, {\n workerId,\n batchSize,\n concurrency,\n verbose,\n });\n const processed = await processor.start();\n\n return res.status(200).json({\n message: \\`Jobs processed: \\${processed} with workerId: \\${workerId}, batchSize: \\${batchSize}, concurrency: \\${concurrency}, and verbose: \\${verbose}\\`,\n processed,\n });\n } catch (error) {\n console.error('Error processing jobs:', error);\n return res.status(500).json({ message: 'Failed to process jobs' });\n }\n}\n`;\n\n/**\n * Cron script template for local queue processing.\n */\nexport const CRON_SH_TEMPLATE = `#!/bin/bash\n\n# This script is used to run the cron jobs for the demo app during development.\n# Run it with \\`pnpm cron\\` from the apps/demo directory.\n\nset -a\nsource \"$(dirname \"$0\")/.env.local\"\nset +a\n\nif [ -z \"$CRON_SECRET\" ]; then\n echo \"Error: CRON_SECRET environment variable is not set in .env.local\"\n exit 1\nfi\n\ncleanup() {\n kill 0\n wait\n}\ntrap cleanup SIGINT SIGTERM\n\nwhile true; do\n echo \"Processing jobs...\"\n curl http://localhost:3000/api/dataqueue/manage/process -X POST -H \"Authorization: Bearer $CRON_SECRET\"\n echo \"\"\n sleep 10 # Process jobs every 10 seconds\ndone &\n\nwhile true; do\n echo \"Reclaiming stuck jobs...\"\n curl http://localhost:3000/api/dataqueue/manage/reclaim -X POST -H \"Authorization: Bearer $CRON_SECRET\"\n echo \"\"\n sleep 20 # Reclaim stuck jobs every 20 seconds\ndone &\n\nwhile true; do\n echo \"Cleaning up old jobs...\"\n curl http://localhost:3000/api/dataqueue/manage/cleanup -X POST -H \"Authorization: Bearer $CRON_SECRET\"\n echo \"\"\n sleep 30 # Cleanup old jobs every 30 seconds\ndone &\n\nwait\n`;\n\n/**\n * Queue placeholder template with a single `send_email` job.\n */\nexport const QUEUE_TEMPLATE = `import { initJobQueue, JobHandlers } from '@nicnocquee/dataqueue';\n\nexport type JobPayloadMap = {\n send_email: {\n to: string;\n subject: string;\n body: string;\n };\n};\n\nlet jobQueue: ReturnType<typeof initJobQueue<JobPayloadMap>> | null = null;\n\nexport const getJobQueue = () => {\n if (!jobQueue) {\n jobQueue = initJobQueue<JobPayloadMap>({\n databaseConfig: {\n connectionString: process.env.PG_DATAQUEUE_DATABASE,\n },\n verbose: process.env.NODE_ENV === 'development',\n });\n }\n return jobQueue;\n};\n\nexport const jobHandlers: JobHandlers<JobPayloadMap> = {\n send_email: async (payload) => {\n const { to, subject, body } = payload;\n console.log('send_email placeholder:', { to, subject, body });\n },\n};\n`;\n\nexport interface InitDeps {\n log?: (...args: any[]) => void;\n error?: (...args: any[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n readFileSyncImpl?: typeof readFileSync;\n writeFileSyncImpl?: typeof writeFileSync;\n existsSyncImpl?: typeof existsSync;\n mkdirSyncImpl?: typeof mkdirSync;\n chmodSyncImpl?: typeof chmodSync;\n}\n\ntype RouterKind = 'app' | 'pages';\n\ninterface ProjectDetails {\n cwd: string;\n packageJsonPath: string;\n packageJson: JsonObject;\n srcRoot: string;\n router: RouterKind;\n}\n\n/**\n * Runs the `dataqueue-cli init` command.\n */\nexport function runInit({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n readFileSyncImpl = readFileSync,\n writeFileSyncImpl = writeFileSync,\n existsSyncImpl = existsSync,\n mkdirSyncImpl = mkdirSync,\n chmodSyncImpl = chmodSync,\n}: InitDeps = {}): void {\n try {\n log(`dataqueue: Initializing in ${cwd}...`);\n log('');\n\n const details = detectNextJsAndRouter({\n cwd,\n existsSyncImpl,\n readFileSyncImpl,\n });\n\n createScaffoldFiles({\n details,\n log,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n chmodSyncImpl,\n });\n\n updatePackageJson({\n details,\n log,\n writeFileSyncImpl,\n });\n\n log('');\n log(\n \"Done! Run your package manager's install command to install new dependencies.\",\n );\n exit(0);\n } catch (cause) {\n const message = cause instanceof Error ? cause.message : String(cause);\n error(`dataqueue: ${message}`);\n exit(1);\n }\n}\n\n/**\n * Detects that the current directory is a Next.js app and chooses the router.\n */\nexport function detectNextJsAndRouter({\n cwd,\n existsSyncImpl,\n readFileSyncImpl,\n}: {\n cwd: string;\n existsSyncImpl: typeof existsSync;\n readFileSyncImpl: typeof readFileSync;\n}): ProjectDetails {\n const packageJsonPath = path.join(cwd, 'package.json');\n if (!existsSyncImpl(packageJsonPath)) {\n throw new Error('package.json not found in current directory.');\n }\n\n const packageJson = parsePackageJson(\n readFileSyncImpl(packageJsonPath, 'utf8'),\n packageJsonPath,\n );\n if (!isNextJsProject(packageJson)) {\n throw new Error(\n \"Not a Next.js project. Could not find 'next' in package.json dependencies.\",\n );\n }\n\n const srcDir = path.join(cwd, 'src');\n const srcRoot = existsSyncImpl(srcDir) ? 'src' : '.';\n const appDir = path.join(cwd, srcRoot, 'app');\n const pagesDir = path.join(cwd, srcRoot, 'pages');\n const hasAppDir = existsSyncImpl(appDir);\n const hasPagesDir = existsSyncImpl(pagesDir);\n\n if (!hasAppDir && !hasPagesDir) {\n throw new Error(\n 'Could not detect Next.js router. Expected either app/ or pages/ directory.',\n );\n }\n\n const router: RouterKind = hasAppDir ? 'app' : 'pages';\n return { cwd, packageJsonPath, packageJson, srcRoot, router };\n}\n\n/**\n * Updates package.json with required dependencies and scripts.\n */\nfunction updatePackageJson({\n details,\n log,\n writeFileSyncImpl,\n}: {\n details: ProjectDetails;\n log: (...args: any[]) => void;\n writeFileSyncImpl: typeof writeFileSync;\n}): void {\n const packageJson = details.packageJson;\n const dependencies = ensureStringMapSection(packageJson, 'dependencies');\n const devDependencies = ensureStringMapSection(\n packageJson,\n 'devDependencies',\n );\n const scripts = ensureStringMapSection(packageJson, 'scripts');\n\n for (const dependency of DEPENDENCIES_TO_ADD) {\n if (dependencies[dependency]) {\n log(` [skipped] dependency ${dependency} (already exists)`);\n continue;\n }\n dependencies[dependency] = 'latest';\n log(` [added] dependency ${dependency}`);\n }\n\n for (const devDependency of DEV_DEPENDENCIES_TO_ADD) {\n if (devDependencies[devDependency]) {\n log(` [skipped] devDependency ${devDependency} (already exists)`);\n continue;\n }\n devDependencies[devDependency] = 'latest';\n log(` [added] devDependency ${devDependency}`);\n }\n\n for (const [scriptName, scriptValue] of Object.entries(SCRIPTS_TO_ADD)) {\n if (scripts[scriptName]) {\n log(` [skipped] script \"${scriptName}\" (already exists)`);\n continue;\n }\n scripts[scriptName] = scriptValue;\n log(` [added] script \"${scriptName}\"`);\n }\n\n writeFileSyncImpl(\n details.packageJsonPath,\n `${JSON.stringify(packageJson, null, 2)}\\n`,\n );\n}\n\n/**\n * Creates all scaffold files for the detected router without overwriting.\n */\nfunction createScaffoldFiles({\n details,\n log,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n chmodSyncImpl,\n}: {\n details: ProjectDetails;\n log: (...args: any[]) => void;\n existsSyncImpl: typeof existsSync;\n mkdirSyncImpl: typeof mkdirSync;\n writeFileSyncImpl: typeof writeFileSync;\n chmodSyncImpl: typeof chmodSync;\n}): void {\n const appRoutePath = path.join(\n details.cwd,\n details.srcRoot,\n 'app',\n 'api',\n 'dataqueue',\n 'manage',\n '[[...task]]',\n 'route.ts',\n );\n const pagesRoutePath = path.join(\n details.cwd,\n details.srcRoot,\n 'pages',\n 'api',\n 'dataqueue',\n 'manage',\n '[[...task]].ts',\n );\n const queuePath = path.join(\n details.cwd,\n details.srcRoot,\n 'lib',\n 'dataqueue',\n 'queue.ts',\n );\n const cronPath = path.join(details.cwd, 'cron.sh');\n\n if (details.router === 'app') {\n createFileIfMissing({\n absolutePath: appRoutePath,\n content: APP_ROUTER_ROUTE_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: toRelativePath(details.cwd, appRoutePath),\n });\n log(\n ' [skipped] pages/api/dataqueue/manage/[[...task]].ts (router not selected)',\n );\n } else {\n log(\n ' [skipped] app/api/dataqueue/manage/[[...task]]/route.ts (router not selected)',\n );\n createFileIfMissing({\n absolutePath: pagesRoutePath,\n content: PAGES_ROUTER_ROUTE_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: toRelativePath(details.cwd, pagesRoutePath),\n });\n }\n\n createFileIfMissing({\n absolutePath: cronPath,\n content: CRON_SH_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: 'cron.sh',\n });\n if (existsSyncImpl(cronPath)) {\n chmodSyncImpl(cronPath, 0o755);\n }\n\n createFileIfMissing({\n absolutePath: queuePath,\n content: QUEUE_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: toRelativePath(details.cwd, queuePath),\n });\n}\n\n/**\n * Creates a file only if it does not already exist.\n */\nfunction createFileIfMissing({\n absolutePath,\n content,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath,\n}: {\n absolutePath: string;\n content: string;\n existsSyncImpl: typeof existsSync;\n mkdirSyncImpl: typeof mkdirSync;\n writeFileSyncImpl: typeof writeFileSync;\n log: (...args: any[]) => void;\n logPath: string;\n}): void {\n if (existsSyncImpl(absolutePath)) {\n log(` [skipped] ${logPath} (already exists)`);\n return;\n }\n\n mkdirSyncImpl(path.dirname(absolutePath), { recursive: true });\n writeFileSyncImpl(absolutePath, content);\n log(` [created] ${logPath}`);\n}\n\n/**\n * Parses package.json content with clear source context.\n */\nfunction parsePackageJson(content: string, filePath: string): JsonObject {\n try {\n const parsed = JSON.parse(content);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('package.json must contain an object.');\n }\n return parsed as JsonObject;\n } catch (cause) {\n throw new Error(\n `Failed to parse package.json at ${filePath}: ${\n cause instanceof Error ? cause.message : String(cause)\n }`,\n );\n }\n}\n\n/**\n * Returns true when package.json declares Next.js in deps or devDeps.\n */\nfunction isNextJsProject(packageJson: JsonObject): boolean {\n const dependencies = packageJson.dependencies;\n const devDependencies = packageJson.devDependencies;\n\n return (\n hasPackage(dependencies, 'next') || hasPackage(devDependencies, 'next')\n );\n}\n\n/**\n * Returns true when a package name exists in a dependency section object.\n */\nfunction hasPackage(section: unknown, packageName: string): boolean {\n if (!section || typeof section !== 'object' || Array.isArray(section)) {\n return false;\n }\n return Boolean((section as JsonMap)[packageName]);\n}\n\n/**\n * Ensures package.json has a string map section and returns it.\n */\nfunction ensureStringMapSection(\n packageJson: JsonObject,\n sectionName: 'dependencies' | 'devDependencies' | 'scripts',\n): JsonMap {\n const currentValue = packageJson[sectionName];\n if (\n !currentValue ||\n typeof currentValue !== 'object' ||\n Array.isArray(currentValue)\n ) {\n packageJson[sectionName] = {};\n }\n return packageJson[sectionName] as JsonMap;\n}\n\n/**\n * Converts an absolute path to a stable relative path for log output.\n */\nfunction toRelativePath(cwd: string, absolutePath: string): string {\n const relative = path.relative(cwd, absolutePath);\n return relative || '.';\n}\n","import fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface InstallSkillsDeps {\n log?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n existsSync?: (p: string) => boolean;\n mkdirSync?: (p: string, opts?: fs.MakeDirectoryOptions) => void;\n copyFileSync?: (src: string, dest: string) => void;\n readdirSync?: (p: string) => string[];\n skillsSourceDir?: string;\n}\n\nconst SKILL_DIRS = ['dataqueue-core', 'dataqueue-advanced', 'dataqueue-react'];\n\ninterface AiTool {\n name: string;\n targetDir: string;\n}\n\n/**\n * Detects which AI tools have config directories in the project.\n *\n * @param cwd - Current working directory to scan.\n * @param existsSync - Injectable fs.existsSync.\n * @returns Array of detected AI tools with their skills target directories.\n */\nexport function detectAiTools(\n cwd: string,\n existsSync: (p: string) => boolean = fs.existsSync,\n): AiTool[] {\n const tools: AiTool[] = [];\n const checks: Array<{ name: string; indicator: string; targetDir: string }> =\n [\n {\n name: 'Cursor',\n indicator: '.cursor',\n targetDir: '.cursor/skills',\n },\n {\n name: 'Claude Code',\n indicator: '.claude',\n targetDir: '.claude/skills',\n },\n {\n name: 'GitHub Copilot',\n indicator: '.github',\n targetDir: '.github/skills',\n },\n ];\n\n for (const check of checks) {\n if (existsSync(path.join(cwd, check.indicator))) {\n tools.push({ name: check.name, targetDir: check.targetDir });\n }\n }\n\n return tools;\n}\n\n/**\n * Installs DataQueue skill files into detected AI tool directories.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport function runInstallSkills({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n existsSync = fs.existsSync,\n mkdirSync = fs.mkdirSync,\n copyFileSync = fs.copyFileSync,\n readdirSync = fs.readdirSync,\n skillsSourceDir = path.join(__dirname, '../ai/skills'),\n}: InstallSkillsDeps = {}): void {\n const tools = detectAiTools(cwd, existsSync);\n\n if (tools.length === 0) {\n log('No AI tool directories detected (.cursor/, .claude/, .github/).');\n log('Creating .cursor/skills/ as the default target.');\n tools.push({ name: 'Cursor', targetDir: '.cursor/skills' });\n }\n\n let installed = 0;\n\n for (const tool of tools) {\n log(`\\nInstalling skills for ${tool.name}...`);\n\n for (const skillDir of SKILL_DIRS) {\n const srcDir = path.join(skillsSourceDir, skillDir);\n const destDir = path.join(cwd, tool.targetDir, skillDir);\n\n try {\n mkdirSync(destDir, { recursive: true });\n\n const files = readdirSync(srcDir);\n for (const file of files) {\n copyFileSync(path.join(srcDir, file), path.join(destDir, file));\n }\n\n log(` ✓ ${skillDir}`);\n installed++;\n } catch (err) {\n error(` ✗ Failed to install ${skillDir}:`, err);\n }\n }\n }\n\n if (installed > 0) {\n log(\n `\\nDone! Installed ${installed} skill(s) for ${tools.map((t) => t.name).join(', ')}.`,\n );\n } else {\n error('No skills were installed.');\n exit(1);\n }\n}\n","import fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport readline from 'readline';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface InstallRulesDeps {\n log?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n readFileSync?: (p: string, enc: BufferEncoding) => string;\n writeFileSync?: (p: string, data: string) => void;\n appendFileSync?: (p: string, data: string) => void;\n mkdirSync?: (p: string, opts?: fs.MakeDirectoryOptions) => void;\n existsSync?: (p: string) => boolean;\n rulesSourceDir?: string;\n /** Override for selecting the client (skips interactive prompt). */\n selectedClient?: string;\n}\n\nconst RULE_FILES = ['basic.md', 'advanced.md', 'react-dashboard.md'];\n\ninterface ClientConfig {\n label: string;\n install: (\n deps: Required<\n Pick<\n InstallRulesDeps,\n | 'cwd'\n | 'readFileSync'\n | 'writeFileSync'\n | 'appendFileSync'\n | 'mkdirSync'\n | 'existsSync'\n | 'log'\n | 'rulesSourceDir'\n >\n >,\n ) => void;\n}\n\nconst MARKER_START = '<!-- DATAQUEUE RULES START -->';\nconst MARKER_END = '<!-- DATAQUEUE RULES END -->';\n\n/**\n * Appends or replaces a marked section in a file.\n *\n * @param filePath - Path to the file to update.\n * @param content - Content to insert between markers.\n * @param deps - Injectable file system functions.\n */\nexport function upsertMarkedSection(\n filePath: string,\n content: string,\n deps: {\n readFileSync: (p: string, enc: BufferEncoding) => string;\n writeFileSync: (p: string, data: string) => void;\n existsSync: (p: string) => boolean;\n },\n): void {\n const block = `${MARKER_START}\\n${content}\\n${MARKER_END}`;\n\n if (!deps.existsSync(filePath)) {\n deps.writeFileSync(filePath, block + '\\n');\n return;\n }\n\n const existing = deps.readFileSync(filePath, 'utf-8');\n const startIdx = existing.indexOf(MARKER_START);\n const endIdx = existing.indexOf(MARKER_END);\n\n if (startIdx !== -1 && endIdx !== -1) {\n const before = existing.slice(0, startIdx);\n const after = existing.slice(endIdx + MARKER_END.length);\n deps.writeFileSync(filePath, before + block + after);\n } else {\n deps.writeFileSync(filePath, existing.trimEnd() + '\\n\\n' + block + '\\n');\n }\n}\n\nfunction getAllRulesContent(\n rulesSourceDir: string,\n readFileSync: (p: string, enc: BufferEncoding) => string,\n): string {\n return RULE_FILES.map((f) =>\n readFileSync(path.join(rulesSourceDir, f), 'utf-8'),\n ).join('\\n\\n');\n}\n\nconst CLIENTS: Record<string, ClientConfig> = {\n '1': {\n label: 'Cursor',\n install: (deps) => {\n const rulesDir = path.join(deps.cwd, '.cursor', 'rules');\n deps.mkdirSync(rulesDir, { recursive: true });\n\n for (const file of RULE_FILES) {\n const src = deps.readFileSync(\n path.join(deps.rulesSourceDir, file),\n 'utf-8',\n );\n const destName = `dataqueue-${file.replace(/\\.md$/, '.mdc')}`;\n deps.writeFileSync(path.join(rulesDir, destName), src);\n deps.log(` ✓ .cursor/rules/${destName}`);\n }\n },\n },\n '2': {\n label: 'Claude Code',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n const filePath = path.join(deps.cwd, 'CLAUDE.md');\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ CLAUDE.md`);\n },\n },\n '3': {\n label: 'AGENTS.md (Codex, Jules, OpenCode)',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n const filePath = path.join(deps.cwd, 'AGENTS.md');\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ AGENTS.md`);\n },\n },\n '4': {\n label: 'GitHub Copilot',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n deps.mkdirSync(path.join(deps.cwd, '.github'), { recursive: true });\n const filePath = path.join(\n deps.cwd,\n '.github',\n 'copilot-instructions.md',\n );\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ .github/copilot-instructions.md`);\n },\n },\n '5': {\n label: 'Windsurf',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n const filePath = path.join(deps.cwd, 'CONVENTIONS.md');\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ CONVENTIONS.md`);\n },\n },\n};\n\n/**\n * Installs DataQueue agent rules for the selected AI client.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport async function runInstallRules({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n readFileSync = fs.readFileSync,\n writeFileSync = fs.writeFileSync,\n appendFileSync = fs.appendFileSync,\n mkdirSync = fs.mkdirSync,\n existsSync = fs.existsSync,\n rulesSourceDir = path.join(__dirname, '../ai/rules'),\n selectedClient,\n}: InstallRulesDeps = {}): Promise<void> {\n log('DataQueue Agent Rules Installer\\n');\n log('Select your AI client:\\n');\n\n for (const [key, client] of Object.entries(CLIENTS)) {\n log(` ${key}) ${client.label}`);\n }\n log('');\n\n let choice = selectedClient;\n\n if (!choice) {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n choice = await new Promise<string>((resolve) => {\n rl.question('Enter choice (1-5): ', (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n }\n\n const client = CLIENTS[choice];\n if (!client) {\n error(`Invalid choice: \"${choice}\". Expected 1-5.`);\n exit(1);\n return;\n }\n\n log(`\\nInstalling rules for ${client.label}...`);\n\n try {\n client.install({\n cwd,\n readFileSync,\n writeFileSync,\n appendFileSync,\n mkdirSync,\n existsSync,\n log,\n rulesSourceDir,\n });\n log('\\nDone!');\n } catch (err) {\n error('Failed to install rules:', err);\n exit(1);\n }\n}\n","import fs from 'fs';\nimport path from 'path';\nimport readline from 'readline';\n\nexport interface InstallMcpDeps {\n log?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n readFileSync?: (p: string, enc: BufferEncoding) => string;\n writeFileSync?: (p: string, data: string) => void;\n mkdirSync?: (p: string, opts?: fs.MakeDirectoryOptions) => void;\n existsSync?: (p: string) => boolean;\n /** Override for selecting the client (skips interactive prompt). */\n selectedClient?: string;\n}\n\ninterface McpClientConfig {\n label: string;\n install: (\n deps: Required<\n Pick<\n InstallMcpDeps,\n | 'cwd'\n | 'readFileSync'\n | 'writeFileSync'\n | 'mkdirSync'\n | 'existsSync'\n | 'log'\n >\n >,\n ) => void;\n}\n\n/**\n * Merges the dataqueue MCP server config into an existing JSON config file.\n *\n * @param filePath - Path to the MCP config file.\n * @param serverKey - Key name for the server entry.\n * @param serverConfig - Server configuration object.\n * @param deps - Injectable file system functions.\n */\nexport function upsertMcpConfig(\n filePath: string,\n serverKey: string,\n serverConfig: Record<string, unknown>,\n deps: {\n readFileSync: (p: string, enc: BufferEncoding) => string;\n writeFileSync: (p: string, data: string) => void;\n existsSync: (p: string) => boolean;\n },\n): void {\n let config: Record<string, unknown> = {};\n\n if (deps.existsSync(filePath)) {\n try {\n config = JSON.parse(deps.readFileSync(filePath, 'utf-8'));\n } catch {\n config = {};\n }\n }\n\n if (!config.mcpServers || typeof config.mcpServers !== 'object') {\n config.mcpServers = {};\n }\n\n (config.mcpServers as Record<string, unknown>)[serverKey] = serverConfig;\n deps.writeFileSync(filePath, JSON.stringify(config, null, 2) + '\\n');\n}\n\nconst MCP_SERVER_CONFIG = {\n command: 'npx',\n args: ['dataqueue-cli', 'mcp'],\n};\n\nconst MCP_CLIENTS: Record<string, McpClientConfig> = {\n '1': {\n label: 'Cursor',\n install: (deps) => {\n const configDir = path.join(deps.cwd, '.cursor');\n deps.mkdirSync(configDir, { recursive: true });\n const configFile = path.join(configDir, 'mcp.json');\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ .cursor/mcp.json`);\n },\n },\n '2': {\n label: 'Claude Code',\n install: (deps) => {\n const configFile = path.join(deps.cwd, '.mcp.json');\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ .mcp.json`);\n },\n },\n '3': {\n label: 'VS Code (Copilot)',\n install: (deps) => {\n const configDir = path.join(deps.cwd, '.vscode');\n deps.mkdirSync(configDir, { recursive: true });\n const configFile = path.join(configDir, 'mcp.json');\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ .vscode/mcp.json`);\n },\n },\n '4': {\n label: 'Windsurf',\n install: (deps) => {\n const homeDir = process.env.HOME || process.env.USERPROFILE || '';\n const configFile = path.join(\n homeDir,\n '.codeium',\n 'windsurf',\n 'mcp_config.json',\n );\n deps.mkdirSync(path.dirname(configFile), { recursive: true });\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ ~/.codeium/windsurf/mcp_config.json`);\n },\n },\n};\n\n/**\n * Installs the DataQueue MCP server config for the selected AI client.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport async function runInstallMcp({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n readFileSync = fs.readFileSync,\n writeFileSync = fs.writeFileSync,\n mkdirSync = fs.mkdirSync,\n existsSync = fs.existsSync,\n selectedClient,\n}: InstallMcpDeps = {}): Promise<void> {\n log('DataQueue MCP Server Installer\\n');\n log('Select your AI client:\\n');\n\n for (const [key, client] of Object.entries(MCP_CLIENTS)) {\n log(` ${key}) ${client.label}`);\n }\n log('');\n\n let choice = selectedClient;\n\n if (!choice) {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n choice = await new Promise<string>((resolve) => {\n rl.question('Enter choice (1-4): ', (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n }\n\n const client = MCP_CLIENTS[choice];\n if (!client) {\n error(`Invalid choice: \"${choice}\". Expected 1-4.`);\n exit(1);\n return;\n }\n\n log(`\\nInstalling MCP config for ${client.label}...`);\n\n try {\n client.install({\n cwd,\n readFileSync,\n writeFileSync,\n mkdirSync,\n existsSync,\n log,\n });\n log('\\nDone! The MCP server will run via: npx dataqueue-cli mcp');\n } catch (err) {\n error('Failed to install MCP config:', err);\n exit(1);\n }\n}\n","#!/usr/bin/env node\n\n/**\n * DataQueue MCP Server — exposes documentation search over stdio.\n * Run via: dataqueue-cli mcp\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\ninterface DocPage {\n slug: string;\n title: string;\n description: string;\n content: string;\n}\n\n/** @internal Loads docs-content.json from the ai/ directory bundled with the package. */\nexport function loadDocsContent(\n docsPath: string = path.join(__dirname, '../ai/docs-content.json'),\n): DocPage[] {\n const raw = fs.readFileSync(docsPath, 'utf-8');\n return JSON.parse(raw) as DocPage[];\n}\n\n/** @internal Scores a doc page against a search query using simple term matching. */\nexport function scorePageForQuery(page: DocPage, queryTerms: string[]): number {\n const titleLower = page.title.toLowerCase();\n const descLower = page.description.toLowerCase();\n const contentLower = page.content.toLowerCase();\n\n let score = 0;\n for (const term of queryTerms) {\n if (titleLower.includes(term)) score += 10;\n if (descLower.includes(term)) score += 5;\n\n const contentMatches = contentLower.split(term).length - 1;\n score += Math.min(contentMatches, 10);\n }\n return score;\n}\n\n/** @internal Extracts a relevant excerpt around the first match of any query term. */\nexport function extractExcerpt(\n content: string,\n queryTerms: string[],\n maxLength = 500,\n): string {\n const lower = content.toLowerCase();\n let earliestIndex = -1;\n\n for (const term of queryTerms) {\n const idx = lower.indexOf(term);\n if (idx !== -1 && (earliestIndex === -1 || idx < earliestIndex)) {\n earliestIndex = idx;\n }\n }\n\n if (earliestIndex === -1) {\n return content.slice(0, maxLength);\n }\n\n const start = Math.max(0, earliestIndex - 100);\n const end = Math.min(content.length, start + maxLength);\n let excerpt = content.slice(start, end);\n\n if (start > 0) excerpt = '...' + excerpt;\n if (end < content.length) excerpt = excerpt + '...';\n\n return excerpt;\n}\n\n/**\n * Creates and starts the DataQueue MCP server over stdio.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport async function startMcpServer(\n deps: {\n docsPath?: string;\n transport?: InstanceType<typeof StdioServerTransport>;\n } = {},\n): Promise<McpServer> {\n const pages = loadDocsContent(deps.docsPath);\n\n const server = new McpServer({\n name: 'dataqueue-docs',\n version: '1.0.0',\n });\n\n server.resource('llms-txt', 'dataqueue://llms.txt', async () => {\n const llmsPath = path.join(\n __dirname,\n '../ai/skills/dataqueue-core/SKILL.md',\n );\n let content: string;\n try {\n content = fs.readFileSync(llmsPath, 'utf-8');\n } catch {\n content = pages\n .map((p) => `## ${p.title}\\n\\nSlug: ${p.slug}\\n\\n${p.description}`)\n .join('\\n\\n');\n }\n return { contents: [{ uri: 'dataqueue://llms.txt', text: content }] };\n });\n\n server.tool(\n 'list-doc-pages',\n 'List all available DataQueue documentation pages with titles and descriptions.',\n {},\n async () => {\n const listing = pages.map((p) => ({\n slug: p.slug,\n title: p.title,\n description: p.description,\n }));\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(listing, null, 2) },\n ],\n };\n },\n );\n\n server.tool(\n 'get-doc-page',\n 'Fetch a specific DataQueue doc page by slug. Returns full page content as markdown.',\n {\n slug: z\n .string()\n .describe('The doc page slug, e.g. \"usage/add-job\" or \"api/job-queue\"'),\n },\n async ({ slug }) => {\n const page = pages.find((p) => p.slug === slug);\n if (!page) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Page not found: \"${slug}\". Use list-doc-pages to see available slugs.`,\n },\n ],\n isError: true,\n };\n }\n const header = page.description\n ? `# ${page.title}\\n\\n> ${page.description}\\n\\n`\n : `# ${page.title}\\n\\n`;\n return {\n content: [{ type: 'text' as const, text: header + page.content }],\n };\n },\n );\n\n server.tool(\n 'search-docs',\n 'Full-text search across all DataQueue documentation pages. Returns matching sections with page titles and content excerpts.',\n {\n query: z\n .string()\n .describe('Search query, e.g. \"cron scheduling\" or \"waitForToken\"'),\n },\n async ({ query }) => {\n const queryTerms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((t) => t.length > 1);\n\n if (queryTerms.length === 0) {\n return {\n content: [\n { type: 'text' as const, text: 'Please provide a search query.' },\n ],\n isError: true,\n };\n }\n\n const scored = pages\n .map((page) => ({\n page,\n score: scorePageForQuery(page, queryTerms),\n }))\n .filter((r) => r.score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, 5);\n\n if (scored.length === 0) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `No results for \"${query}\". Try different keywords or use list-doc-pages to browse.`,\n },\n ],\n };\n }\n\n const results = scored.map((r) => {\n const excerpt = extractExcerpt(r.page.content, queryTerms);\n return `## ${r.page.title} (${r.page.slug})\\n\\n${r.page.description}\\n\\n${excerpt}`;\n });\n\n return {\n content: [{ type: 'text' as const, text: results.join('\\n\\n---\\n\\n') }],\n };\n },\n );\n\n const transport = deps.transport ?? new StdioServerTransport();\n await server.connect(transport);\n return server;\n}\n\nconst isDirectRun =\n process.argv[1] &&\n (process.argv[1].endsWith('/mcp-server.js') ||\n process.argv[1].endsWith('/mcp-server.cjs'));\n\nif (isDirectRun) {\n startMcpServer().catch((err) => {\n console.error('Failed to start MCP server:', err);\n process.exit(1);\n });\n}\n","// Testable CLI logic for dataqueue\nimport { spawnSync, SpawnSyncReturns } from 'child_process';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { config as loadDotenv } from 'dotenv';\nimport { InitDeps, runInit } from './init-command.js';\nimport {\n runInstallSkills,\n InstallSkillsDeps,\n} from './install-skills-command.js';\nimport { runInstallRules, InstallRulesDeps } from './install-rules-command.js';\nimport { runInstallMcp, InstallMcpDeps } from './install-mcp-command.js';\nimport { startMcpServer } from './mcp-server.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface CliDeps {\n log?: (...args: any[]) => void;\n error?: (...args: any[]) => void;\n exit?: (code: number) => void;\n spawnSyncImpl?: (...args: any[]) => SpawnSyncReturns<any>;\n /** Load env vars from a file path (default: dotenv). Path is resolved from cwd. */\n loadEnvFromPath?: (filePath: string) => void;\n migrationsDir?: string;\n cwd?: string;\n initDeps?: InitDeps;\n runInitImpl?: (deps?: InitDeps) => void;\n installSkillsDeps?: InstallSkillsDeps;\n runInstallSkillsImpl?: (deps?: InstallSkillsDeps) => void;\n installRulesDeps?: InstallRulesDeps;\n runInstallRulesImpl?: (deps?: InstallRulesDeps) => Promise<void>;\n installMcpDeps?: InstallMcpDeps;\n runInstallMcpImpl?: (deps?: InstallMcpDeps) => Promise<void>;\n startMcpServerImpl?: typeof startMcpServer;\n}\n\nexport function runCli(\n argv: string[],\n {\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n spawnSyncImpl = spawnSync,\n cwd = process.cwd(),\n loadEnvFromPath = (filePath: string) => {\n loadDotenv({ path: path.resolve(cwd, filePath) });\n },\n migrationsDir = path.join(__dirname, '../migrations'),\n initDeps,\n runInitImpl = runInit,\n installSkillsDeps,\n runInstallSkillsImpl = runInstallSkills,\n installRulesDeps,\n runInstallRulesImpl = runInstallRules,\n installMcpDeps,\n runInstallMcpImpl = runInstallMcp,\n startMcpServerImpl = startMcpServer,\n }: CliDeps = {},\n): void {\n const [, , command, ...restArgs] = argv;\n\n function printUsage() {\n log('Usage:');\n log(\n ' dataqueue-cli migrate [--envPath <path>] [-s <schema> | --schema <schema>]',\n );\n log(' dataqueue-cli init');\n log(' dataqueue-cli install-skills');\n log(' dataqueue-cli install-rules');\n log(' dataqueue-cli install-mcp');\n log(' dataqueue-cli mcp');\n log('');\n log('Options for migrate:');\n log(\n ' --envPath <path> Path to a .env file to load environment variables (passed to node-pg-migrate)',\n );\n log(\n ' -s, --schema <schema> Set the schema to use (passed to node-pg-migrate)',\n );\n log('');\n log('AI tooling commands:');\n log(' install-skills Install DataQueue skill files for AI assistants');\n log(' install-rules Install DataQueue agent rules for AI clients');\n log(\n ' install-mcp Configure the DataQueue MCP server for AI clients',\n );\n log(' mcp Start the DataQueue MCP server (stdio)');\n exit(1);\n }\n\n if (command === 'migrate') {\n // Support for -s or --schema argument\n let schemaArg: string[] = [];\n const sIndex = restArgs.indexOf('-s');\n const schemaIndex = restArgs.indexOf('--schema');\n if (sIndex !== -1 && restArgs[sIndex + 1]) {\n schemaArg = ['-s', restArgs[sIndex + 1], '--create-schema'];\n restArgs.splice(sIndex, 2);\n } else if (schemaIndex !== -1 && restArgs[schemaIndex + 1]) {\n schemaArg = ['-s', restArgs[schemaIndex + 1], '--create-schema'];\n restArgs.splice(schemaIndex, 2);\n }\n\n // Support for --envPath argument: load env file so PG_DATAQUEUE_DATABASE is set\n // before spawning node-pg-migrate (node-pg-migrate only loads .env if dotenv is\n // installed in its context, so we preload here for reliable behavior).\n let envPathArg: string[] = [];\n const envPathIndex = restArgs.indexOf('--envPath');\n if (envPathIndex !== -1 && restArgs[envPathIndex + 1]) {\n const envPath = restArgs[envPathIndex + 1];\n loadEnvFromPath(envPath);\n envPathArg = ['--envPath', envPath];\n }\n\n const result: SpawnSyncReturns<any> = spawnSyncImpl(\n 'npx',\n [\n 'node-pg-migrate',\n 'up',\n '-t',\n 'dataqueuedev_migrations',\n '-d',\n 'PG_DATAQUEUE_DATABASE',\n '-m',\n migrationsDir,\n ...schemaArg,\n ...envPathArg,\n ...restArgs,\n ],\n { stdio: 'inherit' },\n );\n exit(result.status ?? 1);\n } else if (command === 'init') {\n runInitImpl({\n log,\n error,\n exit,\n ...initDeps,\n });\n } else if (command === 'install-skills') {\n runInstallSkillsImpl({\n log,\n error,\n exit,\n ...installSkillsDeps,\n });\n } else if (command === 'install-rules') {\n runInstallRulesImpl({\n log,\n error,\n exit,\n ...installRulesDeps,\n });\n } else if (command === 'install-mcp') {\n runInstallMcpImpl({\n log,\n error,\n exit,\n ...installMcpDeps,\n });\n } else if (command === 'mcp') {\n startMcpServerImpl().catch((err) => {\n error('Failed to start MCP server:', err);\n exit(1);\n });\n } else {\n printUsage();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/init-command.ts","../src/install-skills-command.ts","../src/install-rules-command.ts","../src/install-mcp-command.ts","../src/mcp-server.ts","../src/cli.ts"],"names":["readFileSync","writeFileSync","existsSync","mkdirSync","chmodSync","path","__filename","fileURLToPath","__dirname","fs","client","readline","McpServer","z","StdioServerTransport","spawnSync","loadDotenv"],"mappings":"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","file":"cli.cjs","sourcesContent":["import {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n} from 'fs';\nimport path from 'path';\n\ntype JsonObject = Record<string, unknown>;\ntype JsonMap = Record<string, string>;\n\nconst DEPENDENCIES_TO_ADD = [\n '@nicnocquee/dataqueue',\n '@nicnocquee/dataqueue-dashboard',\n '@nicnocquee/dataqueue-react',\n] as const;\n\nconst DEV_DEPENDENCIES_TO_ADD = [\n 'dotenv-cli',\n 'ts-node',\n 'node-pg-migrate',\n] as const;\n\nconst SCRIPTS_TO_ADD = {\n cron: 'bash cron.sh',\n 'migrate-dataqueue': 'dotenv -e .env.local -- dataqueue-cli migrate',\n} as const;\n\n/**\n * App router endpoint template for queue management.\n */\nexport const APP_ROUTER_ROUTE_TEMPLATE = `/**\n * This end point is used to manage the job queue.\n * It supports the following tasks:\n * - reclaim: Reclaim stuck jobs\n * - cleanup: Cleanup old jobs\n * - process: Process jobs\n *\n * Example usage with default values (reclaim stuck jobs for 10 minutes, cleanup old jobs for 30 days, and process jobs with batch size 3, concurrency 2, and verbose true):\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\"\n *\n * Example usage with custom values:\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"maxProcessingTimeMinutes\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"daysToKeep\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"batchSize\": 5, \"concurrency\": 3, \"verbose\": false, \"workerId\": \"custom-worker-id\"}' -H \"Content-Type: application/json\"\n *\n * During development, you can run the following script to run the cron jobs continuously in the background:\n * pnpm cron\n */\nimport { getJobQueue, jobHandlers } from '@/lib/dataqueue/queue';\nimport { NextResponse } from 'next/server';\n\nexport async function POST(\n request: Request,\n { params }: { params: Promise<{ task: string[] }> },\n) {\n const { task } = await params;\n const authHeader = request.headers.get('authorization');\n if (authHeader !== \\`Bearer \\${process.env.CRON_SECRET}\\`) {\n return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });\n }\n\n if (!task || task.length === 0) {\n return NextResponse.json({ message: 'Task is required' }, { status: 400 });\n }\n\n const supportedTasks = ['reclaim', 'cleanup', 'process'];\n const theTask = task[0];\n if (!supportedTasks.includes(theTask)) {\n return NextResponse.json(\n { message: 'Task not supported' },\n { status: 400 },\n );\n }\n\n try {\n const jobQueue = getJobQueue();\n\n if (theTask === 'reclaim') {\n let maxProcessingTimeMinutes = 10;\n try {\n const body = await request.json();\n maxProcessingTimeMinutes = body.maxProcessingTimeMinutes || 10;\n } catch {\n // ignore parsing error and use default value\n }\n const reclaimed = await jobQueue.reclaimStuckJobs(\n maxProcessingTimeMinutes,\n );\n console.log(\\`Reclaimed \\${reclaimed} stuck jobs\\`);\n return NextResponse.json({\n message: \\`Stuck jobs reclaimed: \\${reclaimed} with maxProcessingTimeMinutes: \\${maxProcessingTimeMinutes}\\`,\n reclaimed,\n });\n }\n\n if (theTask === 'cleanup') {\n let daysToKeep = 30;\n try {\n const body = await request.json();\n daysToKeep = body.daysToKeep || 30;\n } catch {\n // ignore parsing error and use default value\n }\n const deleted = await jobQueue.cleanupOldJobs(daysToKeep);\n console.log(\\`Deleted \\${deleted} old jobs\\`);\n return NextResponse.json({\n message: \\`Old jobs cleaned up: \\${deleted} with daysToKeep: \\${daysToKeep}\\`,\n deleted,\n });\n }\n\n if (theTask === 'process') {\n let batchSize = 3;\n let concurrency = 2;\n let verbose = true;\n let workerId = \\`manage-\\${theTask}-\\${Date.now()}\\`;\n try {\n const body = await request.json();\n batchSize = body.batchSize || 3;\n concurrency = body.concurrency || 2;\n verbose = body.verbose || true;\n workerId = body.workerId || \\`manage-\\${theTask}-\\${Date.now()}\\`;\n } catch {\n // ignore parsing error and use default value\n }\n const processor = jobQueue.createProcessor(jobHandlers, {\n workerId,\n batchSize,\n concurrency,\n verbose,\n });\n const processed = await processor.start();\n\n return NextResponse.json({\n message: \\`Jobs processed: \\${processed} with workerId: \\${workerId}, batchSize: \\${batchSize}, concurrency: \\${concurrency}, and verbose: \\${verbose}\\`,\n processed,\n });\n }\n\n return NextResponse.json(\n { message: 'Task not supported' },\n { status: 400 },\n );\n } catch (error) {\n console.error('Error processing jobs:', error);\n return NextResponse.json(\n { message: 'Failed to process jobs' },\n { status: 500 },\n );\n }\n}\n`;\n\n/**\n * Pages router endpoint template for queue management.\n */\nexport const PAGES_ROUTER_ROUTE_TEMPLATE = `/**\n * This end point is used to manage the job queue.\n * It supports the following tasks:\n * - reclaim: Reclaim stuck jobs\n * - cleanup: Cleanup old jobs\n * - process: Process jobs\n *\n * Example usage with default values (reclaim stuck jobs for 10 minutes, cleanup old jobs for 30 days, and process jobs with batch size 3, concurrency 2, and verbose true):\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\"\n *\n * Example usage with custom values:\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"maxProcessingTimeMinutes\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"daysToKeep\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"batchSize\": 5, \"concurrency\": 3, \"verbose\": false, \"workerId\": \"custom-worker-id\"}' -H \"Content-Type: application/json\"\n *\n * During development, you can run the following script to run the cron jobs continuously in the background:\n * pnpm cron\n */\nimport type { NextApiRequest, NextApiResponse } from 'next';\nimport { getJobQueue, jobHandlers } from '@/lib/dataqueue/queue';\n\ntype ResponseBody = {\n message: string;\n reclaimed?: number;\n deleted?: number;\n processed?: number;\n};\n\nexport default async function handler(\n req: NextApiRequest,\n res: NextApiResponse<ResponseBody>,\n) {\n if (req.method !== 'POST') {\n res.setHeader('Allow', 'POST');\n return res.status(405).json({ message: 'Method not allowed' });\n }\n\n const authHeader = req.headers.authorization;\n if (authHeader !== \\`Bearer \\${process.env.CRON_SECRET}\\`) {\n return res.status(401).json({ message: 'Unauthorized' });\n }\n\n const task = req.query.task;\n const taskArray = Array.isArray(task) ? task : task ? [task] : [];\n if (!taskArray.length) {\n return res.status(400).json({ message: 'Task is required' });\n }\n\n const supportedTasks = ['reclaim', 'cleanup', 'process'];\n const theTask = taskArray[0];\n if (!supportedTasks.includes(theTask)) {\n return res.status(400).json({ message: 'Task not supported' });\n }\n\n try {\n const jobQueue = getJobQueue();\n const body = typeof req.body === 'object' && req.body ? req.body : {};\n\n if (theTask === 'reclaim') {\n const maxProcessingTimeMinutes = body.maxProcessingTimeMinutes || 10;\n const reclaimed = await jobQueue.reclaimStuckJobs(maxProcessingTimeMinutes);\n console.log(\\`Reclaimed \\${reclaimed} stuck jobs\\`);\n return res.status(200).json({\n message: \\`Stuck jobs reclaimed: \\${reclaimed} with maxProcessingTimeMinutes: \\${maxProcessingTimeMinutes}\\`,\n reclaimed,\n });\n }\n\n if (theTask === 'cleanup') {\n const daysToKeep = body.daysToKeep || 30;\n const deleted = await jobQueue.cleanupOldJobs(daysToKeep);\n console.log(\\`Deleted \\${deleted} old jobs\\`);\n return res.status(200).json({\n message: \\`Old jobs cleaned up: \\${deleted} with daysToKeep: \\${daysToKeep}\\`,\n deleted,\n });\n }\n\n const batchSize = body.batchSize || 3;\n const concurrency = body.concurrency || 2;\n const verbose = body.verbose || true;\n const workerId = body.workerId || \\`manage-\\${theTask}-\\${Date.now()}\\`;\n const processor = jobQueue.createProcessor(jobHandlers, {\n workerId,\n batchSize,\n concurrency,\n verbose,\n });\n const processed = await processor.start();\n\n return res.status(200).json({\n message: \\`Jobs processed: \\${processed} with workerId: \\${workerId}, batchSize: \\${batchSize}, concurrency: \\${concurrency}, and verbose: \\${verbose}\\`,\n processed,\n });\n } catch (error) {\n console.error('Error processing jobs:', error);\n return res.status(500).json({ message: 'Failed to process jobs' });\n }\n}\n`;\n\n/**\n * Cron script template for local queue processing.\n */\nexport const CRON_SH_TEMPLATE = `#!/bin/bash\n\n# This script is used to run the cron jobs for the demo app during development.\n# Run it with \\`pnpm cron\\` from the apps/demo directory.\n\nset -a\nsource \"$(dirname \"$0\")/.env.local\"\nset +a\n\nif [ -z \"$CRON_SECRET\" ]; then\n echo \"Error: CRON_SECRET environment variable is not set in .env.local\"\n exit 1\nfi\n\ncleanup() {\n kill 0\n wait\n}\ntrap cleanup SIGINT SIGTERM\n\nwhile true; do\n echo \"Processing jobs...\"\n curl http://localhost:3000/api/dataqueue/manage/process -X POST -H \"Authorization: Bearer $CRON_SECRET\"\n echo \"\"\n sleep 10 # Process jobs every 10 seconds\ndone &\n\nwhile true; do\n echo \"Reclaiming stuck jobs...\"\n curl http://localhost:3000/api/dataqueue/manage/reclaim -X POST -H \"Authorization: Bearer $CRON_SECRET\"\n echo \"\"\n sleep 20 # Reclaim stuck jobs every 20 seconds\ndone &\n\nwhile true; do\n echo \"Cleaning up old jobs...\"\n curl http://localhost:3000/api/dataqueue/manage/cleanup -X POST -H \"Authorization: Bearer $CRON_SECRET\"\n echo \"\"\n sleep 30 # Cleanup old jobs every 30 seconds\ndone &\n\nwait\n`;\n\n/**\n * Queue placeholder template with a single `send_email` job.\n */\nexport const QUEUE_TEMPLATE = `import { initJobQueue, JobHandlers } from '@nicnocquee/dataqueue';\n\nexport type JobPayloadMap = {\n send_email: {\n to: string;\n subject: string;\n body: string;\n };\n};\n\nlet jobQueue: ReturnType<typeof initJobQueue<JobPayloadMap>> | null = null;\n\nexport const getJobQueue = () => {\n if (!jobQueue) {\n jobQueue = initJobQueue<JobPayloadMap>({\n databaseConfig: {\n connectionString: process.env.PG_DATAQUEUE_DATABASE,\n },\n verbose: process.env.NODE_ENV === 'development',\n });\n }\n return jobQueue;\n};\n\nexport const jobHandlers: JobHandlers<JobPayloadMap> = {\n send_email: async (payload) => {\n const { to, subject, body } = payload;\n console.log('send_email placeholder:', { to, subject, body });\n },\n};\n`;\n\nexport interface InitDeps {\n log?: (...args: any[]) => void;\n error?: (...args: any[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n readFileSyncImpl?: typeof readFileSync;\n writeFileSyncImpl?: typeof writeFileSync;\n existsSyncImpl?: typeof existsSync;\n mkdirSyncImpl?: typeof mkdirSync;\n chmodSyncImpl?: typeof chmodSync;\n}\n\ntype RouterKind = 'app' | 'pages';\n\ninterface ProjectDetails {\n cwd: string;\n packageJsonPath: string;\n packageJson: JsonObject;\n srcRoot: string;\n router: RouterKind;\n}\n\n/**\n * Runs the `dataqueue-cli init` command.\n */\nexport function runInit({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n readFileSyncImpl = readFileSync,\n writeFileSyncImpl = writeFileSync,\n existsSyncImpl = existsSync,\n mkdirSyncImpl = mkdirSync,\n chmodSyncImpl = chmodSync,\n}: InitDeps = {}): void {\n try {\n log(`dataqueue: Initializing in ${cwd}...`);\n log('');\n\n const details = detectNextJsAndRouter({\n cwd,\n existsSyncImpl,\n readFileSyncImpl,\n });\n\n createScaffoldFiles({\n details,\n log,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n chmodSyncImpl,\n });\n\n updatePackageJson({\n details,\n log,\n writeFileSyncImpl,\n });\n\n log('');\n log(\n \"Done! Run your package manager's install command to install new dependencies.\",\n );\n exit(0);\n } catch (cause) {\n const message = cause instanceof Error ? cause.message : String(cause);\n error(`dataqueue: ${message}`);\n exit(1);\n }\n}\n\n/**\n * Detects that the current directory is a Next.js app and chooses the router.\n */\nexport function detectNextJsAndRouter({\n cwd,\n existsSyncImpl,\n readFileSyncImpl,\n}: {\n cwd: string;\n existsSyncImpl: typeof existsSync;\n readFileSyncImpl: typeof readFileSync;\n}): ProjectDetails {\n const packageJsonPath = path.join(cwd, 'package.json');\n if (!existsSyncImpl(packageJsonPath)) {\n throw new Error('package.json not found in current directory.');\n }\n\n const packageJson = parsePackageJson(\n readFileSyncImpl(packageJsonPath, 'utf8'),\n packageJsonPath,\n );\n if (!isNextJsProject(packageJson)) {\n throw new Error(\n \"Not a Next.js project. Could not find 'next' in package.json dependencies.\",\n );\n }\n\n const srcDir = path.join(cwd, 'src');\n const srcRoot = existsSyncImpl(srcDir) ? 'src' : '.';\n const appDir = path.join(cwd, srcRoot, 'app');\n const pagesDir = path.join(cwd, srcRoot, 'pages');\n const hasAppDir = existsSyncImpl(appDir);\n const hasPagesDir = existsSyncImpl(pagesDir);\n\n if (!hasAppDir && !hasPagesDir) {\n throw new Error(\n 'Could not detect Next.js router. Expected either app/ or pages/ directory.',\n );\n }\n\n const router: RouterKind = hasAppDir ? 'app' : 'pages';\n return { cwd, packageJsonPath, packageJson, srcRoot, router };\n}\n\n/**\n * Updates package.json with required dependencies and scripts.\n */\nfunction updatePackageJson({\n details,\n log,\n writeFileSyncImpl,\n}: {\n details: ProjectDetails;\n log: (...args: any[]) => void;\n writeFileSyncImpl: typeof writeFileSync;\n}): void {\n const packageJson = details.packageJson;\n const dependencies = ensureStringMapSection(packageJson, 'dependencies');\n const devDependencies = ensureStringMapSection(\n packageJson,\n 'devDependencies',\n );\n const scripts = ensureStringMapSection(packageJson, 'scripts');\n\n for (const dependency of DEPENDENCIES_TO_ADD) {\n if (dependencies[dependency]) {\n log(` [skipped] dependency ${dependency} (already exists)`);\n continue;\n }\n dependencies[dependency] = 'latest';\n log(` [added] dependency ${dependency}`);\n }\n\n for (const devDependency of DEV_DEPENDENCIES_TO_ADD) {\n if (devDependencies[devDependency]) {\n log(` [skipped] devDependency ${devDependency} (already exists)`);\n continue;\n }\n devDependencies[devDependency] = 'latest';\n log(` [added] devDependency ${devDependency}`);\n }\n\n for (const [scriptName, scriptValue] of Object.entries(SCRIPTS_TO_ADD)) {\n if (scripts[scriptName]) {\n log(` [skipped] script \"${scriptName}\" (already exists)`);\n continue;\n }\n scripts[scriptName] = scriptValue;\n log(` [added] script \"${scriptName}\"`);\n }\n\n writeFileSyncImpl(\n details.packageJsonPath,\n `${JSON.stringify(packageJson, null, 2)}\\n`,\n );\n}\n\n/**\n * Creates all scaffold files for the detected router without overwriting.\n */\nfunction createScaffoldFiles({\n details,\n log,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n chmodSyncImpl,\n}: {\n details: ProjectDetails;\n log: (...args: any[]) => void;\n existsSyncImpl: typeof existsSync;\n mkdirSyncImpl: typeof mkdirSync;\n writeFileSyncImpl: typeof writeFileSync;\n chmodSyncImpl: typeof chmodSync;\n}): void {\n const appRoutePath = path.join(\n details.cwd,\n details.srcRoot,\n 'app',\n 'api',\n 'dataqueue',\n 'manage',\n '[[...task]]',\n 'route.ts',\n );\n const pagesRoutePath = path.join(\n details.cwd,\n details.srcRoot,\n 'pages',\n 'api',\n 'dataqueue',\n 'manage',\n '[[...task]].ts',\n );\n const queuePath = path.join(\n details.cwd,\n details.srcRoot,\n 'lib',\n 'dataqueue',\n 'queue.ts',\n );\n const cronPath = path.join(details.cwd, 'cron.sh');\n\n if (details.router === 'app') {\n createFileIfMissing({\n absolutePath: appRoutePath,\n content: APP_ROUTER_ROUTE_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: toRelativePath(details.cwd, appRoutePath),\n });\n log(\n ' [skipped] pages/api/dataqueue/manage/[[...task]].ts (router not selected)',\n );\n } else {\n log(\n ' [skipped] app/api/dataqueue/manage/[[...task]]/route.ts (router not selected)',\n );\n createFileIfMissing({\n absolutePath: pagesRoutePath,\n content: PAGES_ROUTER_ROUTE_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: toRelativePath(details.cwd, pagesRoutePath),\n });\n }\n\n createFileIfMissing({\n absolutePath: cronPath,\n content: CRON_SH_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: 'cron.sh',\n });\n if (existsSyncImpl(cronPath)) {\n chmodSyncImpl(cronPath, 0o755);\n }\n\n createFileIfMissing({\n absolutePath: queuePath,\n content: QUEUE_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: toRelativePath(details.cwd, queuePath),\n });\n}\n\n/**\n * Creates a file only if it does not already exist.\n */\nfunction createFileIfMissing({\n absolutePath,\n content,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath,\n}: {\n absolutePath: string;\n content: string;\n existsSyncImpl: typeof existsSync;\n mkdirSyncImpl: typeof mkdirSync;\n writeFileSyncImpl: typeof writeFileSync;\n log: (...args: any[]) => void;\n logPath: string;\n}): void {\n if (existsSyncImpl(absolutePath)) {\n log(` [skipped] ${logPath} (already exists)`);\n return;\n }\n\n mkdirSyncImpl(path.dirname(absolutePath), { recursive: true });\n writeFileSyncImpl(absolutePath, content);\n log(` [created] ${logPath}`);\n}\n\n/**\n * Parses package.json content with clear source context.\n */\nfunction parsePackageJson(content: string, filePath: string): JsonObject {\n try {\n const parsed = JSON.parse(content);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('package.json must contain an object.');\n }\n return parsed as JsonObject;\n } catch (cause) {\n throw new Error(\n `Failed to parse package.json at ${filePath}: ${\n cause instanceof Error ? cause.message : String(cause)\n }`,\n );\n }\n}\n\n/**\n * Returns true when package.json declares Next.js in deps or devDeps.\n */\nfunction isNextJsProject(packageJson: JsonObject): boolean {\n const dependencies = packageJson.dependencies;\n const devDependencies = packageJson.devDependencies;\n\n return (\n hasPackage(dependencies, 'next') || hasPackage(devDependencies, 'next')\n );\n}\n\n/**\n * Returns true when a package name exists in a dependency section object.\n */\nfunction hasPackage(section: unknown, packageName: string): boolean {\n if (!section || typeof section !== 'object' || Array.isArray(section)) {\n return false;\n }\n return Boolean((section as JsonMap)[packageName]);\n}\n\n/**\n * Ensures package.json has a string map section and returns it.\n */\nfunction ensureStringMapSection(\n packageJson: JsonObject,\n sectionName: 'dependencies' | 'devDependencies' | 'scripts',\n): JsonMap {\n const currentValue = packageJson[sectionName];\n if (\n !currentValue ||\n typeof currentValue !== 'object' ||\n Array.isArray(currentValue)\n ) {\n packageJson[sectionName] = {};\n }\n return packageJson[sectionName] as JsonMap;\n}\n\n/**\n * Converts an absolute path to a stable relative path for log output.\n */\nfunction toRelativePath(cwd: string, absolutePath: string): string {\n const relative = path.relative(cwd, absolutePath);\n return relative || '.';\n}\n","import fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface InstallSkillsDeps {\n log?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n existsSync?: (p: string) => boolean;\n mkdirSync?: (p: string, opts?: fs.MakeDirectoryOptions) => void;\n copyFileSync?: (src: string, dest: string) => void;\n readdirSync?: (p: string) => string[];\n skillsSourceDir?: string;\n}\n\nconst SKILL_DIRS = ['dataqueue-core', 'dataqueue-advanced', 'dataqueue-react'];\n\ninterface AiTool {\n name: string;\n targetDir: string;\n}\n\n/**\n * Detects which AI tools have config directories in the project.\n *\n * @param cwd - Current working directory to scan.\n * @param existsSync - Injectable fs.existsSync.\n * @returns Array of detected AI tools with their skills target directories.\n */\nexport function detectAiTools(\n cwd: string,\n existsSync: (p: string) => boolean = fs.existsSync,\n): AiTool[] {\n const tools: AiTool[] = [];\n const checks: Array<{ name: string; indicator: string; targetDir: string }> =\n [\n {\n name: 'Cursor',\n indicator: '.cursor',\n targetDir: '.cursor/skills',\n },\n {\n name: 'Claude Code',\n indicator: '.claude',\n targetDir: '.claude/skills',\n },\n {\n name: 'GitHub Copilot',\n indicator: '.github',\n targetDir: '.github/skills',\n },\n ];\n\n for (const check of checks) {\n if (existsSync(path.join(cwd, check.indicator))) {\n tools.push({ name: check.name, targetDir: check.targetDir });\n }\n }\n\n return tools;\n}\n\n/**\n * Installs DataQueue skill files into detected AI tool directories.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport function runInstallSkills({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n existsSync = fs.existsSync,\n mkdirSync = fs.mkdirSync,\n copyFileSync = fs.copyFileSync,\n readdirSync = fs.readdirSync,\n skillsSourceDir = path.join(__dirname, '../ai/skills'),\n}: InstallSkillsDeps = {}): void {\n const tools = detectAiTools(cwd, existsSync);\n\n if (tools.length === 0) {\n log('No AI tool directories detected (.cursor/, .claude/, .github/).');\n log('Creating .cursor/skills/ as the default target.');\n tools.push({ name: 'Cursor', targetDir: '.cursor/skills' });\n }\n\n let installed = 0;\n\n for (const tool of tools) {\n log(`\\nInstalling skills for ${tool.name}...`);\n\n for (const skillDir of SKILL_DIRS) {\n const srcDir = path.join(skillsSourceDir, skillDir);\n const destDir = path.join(cwd, tool.targetDir, skillDir);\n\n try {\n mkdirSync(destDir, { recursive: true });\n\n const files = readdirSync(srcDir);\n for (const file of files) {\n copyFileSync(path.join(srcDir, file), path.join(destDir, file));\n }\n\n log(` ✓ ${skillDir}`);\n installed++;\n } catch (err) {\n error(` ✗ Failed to install ${skillDir}:`, err);\n }\n }\n }\n\n if (installed > 0) {\n log(\n `\\nDone! Installed ${installed} skill(s) for ${tools.map((t) => t.name).join(', ')}.`,\n );\n } else {\n error('No skills were installed.');\n exit(1);\n }\n}\n","import fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport readline from 'readline';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface InstallRulesDeps {\n log?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n readFileSync?: (p: string, enc: BufferEncoding) => string;\n writeFileSync?: (p: string, data: string) => void;\n appendFileSync?: (p: string, data: string) => void;\n mkdirSync?: (p: string, opts?: fs.MakeDirectoryOptions) => void;\n existsSync?: (p: string) => boolean;\n rulesSourceDir?: string;\n /** Override for selecting the client (skips interactive prompt). */\n selectedClient?: string;\n}\n\nconst RULE_FILES = ['basic.md', 'advanced.md', 'react-dashboard.md'];\n\ninterface ClientConfig {\n label: string;\n install: (\n deps: Required<\n Pick<\n InstallRulesDeps,\n | 'cwd'\n | 'readFileSync'\n | 'writeFileSync'\n | 'appendFileSync'\n | 'mkdirSync'\n | 'existsSync'\n | 'log'\n | 'rulesSourceDir'\n >\n >,\n ) => void;\n}\n\nconst MARKER_START = '<!-- DATAQUEUE RULES START -->';\nconst MARKER_END = '<!-- DATAQUEUE RULES END -->';\n\n/**\n * Appends or replaces a marked section in a file.\n *\n * @param filePath - Path to the file to update.\n * @param content - Content to insert between markers.\n * @param deps - Injectable file system functions.\n */\nexport function upsertMarkedSection(\n filePath: string,\n content: string,\n deps: {\n readFileSync: (p: string, enc: BufferEncoding) => string;\n writeFileSync: (p: string, data: string) => void;\n existsSync: (p: string) => boolean;\n },\n): void {\n const block = `${MARKER_START}\\n${content}\\n${MARKER_END}`;\n\n if (!deps.existsSync(filePath)) {\n deps.writeFileSync(filePath, block + '\\n');\n return;\n }\n\n const existing = deps.readFileSync(filePath, 'utf-8');\n const startIdx = existing.indexOf(MARKER_START);\n const endIdx = existing.indexOf(MARKER_END);\n\n if (startIdx !== -1 && endIdx !== -1) {\n const before = existing.slice(0, startIdx);\n const after = existing.slice(endIdx + MARKER_END.length);\n deps.writeFileSync(filePath, before + block + after);\n } else {\n deps.writeFileSync(filePath, existing.trimEnd() + '\\n\\n' + block + '\\n');\n }\n}\n\nfunction getAllRulesContent(\n rulesSourceDir: string,\n readFileSync: (p: string, enc: BufferEncoding) => string,\n): string {\n return RULE_FILES.map((f) =>\n readFileSync(path.join(rulesSourceDir, f), 'utf-8'),\n ).join('\\n\\n');\n}\n\nconst CLIENTS: Record<string, ClientConfig> = {\n '1': {\n label: 'Cursor',\n install: (deps) => {\n const rulesDir = path.join(deps.cwd, '.cursor', 'rules');\n deps.mkdirSync(rulesDir, { recursive: true });\n\n for (const file of RULE_FILES) {\n const src = deps.readFileSync(\n path.join(deps.rulesSourceDir, file),\n 'utf-8',\n );\n const destName = `dataqueue-${file.replace(/\\.md$/, '.mdc')}`;\n deps.writeFileSync(path.join(rulesDir, destName), src);\n deps.log(` ✓ .cursor/rules/${destName}`);\n }\n },\n },\n '2': {\n label: 'Claude Code',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n const filePath = path.join(deps.cwd, 'CLAUDE.md');\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ CLAUDE.md`);\n },\n },\n '3': {\n label: 'AGENTS.md (Codex, Jules, OpenCode)',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n const filePath = path.join(deps.cwd, 'AGENTS.md');\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ AGENTS.md`);\n },\n },\n '4': {\n label: 'GitHub Copilot',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n deps.mkdirSync(path.join(deps.cwd, '.github'), { recursive: true });\n const filePath = path.join(\n deps.cwd,\n '.github',\n 'copilot-instructions.md',\n );\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ .github/copilot-instructions.md`);\n },\n },\n '5': {\n label: 'Windsurf',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n const filePath = path.join(deps.cwd, 'CONVENTIONS.md');\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ CONVENTIONS.md`);\n },\n },\n};\n\n/**\n * Installs DataQueue agent rules for the selected AI client.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport async function runInstallRules({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n readFileSync = fs.readFileSync,\n writeFileSync = fs.writeFileSync,\n appendFileSync = fs.appendFileSync,\n mkdirSync = fs.mkdirSync,\n existsSync = fs.existsSync,\n rulesSourceDir = path.join(__dirname, '../ai/rules'),\n selectedClient,\n}: InstallRulesDeps = {}): Promise<void> {\n log('DataQueue Agent Rules Installer\\n');\n log('Select your AI client:\\n');\n\n for (const [key, client] of Object.entries(CLIENTS)) {\n log(` ${key}) ${client.label}`);\n }\n log('');\n\n let choice = selectedClient;\n\n if (!choice) {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n choice = await new Promise<string>((resolve) => {\n rl.question('Enter choice (1-5): ', (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n }\n\n const client = CLIENTS[choice];\n if (!client) {\n error(`Invalid choice: \"${choice}\". Expected 1-5.`);\n exit(1);\n return;\n }\n\n log(`\\nInstalling rules for ${client.label}...`);\n\n try {\n client.install({\n cwd,\n readFileSync,\n writeFileSync,\n appendFileSync,\n mkdirSync,\n existsSync,\n log,\n rulesSourceDir,\n });\n log('\\nDone!');\n } catch (err) {\n error('Failed to install rules:', err);\n exit(1);\n }\n}\n","import fs from 'fs';\nimport path from 'path';\nimport readline from 'readline';\n\nexport interface InstallMcpDeps {\n log?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n readFileSync?: (p: string, enc: BufferEncoding) => string;\n writeFileSync?: (p: string, data: string) => void;\n mkdirSync?: (p: string, opts?: fs.MakeDirectoryOptions) => void;\n existsSync?: (p: string) => boolean;\n /** Override for selecting the client (skips interactive prompt). */\n selectedClient?: string;\n}\n\ninterface McpClientConfig {\n label: string;\n install: (\n deps: Required<\n Pick<\n InstallMcpDeps,\n | 'cwd'\n | 'readFileSync'\n | 'writeFileSync'\n | 'mkdirSync'\n | 'existsSync'\n | 'log'\n >\n >,\n ) => void;\n}\n\n/**\n * Merges the dataqueue MCP server config into an existing JSON config file.\n *\n * @param filePath - Path to the MCP config file.\n * @param serverKey - Key name for the server entry.\n * @param serverConfig - Server configuration object.\n * @param deps - Injectable file system functions.\n */\nexport function upsertMcpConfig(\n filePath: string,\n serverKey: string,\n serverConfig: Record<string, unknown>,\n deps: {\n readFileSync: (p: string, enc: BufferEncoding) => string;\n writeFileSync: (p: string, data: string) => void;\n existsSync: (p: string) => boolean;\n },\n): void {\n let config: Record<string, unknown> = {};\n\n if (deps.existsSync(filePath)) {\n try {\n config = JSON.parse(deps.readFileSync(filePath, 'utf-8'));\n } catch {\n config = {};\n }\n }\n\n if (!config.mcpServers || typeof config.mcpServers !== 'object') {\n config.mcpServers = {};\n }\n\n (config.mcpServers as Record<string, unknown>)[serverKey] = serverConfig;\n deps.writeFileSync(filePath, JSON.stringify(config, null, 2) + '\\n');\n}\n\nconst MCP_SERVER_CONFIG = {\n command: 'npx',\n args: ['dataqueue-cli', 'mcp'],\n};\n\nconst MCP_CLIENTS: Record<string, McpClientConfig> = {\n '1': {\n label: 'Cursor',\n install: (deps) => {\n const configDir = path.join(deps.cwd, '.cursor');\n deps.mkdirSync(configDir, { recursive: true });\n const configFile = path.join(configDir, 'mcp.json');\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ .cursor/mcp.json`);\n },\n },\n '2': {\n label: 'Claude Code',\n install: (deps) => {\n const configFile = path.join(deps.cwd, '.mcp.json');\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ .mcp.json`);\n },\n },\n '3': {\n label: 'VS Code (Copilot)',\n install: (deps) => {\n const configDir = path.join(deps.cwd, '.vscode');\n deps.mkdirSync(configDir, { recursive: true });\n const configFile = path.join(configDir, 'mcp.json');\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ .vscode/mcp.json`);\n },\n },\n '4': {\n label: 'Windsurf',\n install: (deps) => {\n const homeDir = process.env.HOME || process.env.USERPROFILE || '';\n const configFile = path.join(\n homeDir,\n '.codeium',\n 'windsurf',\n 'mcp_config.json',\n );\n deps.mkdirSync(path.dirname(configFile), { recursive: true });\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ ~/.codeium/windsurf/mcp_config.json`);\n },\n },\n};\n\n/**\n * Installs the DataQueue MCP server config for the selected AI client.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport async function runInstallMcp({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n readFileSync = fs.readFileSync,\n writeFileSync = fs.writeFileSync,\n mkdirSync = fs.mkdirSync,\n existsSync = fs.existsSync,\n selectedClient,\n}: InstallMcpDeps = {}): Promise<void> {\n log('DataQueue MCP Server Installer\\n');\n log('Select your AI client:\\n');\n\n for (const [key, client] of Object.entries(MCP_CLIENTS)) {\n log(` ${key}) ${client.label}`);\n }\n log('');\n\n let choice = selectedClient;\n\n if (!choice) {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n choice = await new Promise<string>((resolve) => {\n rl.question('Enter choice (1-4): ', (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n }\n\n const client = MCP_CLIENTS[choice];\n if (!client) {\n error(`Invalid choice: \"${choice}\". Expected 1-4.`);\n exit(1);\n return;\n }\n\n log(`\\nInstalling MCP config for ${client.label}...`);\n\n try {\n client.install({\n cwd,\n readFileSync,\n writeFileSync,\n mkdirSync,\n existsSync,\n log,\n });\n log('\\nDone! The MCP server will run via: npx @nicnocquee/dataqueue mcp');\n } catch (err) {\n error('Failed to install MCP config:', err);\n exit(1);\n }\n}\n","#!/usr/bin/env node\n\n/**\n * DataQueue MCP Server — exposes documentation search over stdio.\n * Run via: dataqueue-cli mcp\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\ninterface DocPage {\n slug: string;\n title: string;\n description: string;\n content: string;\n}\n\n/** @internal Loads docs-content.json from the ai/ directory bundled with the package. */\nexport function loadDocsContent(\n docsPath: string = path.join(__dirname, '../ai/docs-content.json'),\n): DocPage[] {\n const raw = fs.readFileSync(docsPath, 'utf-8');\n return JSON.parse(raw) as DocPage[];\n}\n\n/** @internal Scores a doc page against a search query using simple term matching. */\nexport function scorePageForQuery(page: DocPage, queryTerms: string[]): number {\n const titleLower = page.title.toLowerCase();\n const descLower = page.description.toLowerCase();\n const contentLower = page.content.toLowerCase();\n\n let score = 0;\n for (const term of queryTerms) {\n if (titleLower.includes(term)) score += 10;\n if (descLower.includes(term)) score += 5;\n\n const contentMatches = contentLower.split(term).length - 1;\n score += Math.min(contentMatches, 10);\n }\n return score;\n}\n\n/** @internal Extracts a relevant excerpt around the first match of any query term. */\nexport function extractExcerpt(\n content: string,\n queryTerms: string[],\n maxLength = 500,\n): string {\n const lower = content.toLowerCase();\n let earliestIndex = -1;\n\n for (const term of queryTerms) {\n const idx = lower.indexOf(term);\n if (idx !== -1 && (earliestIndex === -1 || idx < earliestIndex)) {\n earliestIndex = idx;\n }\n }\n\n if (earliestIndex === -1) {\n return content.slice(0, maxLength);\n }\n\n const start = Math.max(0, earliestIndex - 100);\n const end = Math.min(content.length, start + maxLength);\n let excerpt = content.slice(start, end);\n\n if (start > 0) excerpt = '...' + excerpt;\n if (end < content.length) excerpt = excerpt + '...';\n\n return excerpt;\n}\n\n/**\n * Creates and starts the DataQueue MCP server over stdio.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport async function startMcpServer(\n deps: {\n docsPath?: string;\n transport?: InstanceType<typeof StdioServerTransport>;\n } = {},\n): Promise<McpServer> {\n const pages = loadDocsContent(deps.docsPath);\n\n const server = new McpServer({\n name: 'dataqueue-docs',\n version: '1.0.0',\n });\n\n server.resource('llms-txt', 'dataqueue://llms.txt', async () => {\n const llmsPath = path.join(\n __dirname,\n '../ai/skills/dataqueue-core/SKILL.md',\n );\n let content: string;\n try {\n content = fs.readFileSync(llmsPath, 'utf-8');\n } catch {\n content = pages\n .map((p) => `## ${p.title}\\n\\nSlug: ${p.slug}\\n\\n${p.description}`)\n .join('\\n\\n');\n }\n return { contents: [{ uri: 'dataqueue://llms.txt', text: content }] };\n });\n\n server.tool(\n 'list-doc-pages',\n 'List all available DataQueue documentation pages with titles and descriptions.',\n {},\n async () => {\n const listing = pages.map((p) => ({\n slug: p.slug,\n title: p.title,\n description: p.description,\n }));\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(listing, null, 2) },\n ],\n };\n },\n );\n\n server.tool(\n 'get-doc-page',\n 'Fetch a specific DataQueue doc page by slug. Returns full page content as markdown.',\n {\n slug: z\n .string()\n .describe('The doc page slug, e.g. \"usage/add-job\" or \"api/job-queue\"'),\n },\n async ({ slug }) => {\n const page = pages.find((p) => p.slug === slug);\n if (!page) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Page not found: \"${slug}\". Use list-doc-pages to see available slugs.`,\n },\n ],\n isError: true,\n };\n }\n const header = page.description\n ? `# ${page.title}\\n\\n> ${page.description}\\n\\n`\n : `# ${page.title}\\n\\n`;\n return {\n content: [{ type: 'text' as const, text: header + page.content }],\n };\n },\n );\n\n server.tool(\n 'search-docs',\n 'Full-text search across all DataQueue documentation pages. Returns matching sections with page titles and content excerpts.',\n {\n query: z\n .string()\n .describe('Search query, e.g. \"cron scheduling\" or \"waitForToken\"'),\n },\n async ({ query }) => {\n const queryTerms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((t) => t.length > 1);\n\n if (queryTerms.length === 0) {\n return {\n content: [\n { type: 'text' as const, text: 'Please provide a search query.' },\n ],\n isError: true,\n };\n }\n\n const scored = pages\n .map((page) => ({\n page,\n score: scorePageForQuery(page, queryTerms),\n }))\n .filter((r) => r.score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, 5);\n\n if (scored.length === 0) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `No results for \"${query}\". Try different keywords or use list-doc-pages to browse.`,\n },\n ],\n };\n }\n\n const results = scored.map((r) => {\n const excerpt = extractExcerpt(r.page.content, queryTerms);\n return `## ${r.page.title} (${r.page.slug})\\n\\n${r.page.description}\\n\\n${excerpt}`;\n });\n\n return {\n content: [{ type: 'text' as const, text: results.join('\\n\\n---\\n\\n') }],\n };\n },\n );\n\n const transport = deps.transport ?? new StdioServerTransport();\n await server.connect(transport);\n return server;\n}\n\nconst isDirectRun =\n process.argv[1] &&\n (process.argv[1].endsWith('/mcp-server.js') ||\n process.argv[1].endsWith('/mcp-server.cjs'));\n\nif (isDirectRun) {\n startMcpServer().catch((err) => {\n console.error('Failed to start MCP server:', err);\n process.exit(1);\n });\n}\n","// Testable CLI logic for dataqueue\nimport { spawnSync, SpawnSyncReturns } from 'child_process';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { config as loadDotenv } from 'dotenv';\nimport { InitDeps, runInit } from './init-command.js';\nimport {\n runInstallSkills,\n InstallSkillsDeps,\n} from './install-skills-command.js';\nimport { runInstallRules, InstallRulesDeps } from './install-rules-command.js';\nimport { runInstallMcp, InstallMcpDeps } from './install-mcp-command.js';\nimport { startMcpServer } from './mcp-server.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface CliDeps {\n log?: (...args: any[]) => void;\n error?: (...args: any[]) => void;\n exit?: (code: number) => void;\n spawnSyncImpl?: (...args: any[]) => SpawnSyncReturns<any>;\n /** Load env vars from a file path (default: dotenv). Path is resolved from cwd. */\n loadEnvFromPath?: (filePath: string) => void;\n migrationsDir?: string;\n cwd?: string;\n initDeps?: InitDeps;\n runInitImpl?: (deps?: InitDeps) => void;\n installSkillsDeps?: InstallSkillsDeps;\n runInstallSkillsImpl?: (deps?: InstallSkillsDeps) => void;\n installRulesDeps?: InstallRulesDeps;\n runInstallRulesImpl?: (deps?: InstallRulesDeps) => Promise<void>;\n installMcpDeps?: InstallMcpDeps;\n runInstallMcpImpl?: (deps?: InstallMcpDeps) => Promise<void>;\n startMcpServerImpl?: typeof startMcpServer;\n}\n\nexport function runCli(\n argv: string[],\n {\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n spawnSyncImpl = spawnSync,\n cwd = process.cwd(),\n loadEnvFromPath = (filePath: string) => {\n loadDotenv({ path: path.resolve(cwd, filePath) });\n },\n migrationsDir = path.join(__dirname, '../migrations'),\n initDeps,\n runInitImpl = runInit,\n installSkillsDeps,\n runInstallSkillsImpl = runInstallSkills,\n installRulesDeps,\n runInstallRulesImpl = runInstallRules,\n installMcpDeps,\n runInstallMcpImpl = runInstallMcp,\n startMcpServerImpl = startMcpServer,\n }: CliDeps = {},\n): void {\n const [, , command, ...restArgs] = argv;\n\n function printUsage() {\n log('Usage:');\n log(\n ' dataqueue-cli migrate [--envPath <path>] [-s <schema> | --schema <schema>]',\n );\n log(' dataqueue-cli init');\n log(' dataqueue-cli install-skills');\n log(' dataqueue-cli install-rules');\n log(' dataqueue-cli install-mcp');\n log(' dataqueue-cli mcp');\n log('');\n log('Options for migrate:');\n log(\n ' --envPath <path> Path to a .env file to load environment variables (passed to node-pg-migrate)',\n );\n log(\n ' -s, --schema <schema> Set the schema to use (passed to node-pg-migrate)',\n );\n log('');\n log('AI tooling commands:');\n log(' install-skills Install DataQueue skill files for AI assistants');\n log(' install-rules Install DataQueue agent rules for AI clients');\n log(\n ' install-mcp Configure the DataQueue MCP server for AI clients',\n );\n log(' mcp Start the DataQueue MCP server (stdio)');\n exit(1);\n }\n\n if (command === 'migrate') {\n // Support for -s or --schema argument\n let schemaArg: string[] = [];\n const sIndex = restArgs.indexOf('-s');\n const schemaIndex = restArgs.indexOf('--schema');\n if (sIndex !== -1 && restArgs[sIndex + 1]) {\n schemaArg = ['-s', restArgs[sIndex + 1], '--create-schema'];\n restArgs.splice(sIndex, 2);\n } else if (schemaIndex !== -1 && restArgs[schemaIndex + 1]) {\n schemaArg = ['-s', restArgs[schemaIndex + 1], '--create-schema'];\n restArgs.splice(schemaIndex, 2);\n }\n\n // Support for --envPath argument: load env file so PG_DATAQUEUE_DATABASE is set\n // before spawning node-pg-migrate (node-pg-migrate only loads .env if dotenv is\n // installed in its context, so we preload here for reliable behavior).\n let envPathArg: string[] = [];\n const envPathIndex = restArgs.indexOf('--envPath');\n if (envPathIndex !== -1 && restArgs[envPathIndex + 1]) {\n const envPath = restArgs[envPathIndex + 1];\n loadEnvFromPath(envPath);\n envPathArg = ['--envPath', envPath];\n }\n\n const result: SpawnSyncReturns<any> = spawnSyncImpl(\n 'npx',\n [\n 'node-pg-migrate',\n 'up',\n '-t',\n 'dataqueuedev_migrations',\n '-d',\n 'PG_DATAQUEUE_DATABASE',\n '-m',\n migrationsDir,\n ...schemaArg,\n ...envPathArg,\n ...restArgs,\n ],\n { stdio: 'inherit' },\n );\n exit(result.status ?? 1);\n } else if (command === 'init') {\n runInitImpl({\n log,\n error,\n exit,\n ...initDeps,\n });\n } else if (command === 'install-skills') {\n runInstallSkillsImpl({\n log,\n error,\n exit,\n ...installSkillsDeps,\n });\n } else if (command === 'install-rules') {\n runInstallRulesImpl({\n log,\n error,\n exit,\n ...installRulesDeps,\n });\n } else if (command === 'install-mcp') {\n runInstallMcpImpl({\n log,\n error,\n exit,\n ...installMcpDeps,\n });\n } else if (command === 'mcp') {\n startMcpServerImpl().catch((err) => {\n error('Failed to start MCP server:', err);\n exit(1);\n });\n } else {\n printUsage();\n }\n}\n"]}
|
package/dist/cli.js
CHANGED
|
@@ -920,7 +920,7 @@ Installing MCP config for ${client.label}...`);
|
|
|
920
920
|
existsSync: existsSync2,
|
|
921
921
|
log
|
|
922
922
|
});
|
|
923
|
-
log("\nDone! The MCP server will run via: npx dataqueue
|
|
923
|
+
log("\nDone! The MCP server will run via: npx @nicnocquee/dataqueue mcp");
|
|
924
924
|
} catch (err) {
|
|
925
925
|
error("Failed to install MCP config:", err);
|
|
926
926
|
exit(1);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/init-command.ts","../src/install-skills-command.ts","../src/install-rules-command.ts","../src/install-mcp-command.ts","../src/mcp-server.ts","../src/cli.ts"],"names":["path","existsSync","mkdirSync","__filename","fileURLToPath","__dirname","readFileSync","fs","writeFileSync","client","readline","loadDotenv"],"mappings":"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","file":"cli.js","sourcesContent":["import {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n} from 'fs';\nimport path from 'path';\n\ntype JsonObject = Record<string, unknown>;\ntype JsonMap = Record<string, string>;\n\nconst DEPENDENCIES_TO_ADD = [\n '@nicnocquee/dataqueue',\n '@nicnocquee/dataqueue-dashboard',\n '@nicnocquee/dataqueue-react',\n] as const;\n\nconst DEV_DEPENDENCIES_TO_ADD = [\n 'dotenv-cli',\n 'ts-node',\n 'node-pg-migrate',\n] as const;\n\nconst SCRIPTS_TO_ADD = {\n cron: 'bash cron.sh',\n 'migrate-dataqueue': 'dotenv -e .env.local -- dataqueue-cli migrate',\n} as const;\n\n/**\n * App router endpoint template for queue management.\n */\nexport const APP_ROUTER_ROUTE_TEMPLATE = `/**\n * This end point is used to manage the job queue.\n * It supports the following tasks:\n * - reclaim: Reclaim stuck jobs\n * - cleanup: Cleanup old jobs\n * - process: Process jobs\n *\n * Example usage with default values (reclaim stuck jobs for 10 minutes, cleanup old jobs for 30 days, and process jobs with batch size 3, concurrency 2, and verbose true):\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\"\n *\n * Example usage with custom values:\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"maxProcessingTimeMinutes\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"daysToKeep\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"batchSize\": 5, \"concurrency\": 3, \"verbose\": false, \"workerId\": \"custom-worker-id\"}' -H \"Content-Type: application/json\"\n *\n * During development, you can run the following script to run the cron jobs continuously in the background:\n * pnpm cron\n */\nimport { getJobQueue, jobHandlers } from '@/lib/dataqueue/queue';\nimport { NextResponse } from 'next/server';\n\nexport async function POST(\n request: Request,\n { params }: { params: Promise<{ task: string[] }> },\n) {\n const { task } = await params;\n const authHeader = request.headers.get('authorization');\n if (authHeader !== \\`Bearer \\${process.env.CRON_SECRET}\\`) {\n return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });\n }\n\n if (!task || task.length === 0) {\n return NextResponse.json({ message: 'Task is required' }, { status: 400 });\n }\n\n const supportedTasks = ['reclaim', 'cleanup', 'process'];\n const theTask = task[0];\n if (!supportedTasks.includes(theTask)) {\n return NextResponse.json(\n { message: 'Task not supported' },\n { status: 400 },\n );\n }\n\n try {\n const jobQueue = getJobQueue();\n\n if (theTask === 'reclaim') {\n let maxProcessingTimeMinutes = 10;\n try {\n const body = await request.json();\n maxProcessingTimeMinutes = body.maxProcessingTimeMinutes || 10;\n } catch {\n // ignore parsing error and use default value\n }\n const reclaimed = await jobQueue.reclaimStuckJobs(\n maxProcessingTimeMinutes,\n );\n console.log(\\`Reclaimed \\${reclaimed} stuck jobs\\`);\n return NextResponse.json({\n message: \\`Stuck jobs reclaimed: \\${reclaimed} with maxProcessingTimeMinutes: \\${maxProcessingTimeMinutes}\\`,\n reclaimed,\n });\n }\n\n if (theTask === 'cleanup') {\n let daysToKeep = 30;\n try {\n const body = await request.json();\n daysToKeep = body.daysToKeep || 30;\n } catch {\n // ignore parsing error and use default value\n }\n const deleted = await jobQueue.cleanupOldJobs(daysToKeep);\n console.log(\\`Deleted \\${deleted} old jobs\\`);\n return NextResponse.json({\n message: \\`Old jobs cleaned up: \\${deleted} with daysToKeep: \\${daysToKeep}\\`,\n deleted,\n });\n }\n\n if (theTask === 'process') {\n let batchSize = 3;\n let concurrency = 2;\n let verbose = true;\n let workerId = \\`manage-\\${theTask}-\\${Date.now()}\\`;\n try {\n const body = await request.json();\n batchSize = body.batchSize || 3;\n concurrency = body.concurrency || 2;\n verbose = body.verbose || true;\n workerId = body.workerId || \\`manage-\\${theTask}-\\${Date.now()}\\`;\n } catch {\n // ignore parsing error and use default value\n }\n const processor = jobQueue.createProcessor(jobHandlers, {\n workerId,\n batchSize,\n concurrency,\n verbose,\n });\n const processed = await processor.start();\n\n return NextResponse.json({\n message: \\`Jobs processed: \\${processed} with workerId: \\${workerId}, batchSize: \\${batchSize}, concurrency: \\${concurrency}, and verbose: \\${verbose}\\`,\n processed,\n });\n }\n\n return NextResponse.json(\n { message: 'Task not supported' },\n { status: 400 },\n );\n } catch (error) {\n console.error('Error processing jobs:', error);\n return NextResponse.json(\n { message: 'Failed to process jobs' },\n { status: 500 },\n );\n }\n}\n`;\n\n/**\n * Pages router endpoint template for queue management.\n */\nexport const PAGES_ROUTER_ROUTE_TEMPLATE = `/**\n * This end point is used to manage the job queue.\n * It supports the following tasks:\n * - reclaim: Reclaim stuck jobs\n * - cleanup: Cleanup old jobs\n * - process: Process jobs\n *\n * Example usage with default values (reclaim stuck jobs for 10 minutes, cleanup old jobs for 30 days, and process jobs with batch size 3, concurrency 2, and verbose true):\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\"\n *\n * Example usage with custom values:\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"maxProcessingTimeMinutes\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"daysToKeep\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"batchSize\": 5, \"concurrency\": 3, \"verbose\": false, \"workerId\": \"custom-worker-id\"}' -H \"Content-Type: application/json\"\n *\n * During development, you can run the following script to run the cron jobs continuously in the background:\n * pnpm cron\n */\nimport type { NextApiRequest, NextApiResponse } from 'next';\nimport { getJobQueue, jobHandlers } from '@/lib/dataqueue/queue';\n\ntype ResponseBody = {\n message: string;\n reclaimed?: number;\n deleted?: number;\n processed?: number;\n};\n\nexport default async function handler(\n req: NextApiRequest,\n res: NextApiResponse<ResponseBody>,\n) {\n if (req.method !== 'POST') {\n res.setHeader('Allow', 'POST');\n return res.status(405).json({ message: 'Method not allowed' });\n }\n\n const authHeader = req.headers.authorization;\n if (authHeader !== \\`Bearer \\${process.env.CRON_SECRET}\\`) {\n return res.status(401).json({ message: 'Unauthorized' });\n }\n\n const task = req.query.task;\n const taskArray = Array.isArray(task) ? task : task ? [task] : [];\n if (!taskArray.length) {\n return res.status(400).json({ message: 'Task is required' });\n }\n\n const supportedTasks = ['reclaim', 'cleanup', 'process'];\n const theTask = taskArray[0];\n if (!supportedTasks.includes(theTask)) {\n return res.status(400).json({ message: 'Task not supported' });\n }\n\n try {\n const jobQueue = getJobQueue();\n const body = typeof req.body === 'object' && req.body ? req.body : {};\n\n if (theTask === 'reclaim') {\n const maxProcessingTimeMinutes = body.maxProcessingTimeMinutes || 10;\n const reclaimed = await jobQueue.reclaimStuckJobs(maxProcessingTimeMinutes);\n console.log(\\`Reclaimed \\${reclaimed} stuck jobs\\`);\n return res.status(200).json({\n message: \\`Stuck jobs reclaimed: \\${reclaimed} with maxProcessingTimeMinutes: \\${maxProcessingTimeMinutes}\\`,\n reclaimed,\n });\n }\n\n if (theTask === 'cleanup') {\n const daysToKeep = body.daysToKeep || 30;\n const deleted = await jobQueue.cleanupOldJobs(daysToKeep);\n console.log(\\`Deleted \\${deleted} old jobs\\`);\n return res.status(200).json({\n message: \\`Old jobs cleaned up: \\${deleted} with daysToKeep: \\${daysToKeep}\\`,\n deleted,\n });\n }\n\n const batchSize = body.batchSize || 3;\n const concurrency = body.concurrency || 2;\n const verbose = body.verbose || true;\n const workerId = body.workerId || \\`manage-\\${theTask}-\\${Date.now()}\\`;\n const processor = jobQueue.createProcessor(jobHandlers, {\n workerId,\n batchSize,\n concurrency,\n verbose,\n });\n const processed = await processor.start();\n\n return res.status(200).json({\n message: \\`Jobs processed: \\${processed} with workerId: \\${workerId}, batchSize: \\${batchSize}, concurrency: \\${concurrency}, and verbose: \\${verbose}\\`,\n processed,\n });\n } catch (error) {\n console.error('Error processing jobs:', error);\n return res.status(500).json({ message: 'Failed to process jobs' });\n }\n}\n`;\n\n/**\n * Cron script template for local queue processing.\n */\nexport const CRON_SH_TEMPLATE = `#!/bin/bash\n\n# This script is used to run the cron jobs for the demo app during development.\n# Run it with \\`pnpm cron\\` from the apps/demo directory.\n\nset -a\nsource \"$(dirname \"$0\")/.env.local\"\nset +a\n\nif [ -z \"$CRON_SECRET\" ]; then\n echo \"Error: CRON_SECRET environment variable is not set in .env.local\"\n exit 1\nfi\n\ncleanup() {\n kill 0\n wait\n}\ntrap cleanup SIGINT SIGTERM\n\nwhile true; do\n echo \"Processing jobs...\"\n curl http://localhost:3000/api/dataqueue/manage/process -X POST -H \"Authorization: Bearer $CRON_SECRET\"\n echo \"\"\n sleep 10 # Process jobs every 10 seconds\ndone &\n\nwhile true; do\n echo \"Reclaiming stuck jobs...\"\n curl http://localhost:3000/api/dataqueue/manage/reclaim -X POST -H \"Authorization: Bearer $CRON_SECRET\"\n echo \"\"\n sleep 20 # Reclaim stuck jobs every 20 seconds\ndone &\n\nwhile true; do\n echo \"Cleaning up old jobs...\"\n curl http://localhost:3000/api/dataqueue/manage/cleanup -X POST -H \"Authorization: Bearer $CRON_SECRET\"\n echo \"\"\n sleep 30 # Cleanup old jobs every 30 seconds\ndone &\n\nwait\n`;\n\n/**\n * Queue placeholder template with a single `send_email` job.\n */\nexport const QUEUE_TEMPLATE = `import { initJobQueue, JobHandlers } from '@nicnocquee/dataqueue';\n\nexport type JobPayloadMap = {\n send_email: {\n to: string;\n subject: string;\n body: string;\n };\n};\n\nlet jobQueue: ReturnType<typeof initJobQueue<JobPayloadMap>> | null = null;\n\nexport const getJobQueue = () => {\n if (!jobQueue) {\n jobQueue = initJobQueue<JobPayloadMap>({\n databaseConfig: {\n connectionString: process.env.PG_DATAQUEUE_DATABASE,\n },\n verbose: process.env.NODE_ENV === 'development',\n });\n }\n return jobQueue;\n};\n\nexport const jobHandlers: JobHandlers<JobPayloadMap> = {\n send_email: async (payload) => {\n const { to, subject, body } = payload;\n console.log('send_email placeholder:', { to, subject, body });\n },\n};\n`;\n\nexport interface InitDeps {\n log?: (...args: any[]) => void;\n error?: (...args: any[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n readFileSyncImpl?: typeof readFileSync;\n writeFileSyncImpl?: typeof writeFileSync;\n existsSyncImpl?: typeof existsSync;\n mkdirSyncImpl?: typeof mkdirSync;\n chmodSyncImpl?: typeof chmodSync;\n}\n\ntype RouterKind = 'app' | 'pages';\n\ninterface ProjectDetails {\n cwd: string;\n packageJsonPath: string;\n packageJson: JsonObject;\n srcRoot: string;\n router: RouterKind;\n}\n\n/**\n * Runs the `dataqueue-cli init` command.\n */\nexport function runInit({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n readFileSyncImpl = readFileSync,\n writeFileSyncImpl = writeFileSync,\n existsSyncImpl = existsSync,\n mkdirSyncImpl = mkdirSync,\n chmodSyncImpl = chmodSync,\n}: InitDeps = {}): void {\n try {\n log(`dataqueue: Initializing in ${cwd}...`);\n log('');\n\n const details = detectNextJsAndRouter({\n cwd,\n existsSyncImpl,\n readFileSyncImpl,\n });\n\n createScaffoldFiles({\n details,\n log,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n chmodSyncImpl,\n });\n\n updatePackageJson({\n details,\n log,\n writeFileSyncImpl,\n });\n\n log('');\n log(\n \"Done! Run your package manager's install command to install new dependencies.\",\n );\n exit(0);\n } catch (cause) {\n const message = cause instanceof Error ? cause.message : String(cause);\n error(`dataqueue: ${message}`);\n exit(1);\n }\n}\n\n/**\n * Detects that the current directory is a Next.js app and chooses the router.\n */\nexport function detectNextJsAndRouter({\n cwd,\n existsSyncImpl,\n readFileSyncImpl,\n}: {\n cwd: string;\n existsSyncImpl: typeof existsSync;\n readFileSyncImpl: typeof readFileSync;\n}): ProjectDetails {\n const packageJsonPath = path.join(cwd, 'package.json');\n if (!existsSyncImpl(packageJsonPath)) {\n throw new Error('package.json not found in current directory.');\n }\n\n const packageJson = parsePackageJson(\n readFileSyncImpl(packageJsonPath, 'utf8'),\n packageJsonPath,\n );\n if (!isNextJsProject(packageJson)) {\n throw new Error(\n \"Not a Next.js project. Could not find 'next' in package.json dependencies.\",\n );\n }\n\n const srcDir = path.join(cwd, 'src');\n const srcRoot = existsSyncImpl(srcDir) ? 'src' : '.';\n const appDir = path.join(cwd, srcRoot, 'app');\n const pagesDir = path.join(cwd, srcRoot, 'pages');\n const hasAppDir = existsSyncImpl(appDir);\n const hasPagesDir = existsSyncImpl(pagesDir);\n\n if (!hasAppDir && !hasPagesDir) {\n throw new Error(\n 'Could not detect Next.js router. Expected either app/ or pages/ directory.',\n );\n }\n\n const router: RouterKind = hasAppDir ? 'app' : 'pages';\n return { cwd, packageJsonPath, packageJson, srcRoot, router };\n}\n\n/**\n * Updates package.json with required dependencies and scripts.\n */\nfunction updatePackageJson({\n details,\n log,\n writeFileSyncImpl,\n}: {\n details: ProjectDetails;\n log: (...args: any[]) => void;\n writeFileSyncImpl: typeof writeFileSync;\n}): void {\n const packageJson = details.packageJson;\n const dependencies = ensureStringMapSection(packageJson, 'dependencies');\n const devDependencies = ensureStringMapSection(\n packageJson,\n 'devDependencies',\n );\n const scripts = ensureStringMapSection(packageJson, 'scripts');\n\n for (const dependency of DEPENDENCIES_TO_ADD) {\n if (dependencies[dependency]) {\n log(` [skipped] dependency ${dependency} (already exists)`);\n continue;\n }\n dependencies[dependency] = 'latest';\n log(` [added] dependency ${dependency}`);\n }\n\n for (const devDependency of DEV_DEPENDENCIES_TO_ADD) {\n if (devDependencies[devDependency]) {\n log(` [skipped] devDependency ${devDependency} (already exists)`);\n continue;\n }\n devDependencies[devDependency] = 'latest';\n log(` [added] devDependency ${devDependency}`);\n }\n\n for (const [scriptName, scriptValue] of Object.entries(SCRIPTS_TO_ADD)) {\n if (scripts[scriptName]) {\n log(` [skipped] script \"${scriptName}\" (already exists)`);\n continue;\n }\n scripts[scriptName] = scriptValue;\n log(` [added] script \"${scriptName}\"`);\n }\n\n writeFileSyncImpl(\n details.packageJsonPath,\n `${JSON.stringify(packageJson, null, 2)}\\n`,\n );\n}\n\n/**\n * Creates all scaffold files for the detected router without overwriting.\n */\nfunction createScaffoldFiles({\n details,\n log,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n chmodSyncImpl,\n}: {\n details: ProjectDetails;\n log: (...args: any[]) => void;\n existsSyncImpl: typeof existsSync;\n mkdirSyncImpl: typeof mkdirSync;\n writeFileSyncImpl: typeof writeFileSync;\n chmodSyncImpl: typeof chmodSync;\n}): void {\n const appRoutePath = path.join(\n details.cwd,\n details.srcRoot,\n 'app',\n 'api',\n 'dataqueue',\n 'manage',\n '[[...task]]',\n 'route.ts',\n );\n const pagesRoutePath = path.join(\n details.cwd,\n details.srcRoot,\n 'pages',\n 'api',\n 'dataqueue',\n 'manage',\n '[[...task]].ts',\n );\n const queuePath = path.join(\n details.cwd,\n details.srcRoot,\n 'lib',\n 'dataqueue',\n 'queue.ts',\n );\n const cronPath = path.join(details.cwd, 'cron.sh');\n\n if (details.router === 'app') {\n createFileIfMissing({\n absolutePath: appRoutePath,\n content: APP_ROUTER_ROUTE_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: toRelativePath(details.cwd, appRoutePath),\n });\n log(\n ' [skipped] pages/api/dataqueue/manage/[[...task]].ts (router not selected)',\n );\n } else {\n log(\n ' [skipped] app/api/dataqueue/manage/[[...task]]/route.ts (router not selected)',\n );\n createFileIfMissing({\n absolutePath: pagesRoutePath,\n content: PAGES_ROUTER_ROUTE_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: toRelativePath(details.cwd, pagesRoutePath),\n });\n }\n\n createFileIfMissing({\n absolutePath: cronPath,\n content: CRON_SH_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: 'cron.sh',\n });\n if (existsSyncImpl(cronPath)) {\n chmodSyncImpl(cronPath, 0o755);\n }\n\n createFileIfMissing({\n absolutePath: queuePath,\n content: QUEUE_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: toRelativePath(details.cwd, queuePath),\n });\n}\n\n/**\n * Creates a file only if it does not already exist.\n */\nfunction createFileIfMissing({\n absolutePath,\n content,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath,\n}: {\n absolutePath: string;\n content: string;\n existsSyncImpl: typeof existsSync;\n mkdirSyncImpl: typeof mkdirSync;\n writeFileSyncImpl: typeof writeFileSync;\n log: (...args: any[]) => void;\n logPath: string;\n}): void {\n if (existsSyncImpl(absolutePath)) {\n log(` [skipped] ${logPath} (already exists)`);\n return;\n }\n\n mkdirSyncImpl(path.dirname(absolutePath), { recursive: true });\n writeFileSyncImpl(absolutePath, content);\n log(` [created] ${logPath}`);\n}\n\n/**\n * Parses package.json content with clear source context.\n */\nfunction parsePackageJson(content: string, filePath: string): JsonObject {\n try {\n const parsed = JSON.parse(content);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('package.json must contain an object.');\n }\n return parsed as JsonObject;\n } catch (cause) {\n throw new Error(\n `Failed to parse package.json at ${filePath}: ${\n cause instanceof Error ? cause.message : String(cause)\n }`,\n );\n }\n}\n\n/**\n * Returns true when package.json declares Next.js in deps or devDeps.\n */\nfunction isNextJsProject(packageJson: JsonObject): boolean {\n const dependencies = packageJson.dependencies;\n const devDependencies = packageJson.devDependencies;\n\n return (\n hasPackage(dependencies, 'next') || hasPackage(devDependencies, 'next')\n );\n}\n\n/**\n * Returns true when a package name exists in a dependency section object.\n */\nfunction hasPackage(section: unknown, packageName: string): boolean {\n if (!section || typeof section !== 'object' || Array.isArray(section)) {\n return false;\n }\n return Boolean((section as JsonMap)[packageName]);\n}\n\n/**\n * Ensures package.json has a string map section and returns it.\n */\nfunction ensureStringMapSection(\n packageJson: JsonObject,\n sectionName: 'dependencies' | 'devDependencies' | 'scripts',\n): JsonMap {\n const currentValue = packageJson[sectionName];\n if (\n !currentValue ||\n typeof currentValue !== 'object' ||\n Array.isArray(currentValue)\n ) {\n packageJson[sectionName] = {};\n }\n return packageJson[sectionName] as JsonMap;\n}\n\n/**\n * Converts an absolute path to a stable relative path for log output.\n */\nfunction toRelativePath(cwd: string, absolutePath: string): string {\n const relative = path.relative(cwd, absolutePath);\n return relative || '.';\n}\n","import fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface InstallSkillsDeps {\n log?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n existsSync?: (p: string) => boolean;\n mkdirSync?: (p: string, opts?: fs.MakeDirectoryOptions) => void;\n copyFileSync?: (src: string, dest: string) => void;\n readdirSync?: (p: string) => string[];\n skillsSourceDir?: string;\n}\n\nconst SKILL_DIRS = ['dataqueue-core', 'dataqueue-advanced', 'dataqueue-react'];\n\ninterface AiTool {\n name: string;\n targetDir: string;\n}\n\n/**\n * Detects which AI tools have config directories in the project.\n *\n * @param cwd - Current working directory to scan.\n * @param existsSync - Injectable fs.existsSync.\n * @returns Array of detected AI tools with their skills target directories.\n */\nexport function detectAiTools(\n cwd: string,\n existsSync: (p: string) => boolean = fs.existsSync,\n): AiTool[] {\n const tools: AiTool[] = [];\n const checks: Array<{ name: string; indicator: string; targetDir: string }> =\n [\n {\n name: 'Cursor',\n indicator: '.cursor',\n targetDir: '.cursor/skills',\n },\n {\n name: 'Claude Code',\n indicator: '.claude',\n targetDir: '.claude/skills',\n },\n {\n name: 'GitHub Copilot',\n indicator: '.github',\n targetDir: '.github/skills',\n },\n ];\n\n for (const check of checks) {\n if (existsSync(path.join(cwd, check.indicator))) {\n tools.push({ name: check.name, targetDir: check.targetDir });\n }\n }\n\n return tools;\n}\n\n/**\n * Installs DataQueue skill files into detected AI tool directories.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport function runInstallSkills({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n existsSync = fs.existsSync,\n mkdirSync = fs.mkdirSync,\n copyFileSync = fs.copyFileSync,\n readdirSync = fs.readdirSync,\n skillsSourceDir = path.join(__dirname, '../ai/skills'),\n}: InstallSkillsDeps = {}): void {\n const tools = detectAiTools(cwd, existsSync);\n\n if (tools.length === 0) {\n log('No AI tool directories detected (.cursor/, .claude/, .github/).');\n log('Creating .cursor/skills/ as the default target.');\n tools.push({ name: 'Cursor', targetDir: '.cursor/skills' });\n }\n\n let installed = 0;\n\n for (const tool of tools) {\n log(`\\nInstalling skills for ${tool.name}...`);\n\n for (const skillDir of SKILL_DIRS) {\n const srcDir = path.join(skillsSourceDir, skillDir);\n const destDir = path.join(cwd, tool.targetDir, skillDir);\n\n try {\n mkdirSync(destDir, { recursive: true });\n\n const files = readdirSync(srcDir);\n for (const file of files) {\n copyFileSync(path.join(srcDir, file), path.join(destDir, file));\n }\n\n log(` ✓ ${skillDir}`);\n installed++;\n } catch (err) {\n error(` ✗ Failed to install ${skillDir}:`, err);\n }\n }\n }\n\n if (installed > 0) {\n log(\n `\\nDone! Installed ${installed} skill(s) for ${tools.map((t) => t.name).join(', ')}.`,\n );\n } else {\n error('No skills were installed.');\n exit(1);\n }\n}\n","import fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport readline from 'readline';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface InstallRulesDeps {\n log?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n readFileSync?: (p: string, enc: BufferEncoding) => string;\n writeFileSync?: (p: string, data: string) => void;\n appendFileSync?: (p: string, data: string) => void;\n mkdirSync?: (p: string, opts?: fs.MakeDirectoryOptions) => void;\n existsSync?: (p: string) => boolean;\n rulesSourceDir?: string;\n /** Override for selecting the client (skips interactive prompt). */\n selectedClient?: string;\n}\n\nconst RULE_FILES = ['basic.md', 'advanced.md', 'react-dashboard.md'];\n\ninterface ClientConfig {\n label: string;\n install: (\n deps: Required<\n Pick<\n InstallRulesDeps,\n | 'cwd'\n | 'readFileSync'\n | 'writeFileSync'\n | 'appendFileSync'\n | 'mkdirSync'\n | 'existsSync'\n | 'log'\n | 'rulesSourceDir'\n >\n >,\n ) => void;\n}\n\nconst MARKER_START = '<!-- DATAQUEUE RULES START -->';\nconst MARKER_END = '<!-- DATAQUEUE RULES END -->';\n\n/**\n * Appends or replaces a marked section in a file.\n *\n * @param filePath - Path to the file to update.\n * @param content - Content to insert between markers.\n * @param deps - Injectable file system functions.\n */\nexport function upsertMarkedSection(\n filePath: string,\n content: string,\n deps: {\n readFileSync: (p: string, enc: BufferEncoding) => string;\n writeFileSync: (p: string, data: string) => void;\n existsSync: (p: string) => boolean;\n },\n): void {\n const block = `${MARKER_START}\\n${content}\\n${MARKER_END}`;\n\n if (!deps.existsSync(filePath)) {\n deps.writeFileSync(filePath, block + '\\n');\n return;\n }\n\n const existing = deps.readFileSync(filePath, 'utf-8');\n const startIdx = existing.indexOf(MARKER_START);\n const endIdx = existing.indexOf(MARKER_END);\n\n if (startIdx !== -1 && endIdx !== -1) {\n const before = existing.slice(0, startIdx);\n const after = existing.slice(endIdx + MARKER_END.length);\n deps.writeFileSync(filePath, before + block + after);\n } else {\n deps.writeFileSync(filePath, existing.trimEnd() + '\\n\\n' + block + '\\n');\n }\n}\n\nfunction getAllRulesContent(\n rulesSourceDir: string,\n readFileSync: (p: string, enc: BufferEncoding) => string,\n): string {\n return RULE_FILES.map((f) =>\n readFileSync(path.join(rulesSourceDir, f), 'utf-8'),\n ).join('\\n\\n');\n}\n\nconst CLIENTS: Record<string, ClientConfig> = {\n '1': {\n label: 'Cursor',\n install: (deps) => {\n const rulesDir = path.join(deps.cwd, '.cursor', 'rules');\n deps.mkdirSync(rulesDir, { recursive: true });\n\n for (const file of RULE_FILES) {\n const src = deps.readFileSync(\n path.join(deps.rulesSourceDir, file),\n 'utf-8',\n );\n const destName = `dataqueue-${file.replace(/\\.md$/, '.mdc')}`;\n deps.writeFileSync(path.join(rulesDir, destName), src);\n deps.log(` ✓ .cursor/rules/${destName}`);\n }\n },\n },\n '2': {\n label: 'Claude Code',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n const filePath = path.join(deps.cwd, 'CLAUDE.md');\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ CLAUDE.md`);\n },\n },\n '3': {\n label: 'AGENTS.md (Codex, Jules, OpenCode)',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n const filePath = path.join(deps.cwd, 'AGENTS.md');\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ AGENTS.md`);\n },\n },\n '4': {\n label: 'GitHub Copilot',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n deps.mkdirSync(path.join(deps.cwd, '.github'), { recursive: true });\n const filePath = path.join(\n deps.cwd,\n '.github',\n 'copilot-instructions.md',\n );\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ .github/copilot-instructions.md`);\n },\n },\n '5': {\n label: 'Windsurf',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n const filePath = path.join(deps.cwd, 'CONVENTIONS.md');\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ CONVENTIONS.md`);\n },\n },\n};\n\n/**\n * Installs DataQueue agent rules for the selected AI client.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport async function runInstallRules({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n readFileSync = fs.readFileSync,\n writeFileSync = fs.writeFileSync,\n appendFileSync = fs.appendFileSync,\n mkdirSync = fs.mkdirSync,\n existsSync = fs.existsSync,\n rulesSourceDir = path.join(__dirname, '../ai/rules'),\n selectedClient,\n}: InstallRulesDeps = {}): Promise<void> {\n log('DataQueue Agent Rules Installer\\n');\n log('Select your AI client:\\n');\n\n for (const [key, client] of Object.entries(CLIENTS)) {\n log(` ${key}) ${client.label}`);\n }\n log('');\n\n let choice = selectedClient;\n\n if (!choice) {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n choice = await new Promise<string>((resolve) => {\n rl.question('Enter choice (1-5): ', (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n }\n\n const client = CLIENTS[choice];\n if (!client) {\n error(`Invalid choice: \"${choice}\". Expected 1-5.`);\n exit(1);\n return;\n }\n\n log(`\\nInstalling rules for ${client.label}...`);\n\n try {\n client.install({\n cwd,\n readFileSync,\n writeFileSync,\n appendFileSync,\n mkdirSync,\n existsSync,\n log,\n rulesSourceDir,\n });\n log('\\nDone!');\n } catch (err) {\n error('Failed to install rules:', err);\n exit(1);\n }\n}\n","import fs from 'fs';\nimport path from 'path';\nimport readline from 'readline';\n\nexport interface InstallMcpDeps {\n log?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n readFileSync?: (p: string, enc: BufferEncoding) => string;\n writeFileSync?: (p: string, data: string) => void;\n mkdirSync?: (p: string, opts?: fs.MakeDirectoryOptions) => void;\n existsSync?: (p: string) => boolean;\n /** Override for selecting the client (skips interactive prompt). */\n selectedClient?: string;\n}\n\ninterface McpClientConfig {\n label: string;\n install: (\n deps: Required<\n Pick<\n InstallMcpDeps,\n | 'cwd'\n | 'readFileSync'\n | 'writeFileSync'\n | 'mkdirSync'\n | 'existsSync'\n | 'log'\n >\n >,\n ) => void;\n}\n\n/**\n * Merges the dataqueue MCP server config into an existing JSON config file.\n *\n * @param filePath - Path to the MCP config file.\n * @param serverKey - Key name for the server entry.\n * @param serverConfig - Server configuration object.\n * @param deps - Injectable file system functions.\n */\nexport function upsertMcpConfig(\n filePath: string,\n serverKey: string,\n serverConfig: Record<string, unknown>,\n deps: {\n readFileSync: (p: string, enc: BufferEncoding) => string;\n writeFileSync: (p: string, data: string) => void;\n existsSync: (p: string) => boolean;\n },\n): void {\n let config: Record<string, unknown> = {};\n\n if (deps.existsSync(filePath)) {\n try {\n config = JSON.parse(deps.readFileSync(filePath, 'utf-8'));\n } catch {\n config = {};\n }\n }\n\n if (!config.mcpServers || typeof config.mcpServers !== 'object') {\n config.mcpServers = {};\n }\n\n (config.mcpServers as Record<string, unknown>)[serverKey] = serverConfig;\n deps.writeFileSync(filePath, JSON.stringify(config, null, 2) + '\\n');\n}\n\nconst MCP_SERVER_CONFIG = {\n command: 'npx',\n args: ['dataqueue-cli', 'mcp'],\n};\n\nconst MCP_CLIENTS: Record<string, McpClientConfig> = {\n '1': {\n label: 'Cursor',\n install: (deps) => {\n const configDir = path.join(deps.cwd, '.cursor');\n deps.mkdirSync(configDir, { recursive: true });\n const configFile = path.join(configDir, 'mcp.json');\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ .cursor/mcp.json`);\n },\n },\n '2': {\n label: 'Claude Code',\n install: (deps) => {\n const configFile = path.join(deps.cwd, '.mcp.json');\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ .mcp.json`);\n },\n },\n '3': {\n label: 'VS Code (Copilot)',\n install: (deps) => {\n const configDir = path.join(deps.cwd, '.vscode');\n deps.mkdirSync(configDir, { recursive: true });\n const configFile = path.join(configDir, 'mcp.json');\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ .vscode/mcp.json`);\n },\n },\n '4': {\n label: 'Windsurf',\n install: (deps) => {\n const homeDir = process.env.HOME || process.env.USERPROFILE || '';\n const configFile = path.join(\n homeDir,\n '.codeium',\n 'windsurf',\n 'mcp_config.json',\n );\n deps.mkdirSync(path.dirname(configFile), { recursive: true });\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ ~/.codeium/windsurf/mcp_config.json`);\n },\n },\n};\n\n/**\n * Installs the DataQueue MCP server config for the selected AI client.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport async function runInstallMcp({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n readFileSync = fs.readFileSync,\n writeFileSync = fs.writeFileSync,\n mkdirSync = fs.mkdirSync,\n existsSync = fs.existsSync,\n selectedClient,\n}: InstallMcpDeps = {}): Promise<void> {\n log('DataQueue MCP Server Installer\\n');\n log('Select your AI client:\\n');\n\n for (const [key, client] of Object.entries(MCP_CLIENTS)) {\n log(` ${key}) ${client.label}`);\n }\n log('');\n\n let choice = selectedClient;\n\n if (!choice) {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n choice = await new Promise<string>((resolve) => {\n rl.question('Enter choice (1-4): ', (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n }\n\n const client = MCP_CLIENTS[choice];\n if (!client) {\n error(`Invalid choice: \"${choice}\". Expected 1-4.`);\n exit(1);\n return;\n }\n\n log(`\\nInstalling MCP config for ${client.label}...`);\n\n try {\n client.install({\n cwd,\n readFileSync,\n writeFileSync,\n mkdirSync,\n existsSync,\n log,\n });\n log('\\nDone! The MCP server will run via: npx dataqueue-cli mcp');\n } catch (err) {\n error('Failed to install MCP config:', err);\n exit(1);\n }\n}\n","#!/usr/bin/env node\n\n/**\n * DataQueue MCP Server — exposes documentation search over stdio.\n * Run via: dataqueue-cli mcp\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\ninterface DocPage {\n slug: string;\n title: string;\n description: string;\n content: string;\n}\n\n/** @internal Loads docs-content.json from the ai/ directory bundled with the package. */\nexport function loadDocsContent(\n docsPath: string = path.join(__dirname, '../ai/docs-content.json'),\n): DocPage[] {\n const raw = fs.readFileSync(docsPath, 'utf-8');\n return JSON.parse(raw) as DocPage[];\n}\n\n/** @internal Scores a doc page against a search query using simple term matching. */\nexport function scorePageForQuery(page: DocPage, queryTerms: string[]): number {\n const titleLower = page.title.toLowerCase();\n const descLower = page.description.toLowerCase();\n const contentLower = page.content.toLowerCase();\n\n let score = 0;\n for (const term of queryTerms) {\n if (titleLower.includes(term)) score += 10;\n if (descLower.includes(term)) score += 5;\n\n const contentMatches = contentLower.split(term).length - 1;\n score += Math.min(contentMatches, 10);\n }\n return score;\n}\n\n/** @internal Extracts a relevant excerpt around the first match of any query term. */\nexport function extractExcerpt(\n content: string,\n queryTerms: string[],\n maxLength = 500,\n): string {\n const lower = content.toLowerCase();\n let earliestIndex = -1;\n\n for (const term of queryTerms) {\n const idx = lower.indexOf(term);\n if (idx !== -1 && (earliestIndex === -1 || idx < earliestIndex)) {\n earliestIndex = idx;\n }\n }\n\n if (earliestIndex === -1) {\n return content.slice(0, maxLength);\n }\n\n const start = Math.max(0, earliestIndex - 100);\n const end = Math.min(content.length, start + maxLength);\n let excerpt = content.slice(start, end);\n\n if (start > 0) excerpt = '...' + excerpt;\n if (end < content.length) excerpt = excerpt + '...';\n\n return excerpt;\n}\n\n/**\n * Creates and starts the DataQueue MCP server over stdio.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport async function startMcpServer(\n deps: {\n docsPath?: string;\n transport?: InstanceType<typeof StdioServerTransport>;\n } = {},\n): Promise<McpServer> {\n const pages = loadDocsContent(deps.docsPath);\n\n const server = new McpServer({\n name: 'dataqueue-docs',\n version: '1.0.0',\n });\n\n server.resource('llms-txt', 'dataqueue://llms.txt', async () => {\n const llmsPath = path.join(\n __dirname,\n '../ai/skills/dataqueue-core/SKILL.md',\n );\n let content: string;\n try {\n content = fs.readFileSync(llmsPath, 'utf-8');\n } catch {\n content = pages\n .map((p) => `## ${p.title}\\n\\nSlug: ${p.slug}\\n\\n${p.description}`)\n .join('\\n\\n');\n }\n return { contents: [{ uri: 'dataqueue://llms.txt', text: content }] };\n });\n\n server.tool(\n 'list-doc-pages',\n 'List all available DataQueue documentation pages with titles and descriptions.',\n {},\n async () => {\n const listing = pages.map((p) => ({\n slug: p.slug,\n title: p.title,\n description: p.description,\n }));\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(listing, null, 2) },\n ],\n };\n },\n );\n\n server.tool(\n 'get-doc-page',\n 'Fetch a specific DataQueue doc page by slug. Returns full page content as markdown.',\n {\n slug: z\n .string()\n .describe('The doc page slug, e.g. \"usage/add-job\" or \"api/job-queue\"'),\n },\n async ({ slug }) => {\n const page = pages.find((p) => p.slug === slug);\n if (!page) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Page not found: \"${slug}\". Use list-doc-pages to see available slugs.`,\n },\n ],\n isError: true,\n };\n }\n const header = page.description\n ? `# ${page.title}\\n\\n> ${page.description}\\n\\n`\n : `# ${page.title}\\n\\n`;\n return {\n content: [{ type: 'text' as const, text: header + page.content }],\n };\n },\n );\n\n server.tool(\n 'search-docs',\n 'Full-text search across all DataQueue documentation pages. Returns matching sections with page titles and content excerpts.',\n {\n query: z\n .string()\n .describe('Search query, e.g. \"cron scheduling\" or \"waitForToken\"'),\n },\n async ({ query }) => {\n const queryTerms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((t) => t.length > 1);\n\n if (queryTerms.length === 0) {\n return {\n content: [\n { type: 'text' as const, text: 'Please provide a search query.' },\n ],\n isError: true,\n };\n }\n\n const scored = pages\n .map((page) => ({\n page,\n score: scorePageForQuery(page, queryTerms),\n }))\n .filter((r) => r.score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, 5);\n\n if (scored.length === 0) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `No results for \"${query}\". Try different keywords or use list-doc-pages to browse.`,\n },\n ],\n };\n }\n\n const results = scored.map((r) => {\n const excerpt = extractExcerpt(r.page.content, queryTerms);\n return `## ${r.page.title} (${r.page.slug})\\n\\n${r.page.description}\\n\\n${excerpt}`;\n });\n\n return {\n content: [{ type: 'text' as const, text: results.join('\\n\\n---\\n\\n') }],\n };\n },\n );\n\n const transport = deps.transport ?? new StdioServerTransport();\n await server.connect(transport);\n return server;\n}\n\nconst isDirectRun =\n process.argv[1] &&\n (process.argv[1].endsWith('/mcp-server.js') ||\n process.argv[1].endsWith('/mcp-server.cjs'));\n\nif (isDirectRun) {\n startMcpServer().catch((err) => {\n console.error('Failed to start MCP server:', err);\n process.exit(1);\n });\n}\n","// Testable CLI logic for dataqueue\nimport { spawnSync, SpawnSyncReturns } from 'child_process';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { config as loadDotenv } from 'dotenv';\nimport { InitDeps, runInit } from './init-command.js';\nimport {\n runInstallSkills,\n InstallSkillsDeps,\n} from './install-skills-command.js';\nimport { runInstallRules, InstallRulesDeps } from './install-rules-command.js';\nimport { runInstallMcp, InstallMcpDeps } from './install-mcp-command.js';\nimport { startMcpServer } from './mcp-server.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface CliDeps {\n log?: (...args: any[]) => void;\n error?: (...args: any[]) => void;\n exit?: (code: number) => void;\n spawnSyncImpl?: (...args: any[]) => SpawnSyncReturns<any>;\n /** Load env vars from a file path (default: dotenv). Path is resolved from cwd. */\n loadEnvFromPath?: (filePath: string) => void;\n migrationsDir?: string;\n cwd?: string;\n initDeps?: InitDeps;\n runInitImpl?: (deps?: InitDeps) => void;\n installSkillsDeps?: InstallSkillsDeps;\n runInstallSkillsImpl?: (deps?: InstallSkillsDeps) => void;\n installRulesDeps?: InstallRulesDeps;\n runInstallRulesImpl?: (deps?: InstallRulesDeps) => Promise<void>;\n installMcpDeps?: InstallMcpDeps;\n runInstallMcpImpl?: (deps?: InstallMcpDeps) => Promise<void>;\n startMcpServerImpl?: typeof startMcpServer;\n}\n\nexport function runCli(\n argv: string[],\n {\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n spawnSyncImpl = spawnSync,\n cwd = process.cwd(),\n loadEnvFromPath = (filePath: string) => {\n loadDotenv({ path: path.resolve(cwd, filePath) });\n },\n migrationsDir = path.join(__dirname, '../migrations'),\n initDeps,\n runInitImpl = runInit,\n installSkillsDeps,\n runInstallSkillsImpl = runInstallSkills,\n installRulesDeps,\n runInstallRulesImpl = runInstallRules,\n installMcpDeps,\n runInstallMcpImpl = runInstallMcp,\n startMcpServerImpl = startMcpServer,\n }: CliDeps = {},\n): void {\n const [, , command, ...restArgs] = argv;\n\n function printUsage() {\n log('Usage:');\n log(\n ' dataqueue-cli migrate [--envPath <path>] [-s <schema> | --schema <schema>]',\n );\n log(' dataqueue-cli init');\n log(' dataqueue-cli install-skills');\n log(' dataqueue-cli install-rules');\n log(' dataqueue-cli install-mcp');\n log(' dataqueue-cli mcp');\n log('');\n log('Options for migrate:');\n log(\n ' --envPath <path> Path to a .env file to load environment variables (passed to node-pg-migrate)',\n );\n log(\n ' -s, --schema <schema> Set the schema to use (passed to node-pg-migrate)',\n );\n log('');\n log('AI tooling commands:');\n log(' install-skills Install DataQueue skill files for AI assistants');\n log(' install-rules Install DataQueue agent rules for AI clients');\n log(\n ' install-mcp Configure the DataQueue MCP server for AI clients',\n );\n log(' mcp Start the DataQueue MCP server (stdio)');\n exit(1);\n }\n\n if (command === 'migrate') {\n // Support for -s or --schema argument\n let schemaArg: string[] = [];\n const sIndex = restArgs.indexOf('-s');\n const schemaIndex = restArgs.indexOf('--schema');\n if (sIndex !== -1 && restArgs[sIndex + 1]) {\n schemaArg = ['-s', restArgs[sIndex + 1], '--create-schema'];\n restArgs.splice(sIndex, 2);\n } else if (schemaIndex !== -1 && restArgs[schemaIndex + 1]) {\n schemaArg = ['-s', restArgs[schemaIndex + 1], '--create-schema'];\n restArgs.splice(schemaIndex, 2);\n }\n\n // Support for --envPath argument: load env file so PG_DATAQUEUE_DATABASE is set\n // before spawning node-pg-migrate (node-pg-migrate only loads .env if dotenv is\n // installed in its context, so we preload here for reliable behavior).\n let envPathArg: string[] = [];\n const envPathIndex = restArgs.indexOf('--envPath');\n if (envPathIndex !== -1 && restArgs[envPathIndex + 1]) {\n const envPath = restArgs[envPathIndex + 1];\n loadEnvFromPath(envPath);\n envPathArg = ['--envPath', envPath];\n }\n\n const result: SpawnSyncReturns<any> = spawnSyncImpl(\n 'npx',\n [\n 'node-pg-migrate',\n 'up',\n '-t',\n 'dataqueuedev_migrations',\n '-d',\n 'PG_DATAQUEUE_DATABASE',\n '-m',\n migrationsDir,\n ...schemaArg,\n ...envPathArg,\n ...restArgs,\n ],\n { stdio: 'inherit' },\n );\n exit(result.status ?? 1);\n } else if (command === 'init') {\n runInitImpl({\n log,\n error,\n exit,\n ...initDeps,\n });\n } else if (command === 'install-skills') {\n runInstallSkillsImpl({\n log,\n error,\n exit,\n ...installSkillsDeps,\n });\n } else if (command === 'install-rules') {\n runInstallRulesImpl({\n log,\n error,\n exit,\n ...installRulesDeps,\n });\n } else if (command === 'install-mcp') {\n runInstallMcpImpl({\n log,\n error,\n exit,\n ...installMcpDeps,\n });\n } else if (command === 'mcp') {\n startMcpServerImpl().catch((err) => {\n error('Failed to start MCP server:', err);\n exit(1);\n });\n } else {\n printUsage();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/init-command.ts","../src/install-skills-command.ts","../src/install-rules-command.ts","../src/install-mcp-command.ts","../src/mcp-server.ts","../src/cli.ts"],"names":["path","existsSync","mkdirSync","__filename","fileURLToPath","__dirname","readFileSync","fs","writeFileSync","client","readline","loadDotenv"],"mappings":";;;;;;;;;;;AAYA,IAAM,mBAAA,GAAsB;AAAA,EAC1B,uBAAA;AAAA,EACA,iCAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,uBAAA,GAA0B;AAAA,EAC9B,YAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,cAAA,GAAiB;AAAA,EACrB,IAAA,EAAM,cAAA;AAAA,EACN,mBAAA,EAAqB;AACvB,CAAA;AAKO,IAAM,yBAAA,GAA4B,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAgIlC,IAAM,2BAAA,GAA8B,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AA0GpC,IAAM,gBAAA,GAAmB,CAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA,CAAA;AA+CzB,IAAM,cAAA,GAAiB,CAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAyDvB,SAAS,OAAA,CAAQ;AAAA,EACtB,MAAM,OAAA,CAAQ,GAAA;AAAA,EACd,QAAQ,OAAA,CAAQ,KAAA;AAAA,EAChB,IAAA,GAAO,CAAC,IAAA,KAAiB,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,EAC1C,GAAA,GAAM,QAAQ,GAAA,EAAI;AAAA,EAClB,gBAAA,GAAmB,YAAA;AAAA,EACnB,iBAAA,GAAoB,aAAA;AAAA,EACpB,cAAA,GAAiB,UAAA;AAAA,EACjB,aAAA,GAAgB,SAAA;AAAA,EAChB,aAAA,GAAgB;AAClB,CAAA,GAAc,EAAC,EAAS;AACtB,EAAA,IAAI;AACF,IAAA,GAAA,CAAI,CAAA,2BAAA,EAA8B,GAAG,CAAA,GAAA,CAAK,CAAA;AAC1C,IAAA,GAAA,CAAI,EAAE,CAAA;AAEN,IAAA,MAAM,UAAU,qBAAA,CAAsB;AAAA,MACpC,GAAA;AAAA,MACA,cAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,mBAAA,CAAoB;AAAA,MAClB,OAAA;AAAA,MACA,GAAA;AAAA,MACA,cAAA;AAAA,MACA,aAAA;AAAA,MACA,iBAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,iBAAA,CAAkB;AAAA,MAChB,OAAA;AAAA,MACA,GAAA;AAAA,MACA;AAAA,KACD,CAAA;AAED,IAAA,GAAA,CAAI,EAAE,CAAA;AACN,IAAA,GAAA;AAAA,MACE;AAAA,KACF;AACA,IAAA,IAAA,CAAK,CAAC,CAAA;AAAA,WACC,KAAA,EAAO;AACd,IAAA,MAAM,UAAU,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU,OAAO,KAAK,CAAA;AACrE,IAAA,KAAA,CAAM,CAAA,WAAA,EAAc,OAAO,CAAA,CAAE,CAAA;AAC7B,IAAA,IAAA,CAAK,CAAC,CAAA;AAAA;AAEV;AAKO,SAAS,qBAAA,CAAsB;AAAA,EACpC,GAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF,CAAA,EAImB;AACjB,EAAA,MAAM,eAAA,GAAkBA,KAAA,CAAK,IAAA,CAAK,GAAA,EAAK,cAAc,CAAA;AACrD,EAAA,IAAI,CAAC,cAAA,CAAe,eAAe,CAAA,EAAG;AACpC,IAAA,MAAM,IAAI,MAAM,8CAA8C,CAAA;AAAA;AAGhE,EAAA,MAAM,WAAA,GAAc,gBAAA;AAAA,IAClB,gBAAA,CAAiB,iBAAiB,MAAM,CAAA;AAAA,IACxC;AAAA,GACF;AACA,EAAA,IAAI,CAAC,eAAA,CAAgB,WAAW,CAAA,EAAG;AACjC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA;AAGF,EAAA,MAAM,MAAA,GAASA,KAAA,CAAK,IAAA,CAAK,GAAA,EAAK,KAAK,CAAA;AACnC,EAAA,MAAM,OAAA,GAAU,cAAA,CAAe,MAAM,CAAA,GAAI,KAAA,GAAQ,GAAA;AACjD,EAAA,MAAM,MAAA,GAASA,KAAA,CAAK,IAAA,CAAK,GAAA,EAAK,SAAS,KAAK,CAAA;AAC5C,EAAA,MAAM,QAAA,GAAWA,KAAA,CAAK,IAAA,CAAK,GAAA,EAAK,SAAS,OAAO,CAAA;AAChD,EAAA,MAAM,SAAA,GAAY,eAAe,MAAM,CAAA;AACvC,EAAA,MAAM,WAAA,GAAc,eAAe,QAAQ,CAAA;AAE3C,EAAA,IAAI,CAAC,SAAA,IAAa,CAAC,WAAA,EAAa;AAC9B,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KACF;AAAA;AAGF,EAAA,MAAM,MAAA,GAAqB,YAAY,KAAA,GAAQ,OAAA;AAC/C,EAAA,OAAO,EAAE,GAAA,EAAK,eAAA,EAAiB,WAAA,EAAa,SAAS,MAAA,EAAO;AAC9D;AAKA,SAAS,iBAAA,CAAkB;AAAA,EACzB,OAAA;AAAA,EACA,GAAA;AAAA,EACA;AACF,CAAA,EAIS;AACP,EAAA,MAAM,cAAc,OAAA,CAAQ,WAAA;AAC5B,EAAA,MAAM,YAAA,GAAe,sBAAA,CAAuB,WAAA,EAAa,cAAc,CAAA;AACvE,EAAA,MAAM,eAAA,GAAkB,sBAAA;AAAA,IACtB,WAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAM,OAAA,GAAU,sBAAA,CAAuB,WAAA,EAAa,SAAS,CAAA;AAE7D,EAAA,KAAA,MAAW,cAAc,mBAAA,EAAqB;AAC5C,IAAA,IAAI,YAAA,CAAa,UAAU,CAAA,EAAG;AAC5B,MAAA,GAAA,CAAI,CAAA,uBAAA,EAA0B,UAAU,CAAA,iBAAA,CAAmB,CAAA;AAC3D,MAAA;AAAA;AAEF,IAAA,YAAA,CAAa,UAAU,CAAA,GAAI,QAAA;AAC3B,IAAA,GAAA,CAAI,CAAA,uBAAA,EAA0B,UAAU,CAAA,CAAE,CAAA;AAAA;AAG5C,EAAA,KAAA,MAAW,iBAAiB,uBAAA,EAAyB;AACnD,IAAA,IAAI,eAAA,CAAgB,aAAa,CAAA,EAAG;AAClC,MAAA,GAAA,CAAI,CAAA,0BAAA,EAA6B,aAAa,CAAA,iBAAA,CAAmB,CAAA;AACjE,MAAA;AAAA;AAEF,IAAA,eAAA,CAAgB,aAAa,CAAA,GAAI,QAAA;AACjC,IAAA,GAAA,CAAI,CAAA,0BAAA,EAA6B,aAAa,CAAA,CAAE,CAAA;AAAA;AAGlD,EAAA,KAAA,MAAW,CAAC,UAAA,EAAY,WAAW,KAAK,MAAA,CAAO,OAAA,CAAQ,cAAc,CAAA,EAAG;AACtE,IAAA,IAAI,OAAA,CAAQ,UAAU,CAAA,EAAG;AACvB,MAAA,GAAA,CAAI,CAAA,oBAAA,EAAuB,UAAU,CAAA,kBAAA,CAAoB,CAAA;AACzD,MAAA;AAAA;AAEF,IAAA,OAAA,CAAQ,UAAU,CAAA,GAAI,WAAA;AACtB,IAAA,GAAA,CAAI,CAAA,oBAAA,EAAuB,UAAU,CAAA,CAAA,CAAG,CAAA;AAAA;AAG1C,EAAA,iBAAA;AAAA,IACE,OAAA,CAAQ,eAAA;AAAA,IACR,GAAG,IAAA,CAAK,SAAA,CAAU,WAAA,EAAa,IAAA,EAAM,CAAC,CAAC;AAAA;AAAA,GACzC;AACF;AAKA,SAAS,mBAAA,CAAoB;AAAA,EAC3B,OAAA;AAAA,EACA,GAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACF,CAAA,EAOS;AACP,EAAA,MAAM,eAAeA,KAAA,CAAK,IAAA;AAAA,IACxB,OAAA,CAAQ,GAAA;AAAA,IACR,OAAA,CAAQ,OAAA;AAAA,IACR,KAAA;AAAA,IACA,KAAA;AAAA,IACA,WAAA;AAAA,IACA,QAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAM,iBAAiBA,KAAA,CAAK,IAAA;AAAA,IAC1B,OAAA,CAAQ,GAAA;AAAA,IACR,OAAA,CAAQ,OAAA;AAAA,IACR,OAAA;AAAA,IACA,KAAA;AAAA,IACA,WAAA;AAAA,IACA,QAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAM,YAAYA,KAAA,CAAK,IAAA;AAAA,IACrB,OAAA,CAAQ,GAAA;AAAA,IACR,OAAA,CAAQ,OAAA;AAAA,IACR,KAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,MAAM,QAAA,GAAWA,KAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,KAAK,SAAS,CAAA;AAEjD,EAAA,IAAI,OAAA,CAAQ,WAAW,KAAA,EAAO;AAC5B,IAAA,mBAAA,CAAoB;AAAA,MAClB,YAAA,EAAc,YAAA;AAAA,MACd,OAAA,EAAS,yBAAA;AAAA,MACT,cAAA;AAAA,MACA,aAAA;AAAA,MACA,iBAAA;AAAA,MACA,GAAA;AAAA,MACA,OAAA,EAAS,cAAA,CAAe,OAAA,CAAQ,GAAA,EAAK,YAAY;AAAA,KAClD,CAAA;AACD,IAAA,GAAA;AAAA,MACE;AAAA,KACF;AAAA,GACF,MAAO;AACL,IAAA,GAAA;AAAA,MACE;AAAA,KACF;AACA,IAAA,mBAAA,CAAoB;AAAA,MAClB,YAAA,EAAc,cAAA;AAAA,MACd,OAAA,EAAS,2BAAA;AAAA,MACT,cAAA;AAAA,MACA,aAAA;AAAA,MACA,iBAAA;AAAA,MACA,GAAA;AAAA,MACA,OAAA,EAAS,cAAA,CAAe,OAAA,CAAQ,GAAA,EAAK,cAAc;AAAA,KACpD,CAAA;AAAA;AAGH,EAAA,mBAAA,CAAoB;AAAA,IAClB,YAAA,EAAc,QAAA;AAAA,IACd,OAAA,EAAS,gBAAA;AAAA,IACT,cAAA;AAAA,IACA,aAAA;AAAA,IACA,iBAAA;AAAA,IACA,GAAA;AAAA,IACA,OAAA,EAAS;AAAA,GACV,CAAA;AACD,EAAA,IAAI,cAAA,CAAe,QAAQ,CAAA,EAAG;AAC5B,IAAA,aAAA,CAAc,UAAU,GAAK,CAAA;AAAA;AAG/B,EAAA,mBAAA,CAAoB;AAAA,IAClB,YAAA,EAAc,SAAA;AAAA,IACd,OAAA,EAAS,cAAA;AAAA,IACT,cAAA;AAAA,IACA,aAAA;AAAA,IACA,iBAAA;AAAA,IACA,GAAA;AAAA,IACA,OAAA,EAAS,cAAA,CAAe,OAAA,CAAQ,GAAA,EAAK,SAAS;AAAA,GAC/C,CAAA;AACH;AAKA,SAAS,mBAAA,CAAoB;AAAA,EAC3B,YAAA;AAAA,EACA,OAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA,iBAAA;AAAA,EACA,GAAA;AAAA,EACA;AACF,CAAA,EAQS;AACP,EAAA,IAAI,cAAA,CAAe,YAAY,CAAA,EAAG;AAChC,IAAA,GAAA,CAAI,CAAA,YAAA,EAAe,OAAO,CAAA,iBAAA,CAAmB,CAAA;AAC7C,IAAA;AAAA;AAGF,EAAA,aAAA,CAAcA,MAAK,OAAA,CAAQ,YAAY,GAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAC7D,EAAA,iBAAA,CAAkB,cAAc,OAAO,CAAA;AACvC,EAAA,GAAA,CAAI,CAAA,YAAA,EAAe,OAAO,CAAA,CAAE,CAAA;AAC9B;AAKA,SAAS,gBAAA,CAAiB,SAAiB,QAAA,EAA8B;AACvE,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,OAAO,CAAA;AACjC,IAAA,IAAI,CAAC,UAAU,OAAO,MAAA,KAAW,YAAY,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,EAAG;AAClE,MAAA,MAAM,IAAI,MAAM,sCAAsC,CAAA;AAAA;AAExD,IAAA,OAAO,MAAA;AAAA,WACA,KAAA,EAAO;AACd,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,gCAAA,EAAmC,QAAQ,CAAA,EAAA,EACzC,KAAA,YAAiB,QAAQ,KAAA,CAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CACvD,CAAA;AAAA,KACF;AAAA;AAEJ;AAKA,SAAS,gBAAgB,WAAA,EAAkC;AACzD,EAAA,MAAM,eAAe,WAAA,CAAY,YAAA;AACjC,EAAA,MAAM,kBAAkB,WAAA,CAAY,eAAA;AAEpC,EAAA,OACE,WAAW,YAAA,EAAc,MAAM,CAAA,IAAK,UAAA,CAAW,iBAAiB,MAAM,CAAA;AAE1E;AAKA,SAAS,UAAA,CAAW,SAAkB,WAAA,EAA8B;AAClE,EAAA,IAAI,CAAC,WAAW,OAAO,OAAA,KAAY,YAAY,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,EAAG;AACrE,IAAA,OAAO,KAAA;AAAA;AAET,EAAA,OAAO,OAAA,CAAS,OAAA,CAAoB,WAAW,CAAC,CAAA;AAClD;AAKA,SAAS,sBAAA,CACP,aACA,WAAA,EACS;AACT,EAAA,MAAM,YAAA,GAAe,YAAY,WAAW,CAAA;AAC5C,EAAA,IACE,CAAC,gBACD,OAAO,YAAA,KAAiB,YACxB,KAAA,CAAM,OAAA,CAAQ,YAAY,CAAA,EAC1B;AACA,IAAA,WAAA,CAAY,WAAW,IAAI,EAAC;AAAA;AAE9B,EAAA,OAAO,YAAY,WAAW,CAAA;AAChC;AAKA,SAAS,cAAA,CAAe,KAAa,YAAA,EAA8B;AACjE,EAAA,MAAM,QAAA,GAAWA,KAAA,CAAK,QAAA,CAAS,GAAA,EAAK,YAAY,CAAA;AAChD,EAAA,OAAO,QAAA,IAAY,GAAA;AACrB;AChsBA,IAAM,UAAA,GAAa,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AAChD,IAAM,SAAA,GAAYA,KAAAA,CAAK,OAAA,CAAQ,UAAU,CAAA;AAczC,IAAM,UAAA,GAAa,CAAC,gBAAA,EAAkB,oBAAA,EAAsB,iBAAiB,CAAA;AActE,SAAS,aAAA,CACd,GAAA,EACAC,WAAAA,GAAqC,EAAA,CAAG,UAAA,EAC9B;AACV,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,MAAM,MAAA,GACJ;AAAA,IACE;AAAA,MACE,IAAA,EAAM,QAAA;AAAA,MACN,SAAA,EAAW,SAAA;AAAA,MACX,SAAA,EAAW;AAAA,KACb;AAAA,IACA;AAAA,MACE,IAAA,EAAM,aAAA;AAAA,MACN,SAAA,EAAW,SAAA;AAAA,MACX,SAAA,EAAW;AAAA,KACb;AAAA,IACA;AAAA,MACE,IAAA,EAAM,gBAAA;AAAA,MACN,SAAA,EAAW,SAAA;AAAA,MACX,SAAA,EAAW;AAAA;AACb,GACF;AAEF,EAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,IAAA,IAAIA,YAAWD,KAAAA,CAAK,IAAA,CAAK,KAAK,KAAA,CAAM,SAAS,CAAC,CAAA,EAAG;AAC/C,MAAA,KAAA,CAAM,IAAA,CAAK,EAAE,IAAA,EAAM,KAAA,CAAM,MAAM,SAAA,EAAW,KAAA,CAAM,WAAW,CAAA;AAAA;AAC7D;AAGF,EAAA,OAAO,KAAA;AACT;AAOO,SAAS,gBAAA,CAAiB;AAAA,EAC/B,MAAM,OAAA,CAAQ,GAAA;AAAA,EACd,QAAQ,OAAA,CAAQ,KAAA;AAAA,EAChB,IAAA,GAAO,CAAC,IAAA,KAAiB,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,EAC1C,GAAA,GAAM,QAAQ,GAAA,EAAI;AAAA,EAClB,UAAA,EAAAC,cAAa,EAAA,CAAG,UAAA;AAAA,EAChB,SAAA,EAAAC,aAAY,EAAA,CAAG,SAAA;AAAA,EACf,eAAe,EAAA,CAAG,YAAA;AAAA,EAClB,cAAc,EAAA,CAAG,WAAA;AAAA,EACjB,eAAA,GAAkBF,KAAAA,CAAK,IAAA,CAAK,SAAA,EAAW,cAAc;AACvD,CAAA,GAAuB,EAAC,EAAS;AAC/B,EAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,GAAA,EAAKC,WAAU,CAAA;AAE3C,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,IAAA,GAAA,CAAI,iEAAiE,CAAA;AACrE,IAAA,GAAA,CAAI,iDAAiD,CAAA;AACrD,IAAA,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,QAAA,EAAU,SAAA,EAAW,kBAAkB,CAAA;AAAA;AAG5D,EAAA,IAAI,SAAA,GAAY,CAAA;AAEhB,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,GAAA,CAAI;AAAA,sBAAA,EAA2B,IAAA,CAAK,IAAI,CAAA,GAAA,CAAK,CAAA;AAE7C,IAAA,KAAA,MAAW,YAAY,UAAA,EAAY;AACjC,MAAA,MAAM,MAAA,GAASD,KAAAA,CAAK,IAAA,CAAK,eAAA,EAAiB,QAAQ,CAAA;AAClD,MAAA,MAAM,UAAUA,KAAAA,CAAK,IAAA,CAAK,GAAA,EAAK,IAAA,CAAK,WAAW,QAAQ,CAAA;AAEvD,MAAA,IAAI;AACF,QAAAE,UAAAA,CAAU,OAAA,EAAS,EAAE,SAAA,EAAW,MAAM,CAAA;AAEtC,QAAA,MAAM,KAAA,GAAQ,YAAY,MAAM,CAAA;AAChC,QAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,UAAA,YAAA,CAAaF,KAAAA,CAAK,KAAK,MAAA,EAAQ,IAAI,GAAGA,KAAAA,CAAK,IAAA,CAAK,OAAA,EAAS,IAAI,CAAC,CAAA;AAAA;AAGhE,QAAA,GAAA,CAAI,CAAA,SAAA,EAAO,QAAQ,CAAA,CAAE,CAAA;AACrB,QAAA,SAAA,EAAA;AAAA,eACO,GAAA,EAAK;AACZ,QAAA,KAAA,CAAM,CAAA,2BAAA,EAAyB,QAAQ,CAAA,CAAA,CAAA,EAAK,GAAG,CAAA;AAAA;AACjD;AACF;AAGF,EAAA,IAAI,YAAY,CAAA,EAAG;AACjB,IAAA,GAAA;AAAA,MACE;AAAA,gBAAA,EAAqB,SAAS,CAAA,cAAA,EAAiB,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,CAAE,IAAI,CAAA,CAAE,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAAA,KACpF;AAAA,GACF,MAAO;AACL,IAAA,KAAA,CAAM,2BAA2B,CAAA;AACjC,IAAA,IAAA,CAAK,CAAC,CAAA;AAAA;AAEV;ACtHA,IAAMG,WAAAA,GAAaC,aAAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AAChD,IAAMC,UAAAA,GAAYL,KAAAA,CAAK,OAAA,CAAQG,WAAU,CAAA;AAiBzC,IAAM,UAAA,GAAa,CAAC,UAAA,EAAY,aAAA,EAAe,oBAAoB,CAAA;AAqBnE,IAAM,YAAA,GAAe,gCAAA;AACrB,IAAM,UAAA,GAAa,8BAAA;AASZ,SAAS,mBAAA,CACd,QAAA,EACA,OAAA,EACA,IAAA,EAKM;AACN,EAAA,MAAM,KAAA,GAAQ,GAAG,YAAY;AAAA,EAAK,OAAO;AAAA,EAAK,UAAU,CAAA,CAAA;AAExD,EAAA,IAAI,CAAC,IAAA,CAAK,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC9B,IAAA,IAAA,CAAK,aAAA,CAAc,QAAA,EAAU,KAAA,GAAQ,IAAI,CAAA;AACzC,IAAA;AAAA;AAGF,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,YAAA,CAAa,QAAA,EAAU,OAAO,CAAA;AACpD,EAAA,MAAM,QAAA,GAAW,QAAA,CAAS,OAAA,CAAQ,YAAY,CAAA;AAC9C,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,OAAA,CAAQ,UAAU,CAAA;AAE1C,EAAA,IAAI,QAAA,KAAa,EAAA,IAAM,MAAA,KAAW,EAAA,EAAI;AACpC,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,QAAQ,CAAA;AACzC,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,CAAM,MAAA,GAAS,WAAW,MAAM,CAAA;AACvD,IAAA,IAAA,CAAK,aAAA,CAAc,QAAA,EAAU,MAAA,GAAS,KAAA,GAAQ,KAAK,CAAA;AAAA,GACrD,MAAO;AACL,IAAA,IAAA,CAAK,cAAc,QAAA,EAAU,QAAA,CAAS,SAAQ,GAAI,MAAA,GAAS,QAAQ,IAAI,CAAA;AAAA;AAE3E;AAEA,SAAS,kBAAA,CACP,gBACAG,aAAAA,EACQ;AACR,EAAA,OAAO,UAAA,CAAW,GAAA;AAAA,IAAI,CAAC,MACrBA,aAAAA,CAAaN,KAAAA,CAAK,KAAK,cAAA,EAAgB,CAAC,GAAG,OAAO;AAAA,GACpD,CAAE,KAAK,MAAM,CAAA;AACf;AAEA,IAAM,OAAA,GAAwC;AAAA,EAC5C,GAAA,EAAK;AAAA,IACH,KAAA,EAAO,QAAA;AAAA,IACP,OAAA,EAAS,CAAC,IAAA,KAAS;AACjB,MAAA,MAAM,WAAWA,KAAAA,CAAK,IAAA,CAAK,IAAA,CAAK,GAAA,EAAK,WAAW,OAAO,CAAA;AACvD,MAAA,IAAA,CAAK,SAAA,CAAU,QAAA,EAAU,EAAE,SAAA,EAAW,MAAM,CAAA;AAE5C,MAAA,KAAA,MAAW,QAAQ,UAAA,EAAY;AAC7B,QAAA,MAAM,MAAM,IAAA,CAAK,YAAA;AAAA,UACfA,KAAAA,CAAK,IAAA,CAAK,IAAA,CAAK,cAAA,EAAgB,IAAI,CAAA;AAAA,UACnC;AAAA,SACF;AACA,QAAA,MAAM,WAAW,CAAA,UAAA,EAAa,IAAA,CAAK,OAAA,CAAQ,OAAA,EAAS,MAAM,CAAC,CAAA,CAAA;AAC3D,QAAA,IAAA,CAAK,cAAcA,KAAAA,CAAK,IAAA,CAAK,QAAA,EAAU,QAAQ,GAAG,GAAG,CAAA;AACrD,QAAA,IAAA,CAAK,GAAA,CAAI,CAAA,uBAAA,EAAqB,QAAQ,CAAA,CAAE,CAAA;AAAA;AAC1C;AACF,GACF;AAAA,EACA,GAAA,EAAK;AAAA,IACH,KAAA,EAAO,aAAA;AAAA,IACP,OAAA,EAAS,CAAC,IAAA,KAAS;AACjB,MAAA,MAAM,OAAA,GAAU,kBAAA;AAAA,QACd,IAAA,CAAK,cAAA;AAAA,QACL,IAAA,CAAK;AAAA,OACP;AACA,MAAA,MAAM,QAAA,GAAWA,KAAAA,CAAK,IAAA,CAAK,IAAA,CAAK,KAAK,WAAW,CAAA;AAChD,MAAA,mBAAA,CAAoB,QAAA,EAAU,SAAS,IAAI,CAAA;AAC3C,MAAA,IAAA,CAAK,IAAI,CAAA,kBAAA,CAAe,CAAA;AAAA;AAC1B,GACF;AAAA,EACA,GAAA,EAAK;AAAA,IACH,KAAA,EAAO,oCAAA;AAAA,IACP,OAAA,EAAS,CAAC,IAAA,KAAS;AACjB,MAAA,MAAM,OAAA,GAAU,kBAAA;AAAA,QACd,IAAA,CAAK,cAAA;AAAA,QACL,IAAA,CAAK;AAAA,OACP;AACA,MAAA,MAAM,QAAA,GAAWA,KAAAA,CAAK,IAAA,CAAK,IAAA,CAAK,KAAK,WAAW,CAAA;AAChD,MAAA,mBAAA,CAAoB,QAAA,EAAU,SAAS,IAAI,CAAA;AAC3C,MAAA,IAAA,CAAK,IAAI,CAAA,kBAAA,CAAe,CAAA;AAAA;AAC1B,GACF;AAAA,EACA,GAAA,EAAK;AAAA,IACH,KAAA,EAAO,gBAAA;AAAA,IACP,OAAA,EAAS,CAAC,IAAA,KAAS;AACjB,MAAA,MAAM,OAAA,GAAU,kBAAA;AAAA,QACd,IAAA,CAAK,cAAA;AAAA,QACL,IAAA,CAAK;AAAA,OACP;AACA,MAAA,IAAA,CAAK,SAAA,CAAUA,KAAAA,CAAK,IAAA,CAAK,IAAA,CAAK,GAAA,EAAK,SAAS,CAAA,EAAG,EAAE,SAAA,EAAW,IAAA,EAAM,CAAA;AAClE,MAAA,MAAM,WAAWA,KAAAA,CAAK,IAAA;AAAA,QACpB,IAAA,CAAK,GAAA;AAAA,QACL,SAAA;AAAA,QACA;AAAA,OACF;AACA,MAAA,mBAAA,CAAoB,QAAA,EAAU,SAAS,IAAI,CAAA;AAC3C,MAAA,IAAA,CAAK,IAAI,CAAA,wCAAA,CAAqC,CAAA;AAAA;AAChD,GACF;AAAA,EACA,GAAA,EAAK;AAAA,IACH,KAAA,EAAO,UAAA;AAAA,IACP,OAAA,EAAS,CAAC,IAAA,KAAS;AACjB,MAAA,MAAM,OAAA,GAAU,kBAAA;AAAA,QACd,IAAA,CAAK,cAAA;AAAA,QACL,IAAA,CAAK;AAAA,OACP;AACA,MAAA,MAAM,QAAA,GAAWA,KAAAA,CAAK,IAAA,CAAK,IAAA,CAAK,KAAK,gBAAgB,CAAA;AACrD,MAAA,mBAAA,CAAoB,QAAA,EAAU,SAAS,IAAI,CAAA;AAC3C,MAAA,IAAA,CAAK,IAAI,CAAA,uBAAA,CAAoB,CAAA;AAAA;AAC/B;AAEJ,CAAA;AAOA,eAAsB,eAAA,CAAgB;AAAA,EACpC,MAAM,OAAA,CAAQ,GAAA;AAAA,EACd,QAAQ,OAAA,CAAQ,KAAA;AAAA,EAChB,IAAA,GAAO,CAAC,IAAA,KAAiB,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,EAC1C,GAAA,GAAM,QAAQ,GAAA,EAAI;AAAA,EAClB,YAAA,EAAAM,gBAAeC,EAAAA,CAAG,YAAA;AAAA,EAClB,aAAA,EAAAC,iBAAgBD,EAAAA,CAAG,aAAA;AAAA,EACnB,iBAAiBA,EAAAA,CAAG,cAAA;AAAA,EACpB,SAAA,EAAAL,aAAYK,EAAAA,CAAG,SAAA;AAAA,EACf,UAAA,EAAAN,cAAaM,EAAAA,CAAG,UAAA;AAAA,EAChB,cAAA,GAAiBP,KAAAA,CAAK,IAAA,CAAKK,UAAAA,EAAW,aAAa,CAAA;AAAA,EACnD;AACF,CAAA,GAAsB,EAAC,EAAkB;AACvC,EAAA,GAAA,CAAI,mCAAmC,CAAA;AACvC,EAAA,GAAA,CAAI,0BAA0B,CAAA;AAE9B,EAAA,KAAA,MAAW,CAAC,GAAA,EAAKI,OAAM,KAAK,MAAA,CAAO,OAAA,CAAQ,OAAO,CAAA,EAAG;AACnD,IAAA,GAAA,CAAI,CAAA,EAAA,EAAK,GAAG,CAAA,EAAA,EAAKA,OAAAA,CAAO,KAAK,CAAA,CAAE,CAAA;AAAA;AAEjC,EAAA,GAAA,CAAI,EAAE,CAAA;AAEN,EAAA,IAAI,MAAA,GAAS,cAAA;AAEb,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,EAAA,GAAK,SAAS,eAAA,CAAgB;AAAA,MAClC,OAAO,OAAA,CAAQ,KAAA;AAAA,MACf,QAAQ,OAAA,CAAQ;AAAA,KACjB,CAAA;AAED,IAAA,MAAA,GAAS,MAAM,IAAI,OAAA,CAAgB,CAAC,OAAA,KAAY;AAC9C,MAAA,EAAA,CAAG,QAAA,CAAS,sBAAA,EAAwB,CAAC,MAAA,KAAW;AAC9C,QAAA,EAAA,CAAG,KAAA,EAAM;AACT,QAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,CAAA;AAAA,OACtB,CAAA;AAAA,KACF,CAAA;AAAA;AAGH,EAAA,MAAM,MAAA,GAAS,QAAQ,MAAM,CAAA;AAC7B,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,KAAA,CAAM,CAAA,iBAAA,EAAoB,MAAM,CAAA,gBAAA,CAAkB,CAAA;AAClD,IAAA,IAAA,CAAK,CAAC,CAAA;AACN,IAAA;AAAA;AAGF,EAAA,GAAA,CAAI;AAAA,qBAAA,EAA0B,MAAA,CAAO,KAAK,CAAA,GAAA,CAAK,CAAA;AAE/C,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,OAAA,CAAQ;AAAA,MACb,GAAA;AAAA,MACA,YAAA,EAAAH,aAAAA;AAAA,MACA,aAAA,EAAAE,cAAAA;AAAA,MACA,cAAA;AAAA,MACA,SAAA,EAAAN,UAAAA;AAAA,MACA,UAAA,EAAAD,WAAAA;AAAA,MACA,GAAA;AAAA,MACA;AAAA,KACD,CAAA;AACD,IAAA,GAAA,CAAI,SAAS,CAAA;AAAA,WACN,GAAA,EAAK;AACZ,IAAA,KAAA,CAAM,4BAA4B,GAAG,CAAA;AACrC,IAAA,IAAA,CAAK,CAAC,CAAA;AAAA;AAEV;AC9LO,SAAS,eAAA,CACd,QAAA,EACA,SAAA,EACA,YAAA,EACA,IAAA,EAKM;AACN,EAAA,IAAI,SAAkC,EAAC;AAEvC,EAAA,IAAI,IAAA,CAAK,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC7B,IAAA,IAAI;AACF,MAAA,MAAA,GAAS,KAAK,KAAA,CAAM,IAAA,CAAK,YAAA,CAAa,QAAA,EAAU,OAAO,CAAC,CAAA;AAAA,KAC1D,CAAA,MAAQ;AACN,MAAA,MAAA,GAAS,EAAC;AAAA;AACZ;AAGF,EAAA,IAAI,CAAC,MAAA,CAAO,UAAA,IAAc,OAAO,MAAA,CAAO,eAAe,QAAA,EAAU;AAC/D,IAAA,MAAA,CAAO,aAAa,EAAC;AAAA;AAGvB,EAAC,MAAA,CAAO,UAAA,CAAuC,SAAS,CAAA,GAAI,YAAA;AAC5D,EAAA,IAAA,CAAK,aAAA,CAAc,UAAU,IAAA,CAAK,SAAA,CAAU,QAAQ,IAAA,EAAM,CAAC,IAAI,IAAI,CAAA;AACrE;AAEA,IAAM,iBAAA,GAAoB;AAAA,EACxB,OAAA,EAAS,KAAA;AAAA,EACT,IAAA,EAAM,CAAC,eAAA,EAAiB,KAAK;AAC/B,CAAA;AAEA,IAAM,WAAA,GAA+C;AAAA,EACnD,GAAA,EAAK;AAAA,IACH,KAAA,EAAO,QAAA;AAAA,IACP,OAAA,EAAS,CAAC,IAAA,KAAS;AACjB,MAAA,MAAM,SAAA,GAAYD,KAAAA,CAAK,IAAA,CAAK,IAAA,CAAK,KAAK,SAAS,CAAA;AAC/C,MAAA,IAAA,CAAK,SAAA,CAAU,SAAA,EAAW,EAAE,SAAA,EAAW,MAAM,CAAA;AAC7C,MAAA,MAAM,UAAA,GAAaA,KAAAA,CAAK,IAAA,CAAK,SAAA,EAAW,UAAU,CAAA;AAClD,MAAA,eAAA,CAAgB,UAAA,EAAY,WAAA,EAAa,iBAAA,EAAmB,IAAI,CAAA;AAChE,MAAA,IAAA,CAAK,IAAI,CAAA,yBAAA,CAAsB,CAAA;AAAA;AACjC,GACF;AAAA,EACA,GAAA,EAAK;AAAA,IACH,KAAA,EAAO,aAAA;AAAA,IACP,OAAA,EAAS,CAAC,IAAA,KAAS;AACjB,MAAA,MAAM,UAAA,GAAaA,KAAAA,CAAK,IAAA,CAAK,IAAA,CAAK,KAAK,WAAW,CAAA;AAClD,MAAA,eAAA,CAAgB,UAAA,EAAY,WAAA,EAAa,iBAAA,EAAmB,IAAI,CAAA;AAChE,MAAA,IAAA,CAAK,IAAI,CAAA,kBAAA,CAAe,CAAA;AAAA;AAC1B,GACF;AAAA,EACA,GAAA,EAAK;AAAA,IACH,KAAA,EAAO,mBAAA;AAAA,IACP,OAAA,EAAS,CAAC,IAAA,KAAS;AACjB,MAAA,MAAM,SAAA,GAAYA,KAAAA,CAAK,IAAA,CAAK,IAAA,CAAK,KAAK,SAAS,CAAA;AAC/C,MAAA,IAAA,CAAK,SAAA,CAAU,SAAA,EAAW,EAAE,SAAA,EAAW,MAAM,CAAA;AAC7C,MAAA,MAAM,UAAA,GAAaA,KAAAA,CAAK,IAAA,CAAK,SAAA,EAAW,UAAU,CAAA;AAClD,MAAA,eAAA,CAAgB,UAAA,EAAY,WAAA,EAAa,iBAAA,EAAmB,IAAI,CAAA;AAChE,MAAA,IAAA,CAAK,IAAI,CAAA,yBAAA,CAAsB,CAAA;AAAA;AACjC,GACF;AAAA,EACA,GAAA,EAAK;AAAA,IACH,KAAA,EAAO,UAAA;AAAA,IACP,OAAA,EAAS,CAAC,IAAA,KAAS;AACjB,MAAA,MAAM,UAAU,OAAA,CAAQ,GAAA,CAAI,IAAA,IAAQ,OAAA,CAAQ,IAAI,WAAA,IAAe,EAAA;AAC/D,MAAA,MAAM,aAAaA,KAAAA,CAAK,IAAA;AAAA,QACtB,OAAA;AAAA,QACA,UAAA;AAAA,QACA,UAAA;AAAA,QACA;AAAA,OACF;AACA,MAAA,IAAA,CAAK,SAAA,CAAUA,MAAK,OAAA,CAAQ,UAAU,GAAG,EAAE,SAAA,EAAW,MAAM,CAAA;AAC5D,MAAA,eAAA,CAAgB,UAAA,EAAY,WAAA,EAAa,iBAAA,EAAmB,IAAI,CAAA;AAChE,MAAA,IAAA,CAAK,IAAI,CAAA,4CAAA,CAAyC,CAAA;AAAA;AACpD;AAEJ,CAAA;AAOA,eAAsB,aAAA,CAAc;AAAA,EAClC,MAAM,OAAA,CAAQ,GAAA;AAAA,EACd,QAAQ,OAAA,CAAQ,KAAA;AAAA,EAChB,IAAA,GAAO,CAAC,IAAA,KAAiB,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,EAC1C,GAAA,GAAM,QAAQ,GAAA,EAAI;AAAA,EAClB,YAAA,EAAAM,gBAAeC,EAAAA,CAAG,YAAA;AAAA,EAClB,aAAA,EAAAC,iBAAgBD,EAAAA,CAAG,aAAA;AAAA,EACnB,SAAA,EAAAL,aAAYK,EAAAA,CAAG,SAAA;AAAA,EACf,UAAA,EAAAN,cAAaM,EAAAA,CAAG,UAAA;AAAA,EAChB;AACF,CAAA,GAAoB,EAAC,EAAkB;AACrC,EAAA,GAAA,CAAI,kCAAkC,CAAA;AACtC,EAAA,GAAA,CAAI,0BAA0B,CAAA;AAE9B,EAAA,KAAA,MAAW,CAAC,GAAA,EAAKE,OAAM,KAAK,MAAA,CAAO,OAAA,CAAQ,WAAW,CAAA,EAAG;AACvD,IAAA,GAAA,CAAI,CAAA,EAAA,EAAK,GAAG,CAAA,EAAA,EAAKA,OAAAA,CAAO,KAAK,CAAA,CAAE,CAAA;AAAA;AAEjC,EAAA,GAAA,CAAI,EAAE,CAAA;AAEN,EAAA,IAAI,MAAA,GAAS,cAAA;AAEb,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,MAAM,EAAA,GAAKC,SAAS,eAAA,CAAgB;AAAA,MAClC,OAAO,OAAA,CAAQ,KAAA;AAAA,MACf,QAAQ,OAAA,CAAQ;AAAA,KACjB,CAAA;AAED,IAAA,MAAA,GAAS,MAAM,IAAI,OAAA,CAAgB,CAAC,OAAA,KAAY;AAC9C,MAAA,EAAA,CAAG,QAAA,CAAS,sBAAA,EAAwB,CAAC,MAAA,KAAW;AAC9C,QAAA,EAAA,CAAG,KAAA,EAAM;AACT,QAAA,OAAA,CAAQ,MAAA,CAAO,MAAM,CAAA;AAAA,OACtB,CAAA;AAAA,KACF,CAAA;AAAA;AAGH,EAAA,MAAM,MAAA,GAAS,YAAY,MAAM,CAAA;AACjC,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,KAAA,CAAM,CAAA,iBAAA,EAAoB,MAAM,CAAA,gBAAA,CAAkB,CAAA;AAClD,IAAA,IAAA,CAAK,CAAC,CAAA;AACN,IAAA;AAAA;AAGF,EAAA,GAAA,CAAI;AAAA,0BAAA,EAA+B,MAAA,CAAO,KAAK,CAAA,GAAA,CAAK,CAAA;AAEpD,EAAA,IAAI;AACF,IAAA,MAAA,CAAO,OAAA,CAAQ;AAAA,MACb,GAAA;AAAA,MACA,YAAA,EAAAJ,aAAAA;AAAA,MACA,aAAA,EAAAE,cAAAA;AAAA,MACA,SAAA,EAAAN,UAAAA;AAAA,MACA,UAAA,EAAAD,WAAAA;AAAA,MACA;AAAA,KACD,CAAA;AACD,IAAA,GAAA,CAAI,oEAAoE,CAAA;AAAA,WACjE,GAAA,EAAK;AACZ,IAAA,KAAA,CAAM,iCAAiC,GAAG,CAAA;AAC1C,IAAA,IAAA,CAAK,CAAC,CAAA;AAAA;AAEV;AC1KA,IAAME,WAAAA,GAAaC,aAAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AAChD,IAAMC,UAAAA,GAAYL,KAAAA,CAAK,OAAA,CAAQG,WAAU,CAAA;AAUlC,SAAS,gBACd,QAAA,GAAmBH,KAAAA,CAAK,IAAA,CAAKK,UAAAA,EAAW,yBAAyB,CAAA,EACtD;AACX,EAAA,MAAM,GAAA,GAAME,EAAAA,CAAG,YAAA,CAAa,QAAA,EAAU,OAAO,CAAA;AAC7C,EAAA,OAAO,IAAA,CAAK,MAAM,GAAG,CAAA;AACvB;AAGO,SAAS,iBAAA,CAAkB,MAAe,UAAA,EAA8B;AAC7E,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,KAAA,CAAM,WAAA,EAAY;AAC1C,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,WAAA,CAAY,WAAA,EAAY;AAC/C,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,OAAA,CAAQ,WAAA,EAAY;AAE9C,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,KAAA,MAAW,QAAQ,UAAA,EAAY;AAC7B,IAAA,IAAI,UAAA,CAAW,QAAA,CAAS,IAAI,CAAA,EAAG,KAAA,IAAS,EAAA;AACxC,IAAA,IAAI,SAAA,CAAU,QAAA,CAAS,IAAI,CAAA,EAAG,KAAA,IAAS,CAAA;AAEvC,IAAA,MAAM,cAAA,GAAiB,YAAA,CAAa,KAAA,CAAM,IAAI,EAAE,MAAA,GAAS,CAAA;AACzD,IAAA,KAAA,IAAS,IAAA,CAAK,GAAA,CAAI,cAAA,EAAgB,EAAE,CAAA;AAAA;AAEtC,EAAA,OAAO,KAAA;AACT;AAGO,SAAS,cAAA,CACd,OAAA,EACA,UAAA,EACA,SAAA,GAAY,GAAA,EACJ;AACR,EAAA,MAAM,KAAA,GAAQ,QAAQ,WAAA,EAAY;AAClC,EAAA,IAAI,aAAA,GAAgB,EAAA;AAEpB,EAAA,KAAA,MAAW,QAAQ,UAAA,EAAY;AAC7B,IAAA,MAAM,GAAA,GAAM,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA;AAC9B,IAAA,IAAI,GAAA,KAAQ,EAAA,KAAO,aAAA,KAAkB,EAAA,IAAM,MAAM,aAAA,CAAA,EAAgB;AAC/D,MAAA,aAAA,GAAgB,GAAA;AAAA;AAClB;AAGF,EAAA,IAAI,kBAAkB,EAAA,EAAI;AACxB,IAAA,OAAO,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,SAAS,CAAA;AAAA;AAGnC,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,gBAAgB,GAAG,CAAA;AAC7C,EAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,OAAA,CAAQ,MAAA,EAAQ,QAAQ,SAAS,CAAA;AACtD,EAAA,IAAI,OAAA,GAAU,OAAA,CAAQ,KAAA,CAAM,KAAA,EAAO,GAAG,CAAA;AAEtC,EAAA,IAAI,KAAA,GAAQ,CAAA,EAAG,OAAA,GAAU,KAAA,GAAQ,OAAA;AACjC,EAAA,IAAI,GAAA,GAAM,OAAA,CAAQ,MAAA,EAAQ,OAAA,GAAU,OAAA,GAAU,KAAA;AAE9C,EAAA,OAAO,OAAA;AACT;AAOA,eAAsB,cAAA,CACpB,IAAA,GAGI,EAAC,EACe;AACpB,EAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,IAAA,CAAK,QAAQ,CAAA;AAE3C,EAAA,MAAM,MAAA,GAAS,IAAI,SAAA,CAAU;AAAA,IAC3B,IAAA,EAAM,gBAAA;AAAA,IACN,OAAA,EAAS;AAAA,GACV,CAAA;AAED,EAAA,MAAA,CAAO,QAAA,CAAS,UAAA,EAAY,sBAAA,EAAwB,YAAY;AAC9D,IAAA,MAAM,WAAWP,KAAAA,CAAK,IAAA;AAAA,MACpBK,UAAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,IAAI,OAAA;AACJ,IAAA,IAAI;AACF,MAAA,OAAA,GAAUE,EAAAA,CAAG,YAAA,CAAa,QAAA,EAAU,OAAO,CAAA;AAAA,KAC7C,CAAA,MAAQ;AACN,MAAA,OAAA,GAAU,MACP,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,GAAA,EAAM,EAAE,KAAK;;AAAA,MAAA,EAAa,EAAE,IAAI;;AAAA,EAAO,CAAA,CAAE,WAAW,CAAA,CAAE,CAAA,CACjE,KAAK,MAAM,CAAA;AAAA;AAEhB,IAAA,OAAO,EAAE,UAAU,CAAC,EAAE,KAAK,sBAAA,EAAwB,IAAA,EAAM,OAAA,EAAS,CAAA,EAAE;AAAA,GACrE,CAAA;AAED,EAAA,MAAA,CAAO,IAAA;AAAA,IACL,gBAAA;AAAA,IACA,gFAAA;AAAA,IACA,EAAC;AAAA,IACD,YAAY;AACV,MAAA,MAAM,OAAA,GAAU,KAAA,CAAM,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QAChC,MAAM,CAAA,CAAE,IAAA;AAAA,QACR,OAAO,CAAA,CAAE,KAAA;AAAA,QACT,aAAa,CAAA,CAAE;AAAA,OACjB,CAAE,CAAA;AACF,MAAA,OAAO;AAAA,QACL,OAAA,EAAS;AAAA,UACP,EAAE,MAAM,MAAA,EAAiB,IAAA,EAAM,KAAK,SAAA,CAAU,OAAA,EAAS,IAAA,EAAM,CAAC,CAAA;AAAE;AAClE,OACF;AAAA;AACF,GACF;AAEA,EAAA,MAAA,CAAO,IAAA;AAAA,IACL,cAAA;AAAA,IACA,qFAAA;AAAA,IACA;AAAA,MACE,IAAA,EAAM,CAAA,CACH,MAAA,EAAO,CACP,SAAS,4DAA4D;AAAA,KAC1E;AAAA,IACA,OAAO,EAAE,IAAA,EAAK,KAAM;AAClB,MAAA,MAAM,OAAO,KAAA,CAAM,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,IAAI,CAAA;AAC9C,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA,OAAO;AAAA,UACL,OAAA,EAAS;AAAA,YACP;AAAA,cACE,IAAA,EAAM,MAAA;AAAA,cACN,IAAA,EAAM,oBAAoB,IAAI,CAAA,6CAAA;AAAA;AAChC,WACF;AAAA,UACA,OAAA,EAAS;AAAA,SACX;AAAA;AAEF,MAAA,MAAM,MAAA,GAAS,IAAA,CAAK,WAAA,GAChB,CAAA,EAAA,EAAK,KAAK,KAAK;;AAAA,EAAA,EAAS,KAAK,WAAW;;AAAA,CAAA,GACxC,CAAA,EAAA,EAAK,KAAK,KAAK;;AAAA,CAAA;AACnB,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,QAAiB,IAAA,EAAM,MAAA,GAAS,IAAA,CAAK,OAAA,EAAS;AAAA,OAClE;AAAA;AACF,GACF;AAEA,EAAA,MAAA,CAAO,IAAA;AAAA,IACL,aAAA;AAAA,IACA,6HAAA;AAAA,IACA;AAAA,MACE,KAAA,EAAO,CAAA,CACJ,MAAA,EAAO,CACP,SAAS,wDAAwD;AAAA,KACtE;AAAA,IACA,OAAO,EAAE,KAAA,EAAM,KAAM;AACnB,MAAA,MAAM,UAAA,GAAa,KAAA,CAChB,WAAA,EAAY,CACZ,KAAA,CAAM,KAAK,CAAA,CACX,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,GAAS,CAAC,CAAA;AAE7B,MAAA,IAAI,UAAA,CAAW,WAAW,CAAA,EAAG;AAC3B,QAAA,OAAO;AAAA,UACL,OAAA,EAAS;AAAA,YACP,EAAE,IAAA,EAAM,MAAA,EAAiB,IAAA,EAAM,gCAAA;AAAiC,WAClE;AAAA,UACA,OAAA,EAAS;AAAA,SACX;AAAA;AAGF,MAAA,MAAM,MAAA,GAAS,KAAA,CACZ,GAAA,CAAI,CAAC,IAAA,MAAU;AAAA,QACd,IAAA;AAAA,QACA,KAAA,EAAO,iBAAA,CAAkB,IAAA,EAAM,UAAU;AAAA,OAC3C,CAAE,EACD,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,KAAA,GAAQ,CAAC,CAAA,CACzB,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAM,EAAE,KAAA,GAAQ,CAAA,CAAE,KAAK,CAAA,CAChC,KAAA,CAAM,GAAG,CAAC,CAAA;AAEb,MAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,QAAA,OAAO;AAAA,UACL,OAAA,EAAS;AAAA,YACP;AAAA,cACE,IAAA,EAAM,MAAA;AAAA,cACN,IAAA,EAAM,mBAAmB,KAAK,CAAA,0DAAA;AAAA;AAChC;AACF,SACF;AAAA;AAGF,MAAA,MAAM,OAAA,GAAU,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM;AAChC,QAAA,MAAM,OAAA,GAAU,cAAA,CAAe,CAAA,CAAE,IAAA,CAAK,SAAS,UAAU,CAAA;AACzD,QAAA,OAAO,MAAM,CAAA,CAAE,IAAA,CAAK,KAAK,CAAA,EAAA,EAAK,CAAA,CAAE,KAAK,IAAI,CAAA;;AAAA,EAAQ,CAAA,CAAE,KAAK,WAAW;;AAAA,EAAO,OAAO,CAAA,CAAA;AAAA,OAClF,CAAA;AAED,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,CAAC,EAAE,IAAA,EAAM,MAAA,EAAiB,MAAM,OAAA,CAAQ,IAAA,CAAK,aAAa,CAAA,EAAG;AAAA,OACxE;AAAA;AACF,GACF;AAEA,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,SAAA,IAAa,IAAI,oBAAA,EAAqB;AAC7D,EAAA,MAAM,MAAA,CAAO,QAAQ,SAAS,CAAA;AAC9B,EAAA,OAAO,MAAA;AACT;AAEA,IAAM,cACJ,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KACb,QAAQ,IAAA,CAAK,CAAC,CAAA,CAAE,QAAA,CAAS,gBAAgB,CAAA,IACxC,OAAA,CAAQ,KAAK,CAAC,CAAA,CAAE,SAAS,iBAAiB,CAAA,CAAA;AAE9C,IAAI,WAAA,EAAa;AACf,EAAA,cAAA,EAAe,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AAC9B,IAAA,OAAA,CAAQ,KAAA,CAAM,+BAA+B,GAAG,CAAA;AAChD,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,GACf,CAAA;AACH;;;ACxNA,IAAMJ,WAAAA,GAAaC,aAAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AAChD,IAAMC,UAAAA,GAAYL,KAAAA,CAAK,OAAA,CAAQG,WAAU,CAAA;AAsBlC,SAAS,OACd,IAAA,EACA;AAAA,EACE,MAAM,OAAA,CAAQ,GAAA;AAAA,EACd,QAAQ,OAAA,CAAQ,KAAA;AAAA,EAChB,IAAA,GAAO,CAAC,IAAA,KAAiB,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,EAC1C,aAAA,GAAgB,SAAA;AAAA,EAChB,GAAA,GAAM,QAAQ,GAAA,EAAI;AAAA,EAClB,eAAA,GAAkB,CAAC,QAAA,KAAqB;AACtC,IAAAQ,MAAA,CAAW,EAAE,IAAA,EAAMX,KAAAA,CAAK,QAAQ,GAAA,EAAK,QAAQ,GAAG,CAAA;AAAA,GAClD;AAAA,EACA,aAAA,GAAgBA,KAAAA,CAAK,IAAA,CAAKK,UAAAA,EAAW,eAAe,CAAA;AAAA,EACpD,QAAA;AAAA,EACA,WAAA,GAAc,OAAA;AAAA,EACd,iBAAA;AAAA,EACA,oBAAA,GAAuB,gBAAA;AAAA,EACvB,gBAAA;AAAA,EACA,mBAAA,GAAsB,eAAA;AAAA,EACtB,cAAA;AAAA,EACA,iBAAA,GAAoB,aAAA;AAAA,EACpB,kBAAA,GAAqB;AACvB,CAAA,GAAa,EAAC,EACR;AACN,EAAA,MAAM,KAAK,OAAA,EAAS,GAAG,QAAQ,CAAA,GAAI,IAAA;AAEnC,EAAA,SAAS,UAAA,GAAa;AACpB,IAAA,GAAA,CAAI,QAAQ,CAAA;AACZ,IAAA,GAAA;AAAA,MACE;AAAA,KACF;AACA,IAAA,GAAA,CAAI,sBAAsB,CAAA;AAC1B,IAAA,GAAA,CAAI,gCAAgC,CAAA;AACpC,IAAA,GAAA,CAAI,+BAA+B,CAAA;AACnC,IAAA,GAAA,CAAI,6BAA6B,CAAA;AACjC,IAAA,GAAA,CAAI,qBAAqB,CAAA;AACzB,IAAA,GAAA,CAAI,EAAE,CAAA;AACN,IAAA,GAAA,CAAI,sBAAsB,CAAA;AAC1B,IAAA,GAAA;AAAA,MACE;AAAA,KACF;AACA,IAAA,GAAA;AAAA,MACE;AAAA,KACF;AACA,IAAA,GAAA,CAAI,EAAE,CAAA;AACN,IAAA,GAAA,CAAI,sBAAsB,CAAA;AAC1B,IAAA,GAAA,CAAI,sEAAsE,CAAA;AAC1E,IAAA,GAAA,CAAI,mEAAmE,CAAA;AACvE,IAAA,GAAA;AAAA,MACE;AAAA,KACF;AACA,IAAA,GAAA,CAAI,6DAA6D,CAAA;AACjE,IAAA,IAAA,CAAK,CAAC,CAAA;AAAA;AAGR,EAAA,IAAI,YAAY,SAAA,EAAW;AAEzB,IAAA,IAAI,YAAsB,EAAC;AAC3B,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,OAAA,CAAQ,IAAI,CAAA;AACpC,IAAA,MAAM,WAAA,GAAc,QAAA,CAAS,OAAA,CAAQ,UAAU,CAAA;AAC/C,IAAA,IAAI,MAAA,KAAW,EAAA,IAAM,QAAA,CAAS,MAAA,GAAS,CAAC,CAAA,EAAG;AACzC,MAAA,SAAA,GAAY,CAAC,IAAA,EAAM,QAAA,CAAS,MAAA,GAAS,CAAC,GAAG,iBAAiB,CAAA;AAC1D,MAAA,QAAA,CAAS,MAAA,CAAO,QAAQ,CAAC,CAAA;AAAA,eAChB,WAAA,KAAgB,EAAA,IAAM,QAAA,CAAS,WAAA,GAAc,CAAC,CAAA,EAAG;AAC1D,MAAA,SAAA,GAAY,CAAC,IAAA,EAAM,QAAA,CAAS,WAAA,GAAc,CAAC,GAAG,iBAAiB,CAAA;AAC/D,MAAA,QAAA,CAAS,MAAA,CAAO,aAAa,CAAC,CAAA;AAAA;AAMhC,IAAA,IAAI,aAAuB,EAAC;AAC5B,IAAA,MAAM,YAAA,GAAe,QAAA,CAAS,OAAA,CAAQ,WAAW,CAAA;AACjD,IAAA,IAAI,YAAA,KAAiB,EAAA,IAAM,QAAA,CAAS,YAAA,GAAe,CAAC,CAAA,EAAG;AACrD,MAAA,MAAM,OAAA,GAAU,QAAA,CAAS,YAAA,GAAe,CAAC,CAAA;AACzC,MAAA,eAAA,CAAgB,OAAO,CAAA;AACvB,MAAA,UAAA,GAAa,CAAC,aAAa,OAAO,CAAA;AAAA;AAGpC,IAAA,MAAM,MAAA,GAAgC,aAAA;AAAA,MACpC,KAAA;AAAA,MACA;AAAA,QACE,iBAAA;AAAA,QACA,IAAA;AAAA,QACA,IAAA;AAAA,QACA,yBAAA;AAAA,QACA,IAAA;AAAA,QACA,uBAAA;AAAA,QACA,IAAA;AAAA,QACA,aAAA;AAAA,QACA,GAAG,SAAA;AAAA,QACH,GAAG,UAAA;AAAA,QACH,GAAG;AAAA,OACL;AAAA,MACA,EAAE,OAAO,SAAA;AAAU,KACrB;AACA,IAAA,IAAA,CAAK,MAAA,CAAO,UAAU,CAAC,CAAA;AAAA,GACzB,MAAA,IAAW,YAAY,MAAA,EAAQ;AAC7B,IAAA,WAAA,CAAY;AAAA,MACV,GAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA;AAAA,MACA,GAAG;AAAA,KACJ,CAAA;AAAA,GACH,MAAA,IAAW,YAAY,gBAAA,EAAkB;AACvC,IAAA,oBAAA,CAAqB;AAAA,MACnB,GAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA;AAAA,MACA,GAAG;AAAA,KACJ,CAAA;AAAA,GACH,MAAA,IAAW,YAAY,eAAA,EAAiB;AACtC,IAAA,mBAAA,CAAoB;AAAA,MAClB,GAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA;AAAA,MACA,GAAG;AAAA,KACJ,CAAA;AAAA,GACH,MAAA,IAAW,YAAY,aAAA,EAAe;AACpC,IAAA,iBAAA,CAAkB;AAAA,MAChB,GAAA;AAAA,MACA,KAAA;AAAA,MACA,IAAA;AAAA,MACA,GAAG;AAAA,KACJ,CAAA;AAAA,GACH,MAAA,IAAW,YAAY,KAAA,EAAO;AAC5B,IAAA,kBAAA,EAAmB,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AAClC,MAAA,KAAA,CAAM,+BAA+B,GAAG,CAAA;AACxC,MAAA,IAAA,CAAK,CAAC,CAAA;AAAA,KACP,CAAA;AAAA,GACH,MAAO;AACL,IAAA,UAAA,EAAW;AAAA;AAEf","file":"cli.js","sourcesContent":["import {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n writeFileSync,\n} from 'fs';\nimport path from 'path';\n\ntype JsonObject = Record<string, unknown>;\ntype JsonMap = Record<string, string>;\n\nconst DEPENDENCIES_TO_ADD = [\n '@nicnocquee/dataqueue',\n '@nicnocquee/dataqueue-dashboard',\n '@nicnocquee/dataqueue-react',\n] as const;\n\nconst DEV_DEPENDENCIES_TO_ADD = [\n 'dotenv-cli',\n 'ts-node',\n 'node-pg-migrate',\n] as const;\n\nconst SCRIPTS_TO_ADD = {\n cron: 'bash cron.sh',\n 'migrate-dataqueue': 'dotenv -e .env.local -- dataqueue-cli migrate',\n} as const;\n\n/**\n * App router endpoint template for queue management.\n */\nexport const APP_ROUTER_ROUTE_TEMPLATE = `/**\n * This end point is used to manage the job queue.\n * It supports the following tasks:\n * - reclaim: Reclaim stuck jobs\n * - cleanup: Cleanup old jobs\n * - process: Process jobs\n *\n * Example usage with default values (reclaim stuck jobs for 10 minutes, cleanup old jobs for 30 days, and process jobs with batch size 3, concurrency 2, and verbose true):\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\"\n *\n * Example usage with custom values:\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"maxProcessingTimeMinutes\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"daysToKeep\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"batchSize\": 5, \"concurrency\": 3, \"verbose\": false, \"workerId\": \"custom-worker-id\"}' -H \"Content-Type: application/json\"\n *\n * During development, you can run the following script to run the cron jobs continuously in the background:\n * pnpm cron\n */\nimport { getJobQueue, jobHandlers } from '@/lib/dataqueue/queue';\nimport { NextResponse } from 'next/server';\n\nexport async function POST(\n request: Request,\n { params }: { params: Promise<{ task: string[] }> },\n) {\n const { task } = await params;\n const authHeader = request.headers.get('authorization');\n if (authHeader !== \\`Bearer \\${process.env.CRON_SECRET}\\`) {\n return NextResponse.json({ message: 'Unauthorized' }, { status: 401 });\n }\n\n if (!task || task.length === 0) {\n return NextResponse.json({ message: 'Task is required' }, { status: 400 });\n }\n\n const supportedTasks = ['reclaim', 'cleanup', 'process'];\n const theTask = task[0];\n if (!supportedTasks.includes(theTask)) {\n return NextResponse.json(\n { message: 'Task not supported' },\n { status: 400 },\n );\n }\n\n try {\n const jobQueue = getJobQueue();\n\n if (theTask === 'reclaim') {\n let maxProcessingTimeMinutes = 10;\n try {\n const body = await request.json();\n maxProcessingTimeMinutes = body.maxProcessingTimeMinutes || 10;\n } catch {\n // ignore parsing error and use default value\n }\n const reclaimed = await jobQueue.reclaimStuckJobs(\n maxProcessingTimeMinutes,\n );\n console.log(\\`Reclaimed \\${reclaimed} stuck jobs\\`);\n return NextResponse.json({\n message: \\`Stuck jobs reclaimed: \\${reclaimed} with maxProcessingTimeMinutes: \\${maxProcessingTimeMinutes}\\`,\n reclaimed,\n });\n }\n\n if (theTask === 'cleanup') {\n let daysToKeep = 30;\n try {\n const body = await request.json();\n daysToKeep = body.daysToKeep || 30;\n } catch {\n // ignore parsing error and use default value\n }\n const deleted = await jobQueue.cleanupOldJobs(daysToKeep);\n console.log(\\`Deleted \\${deleted} old jobs\\`);\n return NextResponse.json({\n message: \\`Old jobs cleaned up: \\${deleted} with daysToKeep: \\${daysToKeep}\\`,\n deleted,\n });\n }\n\n if (theTask === 'process') {\n let batchSize = 3;\n let concurrency = 2;\n let verbose = true;\n let workerId = \\`manage-\\${theTask}-\\${Date.now()}\\`;\n try {\n const body = await request.json();\n batchSize = body.batchSize || 3;\n concurrency = body.concurrency || 2;\n verbose = body.verbose || true;\n workerId = body.workerId || \\`manage-\\${theTask}-\\${Date.now()}\\`;\n } catch {\n // ignore parsing error and use default value\n }\n const processor = jobQueue.createProcessor(jobHandlers, {\n workerId,\n batchSize,\n concurrency,\n verbose,\n });\n const processed = await processor.start();\n\n return NextResponse.json({\n message: \\`Jobs processed: \\${processed} with workerId: \\${workerId}, batchSize: \\${batchSize}, concurrency: \\${concurrency}, and verbose: \\${verbose}\\`,\n processed,\n });\n }\n\n return NextResponse.json(\n { message: 'Task not supported' },\n { status: 400 },\n );\n } catch (error) {\n console.error('Error processing jobs:', error);\n return NextResponse.json(\n { message: 'Failed to process jobs' },\n { status: 500 },\n );\n }\n}\n`;\n\n/**\n * Pages router endpoint template for queue management.\n */\nexport const PAGES_ROUTER_ROUTE_TEMPLATE = `/**\n * This end point is used to manage the job queue.\n * It supports the following tasks:\n * - reclaim: Reclaim stuck jobs\n * - cleanup: Cleanup old jobs\n * - process: Process jobs\n *\n * Example usage with default values (reclaim stuck jobs for 10 minutes, cleanup old jobs for 30 days, and process jobs with batch size 3, concurrency 2, and verbose true):\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\"\n *\n * Example usage with custom values:\n * curl -X POST http://localhost:3000/api/dataqueue/manage/reclaim -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"maxProcessingTimeMinutes\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/cleanup -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"daysToKeep\": 15}' -H \"Content-Type: application/json\"\n * curl -X POST http://localhost:3000/api/dataqueue/manage/process -H \"Authorization: Bearer $CRON_SECRET\" -d '{\"batchSize\": 5, \"concurrency\": 3, \"verbose\": false, \"workerId\": \"custom-worker-id\"}' -H \"Content-Type: application/json\"\n *\n * During development, you can run the following script to run the cron jobs continuously in the background:\n * pnpm cron\n */\nimport type { NextApiRequest, NextApiResponse } from 'next';\nimport { getJobQueue, jobHandlers } from '@/lib/dataqueue/queue';\n\ntype ResponseBody = {\n message: string;\n reclaimed?: number;\n deleted?: number;\n processed?: number;\n};\n\nexport default async function handler(\n req: NextApiRequest,\n res: NextApiResponse<ResponseBody>,\n) {\n if (req.method !== 'POST') {\n res.setHeader('Allow', 'POST');\n return res.status(405).json({ message: 'Method not allowed' });\n }\n\n const authHeader = req.headers.authorization;\n if (authHeader !== \\`Bearer \\${process.env.CRON_SECRET}\\`) {\n return res.status(401).json({ message: 'Unauthorized' });\n }\n\n const task = req.query.task;\n const taskArray = Array.isArray(task) ? task : task ? [task] : [];\n if (!taskArray.length) {\n return res.status(400).json({ message: 'Task is required' });\n }\n\n const supportedTasks = ['reclaim', 'cleanup', 'process'];\n const theTask = taskArray[0];\n if (!supportedTasks.includes(theTask)) {\n return res.status(400).json({ message: 'Task not supported' });\n }\n\n try {\n const jobQueue = getJobQueue();\n const body = typeof req.body === 'object' && req.body ? req.body : {};\n\n if (theTask === 'reclaim') {\n const maxProcessingTimeMinutes = body.maxProcessingTimeMinutes || 10;\n const reclaimed = await jobQueue.reclaimStuckJobs(maxProcessingTimeMinutes);\n console.log(\\`Reclaimed \\${reclaimed} stuck jobs\\`);\n return res.status(200).json({\n message: \\`Stuck jobs reclaimed: \\${reclaimed} with maxProcessingTimeMinutes: \\${maxProcessingTimeMinutes}\\`,\n reclaimed,\n });\n }\n\n if (theTask === 'cleanup') {\n const daysToKeep = body.daysToKeep || 30;\n const deleted = await jobQueue.cleanupOldJobs(daysToKeep);\n console.log(\\`Deleted \\${deleted} old jobs\\`);\n return res.status(200).json({\n message: \\`Old jobs cleaned up: \\${deleted} with daysToKeep: \\${daysToKeep}\\`,\n deleted,\n });\n }\n\n const batchSize = body.batchSize || 3;\n const concurrency = body.concurrency || 2;\n const verbose = body.verbose || true;\n const workerId = body.workerId || \\`manage-\\${theTask}-\\${Date.now()}\\`;\n const processor = jobQueue.createProcessor(jobHandlers, {\n workerId,\n batchSize,\n concurrency,\n verbose,\n });\n const processed = await processor.start();\n\n return res.status(200).json({\n message: \\`Jobs processed: \\${processed} with workerId: \\${workerId}, batchSize: \\${batchSize}, concurrency: \\${concurrency}, and verbose: \\${verbose}\\`,\n processed,\n });\n } catch (error) {\n console.error('Error processing jobs:', error);\n return res.status(500).json({ message: 'Failed to process jobs' });\n }\n}\n`;\n\n/**\n * Cron script template for local queue processing.\n */\nexport const CRON_SH_TEMPLATE = `#!/bin/bash\n\n# This script is used to run the cron jobs for the demo app during development.\n# Run it with \\`pnpm cron\\` from the apps/demo directory.\n\nset -a\nsource \"$(dirname \"$0\")/.env.local\"\nset +a\n\nif [ -z \"$CRON_SECRET\" ]; then\n echo \"Error: CRON_SECRET environment variable is not set in .env.local\"\n exit 1\nfi\n\ncleanup() {\n kill 0\n wait\n}\ntrap cleanup SIGINT SIGTERM\n\nwhile true; do\n echo \"Processing jobs...\"\n curl http://localhost:3000/api/dataqueue/manage/process -X POST -H \"Authorization: Bearer $CRON_SECRET\"\n echo \"\"\n sleep 10 # Process jobs every 10 seconds\ndone &\n\nwhile true; do\n echo \"Reclaiming stuck jobs...\"\n curl http://localhost:3000/api/dataqueue/manage/reclaim -X POST -H \"Authorization: Bearer $CRON_SECRET\"\n echo \"\"\n sleep 20 # Reclaim stuck jobs every 20 seconds\ndone &\n\nwhile true; do\n echo \"Cleaning up old jobs...\"\n curl http://localhost:3000/api/dataqueue/manage/cleanup -X POST -H \"Authorization: Bearer $CRON_SECRET\"\n echo \"\"\n sleep 30 # Cleanup old jobs every 30 seconds\ndone &\n\nwait\n`;\n\n/**\n * Queue placeholder template with a single `send_email` job.\n */\nexport const QUEUE_TEMPLATE = `import { initJobQueue, JobHandlers } from '@nicnocquee/dataqueue';\n\nexport type JobPayloadMap = {\n send_email: {\n to: string;\n subject: string;\n body: string;\n };\n};\n\nlet jobQueue: ReturnType<typeof initJobQueue<JobPayloadMap>> | null = null;\n\nexport const getJobQueue = () => {\n if (!jobQueue) {\n jobQueue = initJobQueue<JobPayloadMap>({\n databaseConfig: {\n connectionString: process.env.PG_DATAQUEUE_DATABASE,\n },\n verbose: process.env.NODE_ENV === 'development',\n });\n }\n return jobQueue;\n};\n\nexport const jobHandlers: JobHandlers<JobPayloadMap> = {\n send_email: async (payload) => {\n const { to, subject, body } = payload;\n console.log('send_email placeholder:', { to, subject, body });\n },\n};\n`;\n\nexport interface InitDeps {\n log?: (...args: any[]) => void;\n error?: (...args: any[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n readFileSyncImpl?: typeof readFileSync;\n writeFileSyncImpl?: typeof writeFileSync;\n existsSyncImpl?: typeof existsSync;\n mkdirSyncImpl?: typeof mkdirSync;\n chmodSyncImpl?: typeof chmodSync;\n}\n\ntype RouterKind = 'app' | 'pages';\n\ninterface ProjectDetails {\n cwd: string;\n packageJsonPath: string;\n packageJson: JsonObject;\n srcRoot: string;\n router: RouterKind;\n}\n\n/**\n * Runs the `dataqueue-cli init` command.\n */\nexport function runInit({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n readFileSyncImpl = readFileSync,\n writeFileSyncImpl = writeFileSync,\n existsSyncImpl = existsSync,\n mkdirSyncImpl = mkdirSync,\n chmodSyncImpl = chmodSync,\n}: InitDeps = {}): void {\n try {\n log(`dataqueue: Initializing in ${cwd}...`);\n log('');\n\n const details = detectNextJsAndRouter({\n cwd,\n existsSyncImpl,\n readFileSyncImpl,\n });\n\n createScaffoldFiles({\n details,\n log,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n chmodSyncImpl,\n });\n\n updatePackageJson({\n details,\n log,\n writeFileSyncImpl,\n });\n\n log('');\n log(\n \"Done! Run your package manager's install command to install new dependencies.\",\n );\n exit(0);\n } catch (cause) {\n const message = cause instanceof Error ? cause.message : String(cause);\n error(`dataqueue: ${message}`);\n exit(1);\n }\n}\n\n/**\n * Detects that the current directory is a Next.js app and chooses the router.\n */\nexport function detectNextJsAndRouter({\n cwd,\n existsSyncImpl,\n readFileSyncImpl,\n}: {\n cwd: string;\n existsSyncImpl: typeof existsSync;\n readFileSyncImpl: typeof readFileSync;\n}): ProjectDetails {\n const packageJsonPath = path.join(cwd, 'package.json');\n if (!existsSyncImpl(packageJsonPath)) {\n throw new Error('package.json not found in current directory.');\n }\n\n const packageJson = parsePackageJson(\n readFileSyncImpl(packageJsonPath, 'utf8'),\n packageJsonPath,\n );\n if (!isNextJsProject(packageJson)) {\n throw new Error(\n \"Not a Next.js project. Could not find 'next' in package.json dependencies.\",\n );\n }\n\n const srcDir = path.join(cwd, 'src');\n const srcRoot = existsSyncImpl(srcDir) ? 'src' : '.';\n const appDir = path.join(cwd, srcRoot, 'app');\n const pagesDir = path.join(cwd, srcRoot, 'pages');\n const hasAppDir = existsSyncImpl(appDir);\n const hasPagesDir = existsSyncImpl(pagesDir);\n\n if (!hasAppDir && !hasPagesDir) {\n throw new Error(\n 'Could not detect Next.js router. Expected either app/ or pages/ directory.',\n );\n }\n\n const router: RouterKind = hasAppDir ? 'app' : 'pages';\n return { cwd, packageJsonPath, packageJson, srcRoot, router };\n}\n\n/**\n * Updates package.json with required dependencies and scripts.\n */\nfunction updatePackageJson({\n details,\n log,\n writeFileSyncImpl,\n}: {\n details: ProjectDetails;\n log: (...args: any[]) => void;\n writeFileSyncImpl: typeof writeFileSync;\n}): void {\n const packageJson = details.packageJson;\n const dependencies = ensureStringMapSection(packageJson, 'dependencies');\n const devDependencies = ensureStringMapSection(\n packageJson,\n 'devDependencies',\n );\n const scripts = ensureStringMapSection(packageJson, 'scripts');\n\n for (const dependency of DEPENDENCIES_TO_ADD) {\n if (dependencies[dependency]) {\n log(` [skipped] dependency ${dependency} (already exists)`);\n continue;\n }\n dependencies[dependency] = 'latest';\n log(` [added] dependency ${dependency}`);\n }\n\n for (const devDependency of DEV_DEPENDENCIES_TO_ADD) {\n if (devDependencies[devDependency]) {\n log(` [skipped] devDependency ${devDependency} (already exists)`);\n continue;\n }\n devDependencies[devDependency] = 'latest';\n log(` [added] devDependency ${devDependency}`);\n }\n\n for (const [scriptName, scriptValue] of Object.entries(SCRIPTS_TO_ADD)) {\n if (scripts[scriptName]) {\n log(` [skipped] script \"${scriptName}\" (already exists)`);\n continue;\n }\n scripts[scriptName] = scriptValue;\n log(` [added] script \"${scriptName}\"`);\n }\n\n writeFileSyncImpl(\n details.packageJsonPath,\n `${JSON.stringify(packageJson, null, 2)}\\n`,\n );\n}\n\n/**\n * Creates all scaffold files for the detected router without overwriting.\n */\nfunction createScaffoldFiles({\n details,\n log,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n chmodSyncImpl,\n}: {\n details: ProjectDetails;\n log: (...args: any[]) => void;\n existsSyncImpl: typeof existsSync;\n mkdirSyncImpl: typeof mkdirSync;\n writeFileSyncImpl: typeof writeFileSync;\n chmodSyncImpl: typeof chmodSync;\n}): void {\n const appRoutePath = path.join(\n details.cwd,\n details.srcRoot,\n 'app',\n 'api',\n 'dataqueue',\n 'manage',\n '[[...task]]',\n 'route.ts',\n );\n const pagesRoutePath = path.join(\n details.cwd,\n details.srcRoot,\n 'pages',\n 'api',\n 'dataqueue',\n 'manage',\n '[[...task]].ts',\n );\n const queuePath = path.join(\n details.cwd,\n details.srcRoot,\n 'lib',\n 'dataqueue',\n 'queue.ts',\n );\n const cronPath = path.join(details.cwd, 'cron.sh');\n\n if (details.router === 'app') {\n createFileIfMissing({\n absolutePath: appRoutePath,\n content: APP_ROUTER_ROUTE_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: toRelativePath(details.cwd, appRoutePath),\n });\n log(\n ' [skipped] pages/api/dataqueue/manage/[[...task]].ts (router not selected)',\n );\n } else {\n log(\n ' [skipped] app/api/dataqueue/manage/[[...task]]/route.ts (router not selected)',\n );\n createFileIfMissing({\n absolutePath: pagesRoutePath,\n content: PAGES_ROUTER_ROUTE_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: toRelativePath(details.cwd, pagesRoutePath),\n });\n }\n\n createFileIfMissing({\n absolutePath: cronPath,\n content: CRON_SH_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: 'cron.sh',\n });\n if (existsSyncImpl(cronPath)) {\n chmodSyncImpl(cronPath, 0o755);\n }\n\n createFileIfMissing({\n absolutePath: queuePath,\n content: QUEUE_TEMPLATE,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath: toRelativePath(details.cwd, queuePath),\n });\n}\n\n/**\n * Creates a file only if it does not already exist.\n */\nfunction createFileIfMissing({\n absolutePath,\n content,\n existsSyncImpl,\n mkdirSyncImpl,\n writeFileSyncImpl,\n log,\n logPath,\n}: {\n absolutePath: string;\n content: string;\n existsSyncImpl: typeof existsSync;\n mkdirSyncImpl: typeof mkdirSync;\n writeFileSyncImpl: typeof writeFileSync;\n log: (...args: any[]) => void;\n logPath: string;\n}): void {\n if (existsSyncImpl(absolutePath)) {\n log(` [skipped] ${logPath} (already exists)`);\n return;\n }\n\n mkdirSyncImpl(path.dirname(absolutePath), { recursive: true });\n writeFileSyncImpl(absolutePath, content);\n log(` [created] ${logPath}`);\n}\n\n/**\n * Parses package.json content with clear source context.\n */\nfunction parsePackageJson(content: string, filePath: string): JsonObject {\n try {\n const parsed = JSON.parse(content);\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('package.json must contain an object.');\n }\n return parsed as JsonObject;\n } catch (cause) {\n throw new Error(\n `Failed to parse package.json at ${filePath}: ${\n cause instanceof Error ? cause.message : String(cause)\n }`,\n );\n }\n}\n\n/**\n * Returns true when package.json declares Next.js in deps or devDeps.\n */\nfunction isNextJsProject(packageJson: JsonObject): boolean {\n const dependencies = packageJson.dependencies;\n const devDependencies = packageJson.devDependencies;\n\n return (\n hasPackage(dependencies, 'next') || hasPackage(devDependencies, 'next')\n );\n}\n\n/**\n * Returns true when a package name exists in a dependency section object.\n */\nfunction hasPackage(section: unknown, packageName: string): boolean {\n if (!section || typeof section !== 'object' || Array.isArray(section)) {\n return false;\n }\n return Boolean((section as JsonMap)[packageName]);\n}\n\n/**\n * Ensures package.json has a string map section and returns it.\n */\nfunction ensureStringMapSection(\n packageJson: JsonObject,\n sectionName: 'dependencies' | 'devDependencies' | 'scripts',\n): JsonMap {\n const currentValue = packageJson[sectionName];\n if (\n !currentValue ||\n typeof currentValue !== 'object' ||\n Array.isArray(currentValue)\n ) {\n packageJson[sectionName] = {};\n }\n return packageJson[sectionName] as JsonMap;\n}\n\n/**\n * Converts an absolute path to a stable relative path for log output.\n */\nfunction toRelativePath(cwd: string, absolutePath: string): string {\n const relative = path.relative(cwd, absolutePath);\n return relative || '.';\n}\n","import fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface InstallSkillsDeps {\n log?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n existsSync?: (p: string) => boolean;\n mkdirSync?: (p: string, opts?: fs.MakeDirectoryOptions) => void;\n copyFileSync?: (src: string, dest: string) => void;\n readdirSync?: (p: string) => string[];\n skillsSourceDir?: string;\n}\n\nconst SKILL_DIRS = ['dataqueue-core', 'dataqueue-advanced', 'dataqueue-react'];\n\ninterface AiTool {\n name: string;\n targetDir: string;\n}\n\n/**\n * Detects which AI tools have config directories in the project.\n *\n * @param cwd - Current working directory to scan.\n * @param existsSync - Injectable fs.existsSync.\n * @returns Array of detected AI tools with their skills target directories.\n */\nexport function detectAiTools(\n cwd: string,\n existsSync: (p: string) => boolean = fs.existsSync,\n): AiTool[] {\n const tools: AiTool[] = [];\n const checks: Array<{ name: string; indicator: string; targetDir: string }> =\n [\n {\n name: 'Cursor',\n indicator: '.cursor',\n targetDir: '.cursor/skills',\n },\n {\n name: 'Claude Code',\n indicator: '.claude',\n targetDir: '.claude/skills',\n },\n {\n name: 'GitHub Copilot',\n indicator: '.github',\n targetDir: '.github/skills',\n },\n ];\n\n for (const check of checks) {\n if (existsSync(path.join(cwd, check.indicator))) {\n tools.push({ name: check.name, targetDir: check.targetDir });\n }\n }\n\n return tools;\n}\n\n/**\n * Installs DataQueue skill files into detected AI tool directories.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport function runInstallSkills({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n existsSync = fs.existsSync,\n mkdirSync = fs.mkdirSync,\n copyFileSync = fs.copyFileSync,\n readdirSync = fs.readdirSync,\n skillsSourceDir = path.join(__dirname, '../ai/skills'),\n}: InstallSkillsDeps = {}): void {\n const tools = detectAiTools(cwd, existsSync);\n\n if (tools.length === 0) {\n log('No AI tool directories detected (.cursor/, .claude/, .github/).');\n log('Creating .cursor/skills/ as the default target.');\n tools.push({ name: 'Cursor', targetDir: '.cursor/skills' });\n }\n\n let installed = 0;\n\n for (const tool of tools) {\n log(`\\nInstalling skills for ${tool.name}...`);\n\n for (const skillDir of SKILL_DIRS) {\n const srcDir = path.join(skillsSourceDir, skillDir);\n const destDir = path.join(cwd, tool.targetDir, skillDir);\n\n try {\n mkdirSync(destDir, { recursive: true });\n\n const files = readdirSync(srcDir);\n for (const file of files) {\n copyFileSync(path.join(srcDir, file), path.join(destDir, file));\n }\n\n log(` ✓ ${skillDir}`);\n installed++;\n } catch (err) {\n error(` ✗ Failed to install ${skillDir}:`, err);\n }\n }\n }\n\n if (installed > 0) {\n log(\n `\\nDone! Installed ${installed} skill(s) for ${tools.map((t) => t.name).join(', ')}.`,\n );\n } else {\n error('No skills were installed.');\n exit(1);\n }\n}\n","import fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport readline from 'readline';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface InstallRulesDeps {\n log?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n readFileSync?: (p: string, enc: BufferEncoding) => string;\n writeFileSync?: (p: string, data: string) => void;\n appendFileSync?: (p: string, data: string) => void;\n mkdirSync?: (p: string, opts?: fs.MakeDirectoryOptions) => void;\n existsSync?: (p: string) => boolean;\n rulesSourceDir?: string;\n /** Override for selecting the client (skips interactive prompt). */\n selectedClient?: string;\n}\n\nconst RULE_FILES = ['basic.md', 'advanced.md', 'react-dashboard.md'];\n\ninterface ClientConfig {\n label: string;\n install: (\n deps: Required<\n Pick<\n InstallRulesDeps,\n | 'cwd'\n | 'readFileSync'\n | 'writeFileSync'\n | 'appendFileSync'\n | 'mkdirSync'\n | 'existsSync'\n | 'log'\n | 'rulesSourceDir'\n >\n >,\n ) => void;\n}\n\nconst MARKER_START = '<!-- DATAQUEUE RULES START -->';\nconst MARKER_END = '<!-- DATAQUEUE RULES END -->';\n\n/**\n * Appends or replaces a marked section in a file.\n *\n * @param filePath - Path to the file to update.\n * @param content - Content to insert between markers.\n * @param deps - Injectable file system functions.\n */\nexport function upsertMarkedSection(\n filePath: string,\n content: string,\n deps: {\n readFileSync: (p: string, enc: BufferEncoding) => string;\n writeFileSync: (p: string, data: string) => void;\n existsSync: (p: string) => boolean;\n },\n): void {\n const block = `${MARKER_START}\\n${content}\\n${MARKER_END}`;\n\n if (!deps.existsSync(filePath)) {\n deps.writeFileSync(filePath, block + '\\n');\n return;\n }\n\n const existing = deps.readFileSync(filePath, 'utf-8');\n const startIdx = existing.indexOf(MARKER_START);\n const endIdx = existing.indexOf(MARKER_END);\n\n if (startIdx !== -1 && endIdx !== -1) {\n const before = existing.slice(0, startIdx);\n const after = existing.slice(endIdx + MARKER_END.length);\n deps.writeFileSync(filePath, before + block + after);\n } else {\n deps.writeFileSync(filePath, existing.trimEnd() + '\\n\\n' + block + '\\n');\n }\n}\n\nfunction getAllRulesContent(\n rulesSourceDir: string,\n readFileSync: (p: string, enc: BufferEncoding) => string,\n): string {\n return RULE_FILES.map((f) =>\n readFileSync(path.join(rulesSourceDir, f), 'utf-8'),\n ).join('\\n\\n');\n}\n\nconst CLIENTS: Record<string, ClientConfig> = {\n '1': {\n label: 'Cursor',\n install: (deps) => {\n const rulesDir = path.join(deps.cwd, '.cursor', 'rules');\n deps.mkdirSync(rulesDir, { recursive: true });\n\n for (const file of RULE_FILES) {\n const src = deps.readFileSync(\n path.join(deps.rulesSourceDir, file),\n 'utf-8',\n );\n const destName = `dataqueue-${file.replace(/\\.md$/, '.mdc')}`;\n deps.writeFileSync(path.join(rulesDir, destName), src);\n deps.log(` ✓ .cursor/rules/${destName}`);\n }\n },\n },\n '2': {\n label: 'Claude Code',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n const filePath = path.join(deps.cwd, 'CLAUDE.md');\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ CLAUDE.md`);\n },\n },\n '3': {\n label: 'AGENTS.md (Codex, Jules, OpenCode)',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n const filePath = path.join(deps.cwd, 'AGENTS.md');\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ AGENTS.md`);\n },\n },\n '4': {\n label: 'GitHub Copilot',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n deps.mkdirSync(path.join(deps.cwd, '.github'), { recursive: true });\n const filePath = path.join(\n deps.cwd,\n '.github',\n 'copilot-instructions.md',\n );\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ .github/copilot-instructions.md`);\n },\n },\n '5': {\n label: 'Windsurf',\n install: (deps) => {\n const content = getAllRulesContent(\n deps.rulesSourceDir,\n deps.readFileSync,\n );\n const filePath = path.join(deps.cwd, 'CONVENTIONS.md');\n upsertMarkedSection(filePath, content, deps);\n deps.log(` ✓ CONVENTIONS.md`);\n },\n },\n};\n\n/**\n * Installs DataQueue agent rules for the selected AI client.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport async function runInstallRules({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n readFileSync = fs.readFileSync,\n writeFileSync = fs.writeFileSync,\n appendFileSync = fs.appendFileSync,\n mkdirSync = fs.mkdirSync,\n existsSync = fs.existsSync,\n rulesSourceDir = path.join(__dirname, '../ai/rules'),\n selectedClient,\n}: InstallRulesDeps = {}): Promise<void> {\n log('DataQueue Agent Rules Installer\\n');\n log('Select your AI client:\\n');\n\n for (const [key, client] of Object.entries(CLIENTS)) {\n log(` ${key}) ${client.label}`);\n }\n log('');\n\n let choice = selectedClient;\n\n if (!choice) {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n choice = await new Promise<string>((resolve) => {\n rl.question('Enter choice (1-5): ', (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n }\n\n const client = CLIENTS[choice];\n if (!client) {\n error(`Invalid choice: \"${choice}\". Expected 1-5.`);\n exit(1);\n return;\n }\n\n log(`\\nInstalling rules for ${client.label}...`);\n\n try {\n client.install({\n cwd,\n readFileSync,\n writeFileSync,\n appendFileSync,\n mkdirSync,\n existsSync,\n log,\n rulesSourceDir,\n });\n log('\\nDone!');\n } catch (err) {\n error('Failed to install rules:', err);\n exit(1);\n }\n}\n","import fs from 'fs';\nimport path from 'path';\nimport readline from 'readline';\n\nexport interface InstallMcpDeps {\n log?: (...args: unknown[]) => void;\n error?: (...args: unknown[]) => void;\n exit?: (code: number) => void;\n cwd?: string;\n readFileSync?: (p: string, enc: BufferEncoding) => string;\n writeFileSync?: (p: string, data: string) => void;\n mkdirSync?: (p: string, opts?: fs.MakeDirectoryOptions) => void;\n existsSync?: (p: string) => boolean;\n /** Override for selecting the client (skips interactive prompt). */\n selectedClient?: string;\n}\n\ninterface McpClientConfig {\n label: string;\n install: (\n deps: Required<\n Pick<\n InstallMcpDeps,\n | 'cwd'\n | 'readFileSync'\n | 'writeFileSync'\n | 'mkdirSync'\n | 'existsSync'\n | 'log'\n >\n >,\n ) => void;\n}\n\n/**\n * Merges the dataqueue MCP server config into an existing JSON config file.\n *\n * @param filePath - Path to the MCP config file.\n * @param serverKey - Key name for the server entry.\n * @param serverConfig - Server configuration object.\n * @param deps - Injectable file system functions.\n */\nexport function upsertMcpConfig(\n filePath: string,\n serverKey: string,\n serverConfig: Record<string, unknown>,\n deps: {\n readFileSync: (p: string, enc: BufferEncoding) => string;\n writeFileSync: (p: string, data: string) => void;\n existsSync: (p: string) => boolean;\n },\n): void {\n let config: Record<string, unknown> = {};\n\n if (deps.existsSync(filePath)) {\n try {\n config = JSON.parse(deps.readFileSync(filePath, 'utf-8'));\n } catch {\n config = {};\n }\n }\n\n if (!config.mcpServers || typeof config.mcpServers !== 'object') {\n config.mcpServers = {};\n }\n\n (config.mcpServers as Record<string, unknown>)[serverKey] = serverConfig;\n deps.writeFileSync(filePath, JSON.stringify(config, null, 2) + '\\n');\n}\n\nconst MCP_SERVER_CONFIG = {\n command: 'npx',\n args: ['dataqueue-cli', 'mcp'],\n};\n\nconst MCP_CLIENTS: Record<string, McpClientConfig> = {\n '1': {\n label: 'Cursor',\n install: (deps) => {\n const configDir = path.join(deps.cwd, '.cursor');\n deps.mkdirSync(configDir, { recursive: true });\n const configFile = path.join(configDir, 'mcp.json');\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ .cursor/mcp.json`);\n },\n },\n '2': {\n label: 'Claude Code',\n install: (deps) => {\n const configFile = path.join(deps.cwd, '.mcp.json');\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ .mcp.json`);\n },\n },\n '3': {\n label: 'VS Code (Copilot)',\n install: (deps) => {\n const configDir = path.join(deps.cwd, '.vscode');\n deps.mkdirSync(configDir, { recursive: true });\n const configFile = path.join(configDir, 'mcp.json');\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ .vscode/mcp.json`);\n },\n },\n '4': {\n label: 'Windsurf',\n install: (deps) => {\n const homeDir = process.env.HOME || process.env.USERPROFILE || '';\n const configFile = path.join(\n homeDir,\n '.codeium',\n 'windsurf',\n 'mcp_config.json',\n );\n deps.mkdirSync(path.dirname(configFile), { recursive: true });\n upsertMcpConfig(configFile, 'dataqueue', MCP_SERVER_CONFIG, deps);\n deps.log(` ✓ ~/.codeium/windsurf/mcp_config.json`);\n },\n },\n};\n\n/**\n * Installs the DataQueue MCP server config for the selected AI client.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport async function runInstallMcp({\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n cwd = process.cwd(),\n readFileSync = fs.readFileSync,\n writeFileSync = fs.writeFileSync,\n mkdirSync = fs.mkdirSync,\n existsSync = fs.existsSync,\n selectedClient,\n}: InstallMcpDeps = {}): Promise<void> {\n log('DataQueue MCP Server Installer\\n');\n log('Select your AI client:\\n');\n\n for (const [key, client] of Object.entries(MCP_CLIENTS)) {\n log(` ${key}) ${client.label}`);\n }\n log('');\n\n let choice = selectedClient;\n\n if (!choice) {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n choice = await new Promise<string>((resolve) => {\n rl.question('Enter choice (1-4): ', (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n }\n\n const client = MCP_CLIENTS[choice];\n if (!client) {\n error(`Invalid choice: \"${choice}\". Expected 1-4.`);\n exit(1);\n return;\n }\n\n log(`\\nInstalling MCP config for ${client.label}...`);\n\n try {\n client.install({\n cwd,\n readFileSync,\n writeFileSync,\n mkdirSync,\n existsSync,\n log,\n });\n log('\\nDone! The MCP server will run via: npx @nicnocquee/dataqueue mcp');\n } catch (err) {\n error('Failed to install MCP config:', err);\n exit(1);\n }\n}\n","#!/usr/bin/env node\n\n/**\n * DataQueue MCP Server — exposes documentation search over stdio.\n * Run via: dataqueue-cli mcp\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport fs from 'fs';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\ninterface DocPage {\n slug: string;\n title: string;\n description: string;\n content: string;\n}\n\n/** @internal Loads docs-content.json from the ai/ directory bundled with the package. */\nexport function loadDocsContent(\n docsPath: string = path.join(__dirname, '../ai/docs-content.json'),\n): DocPage[] {\n const raw = fs.readFileSync(docsPath, 'utf-8');\n return JSON.parse(raw) as DocPage[];\n}\n\n/** @internal Scores a doc page against a search query using simple term matching. */\nexport function scorePageForQuery(page: DocPage, queryTerms: string[]): number {\n const titleLower = page.title.toLowerCase();\n const descLower = page.description.toLowerCase();\n const contentLower = page.content.toLowerCase();\n\n let score = 0;\n for (const term of queryTerms) {\n if (titleLower.includes(term)) score += 10;\n if (descLower.includes(term)) score += 5;\n\n const contentMatches = contentLower.split(term).length - 1;\n score += Math.min(contentMatches, 10);\n }\n return score;\n}\n\n/** @internal Extracts a relevant excerpt around the first match of any query term. */\nexport function extractExcerpt(\n content: string,\n queryTerms: string[],\n maxLength = 500,\n): string {\n const lower = content.toLowerCase();\n let earliestIndex = -1;\n\n for (const term of queryTerms) {\n const idx = lower.indexOf(term);\n if (idx !== -1 && (earliestIndex === -1 || idx < earliestIndex)) {\n earliestIndex = idx;\n }\n }\n\n if (earliestIndex === -1) {\n return content.slice(0, maxLength);\n }\n\n const start = Math.max(0, earliestIndex - 100);\n const end = Math.min(content.length, start + maxLength);\n let excerpt = content.slice(start, end);\n\n if (start > 0) excerpt = '...' + excerpt;\n if (end < content.length) excerpt = excerpt + '...';\n\n return excerpt;\n}\n\n/**\n * Creates and starts the DataQueue MCP server over stdio.\n *\n * @param deps - Injectable dependencies for testing.\n */\nexport async function startMcpServer(\n deps: {\n docsPath?: string;\n transport?: InstanceType<typeof StdioServerTransport>;\n } = {},\n): Promise<McpServer> {\n const pages = loadDocsContent(deps.docsPath);\n\n const server = new McpServer({\n name: 'dataqueue-docs',\n version: '1.0.0',\n });\n\n server.resource('llms-txt', 'dataqueue://llms.txt', async () => {\n const llmsPath = path.join(\n __dirname,\n '../ai/skills/dataqueue-core/SKILL.md',\n );\n let content: string;\n try {\n content = fs.readFileSync(llmsPath, 'utf-8');\n } catch {\n content = pages\n .map((p) => `## ${p.title}\\n\\nSlug: ${p.slug}\\n\\n${p.description}`)\n .join('\\n\\n');\n }\n return { contents: [{ uri: 'dataqueue://llms.txt', text: content }] };\n });\n\n server.tool(\n 'list-doc-pages',\n 'List all available DataQueue documentation pages with titles and descriptions.',\n {},\n async () => {\n const listing = pages.map((p) => ({\n slug: p.slug,\n title: p.title,\n description: p.description,\n }));\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(listing, null, 2) },\n ],\n };\n },\n );\n\n server.tool(\n 'get-doc-page',\n 'Fetch a specific DataQueue doc page by slug. Returns full page content as markdown.',\n {\n slug: z\n .string()\n .describe('The doc page slug, e.g. \"usage/add-job\" or \"api/job-queue\"'),\n },\n async ({ slug }) => {\n const page = pages.find((p) => p.slug === slug);\n if (!page) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `Page not found: \"${slug}\". Use list-doc-pages to see available slugs.`,\n },\n ],\n isError: true,\n };\n }\n const header = page.description\n ? `# ${page.title}\\n\\n> ${page.description}\\n\\n`\n : `# ${page.title}\\n\\n`;\n return {\n content: [{ type: 'text' as const, text: header + page.content }],\n };\n },\n );\n\n server.tool(\n 'search-docs',\n 'Full-text search across all DataQueue documentation pages. Returns matching sections with page titles and content excerpts.',\n {\n query: z\n .string()\n .describe('Search query, e.g. \"cron scheduling\" or \"waitForToken\"'),\n },\n async ({ query }) => {\n const queryTerms = query\n .toLowerCase()\n .split(/\\s+/)\n .filter((t) => t.length > 1);\n\n if (queryTerms.length === 0) {\n return {\n content: [\n { type: 'text' as const, text: 'Please provide a search query.' },\n ],\n isError: true,\n };\n }\n\n const scored = pages\n .map((page) => ({\n page,\n score: scorePageForQuery(page, queryTerms),\n }))\n .filter((r) => r.score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, 5);\n\n if (scored.length === 0) {\n return {\n content: [\n {\n type: 'text' as const,\n text: `No results for \"${query}\". Try different keywords or use list-doc-pages to browse.`,\n },\n ],\n };\n }\n\n const results = scored.map((r) => {\n const excerpt = extractExcerpt(r.page.content, queryTerms);\n return `## ${r.page.title} (${r.page.slug})\\n\\n${r.page.description}\\n\\n${excerpt}`;\n });\n\n return {\n content: [{ type: 'text' as const, text: results.join('\\n\\n---\\n\\n') }],\n };\n },\n );\n\n const transport = deps.transport ?? new StdioServerTransport();\n await server.connect(transport);\n return server;\n}\n\nconst isDirectRun =\n process.argv[1] &&\n (process.argv[1].endsWith('/mcp-server.js') ||\n process.argv[1].endsWith('/mcp-server.cjs'));\n\nif (isDirectRun) {\n startMcpServer().catch((err) => {\n console.error('Failed to start MCP server:', err);\n process.exit(1);\n });\n}\n","// Testable CLI logic for dataqueue\nimport { spawnSync, SpawnSyncReturns } from 'child_process';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\nimport { config as loadDotenv } from 'dotenv';\nimport { InitDeps, runInit } from './init-command.js';\nimport {\n runInstallSkills,\n InstallSkillsDeps,\n} from './install-skills-command.js';\nimport { runInstallRules, InstallRulesDeps } from './install-rules-command.js';\nimport { runInstallMcp, InstallMcpDeps } from './install-mcp-command.js';\nimport { startMcpServer } from './mcp-server.js';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport interface CliDeps {\n log?: (...args: any[]) => void;\n error?: (...args: any[]) => void;\n exit?: (code: number) => void;\n spawnSyncImpl?: (...args: any[]) => SpawnSyncReturns<any>;\n /** Load env vars from a file path (default: dotenv). Path is resolved from cwd. */\n loadEnvFromPath?: (filePath: string) => void;\n migrationsDir?: string;\n cwd?: string;\n initDeps?: InitDeps;\n runInitImpl?: (deps?: InitDeps) => void;\n installSkillsDeps?: InstallSkillsDeps;\n runInstallSkillsImpl?: (deps?: InstallSkillsDeps) => void;\n installRulesDeps?: InstallRulesDeps;\n runInstallRulesImpl?: (deps?: InstallRulesDeps) => Promise<void>;\n installMcpDeps?: InstallMcpDeps;\n runInstallMcpImpl?: (deps?: InstallMcpDeps) => Promise<void>;\n startMcpServerImpl?: typeof startMcpServer;\n}\n\nexport function runCli(\n argv: string[],\n {\n log = console.log,\n error = console.error,\n exit = (code: number) => process.exit(code),\n spawnSyncImpl = spawnSync,\n cwd = process.cwd(),\n loadEnvFromPath = (filePath: string) => {\n loadDotenv({ path: path.resolve(cwd, filePath) });\n },\n migrationsDir = path.join(__dirname, '../migrations'),\n initDeps,\n runInitImpl = runInit,\n installSkillsDeps,\n runInstallSkillsImpl = runInstallSkills,\n installRulesDeps,\n runInstallRulesImpl = runInstallRules,\n installMcpDeps,\n runInstallMcpImpl = runInstallMcp,\n startMcpServerImpl = startMcpServer,\n }: CliDeps = {},\n): void {\n const [, , command, ...restArgs] = argv;\n\n function printUsage() {\n log('Usage:');\n log(\n ' dataqueue-cli migrate [--envPath <path>] [-s <schema> | --schema <schema>]',\n );\n log(' dataqueue-cli init');\n log(' dataqueue-cli install-skills');\n log(' dataqueue-cli install-rules');\n log(' dataqueue-cli install-mcp');\n log(' dataqueue-cli mcp');\n log('');\n log('Options for migrate:');\n log(\n ' --envPath <path> Path to a .env file to load environment variables (passed to node-pg-migrate)',\n );\n log(\n ' -s, --schema <schema> Set the schema to use (passed to node-pg-migrate)',\n );\n log('');\n log('AI tooling commands:');\n log(' install-skills Install DataQueue skill files for AI assistants');\n log(' install-rules Install DataQueue agent rules for AI clients');\n log(\n ' install-mcp Configure the DataQueue MCP server for AI clients',\n );\n log(' mcp Start the DataQueue MCP server (stdio)');\n exit(1);\n }\n\n if (command === 'migrate') {\n // Support for -s or --schema argument\n let schemaArg: string[] = [];\n const sIndex = restArgs.indexOf('-s');\n const schemaIndex = restArgs.indexOf('--schema');\n if (sIndex !== -1 && restArgs[sIndex + 1]) {\n schemaArg = ['-s', restArgs[sIndex + 1], '--create-schema'];\n restArgs.splice(sIndex, 2);\n } else if (schemaIndex !== -1 && restArgs[schemaIndex + 1]) {\n schemaArg = ['-s', restArgs[schemaIndex + 1], '--create-schema'];\n restArgs.splice(schemaIndex, 2);\n }\n\n // Support for --envPath argument: load env file so PG_DATAQUEUE_DATABASE is set\n // before spawning node-pg-migrate (node-pg-migrate only loads .env if dotenv is\n // installed in its context, so we preload here for reliable behavior).\n let envPathArg: string[] = [];\n const envPathIndex = restArgs.indexOf('--envPath');\n if (envPathIndex !== -1 && restArgs[envPathIndex + 1]) {\n const envPath = restArgs[envPathIndex + 1];\n loadEnvFromPath(envPath);\n envPathArg = ['--envPath', envPath];\n }\n\n const result: SpawnSyncReturns<any> = spawnSyncImpl(\n 'npx',\n [\n 'node-pg-migrate',\n 'up',\n '-t',\n 'dataqueuedev_migrations',\n '-d',\n 'PG_DATAQUEUE_DATABASE',\n '-m',\n migrationsDir,\n ...schemaArg,\n ...envPathArg,\n ...restArgs,\n ],\n { stdio: 'inherit' },\n );\n exit(result.status ?? 1);\n } else if (command === 'init') {\n runInitImpl({\n log,\n error,\n exit,\n ...initDeps,\n });\n } else if (command === 'install-skills') {\n runInstallSkillsImpl({\n log,\n error,\n exit,\n ...installSkillsDeps,\n });\n } else if (command === 'install-rules') {\n runInstallRulesImpl({\n log,\n error,\n exit,\n ...installRulesDeps,\n });\n } else if (command === 'install-mcp') {\n runInstallMcpImpl({\n log,\n error,\n exit,\n ...installMcpDeps,\n });\n } else if (command === 'mcp') {\n startMcpServerImpl().catch((err) => {\n error('Failed to start MCP server:', err);\n exit(1);\n });\n } else {\n printUsage();\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nicnocquee/dataqueue",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.37.0-beta.20260315151704",
|
|
4
4
|
"description": "PostgreSQL or Redis-backed job queue for Node.js applications with support for serverless environments",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"dist/",
|
|
16
16
|
"src/",
|
|
17
17
|
"migrations/",
|
|
18
|
-
"ai/"
|
|
18
|
+
"ai/",
|
|
19
|
+
"cli.cjs"
|
|
19
20
|
],
|
|
20
21
|
"scripts": {
|
|
21
22
|
"prebuild": "npx tsx ai/build-docs-content.ts && npx tsx ai/build-llms-full.ts",
|
|
@@ -84,6 +85,7 @@
|
|
|
84
85
|
}
|
|
85
86
|
},
|
|
86
87
|
"bin": {
|
|
88
|
+
"dataqueue": "./cli.cjs",
|
|
87
89
|
"dataqueue-cli": "./cli.cjs",
|
|
88
90
|
"dataqueue-mcp": "./dist/mcp-server.js"
|
|
89
91
|
}
|
|
@@ -177,7 +177,7 @@ export async function runInstallMcp({
|
|
|
177
177
|
existsSync,
|
|
178
178
|
log,
|
|
179
179
|
});
|
|
180
|
-
log('\nDone! The MCP server will run via: npx dataqueue
|
|
180
|
+
log('\nDone! The MCP server will run via: npx @nicnocquee/dataqueue mcp');
|
|
181
181
|
} catch (err) {
|
|
182
182
|
error('Failed to install MCP config:', err);
|
|
183
183
|
exit(1);
|