# Hooks: Case Status Webhooks Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** כאשר status של תיק משתנה ב-legal-ai (e.g. `qa_failed`, `exported`), ה-plugin מקבל webhook, מעדכן את ה-issue ב-Paperclip, ומעיר את ה-CEO במקרה הצורך.

**Architecture:** Legal-ai REST API קורא `pc_request("POST", "/api/plugins/marcusgroup.legal-ai/webhooks/case-status", ...)` אחרי כל שינוי status. ה-plugin מטפל ב-`onWebhook()` ומגיב: מוסיף תגובה לissue, מעיר CEO אם QA נכשל.

**Tech Stack:** TypeScript (plugin-legal-ai), Python/FastAPI (legal-ai web), `@paperclipai/plugin-sdk@2026.325.0`, `httpx` (Python), `pc_request` helper.

---

## File Map

| Action | File |
|--------|------|
| Modify | `plugin-legal-ai/src/worker.ts` — add `onWebhook()` to `definePlugin({})` |
| Modify | `plugin-legal-ai/plugin.json` — add `"webhooks.receive"` capability |
| Modify | `plugin-legal-ai/src/manifest.ts` — add webhook capability |
| Modify | `legal-ai/web/app.py` — emit webhook after `PUT /api/cases/{case_number}` |
| Modify | `legal-ai/web/paperclip_api.py` — add `emit_webhook()` helper |

---

## Task 1: Add `emit_webhook` helper ב-Python

**Files:**
- Modify: `legal-ai/web/paperclip_api.py`

- [ ] **Step 1: קרא את הקובץ הקיים**

```bash
head -90 /home/chaim/legal-ai/web/paperclip_api.py
```

- [ ] **Step 2: הוסף את ה-helper בסוף הקובץ**

פתח `/home/chaim/legal-ai/web/paperclip_api.py` והוסף אחרי הפונקציה `pc_request`:

```python
async def emit_case_status_webhook(
    case_number: str,
    old_status: str,
    new_status: str,
    company_id: str | None = None,
    run_id: str | None = None,
) -> None:
    """Notify the Paperclip plugin that a case status changed.

    Fire-and-forget: logs errors but never raises, so callers aren't blocked.
    """
    try:
        await pc_request(
            "POST",
            "/api/plugins/marcusgroup.legal-ai/webhooks/case-status",
            json={
                "caseNumber": case_number,
                "oldStatus": old_status,
                "newStatus": new_status,
                "companyId": company_id,
                "timestamp": datetime.utcnow().isoformat() + "Z",
            },
            run_id=run_id,
            timeout=5.0,
        )
    except Exception as exc:
        logger.warning("emit_case_status_webhook failed: %s", exc)
```

> **הערה:** `datetime` ו-`logger` כבר מיובאים ב-`app.py`. בדוק שהם מיובאים גם ב-`paperclip_api.py` — אם לא, הוסף `from datetime import datetime` ו-`import logging; logger = logging.getLogger(__name__)` בראש הקובץ.

- [ ] **Step 3: Commit**

```bash
cd /home/chaim/legal-ai
git add web/paperclip_api.py
git commit -m "feat: add emit_case_status_webhook helper"
```

---

## Task 2: צרף webhook לendpoint `PUT /api/cases/{case_number}`

**Files:**
- Modify: `legal-ai/web/app.py`

- [ ] **Step 1: מצא את ה-endpoint**

```bash
grep -n "PUT\|case_number\|update_case" /home/chaim/legal-ai/web/app.py | head -30
```

- [ ] **Step 2: קרא את הenable endpoint המלא**

זהה את הסקציה המלאה של ה-endpoint ואת הייבוא הקיים.

- [ ] **Step 3: הוסף import ל-emit_webhook**

בראש `app.py`, בסקציית ה-imports מ-`paperclip_api`:
```python
from .paperclip_api import pc_request, emit_case_status_webhook
```

- [ ] **Step 4: הוסף webhook emit בתוך הendpoint**

אחרי שהקוד מעדכן את ה-case (לפני ה-`return`), הוסף:

