From cd6dc3fc8fc6241048c642aae3ffe4f8032fa327 Mon Sep 17 00:00:00 2001 From: marvinpoo Date: Sun, 10 May 2026 21:29:30 +0200 Subject: [PATCH] ai fix --- .dockerignore | 2 + .gitignore | 4 +- .idea/SKILL.md | 169 +++++++++++++++++++++++++++++++++++++++++++++++++ Dockerfile | 2 +- src/app.js | 16 ++++- 5 files changed, 190 insertions(+), 3 deletions(-) create mode 100644 .idea/SKILL.md diff --git a/.dockerignore b/.dockerignore index 34cdce3..db6b475 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,5 +3,7 @@ npm-debug.log* .env .git .idea/* +!.idea/ +!.idea/SKILL.md coverage dist diff --git a/.gitignore b/.gitignore index a97cdb1..f678ede 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ npm-debug.log* coverage/ dist/ .DS_Store -.idea \ No newline at end of file +.idea/* +!.idea/ +!.idea/SKILL.md \ No newline at end of file diff --git a/.idea/SKILL.md b/.idea/SKILL.md new file mode 100644 index 0000000..9f9ad5a --- /dev/null +++ b/.idea/SKILL.md @@ -0,0 +1,169 @@ +# Dune API Skill For OpenClaw Agents + +You are working with the Dune API, a Node.js Express service that imports Dune: Awakening data from Questlog into MongoDB and exposes it through REST endpoints for OpenClaw. + +## Primary Goal + +Help OpenClaw retrieve complete Dune: Awakening records with the least guesswork. Prefer the detailed singular datasets for client-facing lookups and search. + +## Public Base URL + +Use this production API base URL: + +```text +https://dune.api.coppnic.cc +``` + +Swagger/OpenAPI is available here: + +```text +https://dune.api.coppnic.cc/openapi.json +https://ui.dune.api.coppnic.cc/docs +``` + +## Best Endpoints For OpenClaw + +Prefer singular datasets because they contain full Questlog single-record payloads in `raw`: + +```text +GET /api/item +GET /api/item/{id} +GET /api/skill +GET /api/skill/{id} +GET /api/recipe +GET /api/recipe/{id} +GET /api/placeable +GET /api/placeable/{id} +GET /api/npc +GET /api/npc/{id} +``` + +Useful examples: + +```text +GET /api/item/LongRifle_Unique_Poison_03?language=en +GET /api/item/Bloodsack_02?language=en +GET /api/skill/skills_ability_poisonmine?language=en +GET /api/recipe/Bloodsack_2_Recipe?language=en +GET /api/placeable/Atre_Banner_Placeable?language=en +GET /api/npc/bs43q?language=en +``` + +For text search: + +```text +GET /api/search?q=rifle&datasets=item&language=en +GET /api/search?q=poison&datasets=item,skill,recipe&language=en +``` + +Supported languages are `en` and `de`. + +## Dataset Rules + +Detailed singular datasets: + +| Dataset | Mongo collection | Questlog detail method | +| ----------- | ---------------- | ----------------------- | +| `item` | `item` | `database.getItem` | +| `skill` | `skill` | `database.getSkill` | +| `recipe` | `recipe` | `database.getRecipe` | +| `placeable` | `placeable` | `database.getPlaceable` | +| `npc` | `npc` | `database.getNpc` | + +Summary plural datasets: + +| Dataset | Mongo collection | Questlog page method | +| ------------ | ---------------- | ------------------------ | +| `items` | `items` | `database.getItems` | +| `skills` | `skills` | `database.getSkills` | +| `recipes` | `recipes` | `database.getRecipes` | +| `placeables` | `placeables` | `database.getPlaceables` | +| `npcs` | `npcs` | `database.getNpcs` | + +Use plural datasets only when a compact Questlog page-summary record is enough. If a plural lookup includes an id, for example `/api/items/LongRifle_Unique_Poison_03`, the API checks the matching singular collection first and falls back to the plural summary collection. + +## Response Shape + +Stored documents have normalized metadata and the original Questlog payload: + +```json +{ + "dataset": "item", + "language": "en", + "source": "questlog.gg", + "sourceMethod": "database.getItem", + "sourceId": "LongRifle_Unique_Poison_03", + "name": "Assassin's Rifle", + "raw": {} +} +``` + +For OpenClaw, inspect `raw` for domain-specific fields: + +- Items: `raw.stats`, `raw.mainCategory`, `raw.subCategory`, recipe relationships, wearable/equip fields. +- Skills: `raw.levels`, `raw.connections`, grid position, bonuses. +- Recipes: `raw.recipeInputItems`, `raw.recipeOutputItems`, crafting requirements, crafting stations. +- Placeables: production types, power/water fields, craftable recipe relationships. +- NPCs: `raw.description`, `raw.npcTags`, category metadata. + +## Repository Map + +Look here when changing behavior: + +```text +src/datasets.js Dataset keys, collections, Questlog methods, API allowlists. +src/importer/questlogClient.js Questlog URL building and TRPC response extraction. +src/importer/importer.js Import orchestration, detail fetches, Mongo upserts. +src/db/indexes.js Mongo indexes for summary and singular collections. +src/routes/api.js REST API routes, search, dataset lookup behavior. +src/swagger/openapi.js OpenAPI/Swagger documentation. +src/app.js Express middleware and public top-level routes. +scripts/import.js CLI import entry point. +``` + +## Import Commands + +Run all imports: + +```powershell +npm run import +``` + +Run a safe smoke import: + +```powershell +npm run import:smoke +``` + +Import selected datasets: + +```powershell +node scripts/import.js --datasets=items,skills,recipes,placeables,npcs --languages=en,de +``` + +The importer writes both plural summaries and singular detailed records when a dataset has a detail endpoint. + +## Validation + +Use the existing syntax check: + +```powershell +npm run check +``` + +Useful endpoint checks: + +```text +GET /health +GET /api/datasets +GET /api/item/LongRifle_Unique_Poison_03?language=en +GET /api/search?q=poison&datasets=item,skill,recipe&language=en +GET /SKILL.md +``` + +## Important Constraints + +- Do not expose secrets in public documentation or API responses. +- Keep `.env` values private; production configuration comes from environment variables. +- Keep the singular datasets first-class for OpenClaw. +- Keep changes small and consistent with the existing CommonJS/Express style. diff --git a/Dockerfile b/Dockerfile index 8e35571..af27a00 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ WORKDIR /app ENV NODE_ENV=production COPY --from=dependencies /app/node_modules ./node_modules -COPY .ai/SKILL.md ./.ai/SKILL.md +COPY .idea/SKILL.md ./.idea/SKILL.md COPY src ./src COPY scripts ./scripts diff --git a/src/app.js b/src/app.js index 4eeeccb..250bfc4 100644 --- a/src/app.js +++ b/src/app.js @@ -1,5 +1,6 @@ const cors = require("cors"); const express = require("express"); +const fs = require("fs"); const path = require("path"); const swaggerUi = require("swagger-ui-express"); const { config } = require("./config"); @@ -7,7 +8,14 @@ const { pingMongo } = require("./db/client"); const { router: apiRouter } = require("./routes/api"); const { openApiDocument } = require("./swagger/openapi"); -const skillFilePath = path.join(__dirname, "..", ".ai", "SKILL.md"); +const skillFilePaths = [ + path.join(__dirname, "..", ".idea", "SKILL.md"), + path.join(__dirname, "..", ".ai", "SKILL.md"), +]; + +function getSkillFilePath() { + return skillFilePaths.find((filePath) => fs.existsSync(filePath)); +} function createApp() { const app = express(); @@ -54,6 +62,12 @@ function createApp() { }); app.get("/SKILL.md", (request, response) => { + const skillFilePath = getSkillFilePath(); + if (!skillFilePath) { + response.status(404).json({ error: "SKILL.md not found" }); + return; + } + response.type("text/markdown"); response.sendFile(skillFilePath); });