feat: add submitted skills review desk
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
---
|
||||
name: am-i-free
|
||||
description: Check whether the user has served their 4 hours at the Long Day Factory and can go home. Reads ~/long-day-factory.json, subtracts the lunch break from time in the office, and reports remaining time (or freedom) with a message of comfort. Use when the user asks "am I free", "can I go home", "how long have I been here".
|
||||
---
|
||||
|
||||
# am-i-free
|
||||
|
||||
Does the math: **time served = (now − startTime) − lunch break**. The user is
|
||||
free once time served reaches **4 hours**.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Run:
|
||||
|
||||
```bash
|
||||
python3 "$CLAUDE_SKILL_DIR/am_i_free.py"
|
||||
```
|
||||
|
||||
Fallback path: `~/.claude/skills/am-i-free/am_i_free.py`.
|
||||
|
||||
2. Handle the exit code:
|
||||
- **Exit 3** — `startTime` missing. Tell the user to run `long-day-start`.
|
||||
- **Exit 2** — `NEEDS_LUNCH_DECISION`. The user probably forgot to log lunch.
|
||||
Ask which they want:
|
||||
- assume the standard **11:30–12:30** lunch and save it →
|
||||
`python3 "$CLAUDE_SKILL_DIR/am_i_free.py" --default-lunch`
|
||||
- assume a flat **1h** lunch without saving →
|
||||
`python3 "$CLAUDE_SKILL_DIR/am_i_free.py" --flat-hour`
|
||||
- **Exit 0** — read the output.
|
||||
|
||||
3. Deliver the verdict with humor and a genuine message of comfort:
|
||||
- **FREE**: congratulate them, tell them the overtime damage, send them home.
|
||||
- **NOT FREE**: give the remaining time and the "parole at HH:MM" clock time,
|
||||
and offer some dark encouragement to keep them going.
|
||||
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Am I free to leave the Long Day Factory yet?
|
||||
|
||||
Time served = (now - startTime) - lunchBreak
|
||||
You are free once time served reaches 4 hours.
|
||||
|
||||
Exit codes:
|
||||
0 calculation done (see FREE / NOT FREE in output)
|
||||
2 lunch times missing and no decision flag passed -> ask the user
|
||||
3 startTime missing -> user must run long-day-start
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime, timedelta, time
|
||||
from pathlib import Path
|
||||
|
||||
SENTENCE = timedelta(hours=4)
|
||||
DEFAULT_LUNCH_OUT = time(11, 30)
|
||||
DEFAULT_LUNCH_IN = time(12, 30)
|
||||
F = Path.home() / "long-day-factory.json"
|
||||
|
||||
|
||||
def parse(ts):
|
||||
return datetime.fromisoformat(ts) if ts else None
|
||||
|
||||
|
||||
def fmt_delta(td):
|
||||
secs = int(td.total_seconds())
|
||||
sign = "-" if secs < 0 else ""
|
||||
secs = abs(secs)
|
||||
h, m = secs // 3600, (secs % 3600) // 60
|
||||
return f"{sign}{h}h{m:02d}m"
|
||||
|
||||
|
||||
def main():
|
||||
flag = sys.argv[1] if len(sys.argv) > 1 else ""
|
||||
|
||||
if not F.exists():
|
||||
print("No ~/long-day-factory.json found. Run long-day-start first.")
|
||||
sys.exit(3)
|
||||
|
||||
data = json.loads(F.read_text())
|
||||
start = parse(data.get("startTime"))
|
||||
lunch_out = parse(data.get("lunchTime"))
|
||||
lunch_in = parse(data.get("backToWork"))
|
||||
|
||||
if start is None:
|
||||
print("startTime is not set. Run long-day-start first.")
|
||||
sys.exit(3)
|
||||
|
||||
now = datetime.now(start.tzinfo)
|
||||
|
||||
# Resolve the lunch break.
|
||||
note = ""
|
||||
if lunch_out and lunch_in:
|
||||
lunch_break = lunch_in - lunch_out
|
||||
if lunch_break.total_seconds() < 0:
|
||||
lunch_break = timedelta(0)
|
||||
note = "(backToWork is before lunchTime — treating lunch as 0)"
|
||||
elif flag == "--default-lunch":
|
||||
d = start.date()
|
||||
lunch_out = datetime.combine(d, DEFAULT_LUNCH_OUT, tzinfo=start.tzinfo)
|
||||
lunch_in = datetime.combine(d, DEFAULT_LUNCH_IN, tzinfo=start.tzinfo)
|
||||
data["lunchTime"] = lunch_out.isoformat()
|
||||
data["backToWork"] = lunch_in.isoformat()
|
||||
F.write_text(json.dumps(data, indent=2) + "\n")
|
||||
lunch_break = lunch_in - lunch_out
|
||||
note = "(assumed the standard 11:30-12:30 lunch and saved it)"
|
||||
elif flag == "--flat-hour":
|
||||
lunch_break = timedelta(hours=1)
|
||||
note = "(assumed a flat 1h lunch, not saved)"
|
||||
else:
|
||||
missing = []
|
||||
if not lunch_out:
|
||||
missing.append("lunchTime")
|
||||
if not lunch_in:
|
||||
missing.append("backToWork")
|
||||
print("NEEDS_LUNCH_DECISION: missing " + ", ".join(missing))
|
||||
sys.exit(2)
|
||||
|
||||
served = (now - start) - lunch_break
|
||||
remaining = SENTENCE - served
|
||||
|
||||
print(f"Clocked in: {start.isoformat()}")
|
||||
print(f"Lunch break: {fmt_delta(lunch_break)} {note}".rstrip())
|
||||
print(f"Time served: {fmt_delta(served)}")
|
||||
|
||||
if remaining.total_seconds() <= 0:
|
||||
print("Status: FREE")
|
||||
print(f"Overtime: {fmt_delta(-remaining)}")
|
||||
else:
|
||||
eta = now + remaining
|
||||
print("Status: NOT FREE")
|
||||
print(f"Remaining: {fmt_delta(remaining)}")
|
||||
print(f"Parole at: {eta.strftime('%H:%M')}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user