@vibes.diy/prompts 14.3.161 → 14.3.163

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 CHANGED
@@ -100,11 +100,13 @@ visitor can invoke must not run owner-privileged.
100
100
 
101
101
  ### Taking on the authorization job: `config.fetch.unfilteredReads`
102
102
 
103
- Because the `fetch` lane runs as the calling user, a `fetch` handler by default
104
- reads nothing for a caller with no session, and cannot read an access-fn-bound
105
- database without an opt-in. Some routes legitimately need to: a calendar feed at
106
- `GET /_api/faves.ics?t=<token>` is fetched by a calendar app that carries no
107
- login, and the docs it serves are private to one user. For those, `backend.js`
103
+ Because the `fetch` lane runs as the calling user, a signed-in caller's
104
+ `fetch` handler reads exactly what that caller could read from their own page —
105
+ an access-fn-bound database comes back filtered to their channels, like
106
+ `onChange` reads for its triggering user. A caller with no session reads the
107
+ databases the opt-in below names. Some routes need exactly that: a calendar
108
+ feed at `GET /_api/faves.ics?t=<token>` is fetched by a calendar app that carries
109
+ no login, and the docs it serves are private to one user. For those, `backend.js`
108
110
  can opt in — per database, `fetch` lane only:
109
111
 
110
112
  ```js
@@ -155,8 +157,10 @@ const res = await ctx.fetch("https://api.example.com/x", { headers }); // outbou
155
157
  await ctx.notify({ toHandle: "alice", body: "Your turn", dedupeKey: "game-7-turn-3", path: "#game-7" }); // one participant; `path` optional; throws on failure
156
158
  ctx.log("info", "tick finished", { written: 3 }); // diagnostics — read back with: vibes-diy app logs owner/slug
157
159
  const gh = await ctx.github.fetch("/repos/acme/site/issues", { method: "POST", body: { title: "Filed from the vibe" } }); // connected GitHub repo
160
+ const routes = await ctx.github.routes(); // [{ repo, accountLogin, binderHandle, installationId }] — who connected which repo; no GitHub call
158
161
  ```
159
162
 
163
+ - An app that works with somebody's GitHub repo loads the `github` skill: the connect link, `config.github`, `ctx.github.routes()`, deliveries and a complete example.
160
164
  - `ctx.github.fetch(path, init)` calls the GitHub REST API **as the GitHub App
161
165
  installation the owner connected to this vibe**. It is the only GitHub surface
