@pikku/skills 0.12.9 → 0.12.11

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.
Files changed (75) hide show
  1. package/CHANGELOG.md +768 -0
  2. package/dist/skills.gen.js +1 -1
  3. package/package.json +4 -4
  4. package/skills/pikku-addon/SKILL.md +20 -14
  5. package/skills/pikku-addon/references/addon-package-manifest.md +2 -2
  6. package/skills/{pikku-ai-agent → pikku-agent}/SKILL.md +24 -24
  7. package/skills/pikku-ai-vercel/SKILL.md +18 -18
  8. package/skills/pikku-ai-voice/SKILL.md +15 -15
  9. package/skills/pikku-audit/SKILL.md +28 -13
  10. package/skills/pikku-aws/SKILL.md +2 -2
  11. package/skills/pikku-better-auth/SKILL.md +97 -17
  12. package/skills/pikku-build-app/SKILL.md +621 -0
  13. package/skills/pikku-build-app/references/multi-app.md +117 -0
  14. package/skills/pikku-build-app/references/ship.md +98 -0
  15. package/skills/pikku-build-app/references/theming.md +70 -0
  16. package/skills/pikku-build-platform/SKILL.md +239 -0
  17. package/skills/pikku-build-quick/SKILL.md +238 -0
  18. package/skills/pikku-cli/SKILL.md +7 -7
  19. package/skills/pikku-cli/references/complete-example.md +1 -1
  20. package/skills/pikku-concepts/SKILL.md +10 -7
  21. package/skills/pikku-concepts/references/concept-mapping.md +1 -1
  22. package/skills/pikku-config/SKILL.md +5 -3
  23. package/skills/pikku-deploy-azure/SKILL.md +5 -4
  24. package/skills/pikku-deploy-cloudflare/SKILL.md +9 -9
  25. package/skills/pikku-deploy-uws/SKILL.md +5 -2
  26. package/skills/pikku-deps/SKILL.md +42 -3
  27. package/skills/pikku-emails/SKILL.md +5 -5
  28. package/skills/pikku-fabric/SKILL.md +27 -3
  29. package/skills/pikku-fabric-debug/SKILL.md +1 -1
  30. package/skills/pikku-feature/SKILL.md +5 -4
  31. package/skills/pikku-http/SKILL.md +4 -4
  32. package/skills/pikku-http/references/http-options.md +13 -13
  33. package/skills/pikku-i18n/SKILL.md +2 -1
  34. package/skills/pikku-info/SKILL.md +1 -1
  35. package/skills/pikku-knowledge/SKILL.md +13 -13
  36. package/skills/pikku-kysely/SKILL.md +68 -41
  37. package/skills/pikku-machine-auth/SKILL.md +10 -10
  38. package/skills/pikku-mcp/SKILL.md +23 -20
  39. package/skills/pikku-middleware/SKILL.md +19 -12
  40. package/skills/pikku-middleware/references/middleware-patterns.md +14 -8
  41. package/skills/pikku-mongodb/SKILL.md +11 -11
  42. package/skills/pikku-n8n-import/SKILL.md +12 -12
  43. package/skills/pikku-n8n-import/SPEC.md +3 -0
  44. package/skills/pikku-n8n-import/references/addon-mapping.md +14 -8
  45. package/skills/pikku-n8n-import/references/code-translation.md +26 -22
  46. package/skills/pikku-n8n-import/references/loops-and-control.md +7 -7
  47. package/skills/pikku-paraglide/SKILL.md +11 -6
  48. package/skills/pikku-permissions/SKILL.md +19 -15
  49. package/skills/pikku-product-second-opinion/README.md +3 -3
  50. package/skills/pikku-product-second-opinion/SKILL.md +83 -73
  51. package/skills/pikku-product-second-opinion/example/sample-report.md +15 -12
  52. package/skills/pikku-product-second-opinion/references/report-template.md +10 -7
  53. package/skills/pikku-queue/SKILL.md +1 -1
  54. package/skills/pikku-react/SKILL.md +53 -13
  55. package/skills/pikku-realtime/SKILL.md +51 -19
  56. package/skills/pikku-rpc/SKILL.md +1 -1
  57. package/skills/pikku-rtl/SKILL.md +1 -1
  58. package/skills/pikku-scenario/SKILL.md +164 -44
  59. package/skills/pikku-schedule/SKILL.md +6 -1
  60. package/skills/pikku-schema-ajv/SKILL.md +2 -2
  61. package/skills/pikku-schema-cfworker/SKILL.md +1 -1
  62. package/skills/pikku-security/SKILL.md +9 -5
  63. package/skills/pikku-services/SKILL.md +27 -18
  64. package/skills/pikku-services/references/audit-wire-service.md +14 -8
  65. package/skills/pikku-software-archaeology/SKILL.md +27 -23
  66. package/skills/pikku-software-archaeology/references/blueprint.schema.json +580 -102
  67. package/skills/pikku-software-archaeology/scripts/validate.mjs +146 -69
  68. package/skills/pikku-tag-middleware/SKILL.md +1 -0
  69. package/skills/pikku-template-clone/SKILL.md +2 -1
  70. package/skills/pikku-trigger/SKILL.md +3 -3
  71. package/skills/pikku-versioning/SKILL.md +87 -3
  72. package/skills/pikku-websocket/SKILL.md +4 -3
  73. package/skills/pikku-workflow/SKILL.md +2 -2
  74. package/skills/pikku-workflow/references/workflow-reference.md +24 -10
  75. package/skills/pikku-ws/SKILL.md +5 -2
