feat: migrate skills review desk to astro
This commit is contained in:
@@ -0,0 +1 @@
|
||||

|
||||
@@ -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()
|
||||
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: back-to-work
|
||||
description: Log the return from lunch at the Long Day Factory. Records backToWork with the current timestamp in ~/long-day-factory.json. Use when the user says lunch is over / they are back at their desk / "back to work".
|
||||
---
|
||||
|
||||
# back-to-work
|
||||
|
||||
Records when the user returns from lunch. The gap between `lunchTime` and
|
||||
`backToWork` is the lunch break that `am-i-free` subtracts from time served.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Run:
|
||||
|
||||
```bash
|
||||
bash "$CLAUDE_SKILL_DIR/back.sh"
|
||||
```
|
||||
|
||||
Fallback path: `~/.claude/skills/back-to-work/back.sh`.
|
||||
|
||||
2. The script creates `~/long-day-factory.json` if missing and sets `backToWork`
|
||||
to now.
|
||||
- If it warns that `lunchTime` is not set, ask the user whether they want to
|
||||
also set `lunchTime` now (to the current time) or leave it for `am-i-free`
|
||||
to handle with the default 11:30 assumption. If they say yes, re-run with:
|
||||
`bash "$CLAUDE_SKILL_DIR/back.sh" --also-lunch`
|
||||
- If it warns that `startTime` is not set, pass that along.
|
||||
|
||||
3. Reply with humor: the machine missed you, the assembly line resumes, etc.
|
||||
Include the timestamp.
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
# Log return from lunch.
|
||||
set -euo pipefail
|
||||
|
||||
F="$HOME/long-day-factory.json"
|
||||
TS="$(python3 -c 'import datetime;print(datetime.datetime.now().astimezone().isoformat(timespec="seconds"))')"
|
||||
ALSO_LUNCH="${1:-}"
|
||||
|
||||
if [ ! -f "$F" ]; then
|
||||
printf '{\n "startTime": null,\n "lunchTime": null,\n "backToWork": null\n}\n' > "$F"
|
||||
fi
|
||||
|
||||
tmp="$(mktemp)"
|
||||
if [ "$ALSO_LUNCH" = "--also-lunch" ]; then
|
||||
jq --arg ts "$TS" '.backToWork = $ts | (if .lunchTime == null then .lunchTime = $ts else . end)' "$F" > "$tmp" && mv "$tmp" "$F"
|
||||
echo "Back to work at $TS (also set lunchTime to $TS)"
|
||||
else
|
||||
jq --arg ts "$TS" '.backToWork = $ts' "$F" > "$tmp" && mv "$tmp" "$F"
|
||||
echo "Back to work at $TS"
|
||||
fi
|
||||
|
||||
if [ "$(jq -r '.lunchTime' "$F")" = "null" ]; then
|
||||
echo "WARNING: lunchTime is not set — ask the user if they want to set it now (--also-lunch)."
|
||||
fi
|
||||
if [ "$(jq -r '.startTime' "$F")" = "null" ]; then
|
||||
echo "WARNING: startTime is not set — did you skip long-day-start this morning?"
|
||||
fi
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 129 KiB |
@@ -0,0 +1,25 @@
|
||||
---
|
||||
name: long-day-start
|
||||
description: Punch in at the Long Day Factory. Records startTime with the current timestamp in ~/long-day-factory.json and wipes lunchTime / backToWork from any previous shift. Use when the user says they arrived at the office / started their day / "long day start".
|
||||
---
|
||||
|
||||
# long-day-start
|
||||
|
||||
Begins a new shift at the Long Day Factory (the office). The sentence is 4 hours,
|
||||
minus time served at lunch.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Run the script below. It creates `~/long-day-factory.json` if missing, sets
|
||||
`startTime` to now (ISO 8601, `-03:00`), and resets `lunchTime` and
|
||||
`backToWork` to `null`.
|
||||
|
||||
```bash
|
||||
bash "$CLAUDE_SKILL_DIR/start.sh"
|
||||
```
|
||||
|
||||
If `$CLAUDE_SKILL_DIR` is not set, use the absolute path
|
||||
`~/.claude/skills/long-day-start/start.sh`.
|
||||
|
||||
2. Report back to the user with a bit of humor — they've just clocked in and the
|
||||
clock is now running. Mention the time they punched in.
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
# Punch in: set startTime, clear the rest.
|
||||
set -euo pipefail
|
||||
|
||||
F="$HOME/long-day-factory.json"
|
||||
TS="$(python3 -c 'import datetime;print(datetime.datetime.now().astimezone().isoformat(timespec="seconds"))')"
|
||||
|
||||
printf '{\n "startTime": "%s",\n "lunchTime": null,\n "backToWork": null\n}\n' "$TS" > "$F"
|
||||
|
||||
echo "Clocked in to the Long Day Factory at $TS"
|
||||
echo "Wrote $F"
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
name: lunch-time
|
||||
description: Log the start of the lunch break at the Long Day Factory. Records lunchTime with the current timestamp in ~/long-day-factory.json. Use when the user says they are going to lunch / "lunch time".
|
||||
---
|
||||
|
||||
# lunch-time
|
||||
|
||||
Records when the user leaves for lunch. Lunch is time served — it gets subtracted
|
||||
from the 4-hour sentence when `am-i-free` does the math.
|
||||
|
||||
## Steps
|
||||
|
||||
1. Run:
|
||||
|
||||
```bash
|
||||
bash "$CLAUDE_SKILL_DIR/lunch.sh"
|
||||
```
|
||||
|
||||
Fallback path: `~/.claude/skills/lunch-time/lunch.sh`.
|
||||
|
||||
2. The script creates `~/long-day-factory.json` if missing and sets `lunchTime`
|
||||
to now. If it warns that `startTime` is not set, pass that along — the user
|
||||
may have forgotten to run `long-day-start`.
|
||||
|
||||
3. Reply with light humor: bread-and-water break, the parole hearing, etc.
|
||||
Include the timestamp.
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
# Log start of lunch break.
|
||||
set -euo pipefail
|
||||
|
||||
F="$HOME/long-day-factory.json"
|
||||
TS="$(python3 -c 'import datetime;print(datetime.datetime.now().astimezone().isoformat(timespec="seconds"))')"
|
||||
|
||||
if [ ! -f "$F" ]; then
|
||||
printf '{\n "startTime": null,\n "lunchTime": null,\n "backToWork": null\n}\n' > "$F"
|
||||
fi
|
||||
|
||||
tmp="$(mktemp)"
|
||||
jq --arg ts "$TS" '.lunchTime = $ts' "$F" > "$tmp" && mv "$tmp" "$F"
|
||||
|
||||
echo "Lunch break started at $TS"
|
||||
|
||||
if [ "$(jq -r '.startTime' "$F")" = "null" ]; then
|
||||
echo "WARNING: startTime is not set — did you skip long-day-start this morning?"
|
||||
fi
|
||||
Reference in New Issue
Block a user