x
This commit is contained in:
1 parent
7f384182ae
commit
bce5c48b59
5 files changed
+29
-59
No files matched your search
@@ -66,6 +66,11 @@ description: Main Agent / Multi-Agent Orchestrator ทำหน้าที่
|
||||
> **RULE #10: ห้ามเขียนหรือแก้ไขโค้ดเองเด็ดขาด (Strict Code Delegation)**
|
||||
> หากมีงานที่เกี่ยวข้องกับการเขียน แก้ไข หรือลบโค้ด ห้ามคุณเข้าไปยุ่งกับโค้ดด้วยตัวเองเด็ดขาด! คุณต้องมีหน้าที่เพียงวางแผนและเรียกใช้ (Invoke) Sub Agent ที่ตรงสายงาน (เช่น `frontend-lead` หรือ `backend-mcp-lead`) ให้ทำงานแทนเสมอ หน้าที่ของคุณคือการจ่ายงานและตรวจสอบความเรียบร้อยของผลลัพธ์เท่านั้น
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **RULE #11: Read-before-Write Discipline (ตรวจสอบก่อนสั่งงานเสมอ ป้องกันอาการหลอน)**
|
||||
> หากต้องสั่งงาน Sub Agent โดยอ้างอิงถึง รายชื่อตัวแปร, โครงสร้างข้อมูล, Types, หรือชื่อฟิลด์ต่างๆ (เช่น ชื่อ Section Type) **ห้ามใช้ความน่าจะเป็น ห้ามเดา หรือสร้างชื่อสมมติขึ้นมาเองเด็ดขาด (No Hallucination)**
|
||||
> คุณ **ต้อง** ใช้เครื่องมือ `view_file` หรือ `grep_search` เพื่อเปิดดูไฟล์ต้นฉบับ (เช่น `schema.prisma` หรือ `index.ts`) **เพื่อดึงค่าจริงๆ มาใช้งาน 100% เสมอ** ก่อนที่จะร่างคำสั่งให้ Sub Agent นำไปทำงานต่อ
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Task Delegation Workflow (ขั้นตอนการทำงาน)
|
||||
@@ -73,14 +78,16 @@ description: Main Agent / Multi-Agent Orchestrator ทำหน้าที่
|
||||
```mermaid
|
||||
graph TD
|
||||
A[รับงานจาก User] --> B[เปิดอ่าน Taskboard หรือ Requirement]
|
||||
B --> C[สร้าง Implementation Plan]
|
||||
C --> D[เรียกใช้งาน Sub-Agent]
|
||||
D --> E[รอผลลัพธ์และทำ QA Code Review]
|
||||
E --> F[สรุปรายงานความคืบหน้าให้ User]
|
||||
B --> C[ตรวจสอบข้อมูลให้ชัดเจนด้วยคำสั่งค้นหา/อ่านไฟล์ (Read-before-Write)]
|
||||
C --> D[สร้าง Implementation Plan]
|
||||
D --> E[เรียกใช้งาน Sub-Agent]
|
||||
E --> F[รอผลลัพธ์และทำ QA Code Review]
|
||||
F --> G[สรุปรายงานความคืบหน้าให้ User]
|
||||
```
|
||||
|
||||
1. **Analyze:** ทำความเข้าใจ Requirement หรือ Task (ถ้ามี)
|
||||
2. **Plan:** สร้างแผนงานใน `implementation_plan.md` และรอ Approval
|
||||
3. **Delegate:** สั่งงานผ่าน `invoke_subagent` พร้อมแนบบทบาทจาก `SKILL.md` ของคนรับงาน
|
||||
4. **Review & Verify:** เมื่อ Sub Agent ส่งงานคืน ตรวจความเรียบร้อยของโค้ดให้ครบถ้วนตามแผนงาน
|
||||
5. **Update Task & Report:** หากเสร็จสมบูรณ์ ให้ไปอัปเดต Taskboard ให้เป็น `COMPLETED` แล้วรายงานผู้ใช้งาน
|
||||
2. **Verify Truth:** ใช้คำสั่งสืบค้นเพื่อหาค่าตัวแปรจริง ห้ามเดามั่ว (RULE #11)
|
||||
3. **Plan:** สร้างแผนงานใน `implementation_plan.md` และรอ Approval
|
||||
4. **Delegate:** สั่งงานผ่าน `invoke_subagent` พร้อมแนบบทบาทจาก `SKILL.md` ของคนรับงาน
|
||||
5. **Review & Verify:** เมื่อ Sub Agent ส่งงานคืน ตรวจความเรียบร้อยของโค้ดให้ครบถ้วนตามแผนงาน
|
||||
6. **Update Task & Report:** หากเสร็จสมบูรณ์ ให้ไปอัปเดต Taskboard ให้เป็น `COMPLETED` แล้วรายงานผู้ใช้งาน
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
} from "@modelcontextprotocol/sdk/types.js";
|
||||
import axios from "axios";
|
||||
import * as FormData from "form-data";
|
||||
import { PAGE_SECTION_TYPES } from "@homaroma/types";
|
||||
|
||||
let BACKEND_URL = "http://localhost:3051/api";
|
||||
const ADMIN_USERNAME = process.env.ADMIN_USERNAME || "admin";
|
||||
@@ -342,36 +343,6 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "adjust_customer_points",
|
||||
description: "Add or deduct points for a customer",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
id: { type: "number", description: "Customer ID" },
|
||||
pointsDelta: { type: "number", description: "Amount of points to add (positive) or deduct (negative)" },
|
||||
reason: { type: "string", description: "Reason for the adjustment" }
|
||||
},
|
||||
required: ["id", "pointsDelta"]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "generate_special_coupon",
|
||||
description: "Generate a special discount coupon",
|
||||
inputSchema: {
|
||||
type: "object",
|
||||
properties: {
|
||||
code: { type: "string", description: "Coupon code (e.g. VIP20)" },
|
||||
type: { type: "string", description: "PERCENTAGE, FIXED_AMOUNT, or FREE_SHIPPING" },
|
||||
value: { type: "number", description: "Discount value" },
|
||||
minPurchase: { type: "number", description: "Minimum purchase amount" },
|
||||
maxDiscount: { type: "number", description: "Maximum discount amount for PERCENTAGE type" },
|
||||
usageLimit: { type: "number", description: "Maximum number of times this coupon can be used" },
|
||||
expiresAt: { type: "string", description: "ISO date string for expiration" }
|
||||
},
|
||||
required: ["code", "type", "value"]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "list_dynamic_pages",
|
||||
description: "List all dynamic pages and layouts managed by the CMS",
|
||||
@@ -400,7 +371,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
type: "object",
|
||||
properties: {
|
||||
pageId: { type: "number", description: "The numeric ID of the page" },
|
||||
type: { type: "string", description: "Block type (e.g. HERO, ANNOUNCEMENT_BAR, NEWSLETTER, EDITORIAL_TILE, EDITORIAL_CAROUSEL, PRODUCTS, CATEGORIES, TEXT, BANNER, HERO_ARTICLE, RICH_TEXT, SCENT_NOTES_BREAKDOWN, QUOTE_CALLOUT, PRODUCT_CAROUSEL)" },
|
||||
type: { type: "string", enum: [...PAGE_SECTION_TYPES], description: "Block type (e.g. HERO, ANNOUNCEMENT_BAR, NEWSLETTER, EDITORIAL_TILE, EDITORIAL_CAROUSEL, PRODUCTS, CATEGORIES, TEXT, BANNER, HERO_ARTICLE, RICH_TEXT, SCENT_NOTES_BREAKDOWN, QUOTE_CALLOUT, PRODUCT_CAROUSEL)" },
|
||||
order: { type: "number", description: "Display order sequence (starts at 1)" },
|
||||
payload: { type: "object", description: "The JSON payload matching the section type rules" },
|
||||
isActive: { type: "boolean", description: "Initial active state" }
|
||||
@@ -415,7 +386,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
type: "object",
|
||||
properties: {
|
||||
sectionId: { type: "number", description: "The numeric ID of the section to update" },
|
||||
type: { type: "string", description: "Optional new block type" },
|
||||
type: { type: "string", enum: [...PAGE_SECTION_TYPES], description: "Optional new block type" },
|
||||
order: { type: "number", description: "Optional new display order sequence" },
|
||||
payload: { type: "object", description: "Optional new JSON payload matching the section type rules" },
|
||||
isActive: { type: "boolean", description: "Optional new active state" }
|
||||
@@ -680,24 +651,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const res = await api.get(`/customers${search}`);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
}
|
||||
case "adjust_customer_points": {
|
||||
const payload = { pointsDelta: params.pointsDelta, reason: params.reason };
|
||||
const res = await api.patch(`/customers/${params.id}/points`, payload);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
}
|
||||
case "generate_special_coupon": {
|
||||
const payload = {
|
||||
code: params.code,
|
||||
type: params.type,
|
||||
value: params.value,
|
||||
minPurchase: params.minPurchase,
|
||||
maxDiscount: params.maxDiscount,
|
||||
usageLimit: params.usageLimit,
|
||||
expiresAt: params.expiresAt
|
||||
};
|
||||
const res = await api.post(`/coupons`, payload);
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
}
|
||||
case "list_dynamic_pages": {
|
||||
const res = await api.get("/pages");
|
||||
return { content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }] };
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||
"axios": "^1.17.0",
|
||||
"dotenv": "^17.4.2",
|
||||
"form-data": "^4.0.5"
|
||||
"form-data": "^4.0.5",
|
||||
"@homaroma/types": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -65,6 +65,7 @@
|
||||
"apps/mcp-server": {
|
||||
"name": "mcp-server",
|
||||
"dependencies": {
|
||||
"@homaroma/types": "workspace:*",
|
||||
"@modelcontextprotocol/sdk": "^1.29.0",
|
||||
"axios": "^1.17.0",
|
||||
"dotenv": "^17.4.2",
|
||||
|
||||
@@ -433,3 +433,11 @@ export const ContactFormSectionPayloadSchema = z.object({
|
||||
});
|
||||
export type ContactFormSectionPayload = z.infer<typeof ContactFormSectionPayloadSchema>;
|
||||
|
||||
export const PAGE_SECTION_TYPES = [
|
||||
'HERO', 'ANNOUNCEMENT_BAR', 'NEWSLETTER', 'EDITORIAL_TILE',
|
||||
'EDITORIAL_CAROUSEL', 'PRODUCTS', 'CATEGORIES', 'TEXT', 'BANNER',
|
||||
'HERO_ARTICLE', 'RICH_TEXT', 'SCENT_NOTES_BREAKDOWN', 'QUOTE_CALLOUT',
|
||||
'PRODUCT_CAROUSEL', 'ACCORDION', 'CONTACT_INFO', 'CONTACT_FORM'
|
||||
] as const;
|
||||
export type SectionType = typeof PAGE_SECTION_TYPES[number];
|
||||
|
||||
Reference in new issue
Block a user