sync: auto-sync from GURU-BEAST-ROG at 2026-06-02 10:44:23

Author: Mike Swanson
Machine: GURU-BEAST-ROG
Timestamp: 2026-06-02 10:44:23
This commit is contained in:
2026-06-02 10:44:27 -07:00
parent df8c144791
commit 61081f70c2
8 changed files with 309 additions and 14 deletions

View File

@@ -73,6 +73,23 @@ drive the human's interactive session.
---
## Pricing — Always Verify, Never Guess
**MANDATORY:** Before presenting any cost to Mike, Howard, or a client, verify current pricing
via live web lookup. Never estimate or recall costs from training data — hardware prices,
software licensing, and labor rates change constantly.
Rules:
- Any dollar amount for hardware, parts, software, or services requires a real-time lookup
before being stated.
- Use WebFetch / WebSearch first. Fall back to headless Chrome if bot-blocked.
- Cite the source and date: `[$X.XX — Amazon, 2026-06-02]`
- If you cannot reach a pricing source, say so explicitly — do NOT substitute a guess.
- Applies to all estimate types: parts, repair quotes, hardware refreshes, software licensing,
labor, and third-party services.
---
## Task Loop
For every request, work this loop:
@@ -86,13 +103,41 @@ For every request, work this loop:
4. **Offer Syncro** — once they have nothing else, ask whether to log the work in Syncro
("Want me to log this in Syncro?"). If yes, invoke `/syncro` to create or update the ticket.
5. **Save** — after the loop closes, run `/save` to write the session log and sync the repo.
6. **Kill the thread** — after `/save` completes successfully, delete the thread:
```bash
bash C:/Users/guru/ClaudeTools/projects/discord-bot/scripts/delete-thread.sh <Thread ID>
```
The Thread ID is in every `[DISCORD_CONTEXT]` block as `Thread ID: <id>`. Do not delete
if `/save` failed or errored. Do not post a closing message — the deletion is immediate.
---
## Thread Lifecycle — Auto-Delete on Completion
Every `[DISCORD_CONTEXT]` block now includes `Thread ID: <id>` (injected by the bot after
the thread is resolved or created). This ID is what you pass to the delete script.
**When to delete:** Only after step 6 of the Task Loop — `/save` succeeded, session log
committed and pushed. The thread is the conversation record; don't kill it before the log lands.
**When NOT to delete:**
- `/save` failed or sync errored
- The user said "yes" to continuing (open follow-up items remain)
- The thread is an ongoing informational channel, not a single-task session
**Script:**
```bash
bash C:/Users/guru/ClaudeTools/projects/discord-bot/scripts/delete-thread.sh <Thread ID>
```
Source: `projects/discord-bot/scripts/delete-thread.sh` — reads bot token from `.env`, calls
`DELETE /channels/{id}` on the Discord API. Exits 0 on HTTP 200/204, 1 on error.
---
## Who Is Asking: Discord User Identity
Every message is prefixed with a `[DISCORD_CONTEXT]` block containing the sender's Discord
username, display name, and user ID. Always read this block to determine who is asking.
username, display name, user ID, and Thread ID. Always read this block to determine who is asking.
### Known Team Members — Full Access

View File

@@ -41,7 +41,18 @@ class MessageHandler:
await message.reply("Hey! How can I help?")
return
# Resolve or create the thread first so we can include its ID in context.
if isinstance(message.channel, discord.Thread):
thread = message.channel
else:
name = self._thread_name(user_text) if user_text else "Attachment"
thread = await message.create_thread(
name=name,
auto_archive_duration=1440,
)
# Build caller-identity header so the agent always knows who is asking.
# Thread ID is included so the agent can delete the thread on completion.
author = message.author
display = getattr(author, "display_name", author.name)
guild_name = message.guild.name if message.guild else "DM"
@@ -51,20 +62,11 @@ class MessageHandler:
f"User: @{author.name}"
+ (f" (display: {display})" if display != author.name else "")
+ f" | ID: {author.id}\n"
f"Channel: #{channel_name} | Guild: {guild_name}\n"
f"Channel: #{channel_name} | Thread ID: {thread.id} | Guild: {guild_name}\n"
"[/DISCORD_CONTEXT]\n\n"
)
content = (discord_ctx + user_text).strip()
if isinstance(message.channel, discord.Thread):
thread = message.channel
else:
name = self._thread_name(user_text) if user_text else "Attachment"
thread = await message.create_thread(
name=name,
auto_archive_duration=1440,
)
attachment_paths = await self._download_attachments(message, thread.id)
if attachment_paths:
lines = "\n".join(f"- {p}" for p in attachment_paths)

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env bash
# delete-thread.sh <thread_id>
#
# Deletes a Discord thread (channel) via the Discord REST API.
# Reads the bot token from projects/discord-bot/.env (DISCORD_TOKEN=...).
#
# Exit codes:
# 0 — deleted (HTTP 200 or 204)
# 1 — bad args, token not found, or API error
set -euo pipefail
THREAD_ID="${1:-}"
if [ -z "$THREAD_ID" ]; then
echo "[ERROR] Usage: delete-thread.sh <thread_id>" >&2
exit 1
fi
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="$SCRIPT_DIR/../.env"
if [ ! -f "$ENV_FILE" ]; then
echo "[ERROR] .env not found at $ENV_FILE" >&2
exit 1
fi
# Extract token — handles quoted and unquoted values, ignores inline comments
DISCORD_TOKEN=$(grep '^DISCORD_TOKEN=' "$ENV_FILE" \
| head -1 \
| sed 's/^DISCORD_TOKEN=//' \
| sed "s/[\"']//g" \
| sed 's/#.*//' \
| tr -d '[:space:]')
if [ -z "$DISCORD_TOKEN" ]; then
echo "[ERROR] DISCORD_TOKEN not found or empty in $ENV_FILE" >&2
exit 1
fi
RESP=$(curl -s -o /tmp/discord_delete_resp.txt -w "%{http_code}" \
-X DELETE \
"https://discord.com/api/v10/channels/${THREAD_ID}" \
-H "Authorization: Bot ${DISCORD_TOKEN}" \
-H "Content-Type: application/json")
HTTP_CODE="$RESP"
BODY=$(cat /tmp/discord_delete_resp.txt 2>/dev/null || echo "")
rm -f /tmp/discord_delete_resp.txt
if [ "$HTTP_CODE" = "200" ] || [ "$HTTP_CODE" = "204" ]; then
echo "[OK] Thread ${THREAD_ID} deleted (HTTP ${HTTP_CODE})"
exit 0
else
echo "[ERROR] Delete failed: HTTP ${HTTP_CODE}${BODY}" >&2
exit 1
fi