```python
# Notify plugin about status change (fire-and-forget)
if updates.get("status") and old_status != updates["status"]:
    background_tasks.add_task(
        emit_case_status_webhook,
        case_number=case_number,
        old_status=old_status,
        new_status=updates["status"],
        company_id=str(case.get("company_id")),
    )
```

> אם ה-endpoint כבר מקבל `background_tasks: BackgroundTasks` — השתמש בו. אם לא, הוסף `background_tasks: BackgroundTasks` לחתימת הפונקציה. הוסף `from fastapi import BackgroundTasks` ל-imports.

- [ ] **Step 5: שמור את ה-`old_status` לפני ה-update**

בתחילת ה-endpoint handler, לפני קריאת ה-DB update:
```python
old_status = (await db.get_case(case_number) or {}).get("status", "")
```

- [ ] **Step 6: בדיקה בסיסית — שלח PUT ידני**

```bash
curl -s -X PUT https://legal-ai.nautilus.marcusgroup.org/api/cases/1130-25 \
  -H "Content-Type: application/json" \
  -d '{"status": "in_progress"}' | jq .status
```

בדוק ב-Paperclip logs שהwebhook נשלח (עדיין לא מטופל בצד ה-plugin):
```bash
pm2 logs paperclip --lines 20
```

- [ ] **Step 7: Commit**

```bash
cd /home/chaim/legal-ai
git add web/app.py
git commit -m "feat: emit case-status webhook on PUT /api/cases/:case"
```

---

## Task 3: הוסף `onWebhook()` ל-plugin

**Files:**
- Modify: `plugin-legal-ai/src/worker.ts`

- [ ] **Step 1: קרא את `definePlugin({})` הקיים**

```bash
grep -n "definePlugin\|onWebhook\|onHealth\|onShutdown" /home/chaim/plugin-legal-ai/src/worker.ts
```

- [ ] **Step 2: הוסף את `onWebhook` handler**

בתוך הobject שמועבר ל-`definePlugin({})`, אחרי `setup(ctx)`:

```typescript
onWebhook: async (input) => {
  const { endpointKey, payload, companyId } = input as {
    endpointKey: string;
    payload: {
      caseNumber: string;
      oldStatus: string;
      newStatus: string;
      companyId: string;
      timestamp: string;
    };
    companyId: string;
  };

  if (endpointKey !== "case-status") return;

  const { caseNumber, oldStatus, newStatus } = payload;
  ctx.logger.info(`Webhook: ${caseNumber} ${oldStatus} → ${newStatus}`);

  // Find the Paperclip issue linked to this case
  const stateKey = `case:${caseNumber}`;
  const issueId = await ctx.state.get({ companyId }, stateKey);
  if (!issueId) {
    ctx.logger.warn(`No issue found for case ${caseNumber}`);
    return;
  }

  const statusLabels: Record<string, string> = {
    in_progress: "🔄 בעבודה",
    drafted: "✍️ טיוטה מוכנה",
    qa_failed: "❌ QA נכשל",
    exported: "📄 יוצא ל-DOCX",
    reviewed: "✅ נבדק",
    final: "🎯 סופי",
  };

  const label = statusLabels[newStatus] ?? newStatus;

  // Post a status comment on the issue
  await ctx.issues.createComment({
    issueId: issueId as string,
    body: `**עדכון סטטוס:** ${label} (היה: ${oldStatus})`,
  });

  // Wake CEO if QA failed
  if (newStatus === "qa_failed") {
    const companies = await ctx.companies.list();
    const company = companies.find((c) => c.id === companyId);
    if (!company) return;

    const CEO_IDS: Record<string, string> = {
      "42a7acd0-30c5-4cbd-ac97-7424f65df294": "752cebdd-6748-4a04-aacd-c7ab0294ef33",
      "8639e837-4c9d-47fa-a76b-95788d651896": "cdbfa8bc-3d61-41a4-a2e7-677ec7d34562",
    };
    const ceoId = CEO_IDS[companyId];
    if (ceoId) {
      await ctx.agents.invoke(ceoId, companyId, {
        prompt: `תיק ${caseNumber} נכשל בבדיקת QA. עיין בתוצאות QA ותקן את הבעיות.`,
        reason: "qa_failed webhook",
      });
    }
  }
},
```