@@ -5,7 +5,8 @@ description: >-
5
5
  the generated catch-all auth routes, betterAuthSession middleware, OAuth/social providers,
6
6
  email+password credentials, database adapters, and session mapping. TRIGGER when: code uses
7
7
  pikkuBetterAuth, betterAuth, betterAuthSession, createAuthHandler, user asks about Better Auth,
8
- OAuth/social providers, MFA, organizations, login/logout, or @pikku/better-auth. TRIGGER when:
8
+ OAuth/social providers, MFA, organizations, login/logout, or @pikku/better-auth. TRIGGER when: user asks
9
+ about the actor plugin, /sign-in/actor, signing in as a scenario persona, or SCENARIO_ACTOR_SECRET. TRIGGER when:
9
10
  user asks about ANY form of authentication, login, logout, sessions, or user identity — always
10
11
  answer with this skill. DO NOT TRIGGER when: user asks about JWT middleware (use pikku-security)
11
12
  or custom session services (use pikku-services).
@@ -146,6 +147,11 @@ strings):
146
147
  | delete a user and their data | `admin:users:remove` |
147
148
  | revoke a user's sessions | `admin:users:sessions` |
148
149
  | set a user's password | `admin:users:password` |
150
+ | read credential values and who holds them | `admin:credentials:read` |
151
+ | set and delete credentials | `admin:credentials:manage` |
152
+ | view declared scopes, roles, and who holds them | `admin:scopes:read` |
153
+ | create roles, change their scopes, grant them | `admin:scopes:manage` |
154
+ | read the audit trail | `admin:audit:read` |
149
155
 
150
156
  Holding the bare `admin` scope satisfies all of them — a parent grant covers
151
157
  everything nested beneath it — so `admin` is the direct replacement for the old
@@ -166,6 +172,8 @@ defineScope({
166
172
  description: 'Application-wide credentials',
167
173
  scopes: {
168
174
  link: { description: 'Bind a shared credential for every user' },
175
+ read: { description: 'Read credential values and who holds them' },
176
+ manage: { description: 'Set and delete credentials' },
169
177
  },
170
178
  },
171
179
  users: {
@@ -179,6 +187,27 @@ defineScope({
179
187
  password: { description: "Set a user's password" },
180
188
  },
181
189
  },
190
+ scopes: {
191
+ description: 'Authorization management',
192
+ scopes: {
193
+ read: {
194
+ description: 'View declared scopes, roles, and who holds them',
195
+ },
196
+ manage: {
197
+ description:
198
+ 'Create and delete roles, change their scopes, and grant roles to users',
199
+ },
200
+ },
201
+ },
202
+ audit: {
203
+ description: 'The audit trail',
204
+ scopes: {
205
+ read: {
206
+ description:
207
+ 'Read the audit trail — every recorded action, and which user took it',
208
+ },
209
+ },
210
+ },
182
211
  },
183
212
  },
184
213
  })
@@ -191,22 +220,32 @@ a scope, so nothing is authorized, and the denial is logged at `warn` because
191
220
  that is a configuration bug rather than a permissions decision. Pass your own
192
221
  `canImpersonate` / `canLinkSingleton` to override the default entirely.
193
222
 
194
- ### If you do wire better-auth's `admin()` plugin
223
+ ### Do not wire better-auth's `admin()` plugin
224
+
225
+ Every capability in the table is pikku's own, gated by the scope next to it and
226
+ implemented against better-auth's internal adapter — `createAuthUser`,
227
+ `setAuthUserPassword`, `setAuthUserBanned`, `deleteAuthUser` and
228
+ `revokeAuthUserSessions`, all exported from `@pikku/better-auth`.
195
229
 
196
- The last five capabilities in the table are implemented by better-auth's own
197
- `admin()` endpoints, which authorize against `user.role` — a column pikku
198
- otherwise ignores. Rather than making you maintain two grant systems,
199
- `syncProjectedAdminRole` keeps that column as a *projection* of the scope set:
200
- at the session boundary it writes `role = 'admin'` when the user holds any of
201
- `admin:users:{create,ban,remove,sessions,password}`, and the plugin's
202
- `defaultRole` otherwise. `projectedAdminRole(scopes, defaultRole)` computes the
203
- value if you need it yourself.
230
+ `admin()` would add a second gate on a `user.role` column that pikku otherwise
231
+ ignores, which means maintaining two grant systems that have to agree — and the
232
+ column loses, since the scope store is what the rest of the framework reads.
233
+ Pikku used to project scopes onto it for exactly that reason; dropping the
234
+ plugin dropped the projection with it.
204
235
 
