@stacksjs/defaults 0.75.390 → 0.75.398

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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: stacks-actions
3
- description: Use when working with Stacks server actions - creating actions in app/Actions/, auto-generated API actions from the useApi model trait, the 673 default framework actions (auth, dashboard, commerce, content, deployment, jobs), action request/response handling, or action registration. Covers @stacksjs/actions and storage/framework/defaults/app/Actions/.
3
+ description: Use when working with Stacks server actions - creating actions in app/Actions/, auto-generated API actions from the useApi model trait, the 675 default framework actions (auth, dashboard, commerce, content, deployment, jobs), action request/response handling, or action registration. Covers @stacksjs/actions and storage/framework/defaults/app/Actions/.
4
4
  license: MIT
5
5
  compatibility: Bun >= 1.3.0, TypeScript
6
6
  allowed-tools: Read Edit Write Bash Grep Glob
@@ -22,6 +22,7 @@ ai/src/
22
22
  │ ├── openai/index.ts # GPT + image + transcription + TTS
23
23
  │ ├── ollama/index.ts # Local LLM driver
24
24
  │ └── bedrock/ # Amazon Bedrock, through the Converse API
25
+ ├── complete.ts # complete()/completeStream(): inline ghost-text completions
25
26
  ├── image.ts # Image generation & vision
26
27
  ├── speech.ts # Provider-neutral text-to-speech & speech-to-text
27
28
  ├── search.ts # RAG, embeddings, vector index
@@ -341,6 +342,66 @@ const sessionId = driver.getLastSessionId()
341
342
  await driver.resumeSession(sessionId, 'Add validation')
342
343
  ```
343
344
 
345
+ ## Inline completions (ghost text)
346
+
347
+ `complete()` is the continuation at the cursor, for editors that show grey text
348
+ after the caret and accept it with Tab. It uses the app's configured default
349
+ driver (any of the four) and that driver's fast model class, asks for ONLY the
350
+ continuation, and cleans the answer: the echoed prefix, the model's markup,
351
+ chatter and refusals (to `''`), everything past the first sentence or line, and
352
+ anything that runs into the text after the cursor.
353
+
354
+ ```typescript
355
+ import { complete, completeStream } from '@stacksjs/ai'
356
+
357
+ const { completion } = await complete({
358
+ before: 'Remember to buy milk, eggs and ', // the last 2000 chars are sent
359
+ after: '', // the first 500 chars are sent
360
+ kind: 'todo', // 'note' | 'prompt' | 'todo' | 'text'
361
+ context: 'Groceries', // note title, library description
362
+ maxTokens: 48, // default 48
363
+ signal: controller.signal, // abort: rejects with an AbortError
364
+ driver: 'bedrock', // default: ai.completion.driver, then ai.default
365
+ })
366
+
367
+ for await (const { completion } of completeStream({ before })) paint(completion) // the whole suggestion so far
368
+ ```
369
+
370
+ - `{ completion: '' }` is "no suggestion", never an error: nothing to continue,
371
+ `ai.completion.enabled: false`, no driver configured, or the model declined. A
372
+ real driver failure throws.
373
+ - The model is, in order: `input.model`, `ai.completion.model`, a Haiku (Anthropic,
374
+ Bedrock) or Nova Micro/Lite found in `ai.models`, then the fast defaults in
375
+ `models.ts` (`DEFAULT_ANTHROPIC_FAST_MODEL`, `DEFAULT_BEDROCK_FAST_MODEL`); on
376
+ OpenAI and Ollama it is the driver's configured model. Bedrock Claude needs the
377
+ account's Anthropic use-case form submitted, otherwise list a Nova model in
378
+ `ai.models` (or set `ai.completion.model`) and completions use that.
379
+ - A small LRU keyed on the tail of `before` (plus kind, model and the head of
380
+ `after`) makes retyping free; `completionCache.clear()` empties it.
381
+ - Requests carry `maxRetries: 0` and the abort `signal` reaches the HTTP drivers
382
+ (Bedrock rejects at once and drops the late response), and each reports
383
+ `recordUsage` with `metadata: { feature: 'completion', kind }`, so `onUsage`
384
+ can price them separately. `ChatCompletionOptions` gained `signal`,
385
+ `maxRetries` and `usageMetadata` for this; Ollama now honours `maxTokens`
386
+ (`num_predict`) and reports usage like the other drivers.
387
+ - `completionStatus(config)` says whether a driver can answer, without a call;
388
+ `postProcessCompletion(raw, { before, after, kind })` is the cleanup, reusable
389
+ with your own model call.
390
+
391
+ `POST /ai/complete` (default `Actions/AI/CompleteAction`, in the guarded `/ai`
392
+ route group of the dashboard bundle) takes `{ before, after?, kind?, context? }`
393
+ and answers `{ completion }`: 401 when signed out, 422 for a bad body, a 90 per
394
+ minute per-user rate limit (429), `''` when no driver is configured, 502 when the
395
+ provider fails. To mount it elsewhere, one line in `routes/api.ts`:
396
+
397
+ ```typescript
398
+ route.post('/complete', 'Actions/AI/CompleteAction').middleware('auth') // POST /api/complete
399
+ ```
400
+
401
+ The client half is `useCompletion()` and `<AiTextarea>` in stx
402
+ (`stacks-stx`, `stacks-composables/BROWSER.md`): `<AiTextarea kind="note" fetcher="/api/complete" v-model:value="body" />`.
403
+ Tests: `core/ai/tests/complete.test.ts`, `defaults/app/Actions/AI/complete-request.test.ts`.
404
+
344
405
  ## config/ai.ts
345
406
 
346
407
  ```typescript
@@ -352,6 +413,7 @@ await driver.resumeSession(sessionId, 'Add validation')
352
413
  anthropic: { model: 'claude-sonnet-5-5' },
353
414
  bedrock: { model: 'global.anthropic.claude-sonnet-5-5' },
354
415
  },
416
+ completion: { enabled: true, maxTokens: 48 }, // optional: driver, model for inline completions
355
417
  }
356
418
  ```
357
419
 
@@ -129,6 +129,7 @@ buddy dev -i/--interactive # interactive server selection menu
129
129
  buddy dev -l/--with-localhost # include localhost URL in output
130
130
  buddy dev --browser # open the browser app instead of a configured native window
131
131
  buddy dev --site # open the marketing site instead of the detected app entry
132
+ buddy dev --detach # outlive the shell: nohup ./buddy dev --frontend --detach &
132
133
  buddy dev -p/--project [name]
133
134
  buddy dev --verbose
134
135
  ```
@@ -23,6 +23,14 @@ implementation rather than a newer docs list. Demand legacy helpers commonly
23
23
  expose getters, `get()`, `subscribe()`, and `stop()`. Their getters are not
24
24
  automatically signal-tracked template values.
25
25
 
26
+ STX 0.2.762 adds demand-delivered `useCompletion` for inline ghost text:
27
+ `useCompletion({ fetch: (ctx, signal) => Promise<string>, debounceMs = 250, minChars = 12, enabled })`
28
+ returns signals `ghost` and `pending` (plus `error`) and `update(before, after, caret, meta?)`,
29
+ `accept()`, `acceptWord()`, `dismiss()`, `destroy()`. It debounces, aborts the previous request,
30
+ discards stale answers, asks nothing during IME composition, a selection (`meta.selecting`), mid-word
31
+ or below `minChars`, and typing the start of a suggestion consumes it. `<AiTextarea>` from
32
+ `@stacksjs/components` is the textarea built on it (`kind`, `context`, `fetcher` URL or function).
33
+
26
34
  STX 0.2.628 adds demand-delivered `useAnimationFrame` for canvas and simulations.
27
35
  Imported TypeScript controllers use an explicit
28
36
  `import { useAnimationFrame } from '@stacksjs/stx/composables'` and declare
@@ -252,9 +252,94 @@ Two things that bite, both silently:
252
252
  `buddy build:dmg` warns when a finished bundle contains more than one
253
253
  Bun-compiled executable, naming them and what the repetition costs.
254
254
 
