diff --git a/.claude/commands/syncro.md b/.claude/commands/syncro.md index 5418fab..58d708d 100644 --- a/.claude/commands/syncro.md +++ b/.claude/commands/syncro.md @@ -64,23 +64,19 @@ API_KEY=$(sops -d D:/vault/msp-tools/syncro.sops.yaml | py -c "import sys,yaml; - `contact_id` (customer contact) - `ticket_type_id` (ticket category) -#### Comments (with optional time entry) +#### Comments | Operation | Method | Endpoint | Body | |---|---|---|---| | Add comment | POST | `/tickets//comment` | `{"subject": "Update", "body": "...", "hidden": false, "do_not_email": false}` | -| Add comment + time | POST | `/tickets//comment` | Same as above, PLUS: `"product_id": N, "minutes_spent": 60, "bill_time_now": false` | **Comment fields:** - `subject` — comment header (e.g., "Update", "Resolution", "Internal Note") - `body` — comment text (HTML supported) - `hidden` — if true, internal-only (customer can't see) - `do_not_email` — if true, don't email customer about this comment -- `product_id` — labor product ID (see labor products table below). Adds billable time to the ticket. -- `minutes_spent` — integer, minutes of work (60 = 1hr minimum in most cases) -- `bill_time_now` — if true, immediately creates a charge (equivalent to "Charge now" checkbox in GUI) -**This is the primary way to log time.** Comment + time in one call mirrors the GUI workflow exactly. Timer entries (`/tickets/{id}/timer_entry`) exist but are rarely used. +**WARNING:** The comment endpoint accepts but silently ignores `product_id`, `minutes_spent`, and `bill_time_now` fields — they are not saved. Verified 2026-04-20. Always use the timer_entry endpoint to log time. #### Customers @@ -144,17 +140,35 @@ When showing ticket detail, include: ### Billing workflow +**ALWAYS ask the user for minutes and labor type before logging any time entry. Never assume a default.** +**ALWAYS show a preview of the ticket comment/notes to the user before posting. Wait for confirmation.** + When `/syncro bill ` is called: 1. Get ticket details -2. Ask: "How many minutes + labor type?" (default: 60 min, Labor - Remote Business) -3. Add comment with time: `POST /tickets/{id}/comment` with `product_id`, `minutes_spent`, `bill_time_now: false`, and work notes as body -4. Then create invoice: `POST /invoices` with `{"ticket_id": N, "customer_id": N, "category": "Standard"}` -5. Update ticket status to "Invoiced" +2. Ask: "How many minutes should I bill, and what labor type? (remote / onsite / emergency / project / internal)" +3. Draft the comment body and show it to the user for review before posting +3. Add comment: `POST /tickets/{id}/comment` with work notes as body (no time fields — they are broken) +4. Add timer entry: `POST /tickets/{id}/timer_entry` with `start_at`, `end_at`, `billable: true`, `product_id`, `notes` +5. Create invoice: `POST /invoices` with `{"ticket_id": N, "customer_id": N, "category": "Standard"}` +6. Update ticket status to "Invoiced" -**The flow mirrors the GUI: add comment with time attached → Make Invoice.** +**Correct two-call pattern for comment + time:** +```bash +# Step 1: comment (notes only) +curl -X POST "${BASE}/tickets/${ID}/comment?api_key=${API_KEY}" \ + -H "Content-Type: application/json" \ + -d '{"subject": "Resolution", "body": "...", "hidden": false, "do_not_email": true}' + +# Step 2: timer entry (billable time) — compute start_at as end_at minus minutes +NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ") +START=$(date -u -d "60 minutes ago" +"%Y-%m-%dT%H:%M:%SZ") +curl -X POST "${BASE}/tickets/${ID}/timer_entry?api_key=${API_KEY}" \ + -H "Content-Type: application/json" \ + -d "{\"start_at\": \"${START}\", \"end_at\": \"${NOW}\", \"notes\": \"...\", \"billable\": true, \"product_id\": 1190473}" +``` When `/syncro comment --time 60 --labor remote` is called: -- Post the comment with time in one API call +- Post the comment first, then post a separate timer_entry - `--labor` maps to product IDs: `remote` → 1190473, `onsite` → 26118, `emergency` → 26184, `project` → 9269129, `internal` → 9269124, `travel` → 26117, `website` → 68055 ### Error handling diff --git a/session-logs/2026-04-20-session.md b/session-logs/2026-04-20-session.md index 8accc35..b5da3b5 100644 --- a/session-logs/2026-04-20-session.md +++ b/session-logs/2026-04-20-session.md @@ -257,6 +257,54 @@ Refactored `.claude/CLAUDE.md` to reduce context window pressure. Extracted verb --- +## Update: 19:48 UTC — Python Fix + CLAUDE.md Continued + +### Summary + +Fixed Windows python3 Store alias errors (exit code 49) burning tokens on every Python call. Also committed previous CLAUDE.md optimization work. + +### Root Cause + +Windows Store app execution aliases for `python.exe` and `python3.exe` were intercepting calls and returning exit 49 instead of running Python. Fix was two-part: +1. Code: replace `python3` with `py` (Windows launcher) or `jq` throughout all scripts/docs +2. System: Mike disabled the Store aliases in Settings > Apps > Advanced app settings > App execution aliases + +### Files Changed + +**ClaudeTools repo (936ea49):** +- `.claude/OLLAMA.md` — reachability check: `python -c` → `jq -r`, one-liner: `python3` → `py` +- `.claude/commands/syncro.md` — `python` → `py` +- `.claude/scripts/sync.sh` — fallback loop: `python3 python` → `py python3 python`; also updated error message +- `.claude/skills/1password/references/op_commands.md` — all `python3` → `py`; JSON one-liners → `jq` +- `.claude/skills/1password/references/secret_references.md` — all `python3` → `py`; field list → `jq` +- `.claude/skills/1password/scripts/check_setup.sh` — vault list: `python3` → `jq` +- `.claude/skills/1password/scripts/env_from_op.sh` — item lists → `jq`; vault/title extraction → `jq`; heredoc: `python3 -` → `py -` +- `.claude/skills/1password/scripts/store_secret.sh` — item ID + vault name extraction: `python3` → `jq` +- `.claude/skills/remediation-tool/scripts/get-token.sh` — fallback loop: `python3 python py` → `py python python3` +- `.claude/DATABASE_FIRST_PROTOCOL.md` — `python -c` → `jq -r` +- `.claude/settings.local.json` — added `"Bash(py:*)"` to allowlist + +**Vault repo (4590370):** +- `scripts/vault.sh` — fallback loop: `python python3 py` → `py python python3` + +### Python State on DESKTOP-0O8A1RL + +| Command | Status | +|---|---| +| `python3` | BROKEN — Store alias disabled, now fails cleanly | +| `python` | BROKEN — Store alias disabled | +| `py` | WORKS — Windows launcher at `C:\Windows\py.exe` | +| `jq` | WORKS — `C:\Users\guru\AppData\Local\Microsoft\WinGet\Links\jq.exe` | +| Python install | `C:\Program Files\Python314\python.exe` (also Python312 in user AppData) | + +### Memory Saved + +Added `feedback_python_windows.md` to `.claude/memory/`: use `py` not `python3`, prefer `jq` for JSON. + +### No Credentials / No Pending Items from This Update + +--- + ## Key Infrastructure Reference | Resource | Details |