@vibes.diy/prompts 14.3.77 → 14.3.78
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/access.js +1 -1
- package/llms/access.js.map +1 -1
- package/llms/access.md +43 -22
- package/llms/backend.js.map +1 -1
- package/llms/backend.md +8 -1
- package/llms/callai.js +0 -1
- package/llms/callai.js.map +1 -1
- package/llms/callai.md +4 -4
- package/llms/fireproof.js +0 -1
- package/llms/fireproof.js.map +1 -1
- package/llms/fireproof.md +25 -25
- package/llms/image-gen.js +0 -1
- package/llms/image-gen.js.map +1 -1
- package/llms/pouf-event.md +2 -2
- package/llms/pouf-login.md +1 -1
- package/llms/pouf-quiz.md +1 -1
- package/llms/pouf-settings.md +1 -1
- package/llms/pouf-todo.md +1 -1
- package/llms/types.d.ts +0 -1
- package/llms/use-vibe.js +0 -1
- package/llms/use-vibe.js.map +1 -1
- package/llms/use-viewer.js +0 -1
- package/llms/use-viewer.js.map +1 -1
- package/llms/web-audio.md +1 -1
- package/mcp-footer.md +4 -1
- package/package.json +4 -4
- package/prompts.js +1 -1
- package/prompts.js.map +1 -1
- package/system-prompt-initial-oneshot.md +27 -16
- package/system-prompt-initial.md +28 -15
- package/system-prompt.md +19 -9
- package/llms/callai.initial.md +0 -265
- package/llms/fireproof.initial.md +0 -869
- package/llms/image-gen.initial.md +0 -220
- package/llms/use-vibe.initial.md +0 -59
- package/llms/use-viewer.initial.md +0 -319
package/llms/access.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const accessConfig = {
|
|
2
2
|
name: "access",
|
|
3
3
|
label: "access-js",
|
|
4
|
-
description: "server-side access.js file —
|
|
4
|
+
description: "server-side access.js file — the record rules every app ships with: who reads and writes each record, the creator granted at creation, invites into an object, membership/roles, approval-to-join, moderation, private per-user data, DMs. Name it on every first build; the one app that leaves it out is the one whose person asked in their own words for a single-user app or no sharing",
|
|
5
5
|
cues: [
|
|
6
6
|
"private",
|
|
7
7
|
"privately",
|
package/llms/access.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"access.js","sourceRoot":"","sources":["../../jsr/llms/access.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,WAAW;IAClB,WAAW,EACT,
|
|
1
|
+
{"version":3,"file":"access.js","sourceRoot":"","sources":["../../jsr/llms/access.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,WAAW;IAClB,WAAW,EACT,8XAA8X;IAChY,IAAI,EAAE;QACJ,SAAS;QACT,WAAW;QACX,SAAS;QACT,OAAO;QACP,QAAQ;QACR,QAAQ;QACR,SAAS;QACT,MAAM;QACN,OAAO;QACP,QAAQ;QACR,SAAS;QACT,YAAY;QACZ,aAAa;QACb,MAAM;QACN,OAAO;QACP,YAAY;QACZ,aAAa;QACb,cAAc;QACd,QAAQ;QACR,SAAS;QACT,SAAS;QACT,YAAY;QACZ,aAAa;QACb,aAAa;QACb,cAAc;QACd,eAAe;QACf,cAAc;QACd,eAAe;QACf,eAAe;QACf,IAAI;QACJ,KAAK;QACL,gBAAgB;QAChB,iBAAiB;QACjB,UAAU;QACV,WAAW;QACX,SAAS;QACT,WAAW;QACX,YAAY;QACZ,YAAY;QACZ,UAAU;QACV,gBAAgB;QAChB,aAAa;QACb,cAAc;QACd,YAAY;QACZ,SAAS;QACT,cAAc;QACd,eAAe;QACf,iBAAiB;QACjB,YAAY;KACb;CACF,CAAC"}
|
package/llms/access.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Access Control (`access.js`) — permission design
|
|
2
2
|
|
|
3
|
-
This doc is in view because the app is getting its `access.js`:
|
|
3
|
+
This doc is in view because the app is getting its `access.js`: a new app's first build writes its rules with its screens, and a later edit adds or changes them. Either way the records carry their keys (`creatorHandle` on the object, the parent id on each child, `authorHandle` on every record), and this build writes the rules that key on them. The rules and those keys are plumbing with nothing on screen of their own; the invite screen joins the build when the ask names other people, sharing, a group or a person by name, and is otherwise offered as an option after the build. Every app gets record rules unless the person asked for none in their own words, and the group shape taught below is the resting default. A person the ask names is let in by a record — see _A person the ask names is let in by a record_ below — so the build states the membership record's shape and the invite handler that writes it.
|
|
4
4
|
|
|
5
|
-
**
|
|
5
|
+
**When an edit adds the rules to an app that already exists, the edit owes only what the rules need.** Read `App.jsx` for the object type, the field that names its creator and the parent id its children carry; name the channels from those records; write the complete `access.js`; then change `App.jsx` only where the rules require it — stable creator membership, typed content queries, any write surface not yet gated on `can`, and the invite screen when the ask names other people, sharing or a group — with SEARCH/REPLACE edits. A file the rules do not touch is not emitted, and stays as it is.
|
|
6
6
|
|
|
7
7
|
**Honest copy:** until `access.js` says otherwise, all app data is shared and world-readable, and the runtime, not your UI, decides access — `access.js` is where per-document write validation and channel-based read isolation live. Write UI copy that describes what the rules actually do.
|
|
8
8
|
|
|
@@ -59,7 +59,7 @@ type AccessDescriptor = {
|
|
|
59
59
|
|
|
60
60
|
### Person or place: `audience` or `grant`
|
|
61
61
|
|
|
62
|
-
The question that decides which one a doc wants is whose thing it is: **personal content belongs to the PERSON; a contribution to a shared artifact belongs to the PLACE.** Someone's picks, favorites,
|
|
62
|
+
The question that decides which one a doc wants is whose thing it is: **personal content belongs to the PERSON; a contribution to a shared artifact belongs to the PLACE.** Someone's picks, favorites, badges, or profile items are the person's — give them an `audience` arm keyed on their own handle, so the reach tracks that person's settings and follows them everywhere. Guestbook entries, posts on a communal wall, items on a shared board are the place's — route them to the place's channel with `grant.public` or explicit grants exactly as the rest of this doc shows, unaffected by the author's later profile flips: a guestbook entry doesn't vanish because the signer went private.
|
|
63
63
|
|
|
64
64
|
### Two controls: a followers checkbox and an individual buddy picker
|
|
65
65
|
|
|
@@ -423,11 +423,11 @@ export function board(doc, oldDoc, user, ctx) {
|
|
|
423
423
|
|
|
424
424
|
`ctx.requireAccess(channel)` gates on **membership** (a `grant.users`/`grant.roles` grant), not `grant.public` (read-only) — so an open feed anyone signed-in may post to must not gate writes on it; check the author and route the doc. For writes needing no sign-in ("anyone can sign/submit"), return `allowAnonymous: true` instead of throwing on `!user`. A grant/share/request doc must also return `channels` — a channel-less result is rejected. On updates of shared-visible docs, keep ownership immutable (`doc.authorHandle !== oldDoc.authorHandle` → throw) rather than requiring the updater to BE the author — image version appends run as the viewing user, and an author-only update gate turns every other viewer's generation into a billed deny-retry. Reserve author-only updates for genuinely private per-user docs; on shared docs, let a non-author through only when `ctx.isImgGenVersionAppend(doc, oldDoc)` accepts the write (as `wall.post` above shows) — it permits exactly one legitimate ImgGen version append and requires every other field unchanged.
|
|
425
425
|
|
|
426
|
-
**Build the permission model around what a newcomer should be able to do.** When a stranger opens the app, they should immediately be able to do the thing it's _for_ — add their own
|
|
426
|
+
**Build the permission model around what a newcomer should be able to do.** When a stranger opens the app, they should immediately be able to do the thing it's _for_ — add their own entries, post a note, drop a pin, join a shared canvas. So the default is: every signed-in visitor is a first-class participant who creates their own objects and edits what they created (`doc.authorHandle === user.userHandle`, checking `oldDoc` on updates), from first load, with no one needing to let them in.
|
|
427
427
|
|
|
428
428
|
**When the person says "no sharing", "no access control" or "keep it single-user", that is the one case where `access.js` is left out altogether:** the app ships with no rules file, and the object id and `authorHandle` its records already carry are what let rules be added later without touching a doc.
|
|
429
429
|
|
|
430
|
-
**When the person asks for private per-user permissions — "each person sees only their own", "private to every user" — every visitor gets their own private space on a single per-user channel.** A
|
|
430
|
+
**When the person asks for private per-user permissions — "each person sees only their own", "private to every user" — every visitor gets their own private space on a single per-user channel.** A sleep log, a houseplant watering schedule, a savings jar, a notes app or a workout log where the data is one person's own routes every doc that visitor creates to the one channel keyed on their handle — `user:${user.userHandle}` — self-granted so only they read it, with `authorHandle: user.userHandle` fixed at create and held immutable on update (`oldDoc.authorHandle === user.userHandle`). Their whole collection lives on that single private channel, reachable from first load, each visitor's space entirely their own:
|
|
431
431
|
|
|
432
432
|
### `access.js`
|
|
433
433
|
```js partial
|
|
@@ -451,50 +451,50 @@ export function notes(doc, oldDoc, user, ctx) {
|
|
|
451
451
|
|
|
452
452
|
Every item a visitor creates lands on their own `user:<handle>` channel, private to them from the first load. Pair it with a small "Only you can see this" cue near their content. This is the shape whenever the app is one person's own collection kept for themselves — the whole space is one private channel, no membership step in the way. The word "personal" routes on what the data is FOR: a personal tracker/journal/notes app is this private per-user shape, while a personal blog or portfolio exists to be READ — that one is the publication shape below (public read + author-owned posts, a roster of one), not a private channel.
|
|
453
453
|
|
|
454
|
-
**When the prompt asks to share, invite, or collaborate — bring in a partner, a buddy, a friend, a team, or a group that co-edits — each shared thing becomes its own object others can be invited into.** A
|
|
454
|
+
**When the prompt asks to share, invite, or collaborate — bring in a partner, a buddy, a friend, a team, or a group that co-edits — each shared thing becomes its own object others can be invited into.** A seed-swap shelf you invite your sibling to, a board a group co-edits, a document you open to a collaborator: route that shared thing to its **own object channel** (`list:<id>`/`board:<id>`) and self-grant it at creation (`grant: { users: { [user.userHandle]: [ch] } }`), with the `authorHandle` create + `oldDoc` author checks so each item stays on its object. Then let the creator invite a chosen friend in: a `share` doc the creator authors grants that friend the same channel (`grant: { users: { [doc.invitee]: [ch] } }`), so they collaborate on that one list — sharing a single list or a whole space is the same grant at a different node of the object graph. A wall, guestbook, or map where each visitor adds their _own_ items is author-owned writes + public read: any signed-in visitor authors their own and everyone reads.
|
|
455
455
|
|
|
456
456
|
**When a user's work is private by default, show it — and offer a way to publish.** If everything a user does routes to a channel only they can read (a per-user `user:<handle>`, a private journal/notes/tracker with no `grant.public`), the UI must say so: a small, persistent "Only you can see this" / "Private to you" cue near their content, so no one wonders who's watching their unfinished work. Then, where sharing fits the app, give them a publish control — but publish at the granularity of a **channel**, not a doc: channels are the unit of read isolation, so adding `grant.public` to the shared `user:<handle>` channel would expose _every_ private item on it, not just the one they meant to share. To publish a single item, route it to its **own** channel and flip only that channel's read-grant from a `visibility` field the access fn reads — exactly the per-item-channel shape the worked example below uses (`const ch = \`entry:${doc._id}\`; const grant = { users: { [user.userHandle]: [ch] } }; if (doc.visibility === "public") grant.public = [ch];`) — for anonymous visitors, or grant a shared app channel for all granted members. Gate the control on `useVibe(dbName).can`, and reflect the result back in the affordance ("Published — anyone can see this", with an unpublish to flip it back). Making the user's _whole_ space public is fine when that's the intent; silently leaking their other private items by publishing one is the trap to avoid. **If the person asked, in their own words, to keep it to themselves — "only I", "just me", "nobody else" — do not add publish/share controls.** A privacy-sensitive domain on its own (a journal, a health tracker) is not that ask: it gets the two controls from _Two controls_ above, off until the person says so. Keep publish opt-in: for only-me apps, omit the publish UI entirely; for share-capable apps, make publish one tap for user-selected items. **Every app that is neither privacy-sensitive nor an only-me ask ships with a sharing path already in it: either an always-on shared channel its records land on, or a publish control.** **An open-nature app — an image or meme wall, a bingo card, a party game — puts its records on an always-on `grant.public` channel from the first rules it ships, builds no publish step, and admits anonymous readers**, so everyone with the link sees what people make the moment they make it. The always-on channel is the least-surprise shape for anything playful and low-stakes (an image or meme wall, a group list, a guestbook): a `grant.public` channel, a members' channel, or an `audience` arm, so a thing someone makes is seen the moment they make it. The publish control is the shape for work people draft first: the per-item channel whose read-grant flips from a `visibility` field, behind one tap. A publish control that names its destination — "Publish to the wall", "Share to the group" — is the best shape of the second, not a requirement. An ordinary app with neither is a bug: every record lands on a channel only its writer can read, and nobody asked for that.
|
|
457
457
|
|
|
458
458
|
**A share control is a link only where the record's channel admits anonymous readers; everywhere else it is the person picker, which takes a handle or an email and shows the invite as pending until they arrive.** A link — Copy link, the browser's share sheet, a QR code — is a share only when the person who opens it can read the thing: a record on a `grant.public` channel, always on or flipped by its `visibility` field. A record whose channel is reached only by grants is unreadable through a link, so sharing it means letting a person in: the `HandleInput` picker writes the share doc that grants their handle, exactly as the buddy picker above does, and the same picker takes an email address for someone who is not on the platform yet — it mails them an invite and hands the app an opaque `invite:<id>` subject to store as the invitee, which binds to their handle when they arrive, so the app never holds the address and `ViewerTag` shows them as invited until then and by their handle after. The one link that works on a grant-only thing is the one that lands on a `request` doc: it invites a knock, not a read. An app with a publish control changes the share control's shape with the record's state — the picker before the flip, the link after it.
|
|
459
459
|
|
|
460
|
-
**Worked example — a shared catalog people track against, with per-thing visibility (a
|
|
460
|
+
**Worked example — a shared catalog people track against, with per-thing visibility (a music practice ladder, a language drill board, a fitness ladder).** The catalog items are public objects anyone proposes; each person's progress is their own; and each person chooses — _once per item, never per entry_ — whether their practice tally is public (on the leaderboard) or buddy-only. The visibility choice lives on a per-`(person, item)` **tracking** record that sets the read-grant the entries routed to it inherit.
|
|
461
461
|
|
|
462
462
|
### `access.js`
|
|
463
463
|
```js partial
|
|
464
|
-
export function
|
|
464
|
+
export function pieces(doc, oldDoc, user, ctx) {
|
|
465
465
|
if (!user) throw { forbidden: "sign in" };
|
|
466
466
|
|
|
467
|
-
// A
|
|
468
|
-
if (doc.type === "
|
|
467
|
+
// A piece: a public object anyone proposes; everyone can read and adopt it.
|
|
468
|
+
if (doc.type === "piece") {
|
|
469
469
|
if (doc.authorHandle !== user.userHandle) throw { forbidden: "not author" };
|
|
470
470
|
if (oldDoc && doc.authorHandle !== oldDoc.authorHandle) throw { forbidden: "creator is fixed" };
|
|
471
|
-
return { channels: [`
|
|
471
|
+
return { channels: [`piece:${doc._id}`], grant: { public: [`piece:${doc._id}`] } };
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
-
// A tracking record: your enrollment in a
|
|
475
|
-
// read-grant on your per-
|
|
474
|
+
// A tracking record: your enrollment in a piece + ONE visibility choice. It sets the
|
|
475
|
+
// read-grant on your per-piece channel, so the check-ins routed there inherit it.
|
|
476
476
|
if (doc.type === "tracking") {
|
|
477
477
|
if (doc.authorHandle !== user.userHandle) throw { forbidden: "your own enrollment" };
|
|
478
478
|
if (oldDoc && oldDoc.authorHandle !== user.userHandle) throw { forbidden: "your own enrollment" };
|
|
479
|
-
const ch = `track:${doc.
|
|
479
|
+
const ch = `track:${doc.pieceId}:${user.userHandle}`;
|
|
480
480
|
const grant = { users: { [user.userHandle]: [ch] } }; // always yourself
|
|
481
481
|
if (doc.visibility === "public") grant.public = [ch]; // public -> counts on the leaderboard
|
|
482
482
|
else if (doc.buddyHandle) grant.users[doc.buddyHandle] = [ch]; // buddy-only -> you + your buddy
|
|
483
483
|
return { channels: [ch], grant };
|
|
484
484
|
}
|
|
485
485
|
|
|
486
|
-
// A check-in: author-owned, routed to your per-
|
|
486
|
+
// A check-in: author-owned, routed to your per-piece channel — it inherits that piece's visibility.
|
|
487
487
|
if (doc.type === "checkin") {
|
|
488
488
|
if (doc.authorHandle !== user.userHandle) throw { forbidden: "not your check-in" };
|
|
489
489
|
if (oldDoc && oldDoc.authorHandle !== user.userHandle) throw { forbidden: "not your check-in" };
|
|
490
|
-
return { channels: [`track:${doc.
|
|
490
|
+
return { channels: [`track:${doc.pieceId}:${user.userHandle}`] };
|
|
491
491
|
}
|
|
492
492
|
|
|
493
493
|
throw { forbidden: "unknown document type" };
|
|
494
494
|
}
|
|
495
495
|
```
|
|
496
496
|
|
|
497
|
-
The leaderboard is just the access model: read the public `track:` channels and sum them; each viewer additionally sees their own
|
|
497
|
+
The leaderboard is just the access model: read the public `track:` channels and sum them; each viewer additionally sees their own tallies and any buddy who granted them in. A practice log whose owner **asked to keep it to themselves** is instead the per-visitor shape shown above: every visitor's pieces and check-ins on their single `user:${user.userHandle}` channel, self-granted and private to them.
|
|
498
498
|
|
|
499
499
|
**Per-object collaboration is the resting shape of almost every app** (the second worked example above), and certainly of anything that says "invite", "join", "people can join", "collaborate", "share with", "together", "with my partner/team", or names a board/canvas/room/whiteboard a group co-edits — each shared thing is ONE object its members reach directly; it needs no owner. Use the per-object recipe: a channel per object, named from the record (`board:${doc._id}` on the object, `board:${doc.boardId}` on its children); the creator self-grants at creation (`grant: { users: { [user.userHandle]: [ch] } }`); child docs gate on `ctx.requireAccess(ch)` so any member edits any child in it (not just their own); a member-authored `share` doc grants a peer the same channel; a `request` doc — which takes **no** `requireAccess` — lets a not-yet-member ask to join. Keep the _object's own_ creator field write-once (`if (oldDoc && doc.author !== oldDoc.author) throw`) and a child's object-id immutable. **Two traps to avoid:** don't build it as an open public feed where each person only owns their own items (that abandons the shared membership), and don't gate it behind a single writer (members self-serve via share/request). The app owner is not special in the data model: any signed-in person creates their own object and invites a friend into it, and the rule keys on `user.userHandle` or the object's creator, never on `user.isOwner`.
|
|
500
500
|
|
|
@@ -804,7 +804,7 @@ Channel `_id` is the channel identifier everywhere. The access function uses `do
|
|
|
804
804
|
|
|
805
805
|
### Example: Per-object sharing (collaborate on your own objects, no admin)
|
|
806
806
|
|
|
807
|
-
Reach for this by default, and certainly whenever the prompt says **invite, join, collaborate, share with, together, with my partner/team** — a shared
|
|
807
|
+
Reach for this by default, and certainly whenever the prompt says **invite, join, collaborate, share with, together, with my partner/team** — a shared seed-swap shelf you invite a sibling to, a whiteboard people can join, a quilting circle's pattern queue a group builds together, a tracker one person starts and later shares with a coach. A list app where every signed-in user makes their own lists, sees only their own, and can invite anyone to collaborate on a specific list — peer to peer, with no app admin in the loop. The pattern: **a channel per object** (`list:<id>`); the creator grants themselves that channel at creation; child docs (items) gate on `ctx.requireAccess` of the list's channel, so **any member edits any item**; any current member shares the list by granting another user the same channel. Membership is direct `grant.users`, so each viewer's access scales with their own memberships. Nothing a person writes reaches anyone else until they chose it: a per-object channel starts with its creator as the only reader, and every other reader arrives through a grant that creator wrote.
|
|
808
808
|
|
|
809
809
|
### `access.js`
|
|
810
810
|
```js partial
|
|
@@ -886,7 +886,7 @@ App.jsx — `access.hasChannel()` shows only the lists the viewer belongs to; `u
|
|
|
886
886
|
|
|
887
887
|
#### The same shape with a default object per person, and a member doc that names the friend
|
|
888
888
|
|
|
889
|
-
Reach for this variant whenever the app is built around a *thing* people come back to — a board, a
|
|
889
|
+
Reach for this variant whenever the app is built around a *thing* people come back to — a board, a seed-swap shelf, a quilting circle's pattern queue, a beekeeping club's hive log, a sourdough feeding log one person keeps and a baking friend is invited into next month. Everything above still holds; four additions make it feel finished from the first load:
|
|
890
890
|
|
|
891
891
|
- **Every signed-in person gets a default object automatically.** Its stable board record uses `` `default-${me.userHandle}` `` as its id and grants its creator the board channel and admin channel. Establish that record before the first content write or invitation, including when inviting is the first action. The creator remains a member when the board is empty, when a collaborator writes first, and after the last creator-authored item is deleted. Read the board by its fixed id before creating it; an existing board keeps its name and other settings. Child records route to the board channel; the board record carries the lasting creator grant. **The child doc stores that board id rather than having each writer derive one**: the create uses the displayed object’s id, with `` `default-${me.userHandle}` `` for a first action before any object exists and the rule holds it fixed from then on, so a card stays on the board its creator put it on however many people edit it later.
|
|
892
892
|
- **Membership is a `member` doc, and picking the friend is `HandleInput`** (`useViewer()`, see use-viewer.md — the platform's people-picker, so the handle on the doc is one the platform resolved). The doc grants the named person the object's channel: `` grant: { users: { [doc.userHandle]: [chan] } } ``.
|
|
@@ -1017,11 +1017,32 @@ function BoardWorkspace({ ensureDefaultBoard }) {
|
|
|
1017
1017
|
}
|
|
1018
1018
|
```
|
|
1019
1019
|
|
|
1020
|
+
#### The list holds what the person made and what they were let into
|
|
1021
|
+
|
|
1022
|
+
**The app's list of objects reads them by their `type`, so it holds the ones the signed-in person made and the ones a membership lets them into, read through the same rules.** The `member` record grants its board's channel, so the friend's own `useLiveQuery("type", { key: "board" })` returns that board beside their own the moment the membership lands; `creatorHandle` then says who made each one. A shared board carries `ViewerTag` for the person who made it, in the same list or in a section that renders once there is at least one, so a person keeping the app to themselves sees one plain list. Opening a shared board is the same `BoardContents`: its cards are read by its id and written with that id, the rules route them to its channel, and `can` gates each write.
|
|
1023
|
+
|
|
1024
|
+
```jsx
|
|
1025
|
+
const { ViewerTag } = useViewer();
|
|
1026
|
+
const { docs: boards } = useLiveQuery("type", { key: "board" });
|
|
1027
|
+
const sharedWithMe = boards.filter((board) => board.creatorHandle !== me?.userHandle);
|
|
1028
|
+
// …
|
|
1029
|
+
{sharedWithMe.length > 0 && (
|
|
1030
|
+
<section>
|
|
1031
|
+
<h2>Shared with you</h2>
|
|
1032
|
+
{sharedWithMe.map((board) => (
|
|
1033
|
+
<button key={board._id} type="button" onClick={() => setPickedBoardId(board._id)}>
|
|
1034
|
+
{board.name ?? board._id} <ViewerTag userHandle={board.creatorHandle} />
|
|
1035
|
+
</button>
|
|
1036
|
+
))}
|
|
1037
|
+
</section>
|
|
1038
|
+
)}
|
|
1039
|
+
```
|
|
1040
|
+
|
|
1020
1041
|
A new access function has no use for `user.isOwner` at all: a rule about a **person** keys on `user.userHandle` or the object's own creator field, and a rule about the app's **own automation** keys on `user.backend`.
|
|
1021
1042
|
|
|
1022
1043
|
#### A person the ask names is let in by a record
|
|
1023
1044
|
|
|
1024
|
-
When the instruction names somebody by their handle — "let my friend priya-k see and add to my
|
|
1045
|
+
When the instruction names somebody by their handle — "let my friend priya-k see and add to my seed-swap shelf", "an expedition notebook for me and theo" — **the build's part is the rule that admits a membership and the screen that writes one; the membership itself is a record.** It is the same `member` doc the rule admits and the invite surface above writes, saved for that handle on the asker's own default object once the rules are live, by whoever is driving the build acting as the maker, read back, and only then spoken of as in. An app whose first build carried the rules and no invite screen still states this shape in full, in `access.js`'s member branch: the type and fields that branch admits are the record a later save writes, and an edit that adds the screen afterwards writes that same record.
|
|
1025
1046
|
|
|
1026
1047
|
So the record's shape is a contract the files state plainly. The `_id` is fixed by the object and the handle — `` `member:${boardId}:${userHandle}` `` — so a second attempt is the same record rather than a twin, and a read by that id answers "is this person already in?" on its own. The fields are the ones the rule reads: `type`, `boardId`, `userHandle`, and `addedBy` set to the writer's own handle. The invite handler first ensures the stable board record, then writes the membership. The `member` rule admits an identical re-put, so a replay lands quietly. The board record keeps the creator in the collaboration independently of every content and invitation record. One invite handler in `App.jsx` writes exactly that shape, which is what makes the app's own screen and any later save agree on one record.
|
|
1027
1048
|
|
|
@@ -1039,9 +1060,9 @@ const addMember = async (boardId, handle) => {
|
|
|
1039
1060
|
<HandleInput onChange={(h) => h && addMember(board._id, h)} placeholder="Add a friend…" />;
|
|
1040
1061
|
```
|
|
1041
1062
|
|
|
1042
|
-
**A handle is the thing the person typed as one — a platform handle, the same token `HandleInput` would resolve.** A plain first name ("share it with Priya") is a person the maker adds
|
|
1063
|
+
**A handle is the thing the person typed as one — a platform handle, the same token `HandleInput` would resolve.** A plain first name ("share it with Priya") or an email address is a person the maker adds through the invite screen, which takes a handle or an email: the build has no way to know which account that name means, so the invite screen ships with this build and the narration says the maker can add that person there.
|
|
1043
1064
|
|
|
1044
|
-
That bounds what the build's own closing line says: the rules and the screen it just wrote are what the files carry, so the honest sentence is _"your
|
|
1065
|
+
That bounds what the build's own closing line says: the rules and the screen it just wrote are what the files carry, so the honest sentence is _"your seed-swap shelf now admits a membership for priya-k, and the invite screen writes one"_. _"priya-k is in"_ belongs to the save that follows — the read for an existing membership, the write in this shape, and the read that finds it afterwards.
|
|
1045
1066
|
|
|
1046
1067
|
## More worked round-trip examples
|
|
1047
1068
|
|
package/llms/backend.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../../jsr/llms/backend.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../../jsr/llms/backend.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,aAAa,GAAc;IACtC,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,YAAY;IACnB,WAAW,EACT,uXAAuX;IAOzX,IAAI,EAAE,CAAC,QAAQ,EAAE,YAAY,CAAC;CAC/B,CAAC"}
|
package/llms/backend.md
CHANGED
|
@@ -696,6 +696,13 @@ upstream that can be down, input that can be malformed — catches it and answer
|
|
|
696
696
|
`{ ok: false, reason }` with a status the app can show, and the platform's 500
|
|
697
697
|
stays the signal for a bug to fix.
|
|
698
698
|
|
|
699
|
+
A connected GitHub repository's deliveries arrive here too, as a `POST` to
|
|
700
|
+
`/_api/github-webhook`, already verified by the platform, with the event name
|
|
701
|
+
in `x-vibes-github-event`, GitHub's delivery id in `x-vibes-github-delivery`
|
|
702
|
+
(key writes by it — a delivery can arrive twice), and an untrusted third-party
|
|
703
|
+
body; a `4xx` ends the delivery, and a throw marks it failed (GitHub does not
|
|
704
|
+
retry it).
|
|
705
|
+
|
|
699
706
|
`/_api` opens to every caller once the app is published. Before its first
|
|
700
707
|
publish, and after the owner unpublishes it, the routes answer the app's own
|
|
701
708
|
people — its owner, its developers, and anyone it is shared with — and
|
|
@@ -881,7 +888,7 @@ Two rules keep change-reactions sane:
|
|
|
881
888
|
an unguarded write-back loops on itself.
|
|
882
889
|
2. **Write derived docs to a different database** than the one that triggered
|
|
883
890
|
the event. A backend write triggers `onChange` again (one generation deeper);
|
|
884
|
-
the platform
|
|
891
|
+
the platform stops the chain silently after four generations, but a tight
|
|
885
892
|
same-database ping-pong is still wasted work. Different db + dbName guard
|
|
886
893
|
makes loops structurally impossible.
|
|
887
894
|
|
package/llms/callai.js
CHANGED
package/llms/callai.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"callai.js","sourceRoot":"","sources":["../../jsr/llms/callai.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;IACf,WAAW,EAAE,kDAAkD;IAC/D,
|
|
1
|
+
{"version":3,"file":"callai.js","sourceRoot":"","sources":["../../jsr/llms/callai.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;IACf,WAAW,EAAE,kDAAkD;IAC/D,YAAY,EAAE,SAAS;IACvB,UAAU,EAAE,QAAQ;CACrB,CAAC"}
|
package/llms/callai.md
CHANGED
|
@@ -10,15 +10,15 @@ Name what the app does in the app's own words. The function name `callAI` stays
|
|
|
10
10
|
|
|
11
11
|
## Text to records
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
When the person's own words describe input in the shape they already have it — typing entries in their own words, pasting a chat, replies or a list, a photo, adding things however they like — the sentence composer is the front door they asked for. When a specified request names its fields or features and describes no such input, the front door is a plain Add form for those fields; adding by sentence is the first of the closing `▸` options, phrased for this app, such as "Add plants by typing a sentence like 'basil and two tomatoes, bed 3'", and Ask is an option too. An open-ended request may open with the composer as one of its one or two alive defaults. Keep quantity steppers, claim buttons, and toggles on existing records as direct controls; they complement sentence creation. A name-only list, a simple message, and a timer stay direct because their input already is the whole record or an explicit setting.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
When the composer is on screen, wire these visible actions in the same build, using the app's own record names. One composer has Add and Ask actions. Add extracts and normalizes facts, saves each record immediately, and shows saved records with edit actions; one item and a pasted batch share this action. Each saved row has Change by sentence: selecting it changes Add to Apply correction, which saves onto that same record id. Ask sends the typed question with the relevant saved records and displays a read-only answer beside the composer. Edit opens the selected row’s populated fields. One parent-owned Undo restores the latest successful creation batch or the previous document from either a sentence correction or a field edit.
|
|
16
16
|
|
|
17
|
-
A record starts as a sentence. For
|
|
17
|
+
A record the person describes in their own words starts as a sentence. For that intake, use one text box or the app's chat composer, extract the person's facts into the document's fields, normalize them, and save immediately in that same submit action. Show the saved record with editing controls. A pasted list becomes individual records through an array schema. Field-by-field controls belong to the edit view of a saved record. One new record and a pasted batch use the same composer. Opening a saved row’s Edit action reveals its populated field controls. A message whose text IS the record can save directly; extraction is useful when the person would otherwise fill several fields. Requested AI generation remains available for creative work.
|
|
18
18
|
|
|
19
19
|
The extraction schema names the same editable fields the app writes to its documents. Normalize the parsed output into that shape before saving or rendering: check strings, finite numbers, enum values and arrays (including their members), and project only the fields the app owns. Keep `_id`, authorship, parent ids and sharing fields under app control. Submitting the sentence commits the normalized records automatically. The saved card shows the understood facts and is the confirmation; editing follows persistence. For an edit by sentence, pass the current editable fields plus the correction through the same single-record schema, then write the normalized fields onto that saved record's trusted identity.
|
|
20
20
|
|
|
21
|
-
After each successful creation, sentence correction or field edit, the parent owns one Undo action. Keep the created ids or the previous document until the next successful write replaces them; a detail editor reports its previous document to that parent after its save succeeds. Undo deletes the created records or puts the previous document back. An explicit setting — a number, a date, a time, a choice, an on/off state — stays a direct control. The schema can extract ordinary quantities the person describes, such as two tents or six servings, while a saved row keeps its quantity control. Critical values (a dose, a price, a deadline, a timer, a recipient) are set directly. A multi-field record
|
|
21
|
+
After each successful creation, sentence correction or field edit, the parent owns one Undo action. Keep the created ids or the previous document until the next successful write replaces them; a detail editor reports its previous document to that parent after its save succeeds. Undo deletes the created records or puts the previous document back. An explicit setting — a number, a date, a time, a choice, an on/off state — stays a direct control. The schema can extract ordinary quantities the person describes, such as two tents or six servings, while a saved row keeps its quantity control. Critical values (a dose, a price, a deadline, a timer, a recipient) are set directly. A multi-field record the person describes in their own words starts with the composer.
|
|
22
22
|
|
|
23
23
|
This complete example covers **one sentence → one task**, **pasted list → many tasks**, **a selected task + correction → the same task**, **questions from the same box**, and **Undo after a save**. Every new submission uses the array schema, whether it names one task or several. The person sets a due date in the saved task’s date control. A malformed response leaves the typed sentence and saved records available; the waiting state ends when the request settles.
|
|
24
24
|
|
package/llms/fireproof.js
CHANGED
package/llms/fireproof.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fireproof.js","sourceRoot":"","sources":["../../jsr/llms/fireproof.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAc;IACxC,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,cAAc;IACrB,WAAW,EAAE,+CAA+C;IAC5D,
|
|
1
|
+
{"version":3,"file":"fireproof.js","sourceRoot":"","sources":["../../jsr/llms/fireproof.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAc;IACxC,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,cAAc;IACrB,WAAW,EAAE,+CAA+C;IAC5D,YAAY,EAAE,eAAe;IAC7B,UAAU,EAAE,cAAc;CAC3B,CAAC"}
|
package/llms/fireproof.md
CHANGED
|
@@ -43,7 +43,7 @@ function NoteForm({ text }) {
|
|
|
43
43
|
|
|
44
44
|
### Basic Example
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
When the composer is on screen, wire these visible actions in the same build, using the app's own record names. One composer has Add and Ask actions. Add extracts and normalizes facts, saves each record immediately, and shows saved records with edit actions; one item and a pasted batch share this action. Each saved row has Change by sentence: selecting it changes Add to Apply correction, which saves onto that same record id. Ask sends the typed question with the relevant saved records and displays a read-only answer beside the composer. Edit opens the selected row’s populated fields. One parent-owned Undo restores the latest successful creation batch or the previous document from either a sentence correction or a field edit.
|
|
47
47
|
|
|
48
48
|
With the callai skill available, submitting words extracts and normalizes every task they name, then immediately saves one document per task. The saved task is the confirmation and remains editable, with Undo beside the intake after each save. The parent keeps the ids from the last creation or the previous version from an edit, so intake and saved-detail editors share one Undo action. `useLiveQuery` keeps saved tasks visible; `useDocument` supplies the detail editor only after a record exists. For a plain message whose text is already the whole record, save that text directly.
|
|
49
49
|
|
|
@@ -540,7 +540,7 @@ Pass `{ offlineQueue: false }` for **server-first, fail-fast** writes: a `put` r
|
|
|
540
540
|
|
|
541
541
|
```js
|
|
542
542
|
// Default (single-user apps): durable offline writes, no config needed.
|
|
543
|
-
const { useLiveQuery } = useFireproof("
|
|
543
|
+
const { useLiveQuery } = useFireproof("sightings");
|
|
544
544
|
|
|
545
545
|
// Collaborative app: fail fast instead of queueing a stale write.
|
|
546
546
|
const { useLiveQuery } = useFireproof("shared-board", { offlineQueue: false });
|
|
@@ -594,13 +594,13 @@ async function main() {
|
|
|
594
594
|
>>>>>>> REPLACE
|
|
595
595
|
```
|
|
596
596
|
|
|
597
|
-
To subscribe to real-time updates, use the `subscribe` method. This is useful for building backend event handlers or other server-side logic — for instance to send an email when the user
|
|
597
|
+
To subscribe to real-time updates, use the `subscribe` method. This is useful for building backend event handlers or other server-side logic — for instance to send an email when the user confirms a sighting:
|
|
598
598
|
|
|
599
599
|
```js
|
|
600
600
|
database.subscribe((changes) => {
|
|
601
601
|
changes.forEach((change) => {
|
|
602
|
-
if (change.
|
|
603
|
-
sendEmail(change.email, "
|
|
602
|
+
if (change.confirmed) {
|
|
603
|
+
sendEmail(change.email, "Sighting confirmed", "You have confirmed a sighting.");
|
|
604
604
|
}
|
|
605
605
|
});
|
|
606
606
|
}, true);
|
|
@@ -750,7 +750,7 @@ You can use React's `useState` to manage validation states and error messages. V
|
|
|
750
750
|
|
|
751
751
|
## Example React Application
|
|
752
752
|
|
|
753
|
-
Code listing for
|
|
753
|
+
Code listing for a bird sightings log App.jsx. Note the code ordering: hooks, then handlers, then classNames right before JSX.
|
|
754
754
|
|
|
755
755
|
### `App.jsx`
|
|
756
756
|
```js
|
|
@@ -760,32 +760,32 @@ import { Button, Card, CardContent, Input, Label } from "@vibes.diy/look";
|
|
|
760
760
|
|
|
761
761
|
export default function App() {
|
|
762
762
|
// 1. Hooks and document shapes
|
|
763
|
-
const { useLiveQuery, useDocument, database } = useFireproof("
|
|
763
|
+
const { useLiveQuery, useDocument, database } = useFireproof("birdLog");
|
|
764
764
|
|
|
765
765
|
const {
|
|
766
|
-
doc:
|
|
767
|
-
merge:
|
|
768
|
-
submit:
|
|
766
|
+
doc: newSighting,
|
|
767
|
+
merge: mergeNewSighting,
|
|
768
|
+
submit: submitNewSighting,
|
|
769
769
|
} = useDocument({
|
|
770
|
-
|
|
771
|
-
type: "
|
|
772
|
-
|
|
770
|
+
species: "",
|
|
771
|
+
type: "sighting",
|
|
772
|
+
confirmed: false,
|
|
773
773
|
createdAt: Date.now(),
|
|
774
774
|
});
|
|
775
775
|
|
|
776
|
-
const { docs:
|
|
777
|
-
key: "
|
|
776
|
+
const { docs: sightings } = useLiveQuery("type", {
|
|
777
|
+
key: "sighting",
|
|
778
778
|
descending: true,
|
|
779
779
|
});
|
|
780
780
|
|
|
781
781
|
// 2. Event handlers
|
|
782
782
|
const handleInputChange = (e) => {
|
|
783
|
-
|
|
783
|
+
mergeNewSighting({ species: e.target.value });
|
|
784
784
|
};
|
|
785
785
|
|
|
786
786
|
const handleSubmit = (e) => {
|
|
787
787
|
e.preventDefault();
|
|
788
|
-
|
|
788
|
+
submitNewSighting();
|
|
789
789
|
};
|
|
790
790
|
|
|
791
791
|
// 3. ClassNames — right before JSX, for the plain elements only; the look's
|
|
@@ -798,15 +798,15 @@ export default function App() {
|
|
|
798
798
|
// 4. JSX return
|
|
799
799
|
return (
|
|
800
800
|
<div className={`min-h-screen max-w-md mx-auto p-6 ${c.page}`}>
|
|
801
|
-
<h2 className="text-2xl font-bold mb-4">
|
|
801
|
+
<h2 className="text-2xl font-bold mb-4">Bird Sightings</h2>
|
|
802
802
|
<form onSubmit={handleSubmit} className="mb-4">
|
|
803
|
-
<Label htmlFor="
|
|
804
|
-
|
|
803
|
+
<Label htmlFor="species" className="mb-2 block">
|
|
804
|
+
Species
|
|
805
805
|
</Label>
|
|
806
|
-
<Input className="w-full" id="
|
|
806
|
+
<Input className="w-full" id="species" type="text" onChange={handleInputChange} value={newSighting.species} />
|
|
807
807
|
</form>
|
|
808
808
|
<ul className="space-y-3">
|
|
809
|
-
{
|
|
809
|
+
{sightings.map((doc) => (
|
|
810
810
|
<li key={doc._id}>
|
|
811
811
|
<Card>
|
|
812
812
|
<CardContent className="flex flex-col items-start">
|
|
@@ -815,10 +815,10 @@ export default function App() {
|
|
|
815
815
|
<input
|
|
816
816
|
className="mr-2"
|
|
817
817
|
type="checkbox"
|
|
818
|
-
checked={doc.
|
|
819
|
-
onChange={() => database.put({ ...doc,
|
|
818
|
+
checked={doc.confirmed}
|
|
819
|
+
onChange={() => database.put({ ...doc, confirmed: !doc.confirmed })}
|
|
820
820
|
/>
|
|
821
|
-
<span className="font-medium">{doc.
|
|
821
|
+
<span className="font-medium">{doc.species}</span>
|
|
822
822
|
</div>
|
|
823
823
|
<Button variant="destructive" size="sm" onClick={() => database.del(doc._id)}>
|
|
824
824
|
Delete
|
package/llms/image-gen.js
CHANGED
package/llms/image-gen.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-gen.js","sourceRoot":"","sources":["../../jsr/llms/image-gen.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAc;IACvC,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,kBAAkB;IACzB,WAAW,EAAE,0BAA0B;IACvC,
|
|
1
|
+
{"version":3,"file":"image-gen.js","sourceRoot":"","sources":["../../jsr/llms/image-gen.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,cAAc,GAAc;IACvC,IAAI,EAAE,WAAW;IACjB,KAAK,EAAE,kBAAkB;IACzB,WAAW,EAAE,0BAA0B;IACvC,IAAI,EAAE;QACJ,OAAO;QACP,QAAQ;QACR,KAAK;QACL,OAAO;QACP,QAAQ;QACR,SAAS;QACT,UAAU;QACV,QAAQ;QACR,cAAc;QACd,MAAM;QACN,cAAc;QACd,gBAAgB;KACjB;IACD,YAAY,EAAE,WAAW;IACzB,UAAU,EAAE,QAAQ;CACrB,CAAC"}
|
package/llms/pouf-event.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Pouf Event
|
|
2
2
|
|
|
3
|
-
A check-in desk for the door of an event:
|
|
3
|
+
A check-in desk for the door of an event: an astronomy night's arrivals, a wedding reception, a meetup's RSVPs, a workshop's sign-in sheet. Reach for it whenever the app's core is a list of people expected somewhere who get marked as arrived, with a running count of who is in and who is still on the way. Guests and their check-ins persist, so every volunteer at the door sees the same list on their own phone and it survives a reload.
|
|
4
4
|
|
|
5
5
|
Built from @vibes.diy/pouf components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
|
|
6
6
|
|
|
@@ -181,7 +181,7 @@ export default function App() {
|
|
|
181
181
|
|
|
182
182
|
{visible.length === 0 ? (
|
|
183
183
|
<Empty icon="search" title={guests.length === 0 ? "No guests yet" : "No guests found"}>
|
|
184
|
-
{guests.length === 0 ? "Add the
|
|
184
|
+
{guests.length === 0 ? "Add the arrivals list to start checking people in." : "Check the spelling or show everyone."}
|
|
185
185
|
</Empty>
|
|
186
186
|
) : (
|
|
187
187
|
<Stack gap={2}>
|
package/llms/pouf-login.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Pouf Login
|
|
2
2
|
|
|
3
|
-
The join step a member sees once they are signed in: a
|
|
3
|
+
The join step a member sees once they are signed in: a quilting circle's "tell us who you are", a writing group's member card, a team space's first-visit profile. Reach for it whenever the app wants its own profile for each person (the name they go by here, a short bio) before they take part. It is **not** a sign-in form: the platform owns sign-in, so this block never asks for an email, a password or a magic link. The visitor signs in through `useViewer().requestLogin()`, and only then fills in the profile the app keeps. Each profile persists, so a member joins once and finds their card on every visit and device.
|
|
4
4
|
|
|
5
5
|
Built from @vibes.diy/pouf components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
|
|
6
6
|
|
package/llms/pouf-quiz.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Pouf Quiz
|
|
2
2
|
|
|
3
|
-
A short multiple-choice quiz that keeps score:
|
|
3
|
+
A short multiple-choice quiz that keeps score: an astronomy club's star-chart check, a refresher round before a test, a pub quiz warm-up, a training check for new staff. Reach for it when the app asks a handful of questions one at a time, says right or wrong after each answer, ends on a score and lets people come back to beat it. Each finished attempt someone saves is its own document, so their past scores are there on the next visit and on any device.
|
|
4
4
|
|
|
5
5
|
Built from @vibes.diy/pouf components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
|
|
6
6
|
|
package/llms/pouf-settings.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Pouf Settings
|
|
2
2
|
|
|
3
|
-
A settings screen for each person's own preferences: the display name in a
|
|
3
|
+
A settings screen for each person's own preferences: the display name in a sleep log, reminder emails for a reading log, a compact or comfortable layout, how loud an alert should be. Reach for it whenever the app lets someone tune how it treats them and expects those choices to stick. Each person's settings persist as their own document, so a choice made on the phone is there on the laptop.
|
|
4
4
|
|
|
5
5
|
Built from @vibes.diy/pouf components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
|
|
6
6
|
|
package/llms/pouf-todo.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Pouf Todo
|
|
2
2
|
|
|
3
|
-
A checklist the person adds to, filters and ticks off:
|
|
3
|
+
A checklist the person adds to, filters and ticks off: a beekeeper's hive inspection steps, a seed-swap shelf's restock run, today's errands, a quilting circle's supply checklist. Reach for it whenever the app's core is a list of short items that are either done or not. The tasks persist, so the list is still there on the next visit and on every device that opens the app.
|
|
4
4
|
|
|
5
5
|
Built from @vibes.diy/pouf components; persisted state lives in Fireproof. Every write surface is gated on `useVibe(dbName).can`.
|
|
6
6
|
|
package/llms/types.d.ts
CHANGED
package/llms/use-vibe.js
CHANGED
package/llms/use-vibe.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-vibe.js","sourceRoot":"","sources":["../../jsr/llms/use-vibe.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAc;IACtC,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,mBAAmB;IAC1B,WAAW,EAAE,kEAAkE;IAC/E,
|
|
1
|
+
{"version":3,"file":"use-vibe.js","sourceRoot":"","sources":["../../jsr/llms/use-vibe.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAc;IACtC,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,mBAAmB;IAC1B,WAAW,EAAE,kEAAkE;IAC/E,YAAY,EAAE,WAAW;IACzB,UAAU,EAAE,SAAS;CACtB,CAAC"}
|
package/llms/use-viewer.js
CHANGED
package/llms/use-viewer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-viewer.js","sourceRoot":"","sources":["../../jsr/llms/use-viewer.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAc;IACxC,IAAI,EAAE,YAAY;IAClB,KAAK,EAAE,iBAAiB;IACxB,WAAW,EAAE,wDAAwD;IACrE,
|
|
1
|
+
{"version":3,"file":"use-viewer.js","sourceRoot":"","sources":["../../jsr/llms/use-viewer.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,eAAe,GAAc;IACxC,IAAI,EAAE,YAAY;IAClB,KAAK,EAAE,iBAAiB;IACxB,WAAW,EAAE,wDAAwD;IACrE,YAAY,EAAE,WAAW;IACzB,UAAU,EAAE,WAAW;CACxB,CAAC"}
|
package/llms/web-audio.md
CHANGED
|
@@ -242,7 +242,7 @@ Tempo transport and lookahead
|
|
|
242
242
|
- Tempo mapping: `secondsPerBeat = 60 / bpm`; compute bars:beats:ticks → seconds on the audio clock (choose PPQ, e.g., 480/960).
|
|
243
243
|
- Lookahead window: maintain ~50–200 ms rolling schedule; enqueue with absolute `when` times in audio seconds.
|
|
244
244
|
|
|
245
|
-
Multi‑channel
|
|
245
|
+
Multi‑channel sample playback
|
|
246
246
|
|
|
247
247
|
- Pre‑decode all samples; never decode on hit.
|
|
248
248
|
- Per hit: create a fresh `AudioBufferSourceNode` and call `.start(when)`.
|
package/mcp-footer.md
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
## MCP Server Setup
|
|
2
2
|
|
|
3
|
-
Tools: vibes_list_apps, vibes_list_databases, vibes_get, vibes_put, vibes_delete, vibes_query, vibes_generate
|
|
3
|
+
Tools: vibes_list_apps, vibes_list_databases, vibes_get, vibes_put, vibes_delete, vibes_query, vibes_generate, vibes_add_seed_data, vibes_remove_seed_data
|
|
4
4
|
|
|
5
5
|
`vibes_generate` builds a brand-new vibe from a text prompt and deploys it live —
|
|
6
6
|
it takes minutes and spends your AI credits. The new app is separate from the
|
|
7
7
|
`--app-slug` this server was started with; the data tools keep pointing at that
|
|
8
8
|
one.
|
|
9
9
|
|
|
10
|
+
`vibes_add_seed_data` adds the live version's sample data (its `seed.json`) to the
|
|
11
|
+
app's databases, keeping your edits; `vibes_remove_seed_data` takes it out again.
|
|
12
|
+
|
|
10
13
|
Requires: npx vibes-diy login (one time)
|
|
11
14
|
|
|
12
15
|
### Claude Desktop / Cowork
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibes.diy/prompts",
|
|
3
|
-
"version": "14.3.
|
|
3
|
+
"version": "14.3.78",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"exports": {
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"license": "Apache-2.0",
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@adviser/cement": "~0.5.34",
|
|
42
|
-
"@vibes.diy/call-ai-v2": "14.3.
|
|
43
|
-
"@vibes.diy/identity": "14.3.
|
|
44
|
-
"@vibes.diy/use-vibes-types": "14.3.
|
|
42
|
+
"@vibes.diy/call-ai-v2": "14.3.78",
|
|
43
|
+
"@vibes.diy/identity": "14.3.78",
|
|
44
|
+
"@vibes.diy/use-vibes-types": "14.3.78",
|
|
45
45
|
"arktype": "~2.2.6",
|
|
46
46
|
"json-schema-faker": "~0.6.3"
|
|
47
47
|
},
|