162
166
  a backend has: `path` is a GitHub API path rooted at `/` (`/repos/…`, plus
@@ -182,6 +186,58 @@ const gh = await ctx.github.fetch("/repos/acme/site/issues", { method: "POST", b
182
186
  `permission_not_granted` — the installation lacks that permission, or
183
187
  `upstream_error`); branch on `err.reason`, and tell the user which one it was.
184
188
 
189
+ - **Connecting a repository is a link, not a call.** The page links to the
190
+ PLATFORM's `/github/install?vibe=<owner>/<slug>` with an **absolute** URL in a
191
+ **new tab** — never a root-relative `/github/install` (the app is served from
192
+ its own host, where that path is not the platform's) and never `fetch` (the
193
+ next stop is github.com, and the consent page refuses to load in a frame).
194
+ `buildGithubInstallUrl()` from `use-vibes` returns that absolute address for
195
+ the running vibe — on `https://vibes.diy`, or on the PR preview the vibe runs
196
+ under — so the page never writes the host or its own `<owner>/<slug>`:
197
+
198
+ ```jsx
199
+ import { buildGithubInstallUrl } from "use-vibes";
200
+
201
+ <a href={buildGithubInstallUrl()} target="_blank" rel="noopener">
202
+ Connect a GitHub repository
203
+ </a>;
204
+ ```
205
+
206
+ The owner goes straight to GitHub to pick repositories. By default only the
207
+ owner may connect one; to let **visitors** connect their own repositories (a
208
+ PR reviewer, a repo dashboard anyone can use), declare it in `backend.js`:
209
+
210
+ ```js
211
+ export const config = {
212
+ github: { bind: "anyone", why: "Reviews the pull requests you open and leaves comments on them." },
213
+ };
214
+ ```
215
+
216
+ `bind` is `"owner"` (the default) or `"anyone"`; with `"anyone"`, `why` is
217
+ required — one static sentence, 280 characters at most — because the platform
218
+ shows it on the consent page a visitor reads before going to GitHub. Write it
219
+ inline as `github: { … }` — a shorthand `{ github }` or a method is refused —
220
+ and a malformed `config.github` refuses the push. A visitor always passes
221
+ through that consent page: an install that skips it connects nothing. Repositories a visitor connects are
222
+ bound to this vibe like the owner's, so `ctx.github.fetch` and the
223
+ `/_api/github-webhook` deliveries cover them too; a repository someone else
224
+ already connected stays theirs.
225
+ - `ctx.github.routes()` lists the repos connected to THIS vibe and who
226
+ connected each one, as
227
+ `[{ repo, accountLogin, binderHandle, installationId }]`: `repo` is
228
+ `owner/name` (lowercase, as stored), `accountLogin` is the GitHub account the
229
+ App is installed on, `binderHandle` is the vibes.diy handle of the person who
230
+ connected it (`undefined` when that account has no handle), and
231
+ `installationId` is a number. It reads the platform's own records and makes
232
+ no GitHub call, so it is cheap enough to run on every request. An unconnected
233
+ vibe gets `[]`, never an error. This is how ONE vibe serves many people's
234
+ repos: key per-repo settings by `repo`, and let only the person whose handle
235
+ is `binderHandle` change them (compare it to `ctx.userInfo`).
236
+ `/installation/repositories` answers the same question from GitHub: with
237
+ repos from several installations it returns
238
+ `{ total_count, repositories }` holding only the repos connected to this
239
+ vibe, and ignores `per_page`/`page`.
240
+
185
241
  - `{ db }` names the Fireproof database (same names `App.jsx` uses with
186
242
  `useFireproof`). It is **required** — except inside `onChange`, where the
187
243
  database that triggered the event is the default.
@@ -252,14 +308,15 @@ const gh = await ctx.github.fetch("/repos/acme/site/issues", { method: "POST", b
252
308
  array operation (`.filter()`, `.map()`, spread) returns a plain array with no
253
309
  `next`. On the last page the property is absent, not undefined — `"next" in
254
310
  page` is `false`.
255
- - Both reads are read-gated as the acting identity, through the same gate:
256
- anonymous `fetch` callers are denied, and in `fetch` a database bound to an
257
- access function cannot be read at all (keep the fetch lane's read databases
258
- unbound, or declare `config.fetch.unfilteredReads`). In `onChange` a bound
259
- database reads **filtered to the triggering user's channels** — the same
260
- per-reader filter the client's own reads use, so the handler sees exactly
261
- what the user who triggered it could see: neighbouring docs for dedup, rank
262
- and "don't repeat what's already there" checks, and nothing privileged. In
311
+ - Both reads are read-gated as the acting identity, through the same gate. In
312
+ `onChange` and in a signed-in `fetch` a bound database reads **filtered to the
313
+ acting user's channels** — the same per-reader filter the client's own reads
314
+ use, so the handler sees exactly what that user could see: the triggering
315
+ user's neighbouring docs for dedup, rank and "don't repeat what's already
316
+ there" checks, or the calling user's own docs for a page's `apiFetch` route,
317
+ and nothing privileged. A doc outside those channels reads as `null` from
318
+ `get`, the same as one that isn't there. A `fetch` caller with no session
319
+ reads the databases `config.fetch.unfilteredReads` names. In
263
320
  `scheduled` (admin mode) reads are
264
321
  **unfiltered** — access-fn-bound databases return every doc, across all users
265
322
  and channels. Made for `scheduled` sweeps: read, decide, then `put`/`delete`.
@@ -707,9 +764,23 @@ stays the signal for a bug to fix.
707
764
  A connected GitHub repository's deliveries arrive here too, as a `POST` to
708
765
  `/_api/github-webhook`, already verified by the platform, with the event name
709
766
  in `x-vibes-github-event`, GitHub's delivery id in `x-vibes-github-delivery`
710
- (key writes by it — a delivery can arrive twice), and an untrusted third-party
711
- body; a `4xx` ends the delivery, and a throw marks it failed (GitHub does not
712
- retry it).
767
+ (key writes by it — a delivery can arrive twice), the handle of the person
768
+ who connected that repo in `x-vibes-github-binder` (left off when they have no
769
+ handle), and an untrusted third-party body; a `4xx` ends the delivery, and a
770
+ throw marks it failed (GitHub does not retry it). `x-vibes-github-binder` is
771
+ how a vibe shared by many people knows whose repo an event belongs to, and so
772
+ whose settings apply. The platform sets it, the same as
773
+ `x-vibes-github-event`, so you can trust it: any `x-vibes-*` header a caller
774
+ sends is deleted before the platform adds its own. It matches the
775
+ `binderHandle` that `ctx.github.routes()` returns for that repo.
776
+
777
+ A delivery **runs as the person who connected the repo**: `ctx.userInfo` is
778
+ them, `ctx.db` writes pass `access.js` as them (`user.backend === "fetch"`,
779
+ `user.userHandle` equal to `x-vibes-github-binder`), reads see their channels,
780
+ and `ctx.callAI` runs on their credits. So a review bot keeps each person's
781
+ records in that person's channel, and every repo's activity is paid for by
782
+ the person who connected it. The consent page tells them so before they
783
+ connect.
713
784
 
714
785
  `/_api` opens to every caller once the app is published. Before its first
715
786
  publish, and after the owner unpublishes it, the routes answer the app's own
@@ -774,21 +845,43 @@ where the first stopped.
774
845
 
775
846
  ### `backend.js`
776
847
  ```js
777
- export const config = { fetch: { unfilteredReads: ["rsvps"] } };
848
+ export const config = {
849
+ fetch: {
850
+ unfilteredReads: {
851
+ dbs: ["rsvps"],
852
+ why: "/admin/normalize serves only the app owner, checked against ctx.appInfo.ownerHandle before it reads",
853
+ },
854
+ },
855
+ };
856
+
857
+ const STATE_ID = "state:normalize";
858
+
859
+ function json(data, status) {
860
+ return new Response(JSON.stringify(data), { status: status ?? 200, headers: { "content-type": "application/json" } });
861
+ }
778
862
 
779
863
  export async function fetch(request, ctx) {
780
864
  const url = new URL(request.url);
781
- if (url.pathname !== "/admin/normalize") return new Response("not found", { status: 404 });
782
- if (ctx.user?.userHandle !== ctx.ownerHandle) return new Response("forbidden", { status: 403 });
783
- const page = await ctx.db.query("kind", { key: "rsvp", limit: 100, db: "rsvps" });
784
- for (const doc of page) {
785
- if (typeof doc.name === "string" && doc.name !== doc.name.trim()) {
786
- await ctx.db.put({ ...doc, name: doc.name.trim() }, { db: "rsvps" });
865
+ if (url.pathname !== "/admin/normalize") return json({ ok: false, reason: "not found" }, 404);
866
+ if (ctx.userInfo?.userHandle !== ctx.appInfo.ownerHandle) return json({ ok: false, reason: "owner only" }, 403);
867
+ // Progress lives in one state document read by id, so a second run picks up where the first stopped.
868
+ const state = await ctx.db.get(STATE_ID, { db: "rsvps" });
869
+ if (state?.done === true) return json({ ok: true, fixed: 0 });
870
+ let after = state?.after ?? undefined;
871
+ let fixed = 0;
872
+ do {
873
+ const page = await ctx.db.query({ db: "rsvps", field: "kind", key: "rsvp", limit: 100, after });
874
+ for (const doc of page) {
875
+ if (typeof doc.name === "string" && doc.name !== doc.name.trim()) {
876
+ await ctx.db.put({ ...doc, name: doc.name.trim() }, { db: "rsvps", id: doc._id });
877
+ fixed += 1;
878
+ }
787
879
  }
788
- }
789
- return new Response(JSON.stringify({ ok: true, more: page.next ?? null }), {
790
- headers: { "content-type": "application/json" },
791
- });
880
+ after = page.next; // absent on the last page
881
+ await ctx.db.put({ kind: "normalizeState", after: after ?? null, done: after === undefined }, { db: "rsvps", id: STATE_ID });
882
+ } while (after);
883
+ ctx.log("info", "normalized rsvp names", { fixed });
884
+ return json({ ok: true, fixed });
792
885
  }
793
886
  ```
794
887
 
@@ -926,6 +1019,11 @@ export async function onChange(event, ctx) {
926
1019
  }
927
1020
  ```
928
1021
 
1022
+ `fetch` reads the same way for a signed-in caller: when the page calls
1023
+ `apiFetch`, the handler runs as the visitor and a bound database returns the
1024
+ docs in their channels — the same set their page already shows them — so a
1025
+ route can sum, rank or reshape the caller's own docs server-side.
1026
+
929
1027
  ### Jobs that finish even when a run crashes
930
1028
 
931
1029
  **A job that survives a crash carries its status, its claim and its lease on the document.**
@@ -1,7 +1,7 @@
1
1
  export const connectionsConfig = {
2
2
  name: "connections",
3
3
  label: "Connections",
4
- description: "Connect a visitor's own GitHub, Threads or Instagram account with one click and read it from backend.js — config.connections, useConnection, @vibes.diy/social",
4
+ description: "Connect a visitor's own GitHub profile, Threads or Instagram account with one click and read it from backend.js — config.connections, useConnection, @vibes.diy/social",
5
5
  cues: [
6
6
  "connect my",
7
7
  "sign in with github",
@@ -1 +1 @@
1
- {"version":3,"file":"connections.js","sourceRoot":"","sources":["../../jsr/llms/connections.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,iBAAiB,GAAc;IAC1C,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,aAAa;IACpB,WAAW,EACT,gKAAgK;IAClK,IAAI,EAAE;QACJ,YAAY;QACZ,qBAAqB;QACrB,wBAAwB;QACxB,sBAAsB;QACtB,cAAc;QACd,YAAY;QACZ,WAAW;QACX,UAAU;QACV,cAAc;QACd,oBAAoB;QACpB,WAAW;QACX,SAAS;QACT,gBAAgB;KACjB;IACD,YAAY,EAAE,WAAW;IACzB,UAAU,EAAE,eAAe;CAC5B,CAAC"}
1
+ {"version":3,"file":"connections.js","sourceRoot":"","sources":["../../jsr/llms/connections.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,iBAAiB,GAAc;IAC1C,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,aAAa;IACpB,WAAW,EACT,wKAAwK;IAC1K,IAAI,EAAE;QACJ,YAAY;QACZ,qBAAqB;QACrB,wBAAwB;QACxB,sBAAsB;QACtB,cAAc;QACd,YAAY;QACZ,WAAW;QACX,UAAU;QACV,cAAc;QACd,oBAAoB;QACpB,WAAW;QACX,SAAS;QACT,gBAAgB;KACjB;IACD,YAAY,EAAE,WAAW;IACzB,UAAU,EAAE,eAAe;CAC5B,CAAC"}
@@ -23,6 +23,11 @@ A request that names one of the providers below and wants **their** data is a
23
23
  connection. A request for public data nobody has to log in for (a public feed,
24
24
  a public profile) is an ordinary `ctx.fetch` and needs no connection.
25
25
 
26
+ A request about somebody's GitHub **repos** — pull requests, issues, commits,
27
+ files, a bot that answers GitHub events — connects the repo through the
28
+ vibes.diy GitHub App instead: load the `github` skill. The GitHub row below is
29
+ the visitor's profile.
30
+
26
31
  ## The three moving parts
27
32
 
28
33
  **Declare the provider in `config.connections`, render the Connect button from
@@ -66,7 +71,7 @@ refuses the call, not because posting is forbidden but because nobody agreed to
66
71
  it.
67
72
 
68
73
  **GitHub is read-only on this lane** — there is no GitHub write scope to
69
- declare. Instagram views and plays (the `insights` edge) are not available
74
+ declare; reading and writing a repo is the `github` skill's GitHub App lane. Instagram views and plays (the `insights` edge) are not available
70
75
  either. Build the app around what the table gives you; do not add a token field
71
76
  for the rest.
72
77
 
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const githubConfig: LlmConfig;
package/llms/github.js ADDED
@@ -0,0 +1,21 @@
1
+ export const githubConfig = {
2
+ name: "github",
3
+ label: "GitHub repos",
4
+ description: "Work with somebody's GitHub repo — a pull request bot, a code reviewer, an issue sorter, a repo dashboard, anything reading files, commits or a README or answering GitHub webhooks — through the vibes.diy GitHub App: a Connect link to /github/install, config.github in backend.js, ctx.github.fetch for repo calls and the /github-webhook route for events (a visitor's GitHub profile alone is connections)",
5
+ cues: [
6
+ "my repo",
7
+ "github repo",
8
+ "pull request",
9
+ "pull requests",
10
+ "PR",
11
+ "PRs",
12
+ "code review",
13
+ "issues",
14
+ "readme",
15
+ "commits",
16
+ "github bot",
17
+ "webhook from github",
18
+ "github webhook",
19
+ ],
20
+ };
21
+ //# sourceMappingURL=github.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../jsr/llms/github.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,YAAY,GAAc;IACrC,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,cAAc;IACrB,WAAW,EACT,oZAAoZ;IACtZ,IAAI,EAAE;QACJ,SAAS;QACT,aAAa;QACb,cAAc;QACd,eAAe;QACf,IAAI;QACJ,KAAK;QACL,aAAa;QACb,QAAQ;QACR,QAAQ;QACR,SAAS;QACT,YAAY;QACZ,qBAAqB;QACrB,gBAAgB;KACjB;CACF,CAAC"}
package/llms/github.md ADDED
@@ -0,0 +1,564 @@
1
+ # GitHub — connect a repo to your app
2
+
3
+ An app that works with somebody's GitHub repo — answers its pull requests,
4
+ sorts its issues, reads its files, shows its commits — connects that repo in
5
+ one click through the **vibes.diy GitHub App**. The person presses Connect,
6
+ picks repos on GitHub's own screen, and lands back in your app. From then on
7
+ `backend.js` reads and writes those repos with `ctx.github.fetch`, and GitHub's
8
+ events for them arrive at your `/_api/github-webhook` route.
9
+
10
+ **The platform's GitHub App holds the credential, so the app carries no GitHub key of its own.**
11
+ The whole integration is a link, a declaration and `ctx.github.fetch`; the
12
+ person's consent and the credential both live on the platform. (An app built
13
+ without this skill asked its owner to register a GitHub OAuth App and paste its
14
+ client secret into the vibe's secrets — the GitHub App replaces every step of
15
+ that.)
16
+
17
+ ## Which lane — signal words
18
+
19
+ | The ask | Lane | What you write |
20
+ | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------- | ---------------------------------------------------------------------------------------------------- |
21
+ | "my repo", "my GitHub repo", pull requests, PRs, code review, issues, commits, files, a README, "a GitHub bot", "when someone opens a PR" | **The repo lane — this skill** | the `/github/install` link, `config.github`, `ctx.github.fetch`, the `/github-webhook` route |
22
+ | the visitor's GitHub **profile** — their name, avatar, bio next to their entries | **Connections** (`connections` skill) | `config.connections` with `provider: "github"`, `scopes: ["read:user"]`, and `useConnection` |
23
+ | public GitHub data nobody signs in for — stars or releases of a public repo, a public user's repos | **Plain `ctx.fetch`** | `ctx.fetch("https://api.github.com/repos/nodejs/node")` in `backend.js`, no connect step |
24
+
25
+ Repos, pull requests and issues always ride the repo lane, even when the ask
26
+ also says "sign in with GitHub": the Connections lane carries the profile, and
27
+ the GitHub App carries the repos. An app can use both side by side.
28
+
29
+ ## The three pieces
30
+
31
+ ### 1. Declare it — `backend.js`
32
+
33
+ **`backend.js` declares `config.github` with `bind` and a `why` sentence** the
34
+ visitor reads on the platform's consent page before GitHub opens:
35
+
36
+ ```js
37
+ export const config = {
38
+ github: {
39
+ bind: "anyone",
40
+ why: "Leaves a short note on each new pull request in the repos you pick.",
41
+ },
42
+ };
43
+ ```
44
+
45
+ - `bind: "anyone"` lets every signed-in visitor connect their **own** repos —
46
+ the shape for a tool other people use (a reviewer, a triager, a board anyone
47
+ brings their repos to). `bind: "owner"` (the default) keeps connecting to the
48
+ app's owner — the shape for one team's own repo.
49
+ - `why` is one static sentence, 280 characters at most, written to the visitor
50
+ in the app's own voice ("Sorts the issues people open in your repos with a
51
+ label."). It is required with `"anyone"`; write it for `"owner"` too, so a
52
+ remix that opens up to visitors already says what it does.
53
+ - A malformed `config.github` refuses the push, with a message naming the field.
54
+
55
+ ### 2. Connect it — `App.jsx`
56
+
57
+ **The Connect button is a link to `buildGithubInstallUrl()` from `use-vibes`, opened in a new tab**
58
+ with `target="_blank" rel="noopener"`. `buildGithubInstallUrl()` takes no
59
+ arguments and returns the platform's absolute
60
+ `/github/install?vibe=<ownerHandle>/<appSlug>` address for the app that is
61
+ running — on `https://vibes.diy`, or on the preview the app runs under — so the
62
+ link stays right in every copy and remix of the app. The app runs on its own
63
+ subdomain, so a path starting at `/github/install` would point at the app
64
+ itself, and the new tab gives the platform's consent page a whole window of its
65
+ own:
66
+
67
+ ```jsx
68
+ import { buildGithubInstallUrl } from "use-vibes";
69
+
70
+ <a href={buildGithubInstallUrl()} target="_blank" rel="noopener">Connect a GitHub repo</a>
71
+ ```
72
+
73
+ The app's owner goes straight to GitHub. A visitor first sees the platform's
74
+ consent page quoting your `why`; its Continue button carries the visitor on to
75
+ GitHub's install screen, where they pick the repos. **The platform builds every
76
+ step after `/github/install` itself, so the app's one link is
77
+ `buildGithubInstallUrl()`** — GitHub's own install page is reached only through
78
+ that door. When the new tab finishes, the person comes back to the app's tab,
79
+ so re-read the repo list when the window regains focus.
80
+ Connecting needs a signed-in visitor, so a signed-out visitor gets the sign-in
81
+ ask (`requestLogin` from `useViewer`) in that spot.
82
+
83
+ ### 3. Call and listen — `backend.js`
84
+
85
+ **Every call to a connected repo goes through `ctx.github.fetch`** — GitHub's
86
+ REST API, called as the GitHub App installation that covers that repo:
87
+
88
+ ```js
89
+ const res = await ctx.github.fetch(`/repos/${repo}/pulls/${number}/files?per_page=100`);
90
+ const files = await res.json();
91
+ await ctx.github.fetch(`/repos/${repo}/pulls/${number}/reviews`, {
92
+ method: "POST",
93
+ body: { commit_id: sha, event: "COMMENT", body: "Looks tidy." },
94
+ });
95
+ ```
96
+
97
+ `ctx.github.fetch` attaches the App's credential itself, so a repo call carries only its path, method and body.
98
+ `path` starts at `/`: any `/repos/{owner}/{repo}/…` path for a repo connected to
99
+ this app, plus `/installation/repositories`. Methods are GET, POST, PUT, PATCH
100
+ and DELETE; an object `body` is sent as JSON. It resolves a normal `Response`
101
+ (GitHub's own 404 or 422 included — read `res.ok` and `res.status`), and it
102
+ rejects with an `Error` whose `err.reason` names what happened:
103
+ `not_connected` (no repo connected yet), `unmodeled_endpoint` (a path outside
104
+ those, or a repo this app has not connected), `permission_not_granted`,
105
+ `unsupported_method`, `body_too_large`, `upstream_error`. Branch on
106
+ `err.reason` and tell the person which one it was.
107
+
108
+ **`ctx.github.routes()` lists the connected repos and who connected each** —
109
+ `[{ repo, accountLogin, binderHandle, installationId }]`, spending no GitHub
110
+ call. It is how a route answers "which of these repos are mine?": keep the rows
111
+ whose `binderHandle` is `ctx.userInfo.userHandle`. Check a repo name the page
112
+ sends against that list before building a path from it.
113
+
114
+ **A delivery arrives as `POST /github-webhook` with the event name in `x-vibes-github-event`**
115
+ (`pull_request`, `issues`, `push`, …) and GitHub's delivery id in
116
+ `x-vibes-github-delivery`. The platform has already verified it came from
117
+ GitHub, so the headers are trustworthy and the body is GitHub's payload.
118
+
119
+ - **A delivery runs as the person who connected the repo.** `ctx.userInfo` is
120
+ them, and its `ctx.db.put` writes pass `access.js` as them, with
121
+ `user.backend === "fetch"` — so a delivery can keep its own records in that
122
+ person's channel, and the page shows them live.
123
+ - **Claim each unit of work before spending on it.** GitHub can deliver the
124
+ same event twice, and a pull request is pushed to many times. Put a record
125
+ whose `_id` names the work — the repo, the number and the head commit, or the
126
+ delivery id — with `ifRev: null`; the first delivery writes it, and a repeat
127
+ meets `err.code === "conflict"` and answers `200` having done nothing.
128
+ - A `4xx` answer ends the delivery; a thrown handler marks it failed.
129
+
130
+ **Automatic work starts with the repo's team: read `author_association` off the delivery.**
131
+ A delivery runs as the person who connected the repo, so the work it takes on
132
+ by itself spends their credits (`ctx.callAI` included) and writes under their
133
+ name, and on a public repo anyone can open a pull request. GitHub stamps every
134
+ pull request, issue and comment with its author's place in the repo, so the
135
+ delivery already carries the answer, with no extra call:
136
+ `payload.pull_request.author_association`, `payload.issue.author_association`,
137
+ `payload.comment.author_association`. `OWNER`, `MEMBER` and `COLLABORATOR` are
138
+ the repo's team; every other value (`CONTRIBUTOR`, `FIRST_TIME_CONTRIBUTOR`,
139
+ `FIRST_TIMER`, `NONE`, `MANNEQUIN`) is anyone.
140
+
141
+ - **Each repo gets a `who` setting, `"team"` or `"anyone"`, starting at
142
+ `"team"`.** The person who connected the repo saves it, and the page shows it
143
+ as two plain choices: **People on the repo's team** and **Anyone who opens a
144
+ pull request** (for an issue bot, **Anyone who opens an issue**). An app whose
145
+ whole job is greeting newcomers starts at `"anyone"`, with the same two
146
+ choices.
147
+ - **Work from beyond the chosen circle waits for its person.** The delivery
148
+ records it in their channel, so it shows up live on their page, with a
149
+ one-tap **Review it now**: an `apiFetch` route, so the work runs as them and
150
+ the pull request hears from the app the moment they press it.
151
+ - Issue and comment bots read the same stamp off `payload.issue` and
152
+ `payload.comment`, and honour the same setting.
153
+
154
+ **Opening the app and spending on the work are separate dials.** An app can be
155
+ open for anyone to visit and read, while its costly work (a `ctx.callAI`
156
+ review, a comment posted to GitHub) runs only for the people who chose it. Set
157
+ each dial on its own:
158
+
159
+ | Dial | Who it decides | Where it lives |
160
+ | --- | --- | --- |
161
+ | Open the app and read its records | visitors | publishing (apps are public by default) and `access.js` channels and grants |
162
+ | Connect a repo | signed-in visitors | `config.github.bind` |
163
+ | Set off the costly work | pull request, issue and comment authors, and page callers | the repo's `who` setting on deliveries; a `ctx.userInfo` check against `binderHandle` on every route that spends |
164
+
165
+ So a review bot stays published and public, with a landing page that explains
166
+ it and a shared board that anyone can browse, while a stranger's pull request
167
+ or an anonymous page visit sets off no AI call. A route that only reads (a
168
+ public board, the page's own listing) spends nothing and can answer anyone. A
169
+ route that spends (`ctx.callAI`, a POST through `ctx.github.fetch`) first
170
+ checks that `ctx.userInfo?.userHandle` is the `binderHandle` of the repo it
171
+ touches, and answers everyone else with a plain `403` reason. Keep the app
172
+ open; put the gate on the spend.
173
+
174
+ ## A complete example — pull request size notes
175
+
176
+ Each new pull request in a connected repo gets a short review comment saying
177
+ how many lines it changes; past a size the person picks, the note adds where to
178
+ start reading. Anyone can connect their own repos, set their own size, and see
179
+ their notes land live. Pull requests from the repo's team get their note right
180
+ away; one from anyone else waits on the person's page with **Review it now**,
181
+ until they switch the repo to **Anyone who opens a pull request**.
182
+
183
+ ### `backend.js`
184
+ ```js app=size-notes
185
+ export const config = {
186
+ github: {
187
+ bind: "anyone",
188
+ why: "Leaves a short note on each new pull request in the repos you pick, saying how big the change is.",
189
+ },
190
+ };
191
+
192
+ const DB = "sizeNotes";
193
+ const DEFAULT_BIG_AT = 400;
194
+ const PR_ACTIONS = ["opened", "reopened", "synchronize"];
195
+ // The author_association values GitHub gives the people on a repo's team.
196
+ const TEAM = ["OWNER", "MEMBER", "COLLABORATOR"];
197
+ const DEFAULT_WHO = "team";
198
+
199
+ function json(data, status) {
200
+ return new Response(JSON.stringify(data), { status: status ?? 200, headers: { "content-type": "application/json" } });
201
+ }
202
+
203
+ function settingsId(repo) {
204
+ return `settings:${repo.toLowerCase()}`;
205
+ }
206
+
207
+ // The repos the signed-in caller connected to this app.
208
+ async function myRepos(ctx) {
209
+ const me = ctx.userInfo?.userHandle;
210
+ if (me === undefined) return [];
211
+ const routes = await ctx.github.routes();
212
+ return routes.filter((r) => r.binderHandle === me);
213
+ }
214
+
215
+ async function writeNote(ctx, repo, pr, bigAt) {
216
+ const res = await ctx.github.fetch(`/repos/${repo}/pulls/${pr.number}/files?per_page=100`);
217
+ if (res.ok === false) return { status: "failed", reason: `GitHub answered ${res.status} for the file list` };
218
+ const files = await res.json();
219
+ const lines = files.reduce((sum, f) => sum + f.additions + f.deletions, 0);
220
+ const largest = [...files].sort((a, b) => b.changes - a.changes)[0];
221
+ const body =
222
+ lines >= bigAt && largest !== undefined
223
+ ? `This pull request changes ${lines} lines across ${files.length} files. A good place to start reading: \`${largest.filename}\`.`
224
+ : `This pull request changes ${lines} lines across ${files.length} files.`;
225
+ const posted = await ctx.github.fetch(`/repos/${repo}/pulls/${pr.number}/reviews`, {
226
+ method: "POST",
227
+ body: { commit_id: pr.head.sha, event: "COMMENT", body },
228
+ });
229
+ if (posted.ok === false) return { status: "failed", reason: `GitHub answered ${posted.status} to the note` };
230
+ const review = await posted.json();
231
+ return { status: "done", lines, files: files.length, reviewUrl: review.html_url };
232
+ }
233
+
234
+ function noteId(repo, pr) {
235
+ return `note:${repo.toLowerCase()}#${pr.number}@${pr.head.sha}`;
236
+ }
237
+
238
+ function noteRecord(repo, pr, binderHandle, status) {
239
+ return { type: "note", repo, number: pr.number, title: pr.title, url: pr.html_url, author: pr.user?.login, binderHandle, status, at: Date.now() };
240
+ }
241
+
242
+ // The person's `who` setting decides whose pull requests get a note by themselves.
243
+ function takesOn(settings, pr) {
244
+ const who = settings?.who ?? DEFAULT_WHO;
245
+ return who === "anyone" || TEAM.includes(pr.author_association);
246
+ }
247
+
248
+ async function finishNote(ctx, id, repo, pr, bigAt) {
249
+ const outcome = await writeNote(ctx, repo, pr, bigAt).catch((err) => ({
250
+ status: "failed",
251
+ reason: err.reason === "permission_not_granted" ? "the GitHub App needs permission to review pull requests" : String(err.reason ?? err.message),
252
+ }));
253
+ const claimed = await ctx.db.get(id, { db: DB });
254
+ await ctx.db.put({ ...claimed, ...outcome }, { db: DB, id, ifRev: claimed._rev });
255
+ return { ok: outcome.status === "done", ...outcome };
256
+ }
257
+
258
+ async function noteOnPull(ctx, repo, pr, binderHandle) {
259
+ const settings = await ctx.db.get(settingsId(repo), { db: DB });
260
+ // From the team, or the person opened it to anyone: the note runs now. Otherwise it waits for them.
261
+ const status = takesOn(settings, pr) ? "running" : "waiting";
262
+ // One record per pull request and head commit: the first delivery claims it, a repeat steps aside.
263
+ const id = noteId(repo, pr);
264
+ try {
265
+ await ctx.db.put(noteRecord(repo, pr, binderHandle, status), { db: DB, id, ifRev: null });
266
+ } catch (err) {
267
+ if (err.code === "conflict") return { ok: true, skipped: "already-claimed" };
268
+ throw err;
269
+ }
270
+ if (status === "waiting") return { ok: true, waiting: pr.author_association };
271
+ return finishNote(ctx, id, repo, pr, settings?.bigAt ?? DEFAULT_BIG_AT);
272
+ }
273
+
274
+ // "Review it now": the person who connected the repo takes on a waiting pull request, as themselves.
275
+ async function reviewNow(request, ctx) {
276
+ const input = await request.json();
277
+ const mine = await myRepos(ctx);
278
+ const bound = mine.find((r) => r.repo.toLowerCase() === String(input.repo).toLowerCase());
279
+ if (bound === undefined) return json({ ok: false, reason: "Connect this repo first, and its pull requests open here." }, 404);
280
+ const res = await ctx.github.fetch(`/repos/${bound.repo}/pulls/${Number(input.number)}`);
281
+ if (res.ok === false) return json({ ok: false, reason: `GitHub answered ${res.status} for that pull request` }, 422);
282
+ const pr = await res.json();
283
+ const id = noteId(bound.repo, pr);
284
+ const held = await ctx.db.get(id, { db: DB });
285
+ if (held !== null && held.status !== "waiting") return json({ ok: true, skipped: "already-claimed" });
286
+ const record = held === null ? noteRecord(bound.repo, pr, bound.binderHandle, "running") : { ...held, status: "running" };
287
+ try {
288
+ await ctx.db.put(record, { db: DB, id, ifRev: held === null ? null : held._rev });
289
+ } catch (err) {
290
+ if (err.code === "conflict") return json({ ok: true, skipped: "already-claimed" });
291
+ throw err;
292
+ }
293
+ const settings = await ctx.db.get(settingsId(bound.repo), { db: DB });
294
+ const outcome = await finishNote(ctx, id, bound.repo, pr, settings?.bigAt ?? DEFAULT_BIG_AT);
295
+ return json(outcome, outcome.ok ? 200 : 422);
296
+ }
297
+
298
+ async function onDelivery(request, ctx) {
299
+ const event = request.headers.get("x-vibes-github-event");
300
+ if (event !== "pull_request") return json({ ok: true, ignored: event });
301
+ const payload = await request.json();
302
+ if (PR_ACTIONS.includes(payload.action) === false) return json({ ok: true, ignored: payload.action });
303
+ const repo = payload.repository?.full_name;
304
+ const pr = payload.pull_request;
305
+ if (typeof repo !== "string" || pr === undefined) return json({ ok: false, reason: "this delivery carries no pull request" }, 400);
306
+ // The delivery runs as the person who connected this repo.
307
+ const binderHandle = ctx.userInfo?.userHandle;
308
+ if (binderHandle === undefined) return json({ ok: false, reason: "this delivery arrived without its person" }, 422);
309
+ ctx.log("info", "pull request", {
310
+ repo,
311
+ number: pr.number,
312
+ author: pr.author_association,
313
+ delivery: request.headers.get("x-vibes-github-delivery"),
314
+ });
315
+ const outcome = await noteOnPull(ctx, repo, pr, binderHandle);
316
+ return json(outcome, outcome.ok || outcome.skipped ? 200 : 422);
317
+ }
318
+
319
+ async function listRepos(ctx) {
320
+ const rows = [];
321
+ for (const r of await myRepos(ctx)) {
322
+ const settings = await ctx.db.get(settingsId(r.repo), { db: DB });
323
+ rows.push({ repo: r.repo, bigAt: settings?.bigAt ?? DEFAULT_BIG_AT, who: settings?.who ?? DEFAULT_WHO });
324
+ }
325
+ return json({ ok: true, repos: rows });
326
+ }
327
+
328
+ async function saveSettings(request, ctx) {
329
+ const input = await request.json();
330
+ const mine = await myRepos(ctx);
331
+ const bound = mine.find((r) => r.repo.toLowerCase() === String(input.repo).toLowerCase());
332
+ if (bound === undefined) return json({ ok: false, reason: "Connect this repo first, and its settings open here." }, 404);
333
+ const bigAt = Math.max(1, Math.round(Number(input.bigAt) || DEFAULT_BIG_AT));
334
+ const who = input.who === "anyone" ? "anyone" : "team";
335
+ const existing = await ctx.db.get(settingsId(bound.repo), { db: DB });
336
+ await ctx.db.put(
337
+ { type: "settings", repo: bound.repo, binderHandle: bound.binderHandle, bigAt, who },
338
+ { db: DB, id: settingsId(bound.repo), ifRev: existing === null ? null : existing._rev }
339
+ );
340
+ return json({ ok: true, bigAt, who });
341
+ }
342
+
343
+ export async function fetch(request, ctx) {
344
+ const route = `${request.method} ${new URL(request.url).pathname}`;
345
+ const run = async () => {
346
+ if (route === "POST /github-webhook") return onDelivery(request, ctx);
347
+ if (route === "GET /repos") return listRepos(ctx);
348
+ if (route === "POST /settings") return saveSettings(request, ctx);
349
+ if (route === "POST /review") return reviewNow(request, ctx);
350
+ return json({ ok: false, reason: "not found" }, 404);
351
+ };
352
+ return run().catch((err) => {
353
+ ctx.log("error", "route failed", { route, reason: err.reason ?? err.code, message: String(err.message ?? err) });
354
+ return json({ ok: false, reason: err.reason ?? "error" }, err.reason === "not_connected" ? 409 : 500);
355
+ });
356
+ }
357
+ ```
358
+
359
+ ### `access.js`
360
+ ```js app=size-notes
361
+ // Notes and settings are written by backend.js: settings by POST /settings, notes by the GitHub
362
+ // delivery (which runs as the person who connected the repo) and by POST /review. Each lands in
363
+ // that person's channel.
364
+ export default function (doc, oldDoc, user, ctx) {
365
+ if (doc.type === "note" || doc.type === "settings") {
366
+ ctx.requireBackend("fetch");
367
+ const binder = doc.binderHandle;
368
+ if (typeof binder !== "string" || binder === "") throw { forbidden: "missing binderHandle" };
369
+ // write-once: a record stays with the person who connected its repo
370
+ if (oldDoc && oldDoc.binderHandle !== binder) throw { forbidden: "binderHandle is fixed" };
371
+ if (binder !== user.userHandle) throw { forbidden: "not your repo" };
372
+ const ch = `repo-of:${binder}`;
373
+ return { channels: [ch], grant: { users: { [binder]: [ch] } } };
374
+ }
375
+ throw { forbidden: "unknown document type" };
376
+ }
377
+ ```
378
+
379
+ ### `App.jsx`
380
+ ```jsx app=size-notes
381
+ import React, { useCallback, useEffect, useState } from "react";
382
+ import { apiFetch, buildGithubInstallUrl, useViewer } from "use-vibes";
383
+ import { useFireproof } from "use-fireproof";
384
+ import { Badge, Button, Field, Heading, Input, RowCard, Skeleton, Stack, Text } from "@vibes.diy/pouf";
385
+ import { RadioGroup } from "@vibes.diy/pouf/interactive";
386
+
387
+ const TONE = { done: "up", failed: "warn", running: "info", waiting: "info" };
388
+ const WHO_CHOICES = [
389
+ { value: "team", label: "People on the repo's team" },
390
+ { value: "anyone", label: "Anyone who opens a pull request" },
391
+ ];
392
+
393
+ function badgeText(n) {
394
+ if (n.status === "done") return `${n.lines} lines`;
395
+ if (n.status === "failed") return n.reason;
396
+ if (n.status === "waiting") return `From ${n.author ?? "someone new"}`;
397
+ return "Writing…";
398
+ }
399
+
400
+ function NoteRow({ note }) {
401
+ const [busy, setBusy] = useState(false);
402
+
403
+ // Runs as the person who connected the repo; the record turns to "done" live when the note lands.
404
+ async function reviewNow() {
405
+ setBusy(true);
406
+ await apiFetch("/review", {
407
+ method: "POST",
408
+ headers: { "content-type": "application/json" },
409
+ body: JSON.stringify({ repo: note.repo, number: note.number }),
410
+ });
411
+ setBusy(false);
412
+ }
413
+
414
+ return (
415
+ <RowCard>
416
+ <a className="underline" href={note.reviewUrl ?? note.url} target="_blank" rel="noreferrer">
417
+ #{note.number} {note.title}
418
+ </a>
419
+ <Badge tone={TONE[note.status] ?? "info"}>{badgeText(note)}</Badge>
420
+ {note.status === "waiting" && (
421
+ <Button type="button" size="sm" loading={busy} onClick={reviewNow}>
422
+ Review it now
423
+ </Button>
424
+ )}
425
+ </RowCard>
426
+ );
427
+ }
428
+
429
+ // The live ledger: each note record is written by the delivery itself, so new ones appear as
430
+ // pull requests open.
431
+ function RecentNotes({ repo }) {
432
+ const { useLiveQuery } = useFireproof("sizeNotes");
433
+ const { docs } = useLiveQuery("repo", { key: repo });
434
+ const notes = docs.filter((d) => d.type === "note").sort((a, b) => b.at - a.at).slice(0, 10);
435
+ if (notes.length === 0) return <Text muted>Open a pull request and its note shows up here and on GitHub.</Text>;
436
+ return (
437
+ <Stack gap={2}>
438
+ {notes.map((n) => (
439
+ <NoteRow key={n._id} note={n} />
440
+ ))}
441
+ </Stack>
442
+ );
443
+ }
444
+
445
+ function RepoPanel({ row }) {
446
+ const [bigAt, setBigAt] = useState(String(row.bigAt));
447
+ const [who, setWho] = useState(row.who);
448
+ const [message, setMessage] = useState("");
449
+
450
+ async function save() {
451
+ setMessage("Saving…");
452
+ const res = await apiFetch("/settings", {
453
+ method: "POST",
454
+ headers: { "content-type": "application/json" },
455
+ body: JSON.stringify({ repo: row.repo, bigAt: Number(bigAt), who }),
456
+ });
457
+ const body = await res.json();
458
+ setMessage(res.ok ? "Saved. The next pull request uses it." : body.reason);
459
+ }
460
+
461
+ return (
462
+ <Stack gap={3}>
463
+ <Heading level={2}>
464
+ <a href={`https://github.com/${row.repo}`} target="_blank" rel="noreferrer">
465
+ {row.repo}
466
+ </a>
467
+ </Heading>
468
+ <Field label="Suggest where to start reading at this many changed lines">
469
+ {(id, describedBy) => <Input id={id} describedBy={describedBy} value={bigAt} onChange={setBigAt} />}
470
+ </Field>
471
+ <RadioGroup label="Whose pull requests get a note right away" value={who} onChange={setWho} options={WHO_CHOICES} />
472
+ <Button type="button" size="sm" onClick={save}>
473
+ Save
474
+ </Button>
475
+ {message !== "" && <Text size="sm" muted>{message}</Text>}
476
+ <RecentNotes repo={row.repo} />
477
+ </Stack>
478
+ );
479
+ }
480
+
481
+ export default function App() {
482
+ const { viewer, isViewerPending, requestLogin } = useViewer();
483
+ const [state, setState] = useState({ loading: true, repos: [] });
484
+
485
+ const load = useCallback(async () => {
486
+ const res = await apiFetch("/repos");
487
+ const body = await res.json();
488
+ setState({ loading: false, repos: body.repos ?? [] });
489
+ }, []);
490
+
491
+ useEffect(() => {
492
+ if (isViewerPending === false) load();
493
+ }, [isViewerPending, viewer, load]);
494
+
495
+ // Connecting finishes in the tab the link opened; re-read the list when the person comes back.
496
+ useEffect(() => {
497
+ window.addEventListener("focus", load);
498
+ return () => window.removeEventListener("focus", load);
499
+ }, [load]);
500
+
501
+ return (
502
+ <main className="min-h-screen bg-background text-foreground font-sans mx-auto max-w-2xl p-6">
503
+ <Stack gap={5}>
504
+ <Heading level={1}>Pull request size notes</Heading>
505
+ <Text>
506
+ Connect a GitHub repo and each new pull request gets a short note on how big it is, with a place to start reading when it runs long. Your team's pull
507
+ requests get theirs right away, and the rest are one tap away here.
508
+ </Text>
509
+ {viewer && (
510
+ <a className="inline-block rounded-md bg-foreground px-4 py-2 font-bold text-background" href={buildGithubInstallUrl()} target="_blank" rel="noopener">
511
+ Connect a GitHub repo
512
+ </a>
513
+ )}
514
+ {isViewerPending === false && !viewer && (
515
+ <Button type="button" onClick={requestLogin}>
516
+ Sign in to connect a repo
517
+ </Button>
518
+ )}
519
+ {state.loading ? <Skeleton /> : state.repos.map((row) => <RepoPanel key={row.repo} row={row} />)}
520
+ </Stack>
521
+ </main>
522
+ );
523
+ }
524
+ ```
525
+
526
+ `GET /repos`, `POST /settings` and the delivery each run as a signed-in
527
+ person, so their `ctx.db` reads of `sizeNotes` come back filtered to that
528
+ person's own channels — the same records their page sees — with no extra
529
+ config. Before writing, a route still checks the repo against the ones
530
+ `ctx.github.routes()` says the caller connected. A pull request from beyond
531
+ the repo's `who` setting is claimed as a `waiting` record, and **Review it
532
+ now** calls `POST /review`, which runs the same note as the person who pressed
533
+ it. The page reads its notes
534
+ through `useLiveQuery`, which shows each person the records in their own
535
+ channel.
536
+
537
+ ## Good to know
538
+
539
+ - **The page calls its routes with `apiFetch`** from `use-vibes`, so the route
540
+ runs as the signed-in visitor and `ctx.userInfo` says whose repos to list.
541
+ - **The repo's team comes first.** Every app that acts on pull requests,
542
+ issues or comments by itself reads `author_association` and starts each repo
543
+ at `who: "team"` (`OWNER`, `MEMBER`, `COLLABORATOR`), with a two-choice
544
+ control that opens it to anyone. Everything else waits on the connector's
545
+ page with **Review it now**, so their credits and their name go where they
546
+ choose.
547
+ - **The app stays open; the spend has its own gate.** Who can visit and read
548
+ the app is publishing plus `access.js`. Who sets off AI calls and GitHub
549
+ posts is the repo's `who` setting on deliveries and a `binderHandle` check on
550
+ every spending route. Keep the app published and gate the spend.
551
+ - **What the App may do today:** read repository contents, and write to pull
552
+ requests — reviews, review comments, and comments on a pull request's
553
+ conversation. Build on those. Other writes (labels, issue comments, check
554
+ runs) may answer `permission_not_granted`; record that reason on the
555
+ person's record and show it, so they see exactly what happened.
556
+ - **One repo connects to one app.** A repo already connected to another app
557
+ answers the person on the connect screen with "Already connected" — say so on
558
+ your page near the Connect button, so it reads as expected.
559
+ - **Repo names are case-insensitive on GitHub.** Lower-case them in `_id`s and
560
+ comparisons, as the example does, and keep GitHub's spelling for display.
561
+ - **Disconnecting happens on GitHub**, in the person's installed GitHub Apps
562
+ settings.
563
+ - More on `ctx` — `ctx.db`, `ctx.log`, `ifRev`, `apiFetch` — lives in the
564
+ `backend` skill.
package/llms/index.d.ts CHANGED
@@ -16,6 +16,7 @@ export { useVibeConfig } from "./use-vibe.js";
16
16
  export { createVibeConfig } from "./create-vibe.js";
17
17
  export { accessConfig } from "./access.js";
18
18
  export { connectionsConfig } from "./connections.js";
19
+ export { githubConfig } from "./github.js";
19
20
  export { youtubeConfig } from "./youtube.js";
20
21
  export { blueskyConfig } from "./bluesky.js";
21
22
  export { spotifyConfig } from "./spotify.js";
@@ -57,5 +58,5 @@ export { poufCalendarConfig } from "./pouf-calendar.js";
57
58
  export { poufTestimonialsConfig } from "./pouf-testimonials.js";
58
59
  export type { LlmConfig } from "./types.js";
59
60
  export { cueMatches, cueMatchedSkills, type CueCatalogEntry } from "./cues.js";
60
- export declare const allConfigs: readonly [import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig];
61
+ export declare const allConfigs: readonly [import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig];
61
62
  export { mapsConfig } from "./maps.js";
package/llms/index.js CHANGED
@@ -17,6 +17,7 @@ import { useVibeConfig } from "./use-vibe.js";
17
17
  import { createVibeConfig } from "./create-vibe.js";
18
18
  import { accessConfig } from "./access.js";
19
19
  import { connectionsConfig } from "./connections.js";
20
+ import { githubConfig } from "./github.js";
20
21
  import { youtubeConfig } from "./youtube.js";
21
22
  import { blueskyConfig } from "./bluesky.js";
22
23
  import { spotifyConfig } from "./spotify.js";
@@ -74,6 +75,7 @@ export { useVibeConfig } from "./use-vibe.js";
74
75
  export { createVibeConfig } from "./create-vibe.js";
75
76
  export { accessConfig } from "./access.js";
76
77
  export { connectionsConfig } from "./connections.js";
78
+ export { githubConfig } from "./github.js";
77
79
  export { youtubeConfig } from "./youtube.js";
78
80
  export { blueskyConfig } from "./bluesky.js";
79
81
  export { spotifyConfig } from "./spotify.js";
@@ -134,6 +136,7 @@ export const allConfigs = [
134
136
  boardGamesConfig,
135
137
  accessConfig,
136
138
  connectionsConfig,
139
+ githubConfig,
137
140
  youtubeConfig,
138
141
  blueskyConfig,
139
142
  spotifyConfig,
package/llms/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../jsr/llms/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../jsr/llms/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibes.diy/prompts",
3
- "version": "14.3.161",
3
+ "version": "14.3.163",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "exports": {
@@ -39,10 +39,10 @@
39
39
  "license": "Apache-2.0",
40
40
  "dependencies": {
41
41
  "@adviser/cement": "~0.5.34",
42
- "@vibes.diy/api-types": "14.3.161",
43
- "@vibes.diy/call-ai-v2": "14.3.161",
44
- "@vibes.diy/identity": "14.3.161",
45
- "@vibes.diy/use-vibes-types": "14.3.161",
42
+ "@vibes.diy/api-types": "14.3.163",
43
+ "@vibes.diy/call-ai-v2": "14.3.163",
44
+ "@vibes.diy/identity": "14.3.163",
45
+ "@vibes.diy/use-vibes-types": "14.3.163",
46
46
  "arktype": "~2.2.6",
47
47
  "json-schema-faker": "~0.6.3"
48
48
  },