255
+ ## Native macOS apps (`config/desktop.ts`)
256
+
257
+ A project whose app is a client of an HTTP API (a hosted service, not a local server) declares it in
258
+ `config/desktop.ts`, the way `config/mobile.ts` declares a phone app, and `buddy build:desktop` builds a
259
+ native AppKit app from its stx screens: no web view, no launcher.
260
+
261
+ ```ts
262
+ import type { DesktopConfig } from '@stacksjs/types'
263
+
264
+ export default {
265
+ macos: {
266
+ appName: 'Library',
267
+ bundleId: 'com.example.library',
268
+ teamId: '3JJRNQW6B7', // not a secret
269
+ url: process.env.LIBRARY_API_URL || 'http://127.0.0.1:3408',
270
+ nativeScreens: ['Main', 'Settings'], // resources/native/<name>.stx
271
+ shareStorage: { auth_token: 'auth.token' },
272
+ window: { width: 1180, height: 760, minWidth: 860, minHeight: 540 },
273
+ icon: 'resources/native/icon/AppIcon-1024.png',
274
+ privacy: { tracking: false, collectedDataTypes: [] },
275
+ },
276
+ } satisfies DesktopConfig
277
+ ```
278
+
279
+ - `buddy build:desktop` compiles the screens (`compileNativeBundle`), builds Craft's AppKit host
280
+ (`craft-native/macos`, cached per Craft revision), lays out `<App>.app` and signs it ad hoc. `buddy dev:desktop`
281
+ does the same and opens it. Output: `storage/framework/desktop/macos/`.
282
+ - The toolchain is not the app's business: Craft resolves the pinned Zig through Pantry and fetches and builds the pinned
283
+ zig-js into `~/.cache/craft/toolchain` (`CRAFT_TOOLCHAIN_DIR` moves it, `CRAFT_ZIG` overrides the compiler).
284
+ - The host reads `Contents/Resources/craft-app.json` (written by the build) when Finder launches it, so the app has no
285
+ arguments. The API origin is `url`, and `craft.secureStorage` is the Keychain (`craft.session` is the `auth.token` item).
286
+ - `buddy desktop:apple:package` and `publish` build the same bundle for the Mac App Store (sandbox, network client,
287
+ application identifier, Keychain group, embedded profile). Name, bundle id, team, version, category and icon come
288
+ from `config/desktop.ts`; only the credentials (identities, profile, API key) are Apple variables. `--universal` is not
289
+ supported for native apps yet.
290
+ - A `macos` section in `config/desktop.ts` switches `build:desktop` and `dev:desktop` to this path; without one they
291
+ build the Craft web-view app as before.
292
+ - One set of views can be both: the web server resolves the native primitives (`View`, `Text`, `ScrollView`, ...) as
293
+ components of last resort (stx config `nativePrimitives`), so `resources/views` pages written with them are also native
294
+ screens. Menus, windows and the Keychain are the screen's `craft.desktop` and `craft.secureStorage`.
295
+
296
+ ### An app that runs its own API (`macos.agent`)
297
+
298
+ A local-first app (a browser, an inbox, anything whose data is this Mac) runs the project's routes inside the
299
+ app instead of talking to a hosted server. `buddy new <name> --desktop` scaffolds one (combinable with
300
+ `--minimal`, and happy to scaffold into a directory that holds only `.git`):
301
+
302
+ ```ts
303
+ export default {
304
+ macos: {
305
+ appName: 'Browser',
306
+ bundleId: 'com.example.browser',
307
+ agent: true, // or { port, entry, appRoutes, staticDir }
308
+ nativeScreens: ['Main'],
309
+ webkit: true, // link WebKit into the host, for <WebView>
310
+ defaultBrowser: true, // http/https URL types, HTML/XHTML/webarchive/PDF document types
311
+ permissions: { camera: true, microphone: 'For calls in web pages.', location: true, downloads: true, printing: true },
312
+ dockMenu: [{ title: 'New Window', action: 'new-window' }],
313
+ },
314
+ } satisfies DesktopConfig
315
+ ```
316
+
317
+ - The agent (`@stacksjs/desktop-build` `startDesktopAgent`, `src/agent.ts`) is `Bun.serve` on 127.0.0.1, on the
318
+ port remembered in `~/Library/Application Support/<App>/agent.port` (any free port when it is taken). The host fetches
319
+ `GET /native/session` and gets an HttpOnly, SameSite=Strict cookie holding a token minted for this launch; every other
320
+ request needs that cookie and a Host header of `127.0.0.1:<port>` or `localhost:<port>`, so a DNS-rebinding page
321
+ cannot call it. `url` is not needed.
322
+ - It serves the app's routes in process: `routes/` as `app/Routes.ts` mounts them, plus the agent's own module
323
+ (`app/Desktop/Agent.ts` by convention, `agent.entry` otherwise). Routes the agent module adds are not prefixed. A
324
+ default-exported `(request) => Response` there replaces the router entirely.
325
+ - `buddy dev:desktop` runs the launcher from source in the project (`bun`, no bundle), which boots the routes as
326
+ `buddy dev:api` does. `buddy build:desktop` compiles the launcher into `<App>.app/Contents/MacOS/<App>`, with the host
327
+ beside it as `craft-runtime` and `desktop-agent.json` in Resources. A compiled binary cannot import route files off
328
+ disk (the router refuses), so the build imports the registry's route files, the agent module and every
329
+ `'Actions/...'` they name statically (`provideActions`); what they import travels inside the app.
330
+ - The launcher (`src/agent-launcher.ts`) holds a single-instance lock (`agent.pid`), logs to
331
+ `~/Library/Logs/<App>.log` when launched without a terminal, and quits with the window.
332
+ - Entitlements: the Bun executable gets `allow-jit`, `allow-unsigned-executable-memory` and
333
+ `disable-library-validation`; in the sandbox the agent adds `network.server`, and the host is signed with only
334
+ `app-sandbox` and `inherit`. `permissions` adds each device entitlement and its `NS*UsageDescription` (an explicit
335
+ `usageDescriptions` entry wins).
336
+ - `webkit` needs a craft-native whose `buildMacOSNative` takes `webkit`; the build checks Craft's source and fails by
337
+ name rather than building a host with blank web views. `dockMenu` reaches the host through `craft-app.json`.
338
+
255
339
  ## CLI Commands
256
340
 
257
341
  ```bash
342
+ buddy new <name> --desktop # a Stacks app that is also a native Mac app, API inside (macos.agent)
258
343
  buddy dev:desktop # start the desktop development server
259
344
  buddy build:desktop # build the launcher + Craft runtime payload
260
345
  buddy desktop:apple:init # generate the reusable GitHub Actions caller
@@ -11,8 +11,8 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
11
11
  | Package | Task guidance | Source entry | Retained tests |
12
12
  |---|---|---|---|
13
13
  | `@stacksjs/action-runner` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/action-runner/src/index.ts) | 1 |
14
- | `@stacksjs/actions` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/index.ts) | 94 |
15
- | `@stacksjs/ai` | [`stacks-ai`](../stacks-ai/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/index.ts) | 20 |
14
+ | `@stacksjs/actions` | [`stacks-actions`](../stacks-actions/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/index.ts) | 95 |
15
+ | `@stacksjs/ai` | [`stacks-ai`](../stacks-ai/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/index.ts) | 21 |
16
16
  | `@stacksjs/alias` | [`stacks-alias`](../stacks-alias/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/alias/src/index.ts) | 1 |
17
17
  | `@stacksjs/analytics` | [`stacks-analytics`](../stacks-analytics/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/analytics/src/index.ts) | 6 |
18
18
  | `@stacksjs/api` | [`stacks-api`](../stacks-api/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/api/src/index.ts) | 9 |
@@ -21,7 +21,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
21
21
  | `@stacksjs/auth` | [`stacks-auth`](../stacks-auth/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/auth/src/index.ts) | 124 |
22
22
  | `@stacksjs/browser` | [`stacks-browser`](../stacks-browser/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/browser/src/index.ts) | 8 |
23
23
  | `@stacksjs/browser-extension` | [`stacks-browser-extension`](../stacks-browser-extension/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/browser-extension/src/index.ts) | 7 |
24
- | `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) | 174 |
24
+ | `@stacksjs/buddy` | [`stacks-buddy`](../stacks-buddy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/index.ts) | 176 |
25
25
  | `@stacksjs/build` | [`stacks-build`](../stacks-build/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/build/src/index.ts) | 4 |
26
26
  | `@stacksjs/cache` | [`stacks-cache`](../stacks-cache/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/cache/src/index.ts) | 18 |
27
27
  | `@stacksjs/calendar-api` | [`stacks-calendar`](../stacks-calendar/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/calendar-api/src/index.ts) | 2 |
@@ -39,7 +39,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
39
39
  | `@stacksjs/datetime` | [`stacks-datetime`](../stacks-datetime/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/datetime/src/index.ts) | 13 |
40
40
  | `@stacksjs/defaults` | [`stacks-build`](../stacks-build/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/defaults/package.json) | 2 |
41
41
  | `@stacksjs/deploy` | [`stacks-deploy`](../stacks-deploy/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/deploy/package.json) | 1 |
42
- | `@stacksjs/desktop-build` | [`stacks-desktop`](../stacks-desktop/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/index.ts) | 12 |
42
+ | `@stacksjs/desktop-build` | [`stacks-desktop`](../stacks-desktop/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/index.ts) | 15 |
43
43
  | `@stacksjs/development` | [`stacks-development`](../stacks-development/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/development/package.json) | 1 |
44
44
  | `@stacksjs/dns` | [`stacks-dns`](../stacks-dns/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/dns/src/index.ts) | 3 |
45
45
  | `@stacksjs/docs` | [`stacks-docs`](../stacks-docs/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/docs/src/index.ts) | 2 |
@@ -78,7 +78,7 @@ Browser runtime bindings are documented separately in `stacks-auto-imports`.
78
78
  | `@stacksjs/router` | [`stacks-router`](../stacks-router/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts) | 99 |
79
79
  | `@stacksjs/scheduler` | [`stacks-scheduler`](../stacks-scheduler/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/scheduler/src/index.ts) | 15 |
80
80
  | `@stacksjs/search-engine` | [`stacks-search-engine`](../stacks-search-engine/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/search-engine/src/index.ts) | 11 |
81
- | `@stacksjs/security` | [`stacks-security`](../stacks-security/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/index.ts) | 11 |
81
+ | `@stacksjs/security` | [`stacks-security`](../stacks-security/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/index.ts) | 12 |
82
82
  | `@stacksjs/server` | [`stacks-server`](../stacks-server/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/server/src/index.ts) | 28 |
83
83
  | `@stacksjs/shell` | [`stacks-shell`](../stacks-shell/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/shell/src/index.ts) | 1 |
