@vibes.diy/prompts 14.1.37 → 14.1.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/llms/backend.md +81 -0
- package/package.json +4 -4
package/llms/backend.md
CHANGED
|
@@ -842,6 +842,87 @@ And **only say a thing you computed.** "Tonight", "this morning", "in an hour"
|
|
|
842
842
|
are claims about the reader's clock; if the code did not derive them from that
|
|
843
843
|
reader's zone, name the moment instead and let them place it.
|
|
844
844
|
|
|
845
|
+
### Recurring reminders on somebody's clock
|
|
846
|
+
|
|
847
|
+
**A recurring reminder fires on each person's own clock, never the server's.**
|
|
848
|
+
Once a reminder repeats — "every weekday at 7" — the zone stops being one
|
|
849
|
+
setting on one schedule document and becomes a property of each person the
|
|
850
|
+
reminder is for. Everything below is per person, and none of it is the
|
|
851
|
+
server's day or the server's hour.
|
|
852
|
+
|
|
853
|
+
**Capture the zone as an effect, not as a question.** Do not ask them for a
|
|
854
|
+
timezone: the browser already knows it, so write it once when they first sign
|
|
855
|
+
in and leave it alone. Store it where the reminder is addressed — on the
|
|
856
|
+
person's own profile document when the list is shared — and guard the write so
|
|
857
|
+
it only ever happens on a real change, or the effect re-fires forever.
|
|
858
|
+
|
|
859
|
+
**Derive the weekday and the hour together, in that zone, from one
|
|
860
|
+
`formatToParts` call.** `getUTCDay()`/`getUTCHours()` answer a question about
|
|
861
|
+
the machine the handler happens to be running on; at 07:00 in Los Angeles it is
|
|
862
|
+
already a different day in UTC, so a weekday gate on the server's clock silently
|
|
863
|
+
drops Monday mornings and fires on Saturday ones.
|
|
864
|
+
|
|
865
|
+
**An unrecognised zone string throws.** `Intl.DateTimeFormat` raises a
|
|
866
|
+
`RangeError` on a zone it does not know, so in a loop over people the formatting
|
|
867
|
+
goes in a `try` and a bad profile is skipped — one stale record must not stop
|
|
868
|
+
everybody else's reminder.
|
|
869
|
+
|
|
870
|
+
The unit of work is that person's local date (`en-CA` formats it as
|
|
871
|
+
`YYYY-MM-DD`), keyed per person, per "A tick that repeats is not a run that
|
|
872
|
+
repeats" above: the interval is only how often the handler wakes up.
|
|
873
|
+
|
|
874
|
+
App.jsx — write the zone once, when they arrive:
|
|
875
|
+
|
|
876
|
+
```jsx
|
|
877
|
+
useEffect(() => {
|
|
878
|
+
if (!me?.userHandle) return;
|
|
879
|
+
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
880
|
+
if (!timeZone || myProfile?.timeZone === timeZone) return; // already stored — don't churn
|
|
881
|
+
database.put({ _id: `profile:${me.userHandle}`, type: "profile", userHandle: me.userHandle, timeZone });
|
|
882
|
+
}, [me?.userHandle, myProfile?.timeZone]);
|
|
883
|
+
```
|
|
884
|
+
|
|
885
|
+
backend.js — evaluate each person in their own zone:
|
|
886
|
+
|
|
887
|
+
```js
|
|
888
|
+
export const config = { scheduled: { interval: "15m" } };
|
|
889
|
+
const WEEKDAYS = new Set(["Mon", "Tue", "Wed", "Thu", "Fri"]);
|
|
890
|
+
|
|
891
|
+
export async function scheduled(event, ctx) {
|
|
892
|
+
const at = new Date(event.scheduledTime);
|
|
893
|
+
const profiles = await ctx.db.query({ db: DB, field: "type", key: "profile", limit: 500 });
|
|
894
|
+
ctx.log("debug", "reminder tick", { profiles: profiles.length });
|
|
895
|
+
|
|
896
|
+
for (const profile of profiles) {
|
|
897
|
+
const { timeZone, userHandle } = profile;
|
|
898
|
+
if (!timeZone || !userHandle) continue;
|
|
899
|
+
let weekday, hour, dateKey;
|
|
900
|
+
try {
|
|
901
|
+
// One formatter, one zone: the weekday and the hour must agree about the day.
|
|
902
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
903
|
+
timeZone,
|
|
904
|
+
weekday: "short",
|
|
905
|
+
hour: "2-digit",
|
|
906
|
+
hourCycle: "h23",
|
|
907
|
+
}).formatToParts(at);
|
|
908
|
+
weekday = parts.find((p) => p.type === "weekday")?.value;
|
|
909
|
+
hour = Number(parts.find((p) => p.type === "hour")?.value);
|
|
910
|
+
dateKey = new Intl.DateTimeFormat("en-CA", { timeZone }).format(at); // "2026-09-18", their day
|
|
911
|
+
} catch {
|
|
912
|
+
continue; // unrecognised zone on one profile — skip the person, not the tick
|
|
913
|
+
}
|
|
914
|
+
if (!WEEKDAYS.has(weekday) || hour !== 7) continue;
|
|
915
|
+
|
|
916
|
+
const id = `morningReminder:${userHandle}:${dateKey}`; // the unit of work, per person
|
|
917
|
+
if (await ctx.db.get(id, { db: DB })) continue; // this morning is already done
|
|
918
|
+
await ctx.db.put(
|
|
919
|
+
{ _id: id, type: "morningReminder", ownerHandle: userHandle, date: dateKey, checkedAt: at.toISOString() },
|
|
920
|
+
{ db: DB }
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
```
|
|
925
|
+
|
|
845
926
|
### An unattended tick reports what it did
|
|
846
927
|
|
|
847
928
|
**An unattended tick earns its spend.** Nobody is watching a scheduled run, so
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibes.diy/prompts",
|
|
3
|
-
"version": "14.1.
|
|
3
|
+
"version": "14.1.38",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"exports": {
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
"license": "Apache-2.0",
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@adviser/cement": "~0.5.34",
|
|
37
|
-
"@vibes.diy/call-ai-v2": "14.1.
|
|
38
|
-
"@vibes.diy/identity": "14.1.
|
|
39
|
-
"@vibes.diy/use-vibes-types": "14.1.
|
|
37
|
+
"@vibes.diy/call-ai-v2": "14.1.38",
|
|
38
|
+
"@vibes.diy/identity": "14.1.38",
|
|
39
|
+
"@vibes.diy/use-vibes-types": "14.1.38",
|
|
40
40
|
"arktype": "~2.2.3",
|
|
41
41
|
"json-schema-faker": "~0.6.3"
|
|
42
42
|
},
|