chore: fix .gitignore inline comments + add untracked code files
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m32s
G12 Leak-Guard / leak-guard (push) Successful in 5s
Lint — undefined names / undefined-names (push) Successful in 11s

Inline # comments in gitignore are not supported — they were silently
breaking three patterns (data/checkpoints/, data/adapter-migration-state.json,
.claude/agents/.generated/). Moved comments to their own lines and added
missing entries for runtime dirs (data/audit/, data/logs/, etc.) and
temp files (.interaction_tmp.json, .design-build/, .taskmaster bak files).

Also tracks previously untracked legitimate files: scripts, tests, docs,
skills references, .env.example, taskmaster templates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-27 12:46:32 +00:00
parent b4a68cf5da
commit 4de555367d
17 changed files with 3108 additions and 3 deletions

View File

@@ -0,0 +1,348 @@
# 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 |