205
- The projection is deliberately not "any `admin:*` scope": `impersonate` and
206
- `users:list` are pikku's own gates, and rolling them in would hand ban and delete
207
- rights to someone granted only the ability to look. The plugin is auto-detected
208
- from the live instance, so an app without it never writes to a column that does
209
- not exist.
236
+ Banning is the one capability with a schema requirement, and it has its own
237
+ small plugin:
238
+
239
+ ```typescript
240
+ import { ban } from '@pikku/better-auth'
241
+
242
+ betterAuth({ plugins: [ban()] })
243
+ ```
244
+
245
+ `ban()` adds `banned`, `banReason` and `banExpires` to `user` and refuses to
246
+ create a session for a banned user, lapsing an expired ban as it goes. It makes
247
+ no authorization decision — who may ban is decided by `admin:users:ban` — so it
248
+ never needs to know about scopes or roles.
210
249
 
211
250
  ### 2. Production database adapter
212
251
 
@@ -273,7 +312,7 @@ export const auth = pikkuBetterAuth(async ({ secrets, variables }) => {
273
312
  Functions that require a session use `pikkuFunc` — anonymous callers are rejected automatically. `betterAuthSession` has already bridged better-auth's session into `session`:
274
313
 
275
314
  ```typescript
276
- import { pikkuFunc } from '#pikku'
315
+ import { pikkuFunc } from '#pikku/function'
277
316
 
278
317
  export const me = pikkuFunc({
279
318
  expose: true,
@@ -311,11 +350,52 @@ The session cookie is `better-auth.session_token` (dev) / `__Secure-better-auth.
311
350
 
312
351
  Set `PIKKU_DEV_QUICK_LOGIN=true` and `${basePath}/dev/quick-login` signs in a
313
352
  fixed dev admin (`admin@pikku.dev`), creating the user idempotently and granting
314
- it the bare `admin` scope. It is guarded twice — the env var *and* a localhost
353
+ it the bare `admin` scope. It is guarded twice — the env var _and_ a localhost
315
354
  hostname check — because a one-request path to an admin session is exactly the
316
355
  thing that must not survive a deploy. An app that has not declared the `admin`
317
356
  scope still gets a session, with a warning, since a scopeless dev user is useful.
318
357
 
358
+ ### Actor sign-in (`actor` plugin)
359
+
360
+ A different thing from dev quick login, and the one to reach for when "sign in as
361
+ someone" means **a particular kind of user** rather than one fixed admin.
362
+ Register it explicitly — it is not automatic:
363
+
364
+ ```typescript
365
+ import { actor } from '@pikku/better-auth'
366
+
367
+ plugins: [actor({ secret: SCENARIO_ACTOR_SECRET })]
368
+ ```
369
+
370
+ `POST ${basePath}/sign-in/actor` `{ email, secret, name? }` → 200 + the normal
371
+ session cookie. `secret` may also be a (possibly async) function, so it can come
372
+ off the secrets service instead of a captured value.
373
+
374
+ **`SCENARIO_ACTOR_SECRET` is a credential as powerful as the most privileged
375
+ persona.** `pikku persona sync` grants declared roles to actor accounts, so an
376
+ `admin` persona is an actor holding real admin — anyone with the secret can take
377
+ a session as one. Keep the endpoint **off outside development and sandbox
378
+ deployments**: leave the secret unset on any stage that should not run scenarios,
379
+ which is the supported switch (`Actor sign-in is not configured`), rather than
380
+ conditionally registering the plugin. Do not treat "actors only" as a licence to
381
+ enable it in production.
382
+
383
+ Within that boundary, three properties bound the damage:
384
+
385
+ - **It only ever signs in actors.** The plugin adds a `user.actor` boolean
386
+ column; an email matching a row without it is refused with `User is not an
387
+ actor`. So the secret cannot take over a **real user's** account — the blast
388
+ radius is the actor accounts and whatever roles they were granted.
389
+ - **Unknown emails are created**, flagged `actor: true`, so a scenario that
390
+ declares a new persona needs no seed step. Note the flip side: the secret
391
+ mints accounts, it does not merely use existing ones.
392
+ - **The comparison is constant-time and length-hiding**, so a wrong secret leaks
393
+ neither the length nor a prefix of the right one.
394
+
395
+ This is the endpoint `pikku scenario` signs its actors in through, and the one
396
+ the frontend dev switcher posts to — see `pikku-scenario` for declaring the
397
+ actors and `pikku-react` for `useDevActors()`.
398
+
319
399
  ---
320
400
 
321
401
  ## Secret Management