84
84
  | `@stacksjs/sites` | [`stacks-sites`](../stacks-sites/SKILL.md) | [entrypoint](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/sites/src/index.ts) | 3 |
@@ -115,11 +115,11 @@ Evidence directory: [1 retained tests](https://github.com/stacksjs/stacks/blob/m
115
115
 
116
116
  Guidance: [`stacks-actions`](../stacks-actions/SKILL.md). Source: [storage/framework/core/actions/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/index.ts).
117
117
 
118
- Declared runtime exports: `BlogAdminError`, `DEFAULT_IOS_DEPENDENCIES`, `DEFAULT_STX_LINT_CONFIG`, `IosToolchainError`, `PUBLICATION_CHECK_SCRIPT`, `XCODE_NOTE`, `assertPublicationAllowed`, `blogSlugify`, `createComponent`, `createDatabase`, `createFactory`, `createFunction`, `createLanguage`, `createMail`, `createMiddleware`, `createMigration`, `createModel`, `createNotification`, `createPage`, `deleteBlogPost`, `describeDanglingRouteActions`, `describeGitHubRelease`, `discoverPackages`, `ensureDiscoveredPackages`, `findDanglingRouteActions`, `formatProject`, `getBlogPost`, `installStack`, `isDryRunActive`, `lintFix`, `lintProject`, `listBlogPosts`, `listStacks`, `loadIosDependencies`, `loadStxLintConfig`, `makeAction`, `makeCertificate`, `makeCommand`, `makeComponent`, `makeDatabase`, `makeFunction`, `makeJob`, `makeLanguage`, `makeMail`, `makeNotification`, `makePage`, `makePolicy`, `makeQueueTable`, `makeResource`, `makeStack`, `measureDefaultsDrift`, `pantryExecutable`, `pantryInstallArgs`, `parseFields`, `parseGitHubRemote`, `publicationChannels`, `publishGitHubRelease`, `resolveStxSource`, `resolveXcodegen`, `runAdd`, `runCommit`, `runMake`, `runStxLint`, `saveBlogPost`, `scaffoldCrud`, `setDryRun`, `summarizeStructureChanges`, `uninstallStack`, `validateReleaseEvidencePlan`, `verifyReleaseEvidence`, `xcodeDeveloperDir`.
118
+ Declared runtime exports: `BlogAdminError`, `DEFAULT_IOS_DEPENDENCIES`, `DEFAULT_STX_LINT_CONFIG`, `IosToolchainError`, `PUBLICATION_CHECK_SCRIPT`, `XCODE_NOTE`, `assertPublicationAllowed`, `blogSlugify`, `craftSupportsWebkit`, `createComponent`, `createDatabase`, `createFactory`, `createFunction`, `createLanguage`, `createMail`, `createMiddleware`, `createMigration`, `createModel`, `createNotification`, `createPage`, `deleteBlogPost`, `describeDanglingRouteActions`, `describeGitHubRelease`, `discoverPackages`, `ensureDiscoveredPackages`, `findDanglingRouteActions`, `formatProject`, `getBlogPost`, `installStack`, `isDryRunActive`, `lintFix`, `lintProject`, `listBlogPosts`, `listStacks`, `loadIosDependencies`, `loadStxLintConfig`, `macosAgentActionFiles`, `macosAgentDevFiles`, `macosAgentDevManifest`, `macosAgentEntry`, `macosAgentRouteFiles`, `makeAction`, `makeCertificate`, `makeCommand`, `makeComponent`, `makeDatabase`, `makeFunction`, `makeJob`, `makeLanguage`, `makeMail`, `makeNotification`, `makePage`, `makePolicy`, `makeQueueTable`, `makeResource`, `makeStack`, `measureDefaultsDrift`, `pantryExecutable`, `pantryInstallArgs`, `parseFields`, `parseGitHubRemote`, `prepareMacosAgent`, `prepareMacosNative`, `publicationChannels`, `publishGitHubRelease`, `resolveStxSource`, `resolveXcodegen`, `runAdd`, `runCommit`, `runMake`, `runStxLint`, `saveBlogPost`, `scaffoldCrud`, `setDryRun`, `summarizeStructureChanges`, `uninstallStack`, `validateReleaseEvidencePlan`, `verifyReleaseEvidence`, `xcodeDeveloperDir`.
119
119
 
120
- Local source modules: [src/action.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/action.ts), [src/add.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/add.ts), [src/blog-admin.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/blog-admin.ts), [src/build/ios-toolchain.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/build/ios-toolchain.ts), [src/commit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/commit.ts), [src/dev/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/dev/index.ts), [src/discover-packages.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/discover-packages.ts), [src/generate/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/generate/index.ts), [src/github-release.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/github-release.ts), [src/helpers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/helpers/index.ts), [src/library/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/library/index.ts), [src/lint/lint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/lint/lint.ts), [src/lint/stx-gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/lint/stx-gate.ts), [src/make-command.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-command.ts), [src/make-job.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-job.ts), [src/make-policy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-policy.ts), [src/make-resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-resource.ts), [src/make.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make.ts), [src/publication-preflight.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/publication-preflight.ts), [src/release-evidence.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/release-evidence.ts), [src/scaffold-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/scaffold-crud.ts), [src/setup/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/setup/index.ts), [src/stacks.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/stacks.ts), [src/stx-source.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/stx-source.ts), [src/upgrade/package-project.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/upgrade/package-project.ts), [src/upgrade/route-actions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/upgrade/route-actions.ts).
120
+ Local source modules: [src/action.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/action.ts), [src/add.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/add.ts), [src/blog-admin.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/blog-admin.ts), [src/build/ios-toolchain.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/build/ios-toolchain.ts), [src/build/macos-native.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/build/macos-native.ts), [src/commit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/commit.ts), [src/dev/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/dev/index.ts), [src/discover-packages.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/discover-packages.ts), [src/generate/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/generate/index.ts), [src/github-release.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/github-release.ts), [src/helpers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/helpers/index.ts), [src/library/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/library/index.ts), [src/lint/lint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/lint/lint.ts), [src/lint/stx-gate.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/lint/stx-gate.ts), [src/make-command.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-command.ts), [src/make-job.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-job.ts), [src/make-policy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-policy.ts), [src/make-resource.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make-resource.ts), [src/make.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/make.ts), [src/publication-preflight.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/publication-preflight.ts), [src/release-evidence.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/release-evidence.ts), [src/scaffold-crud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/scaffold-crud.ts), [src/setup/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/setup/index.ts), [src/stacks.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/stacks.ts), [src/stx-source.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/stx-source.ts), [src/upgrade/package-project.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/upgrade/package-project.ts), [src/upgrade/route-actions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/src/upgrade/route-actions.ts).
121
121
 
122
- Evidence directory: [94 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
122
+ Evidence directory: [95 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/actions/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
123
123
 
124
124
  ### @stacksjs/ai
125
125
 
@@ -127,9 +127,9 @@ Guidance: [`stacks-ai`](../stacks-ai/SKILL.md). Source: [storage/framework/core/
127
127
 
128
128
  Declared runtime exports: `assistantTurn`, `buildMessageWithImages`, `clearUsageReporters`, `estimateMessageTokens`, `estimateTokens`, `fetchWithRetry`, `listUsageReporters`, `normalizeMessagesForProvider`, `onUsage`, `recordUsage`, `sanitizePrompt`, `toolResultsTurn`.
129
129
 
130
- Local source modules: [src/agents/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/agents/index.ts), [src/buddy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/buddy.ts), [src/client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/client.ts), [src/context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/context.ts), [src/documents.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/documents.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/drivers/index.ts), [src/image.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/image.ts), [src/mcp-server.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/mcp-server.ts), [src/mcp.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/mcp.ts), [src/models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/models.ts), [src/personalization.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/personalization.ts), [src/search.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/search.ts), [src/speech.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/speech.ts), [src/text.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/text.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/types.ts), [src/utils/client-bedrock-runtime.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/client-bedrock-runtime.ts), [src/utils/client-bedrock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/client-bedrock.ts), [src/utils/model-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/model-access.ts), [src/utils/retry.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/retry.ts), [src/utils/tokens.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/tokens.ts), [src/utils/tools.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/tools.ts), [src/utils/usage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/usage.ts), [src/utils/vision.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/vision.ts).
130
+ Local source modules: [src/agents/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/agents/index.ts), [src/buddy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/buddy.ts), [src/client.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/client.ts), [src/complete.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/complete.ts), [src/context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/context.ts), [src/documents.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/documents.ts), [src/drivers/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/drivers/index.ts), [src/image.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/image.ts), [src/mcp-server.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/mcp-server.ts), [src/mcp.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/mcp.ts), [src/models.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/models.ts), [src/personalization.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/personalization.ts), [src/search.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/search.ts), [src/speech.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/speech.ts), [src/text.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/text.ts), [src/types.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/types.ts), [src/utils/client-bedrock-runtime.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/client-bedrock-runtime.ts), [src/utils/client-bedrock.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/client-bedrock.ts), [src/utils/model-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/model-access.ts), [src/utils/retry.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/retry.ts), [src/utils/tokens.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/tokens.ts), [src/utils/tools.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/tools.ts), [src/utils/usage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/usage.ts), [src/utils/vision.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/src/utils/vision.ts).
131
131
 
132
- Evidence directory: [20 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
132
+ Evidence directory: [21 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/ai/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
133
133
 
134
134
  ### @stacksjs/alias
135
135
 
@@ -217,7 +217,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
217
217
 
218
218
  Local source modules: [src/commands/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/src/commands/index.ts).
219
219
 
220
- Evidence directory: [174 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
220
+ Evidence directory: [176 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/buddy/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
221
221
 
222
222
  ### @stacksjs/build
223
223
 
@@ -387,9 +387,9 @@ Guidance: [`stacks-desktop`](../stacks-desktop/SKILL.md). Source: [storage/frame
387
387
 
388
388
  Declared runtime exports: `BUN_EXECUTABLE_MARKER`, `RESERVED_PLIST_KEYS`, `USERLAND_LAUNCHER`, `bundleDirectoryFor`, `codesignArgs`, `craftDevCommand`, `createUpdateManifestUrl`, `describeRuntimeDuplication`, `desktopAppVersion`, `desktopLauncherCompileArgs`, `dmgVolumeName`, `hasUserlandDesktopLauncher`, `isMachO`, `looksLikeBunExecutable`, `openDevWindow`, `plistValue`, `renderInfoPlist`, `renderUserlandPlistEntries`, `resolveCraftBinary`, `resolveCraftExecutable`, `resolveDesktopLauncher`, `resolveDevWindowUrl`, `resolveDmgPackaging`, `xmlEscape`.
389
389
 
390
- Local source modules: [src/invites.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/invites.ts), [src/support.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/support.ts), [src/updater.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/updater.ts).
390
+ Local source modules: [src/agent-launcher.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/agent-launcher.ts), [src/agent.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/agent.ts), [src/invites.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/invites.ts), [src/macos-app.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/macos-app.ts), [src/macos-bundle.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/macos-bundle.ts), [src/support.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/support.ts), [src/updater.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/src/updater.ts).
391
391
 
392
- Evidence directory: [12 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
392
+ Evidence directory: [15 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/desktop/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
393
393
 
394
394
  ### @stacksjs/development
395
395
 
@@ -721,7 +721,7 @@ Evidence directory: [2 retained tests](https://github.com/stacksjs/stacks/blob/m
721
721
 
722
722
  Guidance: [`stacks-router`](../stacks-router/SKILL.md). Source: [storage/framework/core/router/src/index.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/index.ts).
723
723
 
724
- Declared runtime exports: `DASHBOARD_ROUTE_GROUPS`, `DEFAULT_ROUTE_BUNDLE_FEATURES`, `DEFAULT_ROUTE_REGISTRY`, `DatabaseSessionStore`, `EncryptedSessionStore`, `FileSessionStore`, `JSON_CONTENT_TYPE`, `MemorySessionStore`, `Middleware`, `PathParamError`, `RedisSessionStore`, `RequestBodyError`, `appRouteRegistry`, `assertRouteMiddlewareResolvable`, `bundleMounts`, `cacheRedisConnection`, `cacheRequestQuery`, `checkApplicationHealth`, `clearCsrfModuleCache`, `clearCurrentRequest`, `clearMiddlewareCache`, `clearRateLimit`, `clearRouteModelBindings`, `clearTrackedQueries`, `clientAddress`, `configureViewDirectories`, `createErrorResponse`, `createMiddlewareErrorResponse`, `createNotFoundResponse`, `createSessionStore`, `createStacksRouter`, `createStacksSessionStore`, `createTypedRouter`, `createValidationErrorResponse`, `dashboardGroupMiddleware`, `defineMiddleware`, `defineRouteModelBinding`, `describeUnknownDashboardGroups`, `disableViewRouting`, `enhanceRequest`, `fallbackStorage`, `findUnresolvableRouteMiddleware`, `getCurrentRequest`, `getQueryShapeCounts`, `getTraceId`, `installMiddlewareHotReload`, `isApiRequest`, `isRouterAction`, `listNamedRoutes`, `listRedirectRoutes`, `listRegisteredRoutes`, `listRootMountedAppRoutes`, `loadMiddlewareHandlers`, `loadRoutes`, `mountedDefaultRouteBundles`, `parseJsonText`, `rateLimit`, `rateLimitScale`, `rateLimitStatus`, `readJsonBody`, `readTextBody`, `request`, `resetBootHooks`, `resetRateLimiters`, `resetSharedRateLimitStorage`, `resetShutdownHooks`, `resolveDashboardAccess`, `resolveRouteModel`, `route`, `routeModelBindings`, `routeParams`, `runBootHooks`, `runHealthProbes`, `runShutdownHooks`, `runWithRequest`, `safePathParam`, `sanitizePathParam`, `scaledLimit`, `serve`, `serverResponse`, `setCurrentRequest`, `setRouteModelFallback`, `sharedRateLimitStorage`, `signUrl`, `signedUrl`, `stream`, `trackQuery`, `trustedProxies`, `url`, `useRateLimitStorage`, `verifySignedUrl`, `verifySignedUrlMiddleware`, `warnOnMultipleRouterInstances`, `withRouteAdmission`, `withTraceId`, `wrapAction`.
724
+ Declared runtime exports: `DASHBOARD_ROUTE_GROUPS`, `DEFAULT_ROUTE_BUNDLE_FEATURES`, `DEFAULT_ROUTE_REGISTRY`, `DatabaseSessionStore`, `EncryptedSessionStore`, `FileSessionStore`, `JSON_CONTENT_TYPE`, `MemorySessionStore`, `Middleware`, `PathParamError`, `RedisSessionStore`, `RequestBodyError`, `appRouteRegistry`, `assertRouteMiddlewareResolvable`, `bundleMounts`, `cacheRedisConnection`, `cacheRequestQuery`, `checkApplicationHealth`, `clearCsrfModuleCache`, `clearCurrentRequest`, `clearMiddlewareCache`, `clearRateLimit`, `clearRouteModelBindings`, `clearTrackedQueries`, `clientAddress`, `configureViewDirectories`, `createErrorResponse`, `createMiddlewareErrorResponse`, `createNotFoundResponse`, `createSessionStore`, `createStacksRouter`, `createStacksSessionStore`, `createTypedRouter`, `createValidationErrorResponse`, `dashboardGroupMiddleware`, `defineMiddleware`, `defineRouteModelBinding`, `describeUnknownDashboardGroups`, `disableViewRouting`, `enhanceRequest`, `fallbackStorage`, `findUnresolvableRouteMiddleware`, `getCurrentRequest`, `getQueryShapeCounts`, `getTraceId`, `installMiddlewareHotReload`, `isApiRequest`, `isRouterAction`, `listNamedRoutes`, `listRedirectRoutes`, `listRegisteredRoutes`, `listRootMountedAppRoutes`, `loadMiddlewareHandlers`, `loadRoutes`, `mountedDefaultRouteBundles`, `parseJsonText`, `provideActions`, `rateLimit`, `rateLimitScale`, `rateLimitStatus`, `readJsonBody`, `readTextBody`, `request`, `resetBootHooks`, `resetRateLimiters`, `resetSharedRateLimitStorage`, `resetShutdownHooks`, `resolveDashboardAccess`, `resolveRouteModel`, `route`, `routeModelBindings`, `routeParams`, `runBootHooks`, `runHealthProbes`, `runShutdownHooks`, `runWithRequest`, `safePathParam`, `sanitizePathParam`, `scaledLimit`, `serve`, `serverResponse`, `setCurrentRequest`, `setRouteModelFallback`, `sharedRateLimitStorage`, `signUrl`, `signedUrl`, `stream`, `trackQuery`, `trustedProxies`, `url`, `useRateLimitStorage`, `verifySignedUrl`, `verifySignedUrlMiddleware`, `warnOnMultipleRouterInstances`, `withRouteAdmission`, `withTraceId`, `wrapAction`.
725
725
 
726
726
  Local source modules: [src/api-shape.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/api-shape.ts), [src/body.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/body.ts), [src/dashboard-access.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/dashboard-access.ts), [src/encrypted-session-store.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/encrypted-session-store.ts), [src/error-handler.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/error-handler.ts), [src/health.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/health.ts), [src/json.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/json.ts), [src/middleware.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/middleware.ts), [src/path-sanitize.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/path-sanitize.ts), [src/rate-limit.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/rate-limit.ts), [src/request-augmentation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-augmentation.ts), [src/request-context.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/request-context.ts), [src/route-loader.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-loader.ts), [src/route-model-binding.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/route-model-binding.ts), [src/security-settings.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/security-settings.ts), [src/session-factory.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/session-factory.ts), [src/signed-url.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/signed-url.ts), [src/stacks-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/stacks-router.ts), [src/typed-router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/router/src/typed-router.ts).
727
727
 
@@ -755,7 +755,7 @@ Read the entrypoint and package export map for re-exported or type-only surfaces
755
755
 
756
756
  Local source modules: [src/api-key.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/api-key.ts), [src/crypt.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/crypt.ts), [src/hash.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/hash.ts), [src/key.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/key.ts), [src/outbound.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/outbound.ts), [src/regex.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/regex.ts), [src/webhook.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/src/webhook.ts).
757
757
 
758
- Evidence directory: [11 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
758
+ Evidence directory: [12 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/security/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
759
759
 
760
760
  ### @stacksjs/server
761
761
 
@@ -879,7 +879,7 @@ Guidance: [`stacks-types`](../stacks-types/SKILL.md). Source: [storage/framework
879
879
 
880
880
  Read the entrypoint and package export map for re-exported or type-only surfaces.
881
881
 
882
- Local source modules: [src/ai.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/ai.ts), [src/analytics.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/analytics.ts), [src/api.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/api.ts), [src/app.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/app.ts), [src/auction.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/auction.ts), [src/auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/auth.ts), [src/auto-imports.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/auto-imports.ts), [src/binary.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/binary.ts), [src/cache.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cache.ts), [src/cdn.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cdn.ts), [src/chat.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/chat.ts), [src/cli.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cli.ts), [src/cloud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cloud.ts), [src/cms.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cms.ts), [src/commands.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/commands.ts), [src/commerce.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/commerce.ts), [src/components.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/components.ts), [src/configure.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/configure.ts), [src/cors.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cors.ts), [src/cron-jobs.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cron-jobs.ts), [src/dashboard.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/dashboard.ts), [src/database.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/database.ts), [src/dependencies.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/dependencies.ts), [src/deploy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/deploy.ts), [src/dns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/dns.ts), [src/docs.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/docs.ts), [src/email.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/email.ts), [src/env.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/env.ts), [src/errors.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/errors.ts), [src/events.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/events.ts), [src/exit-code.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/exit-code.ts), [src/feature-flags.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/feature-flags.ts), [src/file-systems.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/file-systems.ts), [src/forms.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/forms.ts), [src/git.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/git.ts), [src/hashing.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/hashing.ts), [src/helpers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/helpers.ts), [src/i18n.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/i18n.ts), [src/images.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/images.ts), [src/library.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/library.ts), [src/lint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/lint.ts), [src/logging.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/logging.ts), [src/manifest.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/manifest.ts), [src/marketing.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/marketing.ts), [src/mobile.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/mobile.ts), [src/model-dashboard-augmentation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/model-dashboard-augmentation.ts), [src/model-names.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/model-names.ts), [src/model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/model.ts), [src/monitoring.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/monitoring.ts), [src/notifications.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/notifications.ts), [src/oauth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/oauth.ts), [src/pages.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/pages.ts), [src/payments.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/payments.ts), [src/phone.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/phone.ts), [src/ports.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/ports.ts), [src/promise.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/promise.ts), [src/push.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/push.ts), [src/queue.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/queue.ts), [src/reactivity.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/reactivity.ts), [src/realtime.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/realtime.ts), [src/request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/request.ts), [src/response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/response.ts), [src/router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/router.ts), [src/saas.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/saas.ts), [src/scheduler.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/scheduler.ts), [src/search-engine.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/search-engine.ts), [src/security.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/security.ts), [src/seo.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/seo.ts), [src/server.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/server.ts), [src/services.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/services.ts), [src/settings-config.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/settings-config.ts), [src/sites.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/sites.ts), [src/sms.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/sms.ts), [src/socials.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/socials.ts), [src/stack-extensions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/stack-extensions.ts), [src/stacks.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/stacks.ts), [src/storage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/storage.ts), [src/table-names.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/table-names.ts), [src/tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/tables.ts), [src/team.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/team.ts), [src/ui.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/ui.ts), [src/utils.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/utils.ts).
882
+ Local source modules: [src/ai.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/ai.ts), [src/analytics.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/analytics.ts), [src/api.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/api.ts), [src/app.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/app.ts), [src/auction.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/auction.ts), [src/auth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/auth.ts), [src/auto-imports.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/auto-imports.ts), [src/binary.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/binary.ts), [src/cache.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cache.ts), [src/cdn.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cdn.ts), [src/chat.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/chat.ts), [src/cli.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cli.ts), [src/cloud.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cloud.ts), [src/cms.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cms.ts), [src/commands.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/commands.ts), [src/commerce.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/commerce.ts), [src/components.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/components.ts), [src/configure.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/configure.ts), [src/cors.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cors.ts), [src/cron-jobs.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/cron-jobs.ts), [src/dashboard.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/dashboard.ts), [src/database.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/database.ts), [src/dependencies.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/dependencies.ts), [src/deploy.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/deploy.ts), [src/desktop.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/desktop.ts), [src/dns.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/dns.ts), [src/docs.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/docs.ts), [src/email.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/email.ts), [src/env.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/env.ts), [src/errors.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/errors.ts), [src/events.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/events.ts), [src/exit-code.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/exit-code.ts), [src/feature-flags.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/feature-flags.ts), [src/file-systems.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/file-systems.ts), [src/forms.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/forms.ts), [src/git.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/git.ts), [src/hashing.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/hashing.ts), [src/helpers.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/helpers.ts), [src/i18n.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/i18n.ts), [src/images.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/images.ts), [src/library.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/library.ts), [src/lint.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/lint.ts), [src/logging.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/logging.ts), [src/manifest.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/manifest.ts), [src/marketing.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/marketing.ts), [src/mobile.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/mobile.ts), [src/model-dashboard-augmentation.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/model-dashboard-augmentation.ts), [src/model-names.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/model-names.ts), [src/model.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/model.ts), [src/monitoring.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/monitoring.ts), [src/notifications.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/notifications.ts), [src/oauth.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/oauth.ts), [src/pages.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/pages.ts), [src/payments.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/payments.ts), [src/phone.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/phone.ts), [src/ports.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/ports.ts), [src/promise.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/promise.ts), [src/push.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/push.ts), [src/queue.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/queue.ts), [src/reactivity.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/reactivity.ts), [src/realtime.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/realtime.ts), [src/request.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/request.ts), [src/response.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/response.ts), [src/router.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/router.ts), [src/saas.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/saas.ts), [src/scheduler.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/scheduler.ts), [src/search-engine.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/search-engine.ts), [src/security.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/security.ts), [src/seo.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/seo.ts), [src/server.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/server.ts), [src/services.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/services.ts), [src/settings-config.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/settings-config.ts), [src/sites.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/sites.ts), [src/sms.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/sms.ts), [src/socials.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/socials.ts), [src/stack-extensions.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/stack-extensions.ts), [src/stacks.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/stacks.ts), [src/storage.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/storage.ts), [src/table-names.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/table-names.ts), [src/tables.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/tables.ts), [src/team.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/team.ts), [src/ui.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/ui.ts), [src/utils.ts](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/src/utils.ts).
883
883
 
884
884
  Evidence directory: [2 retained tests](https://github.com/stacksjs/stacks/blob/main/storage/framework/core/types/tests). These files are evidence pointers, not a claim that all tests were run for this catalog.
885
885
 
@@ -22,6 +22,32 @@ security/src/
22
22
  └── hash.ts # password hashing (bcrypt/argon2)
23
23
  ```
24
24
 
25
+ ## Scanning a project: `buddy security:scan`
26
+
27
+ `buddy security:scan` (alias `buddy audit`) checks a project for security problems and exits non-zero on findings at or above `--fail-on` (default `high`), so it drops into CI. Five checks, each runnable alone with `--only` or left out with `--skip`:
28
+
29
+ | Check | Finds |
30
+ |---|---|
31
+ | `dependencies` | Known vulnerabilities in the lockfile (`bun audit`; needs the network, skipped with `--offline`) |
32
+ | `secrets` | Committed credentials: private keys, AWS/Stripe/GitHub/Anthropic/OpenAI/Slack/Google/Twilio/SendGrid/npm tokens, database URLs with passwords, `secret = "high-entropy value"` |
33
+ | `code` | `eval` / `new Function`, shell commands built from strings, SQL built with interpolation, disabled TLS verification, `alg: none`, `innerHTML`, `Math.random()` for tokens, MD5/SHA-1, CORS `*` with credentials |
34
+ | `workflows` | GitHub Actions that paste untrusted text into `run:`, check out a pull request under `pull_request_target`, echo secrets, or follow a branch |
35
+ | `hygiene` | Committed `.env` files with readable secrets (encrypted values are fine), key files, a `.gitignore` without `.env`, no lockfile |
36
+
37
+ ```bash
38
+ buddy security:scan # everything, fail on high or worse
39
+ buddy security:scan --only dependencies,secrets --fail-on medium
40
+ buddy security:scan --json # the report, for tooling
41
+ buddy security:scan --show-ignored # what exceptions set aside
42
+ ```
43
+
44
+ A finding that is fine is set aside with a reason, never silently:
45
+
46
+ - On the line (or the line above): `// security-ignore: code/inner-html the HTML is sanitized by sanitize()`
47
+ - In `.security-ignore.json`: `{ "ignore": [{ "rule": "code/sql-interpolation", "path": "database/seed.ts", "reason": "ids from rows it just selected", "expires": "2027-06-30" }] }`. `rule` takes `code/*`; `path` is a file or a directory ending in `/`; for an advisory use `"reference": "GHSA-…"` or the package name. An entry without a reason, or past its `expires`, is reported and no longer applies.
48
+
49
+ A check that cannot run (offline, no `bun.lock`) is listed under "not checked", never reported as clean. Programmatic use: `import { runSecurityScan } from '@stacksjs/security/scan'`.
50
+
25
51
  ## App Key Generation
26
52
 
27
53
  ```typescript
@@ -10,6 +10,10 @@ allowed-tools: Read Edit Write Bash Grep Glob
10
10
 
11
11
  You are performing a security analysis for a Stacks application. Be concrete — every finding must include a realistic exploit scenario. Vague warnings are worthless.
12
12
 
13
+ ## Step 0: Run the scanner
14
+
15
+ Run `buddy security:scan --show-ignored` first (see the `stacks-security` skill). It already covers vulnerable dependencies, committed secrets, dangerous calls, risky GitHub workflows and repository hygiene, so do not repeat those by hand: verify each finding it reports (read the code, confirm it is reachable) and spend your own effort on what a pattern scan cannot see: authorization gaps, business-logic abuse, trust boundaries and data exposure. Treat every `security-ignore` reason as a claim to check.
16
+
13
17
  ## Determine Scope
14
18
 
15
19
  1. If the user specifies files or a feature, analyze that scope
@@ -185,7 +185,8 @@ through STX's asynchronous render boundary. Pair tenant features with
185
185
  `stacks-sites`.
186
186
 
187
187
  The browser has both eagerly delivered and demand-bundled composables.
188
- Observers, motion helpers and STX `useForm` are usable client primitives in
188
+ Observers, motion helpers, STX `useForm` and `useCompletion` (inline AI ghost
189
+ text; `<AiTextarea>` is the ready-made textarea) are usable client primitives in
189
190
  current STX, even when they are not explicit `window.name` aliases. Read
190
191
  `stacks-composables/BROWSER.md` before choosing a signature or mixing the
191
192
  browser signal API with explicit module Refs.
@@ -0,0 +1,50 @@
1
+ import type { ConfiguredAIOptions } from '@stacksjs/ai'
2
+ import type { RequestInstance } from '@stacksjs/types'
3
+ import { Action } from '@stacksjs/actions/runtime'
4
+ import { complete, completionStatus } from '@stacksjs/ai'
5
+ import { resolveAuthenticatedUser } from '@stacksjs/auth'
6
+ import { config } from '@stacksjs/config'
7
+ import { log } from '@stacksjs/logging'
8
+ import type { ResponseStatus } from '@stacksjs/router'
9
+ import { rateLimit, response } from '@stacksjs/router'
10
+ import { COMPLETE_RATE_PER_MINUTE, handleCompleteRequest } from './complete-request'
11
+
12
+ /**
13
+ * `POST /ai/complete`: the ghost text behind an editor's Tab-to-accept.
14
+ *
15
+ * Body `{ before, after?, kind?: 'note' | 'prompt' | 'todo' | 'text', context? }`,
16
+ * answer `{ completion }`. `''` means "no suggestion", including when the app
17
+ * has no AI driver configured; a provider failure is a 502.
18
+ *
19
+ * Needs a signed-in user and is rate limited per user. Mount it under another
20
+ * path with `route.post('/complete', 'Actions/AI/CompleteAction').middleware('auth')`.
21
+ */
22
+ export default new Action({
23
+ name: 'AiCompleteAction',
24
+ description: 'Complete the text at the cursor with the configured AI driver',
25
+ method: 'POST',
26
+ apiResponse: true,
27
+
28
+ async handle(request: RequestInstance) {
29
+ const aiConfig = (config.ai || {}) as ConfiguredAIOptions
30
+ const body = {
31
+ before: request.get('before'),
32
+ after: request.get('after'),
33
+ kind: request.get('kind'),
34
+ context: request.get('context'),
35
+ }
36
+
37
+ const result = await handleCompleteRequest({
38
+ body,
39
+ config: aiConfig,
40
+ authenticate: () => resolveAuthenticatedUser(request as any),
41
+ limit: userId => rateLimit('ai-complete', COMPLETE_RATE_PER_MINUTE, { identity: `user:${userId}` }).per('minute'),
42
+ available: cfg => completionStatus(cfg).available,
43
+ complete: input => complete(input, { config: aiConfig }),
44
+ signal: (request as { signal?: AbortSignal }).signal,
45
+ log: (message, context) => void log.error(message, context),
46
+ })
47
+
48
+ return response.json(result.body, result.status as ResponseStatus)
49
+ },
50
+ })
@@ -0,0 +1,20 @@
1
+ import { describe, expect, test } from 'bun:test'
2
+ import { readFileSync } from 'node:fs'
3
+ import { join } from 'node:path'
4
+
5
+ describe('CompleteAction wiring', () => {
6
+ test('is a POST action the default /ai route group mounts', () => {
7
+ const routes = readFileSync(join(import.meta.dir, '../../../routes/dashboard.ts'), 'utf8')
8
+ expect(routes).toContain('route.post(\'/complete\', \'Actions/AI/CompleteAction\')')
9
+ // Inside the guarded `/ai` group, so it is mounted at /ai/complete behind auth.
10
+ const group = routes.slice(routes.indexOf('route.group({ prefix: \'/ai\''))
11
+ expect(group.indexOf('/complete')).toBeGreaterThan(0)
12
+ expect(group.indexOf('/complete')).toBeLessThan(group.indexOf('})'))
13
+ })
14
+
15
+ test('loads and declares POST', async () => {
16
+ const action = (await import('./CompleteAction')).default as { name?: string, method?: string }
17
+ expect(action.method).toBe('POST')
18
+ expect(action.name).toBe('AiCompleteAction')
19
+ })
20
+ })
@@ -0,0 +1,91 @@
1
+ import type { CompleteRequestDeps } from './complete-request'
2
+ import { describe, expect, test } from 'bun:test'
3
+ import { COMPLETE_MAX_BEFORE, handleCompleteRequest, parseCompleteBody } from './complete-request'
4
+
5
+ function deps(overrides: Partial<CompleteRequestDeps> = {}): CompleteRequestDeps & { calls: unknown[], limited: Array<number | string> } {
6
+ const calls: unknown[] = []
7
+ const limited: Array<number | string> = []
8
+ return {
9
+ calls,
10
+ limited,
11
+ body: { before: 'Remember to buy ', kind: 'todo' },
12
+ config: { default: 'anthropic' },
13
+ authenticate: async () => ({ id: 7 }),
14
+ limit: async (id) => { limited.push(id) },
15
+ available: () => true,
16
+ complete: async (input) => {
17
+ calls.push(input)
18
+ return { completion: 'milk' }
19
+ },
20
+ ...overrides,
21
+ }
22
+ }
23
+
24
+ describe('POST /ai/complete', () => {
25
+ test('requires a signed-in user', async () => {
26
+ const d = deps({ authenticate: async () => undefined })
27
+ const result = await handleCompleteRequest(d)
28
+ expect(result.status).toBe(401)
29
+ expect(d.calls).toHaveLength(0)
30
+ expect(d.limited).toHaveLength(0)
31
+ })
32
+
33
+ test('an auth backend failure is a 503, not a silent pass', async () => {
34
+ const result = await handleCompleteRequest(deps({ authenticate: async () => { throw new Error('db down') } }))
35
+ expect(result.status).toBe(503)
36
+ })
37
+
38
+ test('validates the body', async () => {
39
+ expect((await handleCompleteRequest(deps({ body: {} }))).status).toBe(422)
40
+ expect((await handleCompleteRequest(deps({ body: { before: 5 } }))).status).toBe(422)
41
+ expect((await handleCompleteRequest(deps({ body: { before: 'x', kind: 'poem' } }))).status).toBe(422)
42
+ expect((await handleCompleteRequest(deps({ body: { before: 'x', after: 5 } }))).status).toBe(422)
43
+ expect((await handleCompleteRequest(deps({ body: { before: 'x'.repeat(COMPLETE_MAX_BEFORE + 1) } }))).status).toBe(422)
44
+ expect(parseCompleteBody({ before: 'x' })).toEqual({ ok: true, value: { before: 'x', after: '', kind: 'text', context: '' } })
45
+ })
46
+
47
+ test('returns the completion and spends one slot of that user\'s budget', async () => {
48
+ const d = deps({ body: { before: 'Remember to buy ', after: '', kind: 'todo', context: 'Groceries' } })
49
+ const result = await handleCompleteRequest(d)
50
+ expect(result).toEqual({ status: 200, body: { completion: 'milk' } })
51
+ expect(d.limited).toEqual([7])
52
+ expect(d.calls[0]).toMatchObject({ before: 'Remember to buy ', kind: 'todo', context: 'Groceries' })
53
+ })
54
+
55
+ test('answers an empty completion, not an error, when no AI driver is configured', async () => {
56
+ const d = deps({ available: () => false })
57
+ const result = await handleCompleteRequest(d)
58
+ expect(result).toEqual({ status: 200, body: { completion: '' } })
59
+ expect(d.calls).toHaveLength(0)
60
+ expect(d.limited).toHaveLength(0)
61
+ })
62
+
63
+ test('nothing to continue is an empty completion without a model call', async () => {
64
+ const d = deps({ body: { before: ' \n' } })
65
+ expect(await handleCompleteRequest(d)).toEqual({ status: 200, body: { completion: '' } })
66
+ expect(d.calls).toHaveLength(0)
67
+ })
68
+
69
+ test('a provider failure is a 502 with a clear message', async () => {
70
+ const logged: string[] = []
71
+ const result = await handleCompleteRequest(deps({
72
+ complete: async () => { throw new Error('Claude API error: overloaded') },
73
+ log: message => void logged.push(message),
74
+ }))
75
+ expect(result.status).toBe(502)
76
+ expect(result.body).toEqual({ message: 'The AI provider could not complete the text.' })
77
+ expect(logged).toHaveLength(1)
78
+ })
79
+
80
+ test('an aborted request is not reported as a failure', async () => {
81
+ const abort = Object.assign(new Error('aborted'), { name: 'AbortError' })
82
+ const result = await handleCompleteRequest(deps({ complete: async () => { throw abort } }))
83
+ expect(result).toEqual({ status: 200, body: { completion: '' } })
84
+ })
85
+
86
+ test('the rate limit rejection propagates for the framework to turn into a 429', async () => {
87
+ const d = deps({ limit: async () => { throw Object.assign(new Error('Too many requests'), { status: 429 }) } })
88
+ await expect(handleCompleteRequest(d)).rejects.toMatchObject({ status: 429 })
89
+ expect(d.calls).toHaveLength(0)
90
+ })
91
+ })
@@ -0,0 +1,119 @@
1
+ import type { CompleteInput, CompletionKind, ConfiguredAIOptions } from '@stacksjs/ai'
2
+
3
+ /**
4
+ * The testable core of `POST /ai/complete`. The Action reads the request and
5
+ * hands this its parts; everything decided here is a status and a body.
6
+ *
7
+ * Two answers matter to an editor drawing ghost text:
8
+ * - `200 { completion: '' }` is "no suggestion", and it covers a missing or
9
+ * disabled AI driver, so an app without AI keys never shows an error while
10
+ * someone types.
11
+ * - `502` is a real provider failure, with a message worth logging.
12
+ */
13
+
14
+ export const COMPLETE_MAX_BEFORE = 20_000
15
+ export const COMPLETE_MAX_AFTER = 5_000
16
+ export const COMPLETE_MAX_CONTEXT = 2_000
17
+ /** Suggestions per user per minute. The client debounces; this is the backstop. */
18
+ export const COMPLETE_RATE_PER_MINUTE = 90
19
+
20
+ const KINDS: readonly CompletionKind[] = ['note', 'prompt', 'todo', 'text']
21
+
22
+ export interface CompleteRequestBody {
23
+ before?: unknown
24
+ after?: unknown
25
+ kind?: unknown
26
+ context?: unknown
27
+ }
28
+
29
+ export interface ParsedCompleteBody {
30
+ before: string
31
+ after: string
32
+ kind: CompletionKind
33
+ context: string
34
+ }
35
+
36
+ export function parseCompleteBody(body: CompleteRequestBody): { ok: true, value: ParsedCompleteBody } | { ok: false, message: string } {
37
+ if (typeof body.before !== 'string')
38
+ return { ok: false, message: 'The before field must be the text before the cursor.' }
39
+ if (body.before.length > COMPLETE_MAX_BEFORE)
40
+ return { ok: false, message: `The before field must be ${COMPLETE_MAX_BEFORE} characters or fewer.` }
41
+
42
+ if (body.after !== undefined && body.after !== null && typeof body.after !== 'string')
43
+ return { ok: false, message: 'The after field must be the text after the cursor.' }
44
+ if (typeof body.after === 'string' && body.after.length > COMPLETE_MAX_AFTER)
45
+ return { ok: false, message: `The after field must be ${COMPLETE_MAX_AFTER} characters or fewer.` }
46
+
47
+ if (body.kind !== undefined && body.kind !== null && !KINDS.includes(body.kind as CompletionKind))
48
+ return { ok: false, message: `The kind field must be one of ${KINDS.join(', ')}.` }
49
+
50
+ if (body.context !== undefined && body.context !== null && typeof body.context !== 'string')
51
+ return { ok: false, message: 'The context field must be text.' }
52
+ if (typeof body.context === 'string' && body.context.length > COMPLETE_MAX_CONTEXT)
53
+ return { ok: false, message: `The context field must be ${COMPLETE_MAX_CONTEXT} characters or fewer.` }
54
+
55
+ return {
56
+ ok: true,
57
+ value: {
58
+ before: body.before,
59
+ after: typeof body.after === 'string' ? body.after : '',
60
+ kind: (body.kind as CompletionKind | undefined | null) ?? 'text',
61
+ context: typeof body.context === 'string' ? body.context : '',
62
+ },
63
+ }
64
+ }
65
+
66
+ export interface CompleteRequestDeps {
67
+ body: CompleteRequestBody
68
+ /** Resolves the signed-in user, or undefined. Throws when auth itself broke. */
69
+ authenticate: () => Promise<{ id: number | string } | undefined>
70
+ /** Consumes one slot of the user's budget; throws an HttpError(429) when spent. */
71
+ limit: (userId: number | string) => Promise<void>
72
+ config: ConfiguredAIOptions
73
+ complete: (input: CompleteInput) => Promise<{ completion: string }>
74
+ /** Whether a driver can answer at all; false answers `''` without a call. */
75
+ available: (config: ConfiguredAIOptions) => boolean
76
+ signal?: AbortSignal
77
+ log?: (message: string, context: Record<string, unknown>) => void
78
+ }
79
+
80
+ export interface CompleteRequestResult {
81
+ status: number
82
+ body: { completion: string } | { message: string }
83
+ }
84
+
85
+ export async function handleCompleteRequest(deps: CompleteRequestDeps): Promise<CompleteRequestResult> {
86
+ let user
87
+ try {
88
+ user = await deps.authenticate()
89
+ }
90
+ catch (error) {
91
+ deps.log?.('[ai] Completion auth failed', { error })
92
+ return { status: 503, body: { message: 'Authentication could not be verified.' } }
93
+ }
94
+ if (!user?.id)
95
+ return { status: 401, body: { message: 'Sign in to use completions.' } }
96
+
97
+ const parsed = parseCompleteBody(deps.body)
98
+ if (!parsed.ok)
99
+ return { status: 422, body: { message: parsed.message } }
100
+
101
+ // Nothing to continue, or nowhere to ask: the same quiet answer, and no
102
+ // budget spent.
103
+ if (!parsed.value.before.trim() || !deps.available(deps.config))
104
+ return { status: 200, body: { completion: '' } }
105
+
106
+ await deps.limit(user.id)
107
+
108
+ try {
109
+ const { completion } = await deps.complete({ ...parsed.value, signal: deps.signal })
110
+ return { status: 200, body: { completion } }
111
+ }
112
+ catch (error) {
113
+ // The client moved on (aborted its request): not a failure to report.
114
+ if ((error as Error)?.name === 'AbortError')
115
+ return { status: 200, body: { completion: '' } }
116
+ deps.log?.('[ai] Completion request failed', { error })
117
+ return { status: 502, body: { message: 'The AI provider could not complete the text.' } }
118
+ }
119
+ }
@@ -2,7 +2,7 @@
2
2
  "publisher": "Stacks",
3
3
  "name": "vscode-stacks",
4
4
  "displayName": "Stacks",
5
- "version": "0.75.390",
5
+ "version": "0.75.398",
6
6
  "description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
7
7
  "license": "MIT",
8
8
  "funding": "https://github.com/sponsors/chrisbbreuer",
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/defaults",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.390",
5
+ "version": "0.75.398",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/stacksjs/stacks.git",
@@ -45,9 +45,9 @@
45
45
  "dependencies": {
46
46
  "@iconify-json/f7": "^1.2.2",
47
47
  "@iconify-json/hugeicons": "^1.2.35",
48
- "@stacksjs/mobile": "0.75.390",
49
- "@stacksjs/sanitizer": "0.2.752",
50
- "@stacksjs/stx": "0.2.752",
48
+ "@stacksjs/mobile": "0.75.398",
49
+ "@stacksjs/sanitizer": "0.2.775",
50
+ "@stacksjs/stx": "0.2.775",
51
51
  "@xterm/addon-fit": "^0.11.0",
52
52
  "@xterm/xterm": "^6.0.0",
53
53
  "ts-qr-codes": "^0.1.8"
@@ -12,14 +12,21 @@
12
12
  */
13
13
  const title = useReactiveProp('title', '')
14
14
  const subtitle = useReactiveProp('subtitle', '')
15
+ // The mark above the heading. An app brands it with an Iconify class, a short line above the title, or its own
16
+ // markup in the `brand` slot, without forking the four pages that sit in this card (stacksjs/stacks#3086).
17
+ const icon = useReactiveProp('icon', 'i-hugeicons-cube')
18
+ const eyebrow = useReactiveProp('eyebrow', '')
15
19
  </script>
16
20
 
17
21
  <div class="flex items-center justify-center px-4 py-12 min-h-screen">
18
22
  <div class="max-w-sm w-full">
19
23
  <div class="mb-8 text-center">
20
- <div class="inline-flex items-center justify-center mb-4 h-12 w-12 bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl shadow-blue-500/25 shadow-lg">
21
- <span class="h-7 w-7 text-white i-hugeicons-cube"></span>
22
- </div>
24
+ <slot name="brand">
25
+ <div class="inline-flex items-center justify-center mb-4 h-12 w-12 bg-gradient-to-br from-blue-500 to-blue-600 rounded-xl shadow-blue-500/25 shadow-lg">
26
+ <span class="h-7 w-7 text-white" :class="icon()"></span>
27
+ </div>
28
+ </slot>
29
+ <p :if="eyebrow()" class="mb-1 font-semibold text-blue-600 text-xs tracking-widest uppercase dark:text-blue-400">{{ eyebrow() }}</p>
23
30
  <h1 class="font-semibold text-2xl text-neutral-900 dark:text-white">{{ title() }}</h1>
24
31
  <p class="mt-2 text-neutral-500 text-sm dark:text-neutral-400">{{ subtitle() }}</p>
25
32
  </div>
@@ -4,6 +4,8 @@
4
4
  const emit = defineEmits(['submit', 'retry'])
5
5
  const title = useReactiveProp<string>('title', 'Forgot password?')
6
6
  const subtitle = useReactiveProp<string>('subtitle', 'Enter your email and we\'ll send you a reset link')
7
+ const icon = useReactiveProp<string>('icon', 'i-hugeicons-cube')
8
+ const eyebrow = useReactiveProp<string>('eyebrow', '')
7
9
  const isLoading = useReactiveProp<boolean>('isLoading', false)
8
10
  const error = useReactiveProp<string>('error', '')
9
11
  const success = useReactiveProp<boolean>('success', false)
@@ -19,7 +21,7 @@ function retry(): void {
19
21
  emit('retry')
20
22
  }
21
23
  </script>
22
- <AuthCard :title="title()" :subtitle="subtitle()">
24
+ <AuthCard :title="title()" :subtitle="subtitle()" :icon="icon()" :eyebrow="eyebrow()">
23
25
 
24
26
  <!-- Form Card -->
25
27
  <div class="p-6 bg-white dark:bg-neutral-900 border border-neutral-200/60 rounded-2xl dark:border-neutral-800 shadow-black/5 shadow-xl dark:shadow-black/20">
@@ -6,6 +6,9 @@
6
6
  // "dashboardApi is not defined", which the catch below then showed to the
7
7
  // visitor as the reason their reset link could not be sent.
8
8
  import { dashboardApi } from '../../../../functions/dashboard-api'
9
+ // Branding passes through to the card: an Iconify class for the mark and a short line above the title (stacksjs/stacks#3086).
10
+ const icon = useReactiveProp<string>('icon', 'i-hugeicons-cube')
11
+ const eyebrow = useReactiveProp<string>('eyebrow', '')
9
12
 
10
13
  const isLoading = state(false)
11
14
  const error = state('')
@@ -39,6 +42,8 @@ function handleRetry(): void {
39
42
 
40
43
  <template>
41
44
  <ForgotPassword
45
+ :icon="icon()"
46
+ :eyebrow="eyebrow()"
42
47
  @submit="handleForgotPassword"
43
48
  @retry="handleRetry"
44
49
  :isLoading="isLoading()"
@@ -4,6 +4,8 @@
4
4
  const emit = defineEmits(['submit'])
5
5
  const title = useReactiveProp<string>('title', 'Welcome back')
6
6
  const subtitle = useReactiveProp<string>('subtitle', 'Sign in to your account')
7
+ const icon = useReactiveProp<string>('icon', 'i-hugeicons-cube')
8
+ const eyebrow = useReactiveProp<string>('eyebrow', '')
7
9
  const isLoading = useReactiveProp<boolean>('isLoading', false)
8
10
  const error = useReactiveProp<string>('error', '')
9
11
  const showRememberMe = useReactiveProp<boolean>('showRememberMe', true)
@@ -56,7 +58,7 @@ function handleSubmit(): void {
56
58
  }
57
59
  </script>
58
60
 
59
- <AuthCard :title="title()" :subtitle="subtitle()">
61
+ <AuthCard :title="title()" :subtitle="subtitle()" :icon="icon()" :eyebrow="eyebrow()">
60
62
 
61
63
  <div class="p-6 bg-white dark:bg-neutral-900 border border-neutral-200/60 rounded-2xl dark:border-neutral-800 shadow-black/5 shadow-xl dark:shadow-black/20">
62
64
  <div :if="error()" role="alert" class="mb-4 p-3 bg-red-50 dark:bg-red-900/20 border border-red-200 rounded-lg dark:border-red-800">
@@ -1,6 +1,9 @@
1
1
  <script client>
2
2
  import type { AuthUser } from '../../../../types/dashboard'
3
3
  import { describeAuthError, isLoginResponse, isTwoFactorChallenge, safeAuthRedirect, useAuth } from '../../../../functions/auth'
4
+ // Branding passes through to the card: an Iconify class for the mark and a short line above the title (stacksjs/stacks#3086).
5
+ const icon = useReactiveProp<string>('icon', 'i-hugeicons-cube')
6
+ const eyebrow = useReactiveProp<string>('eyebrow', '')
4
7
 
5
8
  const { login, verifyTwoFactorLogin } = useAuth()
6
9
  const route = useRoute()
@@ -71,6 +74,8 @@ function restartLogin(): void {
71
74
 
72
75
  <template>
73
76
  <Login
77
+ :icon="icon()"
78
+ :eyebrow="eyebrow()"
74
79
  :if="!challengeToken()"
75
80
  @submit="handleLogin"
76
81
  :isLoading="isLoading()"
@@ -4,6 +4,8 @@
4
4
  const emit = defineEmits(['submit'])
5
5
  const title = useReactiveProp<string>('title', 'Create an account')
6
6
  const subtitle = useReactiveProp<string>('subtitle', 'Get started with your free account')
7
+ const icon = useReactiveProp<string>('icon', 'i-hugeicons-cube')
8
+ const eyebrow = useReactiveProp<string>('eyebrow', '')
7
9
  const isLoading = useReactiveProp<boolean>('isLoading', false)
8
10
  const error = useReactiveProp<string>('error', '')
9
11
  const showLogin = useReactiveProp<boolean>('showLogin', true)
@@ -98,7 +100,7 @@ function handleSubmit(): void {
98
100
  })
99
101
  }
100
102
  </script>
101
- <AuthCard :title="title()" :subtitle="subtitle()">
103
+ <AuthCard :title="title()" :subtitle="subtitle()" :icon="icon()" :eyebrow="eyebrow()">
102
104
 
103
105
  <!-- Register Form -->
104
106
  <div class="p-6 bg-white dark:bg-neutral-900 border border-neutral-200/60 rounded-2xl dark:border-neutral-800 shadow-black/5 shadow-xl dark:shadow-black/20">
@@ -1,6 +1,9 @@
1
1
  <script client>
2
2
  import type { RegisterCredentials } from '../../../../types/dashboard'
3
3
  import { describeAuthError, safeAuthRedirect, useAuth } from '../../../../functions/auth'
4
+ // Branding passes through to the card: an Iconify class for the mark and a short line above the title (stacksjs/stacks#3086).
5
+ const icon = useReactiveProp<string>('icon', 'i-hugeicons-cube')
6
+ const eyebrow = useReactiveProp<string>('eyebrow', '')
4
7
 
5
8
  const { register } = useAuth()
6
9
  const route = useRoute()
@@ -38,6 +41,8 @@ async function handleRegister(credentials: RegisterCredentials): Promise<void> {
38
41
 
39
42
  <template>
40
43
  <Register
44
+ :icon="icon()"
45
+ :eyebrow="eyebrow()"
41
46
  @submit="handleRegister"
42
47
  :isLoading="isLoading()"
43
48
  :error="error()"
@@ -16,6 +16,8 @@
16
16
  const emit = defineEmits(['submit'])
17
17
  const title = useReactiveProp<string>('title', 'Choose a new password')
18
18
  const subtitle = useReactiveProp<string>('subtitle', 'Set the password you will use to sign in')
19
+ const icon = useReactiveProp<string>('icon', 'i-hugeicons-cube')
20
+ const eyebrow = useReactiveProp<string>('eyebrow', '')
19
21
  const isLoading = useReactiveProp<boolean>('isLoading', false)
20
22
  const error = useReactiveProp<string>('error', '')
21
23
  const success = useReactiveProp<boolean>('success', false)
@@ -43,7 +45,7 @@ function handleSubmit(): void {
43
45
  }
44
46
  </script>
45
47
 
46
- <AuthCard :title="title()" :subtitle="subtitle()">
48
+ <AuthCard :title="title()" :subtitle="subtitle()" :icon="icon()" :eyebrow="eyebrow()">
47
49
 
48
50
  <!-- Form Card -->
49
51
  <div class="p-6 bg-white dark:bg-neutral-900 border border-neutral-200/60 rounded-2xl dark:border-neutral-800 shadow-black/5 shadow-xl dark:shadow-black/20">
@@ -12,6 +12,9 @@
12
12
  * instead of after someone has chosen and typed a new password twice.
13
13
  */
14
14
  import { dashboardApi } from '../../../../functions/dashboard-api'
15
+ // Branding passes through to the card: an Iconify class for the mark and a short line above the title (stacksjs/stacks#3086).
16
+ const icon = useReactiveProp<string>('icon', 'i-hugeicons-cube')
17
+ const eyebrow = useReactiveProp<string>('eyebrow', '')
15
18
 
16
19
  const route = useRoute()
17
20
 
@@ -85,6 +88,8 @@ effect(() => {
85
88
 
86
89
  <template>
87
90
  <ResetPassword
91
+ :icon="icon()"
92
+ :eyebrow="eyebrow()"
88
93
  @submit="handleReset"
89
94
  :checking="checking()"
90
95
  :invalid="invalid()"
@@ -182,6 +182,8 @@ route.get('/robots.txt', 'Actions/RobotsAction')
182
182
  route.group({ prefix: '/ai', middleware: guarded('/ai') }, () => {
183
183
  route.post('/ask', 'Actions/AI/AskAction')
184
184
  route.post('/summary', 'Actions/AI/SummaryAction')
185
+ // Ghost-text completions for editors: `{ before, after?, kind?, context? }` -> `{ completion }`.
186
+ route.post('/complete', 'Actions/AI/CompleteAction')
185
187
  })
186
188
 
187
189
  // ============================================================================