> **הערה:** `ctx` חייב להיות נגיש ב-`onWebhook`. אם `ctx` מוגדר בתוך `setup()` בלבד — הוצא אותו ל-closure חיצוני של ה-plugin object (ראה את הדפוס הקיים ב-`worker.ts`).

- [ ] **Step 3: בדק TypeScript**

```bash
cd /home/chaim/plugin-legal-ai && npx tsc --noEmit
```

Expected: 0 errors.

- [ ] **Step 4: Build**

```bash
cd /home/chaim/plugin-legal-ai && npm run build
```

Expected: `dist/worker.js` נוצר ללא שגיאות.

- [ ] **Step 5: Commit**

```bash
cd /home/chaim/plugin-legal-ai
git add src/worker.ts
git commit -m "feat: add onWebhook handler for case-status events"
```

---

## Task 4: הוסף capability ל-`plugin.json` ול-`manifest.ts`

**Files:**
- Modify: `plugin-legal-ai/plugin.json`
- Modify: `plugin-legal-ai/src/manifest.ts`

- [ ] **Step 1: הוסף `"webhooks.receive"` ל-capabilities**

ב-`plugin-legal-ai/plugin.json`, בarray `"capabilities"`, הוסף:
```json
"webhooks.receive"
```

- [ ] **Step 2: הוסף גם ב-`manifest.ts`**

```bash
grep -n "capabilities\|webhooks" /home/chaim/plugin-legal-ai/src/manifest.ts
```

הוסף `"webhooks.receive"` לarray שם.

- [ ] **Step 3: Re-install plugin**

```bash
cd /home/chaim/plugin-legal-ai && npm run build
npx paperclipai plugin uninstall marcusgroup.legal-ai \
  --api-base http://localhost:3100 --api-key pcapi_legal_install_key_2026
npx paperclipai plugin install /home/chaim/plugin-legal-ai \
  --api-base http://localhost:3100 --api-key pcapi_legal_install_key_2026
pm2 restart paperclip
```

- [ ] **Step 4: Commit**

```bash
cd /home/chaim/plugin-legal-ai
git add plugin.json src/manifest.ts
git commit -m "feat: add webhooks.receive capability to plugin manifest"
```

---

## Task 5: בדיקה end-to-end

- [ ] **Step 1: Deploy legal-ai**

```bash
cd /home/chaim/legal-ai
git push origin main
# המתן לבנייה (~2-4 דקות)
```

- [ ] **Step 2: שנה סטטוס תיק**

```bash
curl -s -X PUT https://legal-ai.nautilus.marcusgroup.org/api/cases/1130-25 \
  -H "Content-Type: application/json" \
  -d '{"status": "qa_failed"}' | jq .status
```

- [ ] **Step 3: בדוק שהתגובה הוספה ל-Paperclip issue**

```bash
# מצא את ה-issue הקשור לתיק 1130-25
pm2 logs paperclip --lines 30 | grep "1130-25\|webhook\|qa_failed"
```

Expected: תגובה "❌ QA נכשל" הוספה לissue. CEO הועיר.

- [ ] **Step 4: בדוק שינוי סטטוס שגרתי (לא QA)**

```bash
curl -s -X PUT https://legal-ai.nautilus.marcusgroup.org/api/cases/1130-25 \
  -H "Content-Type: application/json" \
  -d '{"status": "drafted"}' | jq .status
```

Expected: תגובה "✍️ טיוטה מוכנה" בissue. CEO **לא** הועיר.

---

## אימות סופי

| בדיקה | פקודה | תוצאה מצופה |
|-------|-------|-------------|
| QA נכשל → CEO מועיר | `PUT status=qa_failed` | תגובה + agent invocation |
| exported → תגובה בלבד | `PUT status=exported` | תגובה בלבד |
| שינוי ללא status | `PUT title=...` | שום webhook |
| תיק ללא issue | webhook לתיק חדש | לוג warning, ללא crash |
