@stacksjs/defaults 0.72.103 → 0.73.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ai/AGENTS.md +25 -4
- package/ai/README.md +26 -4
- package/ai/skills/stacks-actions/SKILL.md +1 -1
- package/ai/skills/stacks-ai/SKILL.md +1 -1
- package/ai/skills/stacks-alias/SKILL.md +1 -1
- package/ai/skills/stacks-analytics/SKILL.md +1 -1
- package/ai/skills/stacks-api/SKILL.md +1 -1
- package/ai/skills/stacks-arrays/SKILL.md +1 -1
- package/ai/skills/stacks-auto-imports/SKILL.md +1 -1
- package/ai/skills/stacks-browse/SKILL.md +1 -1
- package/ai/skills/stacks-browser/SKILL.md +1 -1
- package/ai/skills/stacks-buddy/SKILL.md +1 -1
- package/ai/skills/stacks-build/SKILL.md +79 -5
- package/ai/skills/stacks-cache/SKILL.md +1 -1
- package/ai/skills/stacks-calendar/SKILL.md +1 -1
- package/ai/skills/stacks-chat/SKILL.md +1 -1
- package/ai/skills/stacks-cli/SKILL.md +1 -1
- package/ai/skills/stacks-cloud/SKILL.md +1 -1
- package/ai/skills/stacks-cms/SKILL.md +1 -1
- package/ai/skills/stacks-codebase-design/DEEPENING.md +79 -0
- package/ai/skills/stacks-codebase-design/DESIGN-IT-TWICE.md +72 -0
- package/ai/skills/stacks-codebase-design/SKILL.md +180 -0
- package/ai/skills/stacks-collections/SKILL.md +1 -1
- package/ai/skills/stacks-commerce/SKILL.md +141 -35
- package/ai/skills/stacks-composables/SKILL.md +1 -1
- package/ai/skills/stacks-config/SKILL.md +1 -1
- package/ai/skills/stacks-configuration/SKILL.md +1 -1
- package/ai/skills/stacks-cron/SKILL.md +1 -1
- package/ai/skills/stacks-crosswind/SKILL.md +1 -1
- package/ai/skills/stacks-database/SKILL.md +1 -1
- package/ai/skills/stacks-datetime/SKILL.md +1 -1
- package/ai/skills/stacks-dependencies/SKILL.md +1 -1
- package/ai/skills/stacks-deploy/SKILL.md +1 -1
- package/ai/skills/stacks-desktop/SKILL.md +1 -1
- package/ai/skills/stacks-development/SKILL.md +1 -1
- package/ai/skills/stacks-dns/SKILL.md +1 -1
- package/ai/skills/stacks-docs/SKILL.md +1 -1
- package/ai/skills/stacks-domain-modeling/FORMATS.md +123 -0
- package/ai/skills/stacks-domain-modeling/SKILL.md +109 -0
- package/ai/skills/stacks-enums/SKILL.md +1 -1
- package/ai/skills/stacks-error-handling/SKILL.md +1 -1
- package/ai/skills/stacks-events/SKILL.md +1 -1
- package/ai/skills/stacks-faker/SKILL.md +1 -1
- package/ai/skills/stacks-flow/PHASE-BOUNDARIES.md +91 -0
- package/ai/skills/stacks-flow/SKILL.md +117 -0
- package/ai/skills/stacks-git/SKILL.md +37 -9
- package/ai/skills/stacks-grilling/SKILL.md +85 -0
- package/ai/skills/stacks-guard/SKILL.md +86 -11
- package/ai/skills/stacks-guard/scripts/block-destructive.sh +67 -0
- package/ai/skills/stacks-handoff/SKILL.md +70 -0
- package/ai/skills/stacks-health/SKILL.md +1 -1
- package/ai/skills/stacks-http/SKILL.md +1 -1
- package/ai/skills/stacks-i18n/SKILL.md +1 -1
- package/ai/skills/stacks-investigate/SKILL.md +234 -106
- package/ai/skills/stacks-investigate/scripts/hitl-loop.template.sh +47 -0
- package/ai/skills/stacks-jobs/SKILL.md +1 -1
- package/ai/skills/stacks-listeners/SKILL.md +1 -1
- package/ai/skills/stacks-logging/SKILL.md +1 -1
- package/ai/skills/stacks-mail/SKILL.md +1 -1
- package/ai/skills/stacks-middleware/SKILL.md +1 -1
- package/ai/skills/stacks-migrations/SKILL.md +1 -1
- package/ai/skills/stacks-models/SKILL.md +1 -1
- package/ai/skills/stacks-new-feature/SKILL.md +65 -5
- package/ai/skills/stacks-notifications/SKILL.md +1 -1
- package/ai/skills/stacks-objects/SKILL.md +1 -1
- package/ai/skills/stacks-office-hours/SKILL.md +16 -2
- package/ai/skills/stacks-orm/SKILL.md +1 -1
- package/ai/skills/stacks-path/SKILL.md +1 -1
- package/ai/skills/stacks-payments/SKILL.md +35 -1
- package/ai/skills/stacks-plan-review/SKILL.md +27 -6
- package/ai/skills/stacks-plugins/SKILL.md +1 -1
- package/ai/skills/stacks-prototype/LOGIC.md +103 -0
- package/ai/skills/stacks-prototype/SKILL.md +66 -0
- package/ai/skills/stacks-prototype/UI.md +112 -0
- package/ai/skills/stacks-push/SKILL.md +1 -1
- package/ai/skills/stacks-query-builder/SKILL.md +1 -1
- package/ai/skills/stacks-queue/SKILL.md +1 -1
- package/ai/skills/stacks-realtime/SKILL.md +1 -1
- package/ai/skills/stacks-registry/SKILL.md +1 -1
- package/ai/skills/stacks-repl/SKILL.md +1 -1
- package/ai/skills/stacks-retro/SKILL.md +121 -75
- package/ai/skills/stacks-review/SKILL.md +182 -74
- package/ai/skills/stacks-router/SKILL.md +1 -1
- package/ai/skills/stacks-routes/SKILL.md +1 -1
- package/ai/skills/stacks-scaffolding/SKILL.md +1 -1
- package/ai/skills/stacks-scheduler/SKILL.md +1 -1
- package/ai/skills/stacks-search-engine/SKILL.md +1 -1
- package/ai/skills/stacks-security/SKILL.md +1 -1
- package/ai/skills/stacks-security-audit/SKILL.md +1 -1
- package/ai/skills/stacks-server/SKILL.md +1 -1
- package/ai/skills/stacks-shell/SKILL.md +1 -1
- package/ai/skills/stacks-slug/SKILL.md +1 -1
- package/ai/skills/stacks-sms/SKILL.md +1 -1
- package/ai/skills/stacks-socials/SKILL.md +1 -1
- package/ai/skills/stacks-storage/SKILL.md +1 -1
- package/ai/skills/stacks-strings/SKILL.md +1 -1
- package/ai/skills/stacks-stx/SKILL.md +1 -1
- package/ai/skills/stacks-tdd/EXAMPLES.md +136 -0
- package/ai/skills/stacks-tdd/SKILL.md +125 -0
- package/ai/skills/stacks-testing/SKILL.md +13 -3
- package/ai/skills/stacks-tunnel/SKILL.md +1 -1
- package/ai/skills/stacks-types/SKILL.md +1 -1
- package/ai/skills/stacks-ui/SKILL.md +1 -1
- package/ai/skills/stacks-utils/SKILL.md +1 -1
- package/ai/skills/stacks-validation/SKILL.md +1 -1
- package/ai/skills/stacks-whois/SKILL.md +1 -1
- package/ai/skills/stacks-wizard/SKILL.md +127 -0
- package/ai/skills/stacks-wizard/scripts/template.sh +208 -0
- package/ai/skills/stacks-writing-for-agents/MECHANICS.md +125 -0
- package/ai/skills/stacks-writing-for-agents/SKILL.md +218 -0
- package/app/Actions/Auth/GenerateTwoFactorSecretAction.ts +12 -2
- package/app/Actions/Commerce/Shipping/{DriverDestroyAction.ts → CourierDestroyAction.ts} +6 -6
- package/app/Actions/Commerce/Shipping/{DriverIndexAction.ts → CourierIndexAction.ts} +3 -3
- package/app/Actions/Commerce/Shipping/CourierPingStoreAction.ts +61 -0
- package/app/Actions/Commerce/Shipping/{DriverShowAction.ts → CourierShowAction.ts} +5 -5
- package/app/Actions/Commerce/Shipping/{DriverStoreAction.ts → CourierStoreAction.ts} +4 -4
- package/app/Actions/Commerce/Shipping/{DriverUpdateAction.ts → CourierUpdateAction.ts} +6 -6
- package/app/Actions/Commerce/Shipping/DeliveryRouteStartAction.ts +38 -0
- package/app/Actions/Commerce/Shipping/DeliveryStopCompleteAction.ts +40 -0
- package/app/Actions/Commerce/Shipping/DeliveryStopFailAction.ts +44 -0
- package/app/Actions/Commerce/Shipping/DeliveryStopStartAction.ts +39 -0
- package/app/Actions/Commerce/Shipping/courier-session.ts +75 -0
- package/app/Actions/Commerce/commerce-action.test.ts +5 -5
- package/app/Actions/Dashboard/Commerce/CommerceDeliveryAction.ts +5 -5
- package/app/Actions/Dashboard/Commerce/CourierIndexAction.ts +24 -0
- package/app/Actions/Dashboard/Commerce/DeliveryRouteIndexAction.ts +7 -7
- package/app/Actions/Dashboard/Commerce/commerce-delivery.test.ts +11 -11
- package/app/Actions/Dashboard/Commerce/commerce-delivery.ts +29 -29
- package/app/Actions/Dashboard/Commerce/{driver-records.test.ts → courier-records.test.ts} +9 -9
- package/app/Actions/Dashboard/Commerce/{driver-records.ts → courier-records.ts} +14 -14
- package/app/Actions/Dashboard/Commerce/delivery-route-records.test.ts +13 -13
- package/app/Actions/Dashboard/Commerce/delivery-route-records.ts +25 -25
- package/app/Models/User.ts +1 -1
- package/app/Models/commerce/{Driver.ts → Courier.ts} +7 -7
- package/app/Models/commerce/{DriverPing.ts → CourierPing.ts} +7 -7
- package/app/Models/commerce/DeliveryRoute.ts +6 -6
- package/app/Models/commerce/DeliveryStop.ts +31 -8
- package/bootstrap.ts +7 -0
- package/functions/commerce/shippings/couriers.ts +19 -0
- package/ide/vscode/package.json +1 -1
- package/package.json +4 -3
- package/resources/components/Dashboard/Commerce/Delivery/{DriverDeleteDialog.stx → CourierDeleteDialog.stx} +5 -5
- package/resources/components/Dashboard/Commerce/Delivery/{DriverDialog.stx → CourierDialog.stx} +10 -10
- package/resources/components/Dashboard/Commerce/Delivery/{DriversDashboard.stx → CouriersDashboard.stx} +43 -43
- package/resources/components/Dashboard/Commerce/Delivery/{DriversTable.stx → CouriersTable.stx} +21 -21
- package/resources/components/Dashboard/Commerce/Delivery/DeliveryOverviewDashboard.stx +18 -18
- package/resources/components/Dashboard/Commerce/Delivery/DeliveryRouteDeleteDialog.stx +2 -2
- package/resources/components/Dashboard/Commerce/Delivery/DeliveryRouteDialog.stx +22 -22
- package/resources/components/Dashboard/Commerce/Delivery/DeliveryRoutesDashboard.stx +24 -24
- package/resources/components/Dashboard/Commerce/Delivery/DeliveryRoutesTable.stx +8 -8
- package/resources/components/Dashboard/Commerce/Delivery/TabNavigation.stx +1 -1
- package/resources/functions/dashboard/data.ts +1 -1
- package/resources/functions/dashboard/sidebar.ts +2 -2
- package/routes/dashboard-api.ts +6 -6
- package/routes/dashboard.ts +7 -7
- package/routes/delivery.ts +24 -0
- package/types/defaults.ts +3 -3
- package/views/dashboard/.discovered-models.json +18 -18
- package/views/dashboard/AUDIT.md +1 -1
- package/views/dashboard/commerce/delivery/{drivers.stx → couriers.stx} +2 -2
- package/views/dashboard/composables/useChart.ts +16 -2
- package/app/Actions/Dashboard/Commerce/DriverIndexAction.ts +0 -24
- package/functions/commerce/shippings/drivers.ts +0 -19
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-slug
|
|
3
|
-
description: Use when generating URL slugs in Stacks
|
|
3
|
+
description: Use when generating URL slugs in Stacks - creating unique slugs with database collision detection, the uniqueSlug function with table/column configuration, or basic slugification. Covers @stacksjs/slug.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-sms
|
|
3
|
-
description: Use when implementing SMS in Stacks
|
|
3
|
+
description: Use when implementing SMS in Stacks - sending text messages, the SmsBuilder fluent API, SMS templates, phone verification (OTP/2FA), bulk sending, Twilio/Vonage drivers, E.164 formatting, or the SMS facade. Covers @stacksjs/sms and config/sms.ts.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-socials
|
|
3
|
-
description: Use when implementing social authentication in Stacks
|
|
3
|
+
description: Use when implementing social authentication in Stacks - OAuth2 flows with GitHub/Google/Facebook/Twitter providers, the AbstractProvider base class, PKCE support, state management, scope configuration, social user profiles, or token handling. Covers @stacksjs/socials.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-storage
|
|
3
|
-
description: Use when working with file storage in Stacks
|
|
3
|
+
description: Use when working with file storage in Stacks - the Storage facade (put/get/delete/copy/move/list), StorageAdapter interface, local and S3 disk configurations, file uploads (UploadedFile class), file operations (read/write/copy/move/delete/hash/glob/zip), visibility management, checksums, MIME types, temporary URLs, or filesystem configuration. Covers @stacksjs/storage and config/filesystems.ts.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-strings
|
|
3
|
-
description: Use when working with string utilities in Stacks
|
|
3
|
+
description: Use when working with string utilities in Stacks - case conversion (camelCase, PascalCase, snake_case, kebab-case, CONSTANT_CASE, Train-Case, etc.), pluralization, string validation (email, URL, UUID, credit card, etc.), slug generation, random strings, template interpolation, or the Str facade. Covers @stacksjs/strings.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-stx
|
|
3
|
-
description: Use when working with STX templates in a Stacks application
|
|
3
|
+
description: Use when working with STX templates in a Stacks application - template syntax, components, directives, signals, reactivity, SSR, streaming, hydration, or debugging STX rendering. STX is the ONLY templating system for Stacks.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Good and bad tests
|
|
2
|
+
|
|
3
|
+
## Good
|
|
4
|
+
|
|
5
|
+
**Integration-style**: through real interfaces, not mocks of internal parts.
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { describe, expect, test } from 'bun:test'
|
|
9
|
+
|
|
10
|
+
test('a customer can check out with a valid cart', async () => {
|
|
11
|
+
const cart = await Cart.create({ customer_id: customer.id })
|
|
12
|
+
await cart.add(product)
|
|
13
|
+
|
|
14
|
+
const result = await checkout(cart, paymentMethod)
|
|
15
|
+
|
|
16
|
+
expect(result.status).toBe('confirmed')
|
|
17
|
+
})
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Characteristics:
|
|
21
|
+
|
|
22
|
+
- Tests behaviour callers care about.
|
|
23
|
+
- Uses the public surface only.
|
|
24
|
+
- Survives internal refactors.
|
|
25
|
+
- Describes what, not how.
|
|
26
|
+
- One logical assertion per test.
|
|
27
|
+
|
|
28
|
+
## Bad
|
|
29
|
+
|
|
30
|
+
**Implementation-detail tests**: coupled to internal structure.
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// bad: asserts on an internal collaborator
|
|
34
|
+
test('checkout calls the payment driver', async () => {
|
|
35
|
+
const spy = mock(paymentDriver.process)
|
|
36
|
+
await checkout(cart, payment)
|
|
37
|
+
expect(spy).toHaveBeenCalledWith(cart.total)
|
|
38
|
+
})
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Red flags: mocking internal collaborators, testing private methods, asserting on
|
|
42
|
+
call counts or ordering, a test that breaks on a refactor with no behaviour
|
|
43
|
+
change, a test name that describes how.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// bad: bypasses the interface to verify
|
|
47
|
+
test('createUser saves to the database', async () => {
|
|
48
|
+
await createUser({ name: 'Alice' })
|
|
49
|
+
const row = await db.raw('select * from users where name = ?', ['Alice'])
|
|
50
|
+
expect(row).toBeDefined()
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
// good: verifies through the interface
|
|
54
|
+
test('createUser makes the user retrievable', async () => {
|
|
55
|
+
const user = await createUser({ name: 'Alice' })
|
|
56
|
+
const retrieved = await User.find(user.id)
|
|
57
|
+
expect(retrieved?.name).toBe('Alice')
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Tautological tests**: the expected value restates the implementation, so the
|
|
62
|
+
test passes by construction.
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// bad: expected value recomputed the way the code computes it
|
|
66
|
+
test('calculateTotal sums line items', () => {
|
|
67
|
+
const items = [{ price: 10 }, { price: 5 }]
|
|
68
|
+
const expected = items.reduce((sum, i) => sum + i.price, 0)
|
|
69
|
+
expect(calculateTotal(items)).toBe(expected)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
// good: expected value is an independent literal
|
|
73
|
+
test('calculateTotal sums line items', () => {
|
|
74
|
+
expect(calculateTotal([{ price: 10 }, { price: 5 }])).toBe(15)
|
|
75
|
+
})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## When to stand something in
|
|
79
|
+
|
|
80
|
+
Stand in at **system boundaries** only:
|
|
81
|
+
|
|
82
|
+
- Third-party HTTP: Stripe, SES, SendGrid, Mailgun, Twilio, Anthropic, OpenAI,
|
|
83
|
+
Meilisearch, Algolia, Route53.
|
|
84
|
+
- Time and randomness.
|
|
85
|
+
- The queue, when the assertion is "this job was dispatched" rather than "this
|
|
86
|
+
job ran".
|
|
87
|
+
- The filesystem, sometimes. The local storage driver is usually enough.
|
|
88
|
+
|
|
89
|
+
Do not stand in for:
|
|
90
|
+
|
|
91
|
+
- Your own actions, models, jobs or listeners.
|
|
92
|
+
- The database. Use `setupDatabase()` and `refreshDatabase()`.
|
|
93
|
+
- The cache. Use the `memory` driver.
|
|
94
|
+
- Anything under `@stacksjs/*` that you control.
|
|
95
|
+
|
|
96
|
+
## Designing for a stand-in
|
|
97
|
+
|
|
98
|
+
**Accept the dependency.**
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// easy to substitute
|
|
102
|
+
export async function processPayment(order: Order, gateway: PaymentGateway) {
|
|
103
|
+
return gateway.charge(order.total)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// hard to substitute
|
|
107
|
+
export async function processPayment(order: Order) {
|
|
108
|
+
const gateway = new StripeGateway(env.STRIPE_KEY)
|
|
109
|
+
return gateway.charge(order.total)
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Prefer an SDK-shaped surface over one generic fetcher.** A named function per
|
|
114
|
+
external operation is independently substitutable and self-documenting. One
|
|
115
|
+
`fetch(endpoint, options)` forces conditional logic into every stand-in. This is
|
|
116
|
+
the shape the framework's own driver packages use, so a new external integration
|
|
117
|
+
should copy it rather than invent a third pattern.
|
|
118
|
+
|
|
119
|
+
## Queue assertions
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { fake, restore } from '@stacksjs/queue'
|
|
123
|
+
|
|
124
|
+
test('publishing an article dispatches the index job', async () => {
|
|
125
|
+
const queue = fake()
|
|
126
|
+
|
|
127
|
+
await publishArticle(article.id)
|
|
128
|
+
|
|
129
|
+
queue.assertDispatched('IndexArticle')
|
|
130
|
+
restore()
|
|
131
|
+
})
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
`fake()` mutates global state, so `restore()` belongs in the same test or in
|
|
135
|
+
`afterEach`. A suite that forgets it will fail somewhere else and blame the wrong
|
|
136
|
+
code.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stacks-tdd
|
|
3
|
+
description: Use when building a feature or fixing a bug test-first in a Stacks project, when the user mentions red-green-refactor or vertical slices, or when deciding which seam a test belongs at. Covers the red-green loop over bun test and @stacksjs/testing, seam selection, and the test anti-patterns.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
|
+
allowed-tools: Read Edit Write Bash Grep Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Test-driven development
|
|
10
|
+
|
|
11
|
+
TDD is the red to green loop. This skill is the reference that makes the loop
|
|
12
|
+
produce tests worth keeping: what a good test is, where tests go, the
|
|
13
|
+
anti-patterns, and the rules of the loop. Every section applies on every cycle.
|
|
14
|
+
Consult them before and during, not after.
|
|
15
|
+
|
|
16
|
+
`stacks-testing` is the *mechanics*: `setupDatabase()`, `refreshDatabase()`,
|
|
17
|
+
DynamoDB Local, `bunfig.toml` preload, the CLI flags. This skill is the
|
|
18
|
+
*discipline*. Read that one for the API and this one for the decisions.
|
|
19
|
+
|
|
20
|
+
Credit: adapted from Matt Pocock's `tdd` skill (MIT),
|
|
21
|
+
<https://github.com/mattpocock/skills>.
|
|
22
|
+
|
|
23
|
+
## What a good test is
|
|
24
|
+
|
|
25
|
+
Tests verify behaviour through public interfaces, never implementation details.
|
|
26
|
+
Code can change entirely, tests should not. A good test reads like a
|
|
27
|
+
specification: "a customer can check out with a valid cart" tells you exactly
|
|
28
|
+
what capability exists, and it survives refactors because it does not care about
|
|
29
|
+
internal structure.
|
|
30
|
+
|
|
31
|
+
See [EXAMPLES.md](EXAMPLES.md) for good and bad tests side by side, and for
|
|
32
|
+
where mocking is legitimate.
|
|
33
|
+
|
|
34
|
+
## Seams: where tests go
|
|
35
|
+
|
|
36
|
+
A **seam** is the public boundary you test at, the interface where you observe
|
|
37
|
+
behaviour without reaching inside. Tests live at seams, never against internals.
|
|
38
|
+
When the shape of that interface is itself in question, call the Skill tool with
|
|
39
|
+
`stacks-codebase-design` for the vocabulary. It owns the module, interface,
|
|
40
|
+
depth, seam, adapter, leverage and locality terms.
|
|
41
|
+
|
|
42
|
+
**Test only at pre-agreed seams.** Before writing any test, write down the seams
|
|
43
|
+
under test and confirm them with the user. No test is written at an unconfirmed
|
|
44
|
+
seam. You cannot test everything, so agreeing the seams up front is how testing
|
|
45
|
+
effort lands on the critical paths instead of on every edge case.
|
|
46
|
+
|
|
47
|
+
A Stacks app has four seams worth naming, from highest to lowest. Prefer the
|
|
48
|
+
highest one that can go red on the behaviour you care about:
|
|
49
|
+
|
|
50
|
+
| Seam | Test through | Use when |
|
|
51
|
+
|---|---|---|
|
|
52
|
+
| Route | an HTTP request against the running route, middleware included | the behaviour is a user-visible endpoint |
|
|
53
|
+
| Action | calling the action in `app/Actions/` directly | the behaviour is the request-to-response logic, and you do not need middleware in the picture |
|
|
54
|
+
| Model | the model's query and mutation surface, against the test database | the behaviour is a trait, a relationship, a computed attribute, or a validation rule |
|
|
55
|
+
| Function | a plain import from `resources/functions/` or a `@stacksjs/*` package | the behaviour is pure computation |
|
|
56
|
+
|
|
57
|
+
The fewer seams you cross for one feature, the better. One is ideal.
|
|
58
|
+
|
|
59
|
+
## The database is not a boundary to mock
|
|
60
|
+
|
|
61
|
+
The framework hands you a real one. `setupDatabase()` creates
|
|
62
|
+
`database/stacks_testing.sqlite`, `refreshDatabase()` drops and re-migrates it,
|
|
63
|
+
and the per-attribute `factory` functions in each model produce realistic rows.
|
|
64
|
+
Use them. A test that mocks `User.find()` is testing the mock.
|
|
65
|
+
|
|
66
|
+
Real boundaries in a Stacks app, the ones where a stand-in is correct: third
|
|
67
|
+
party HTTP (Stripe, SES, Anthropic, Meilisearch), the clock, randomness, and the
|
|
68
|
+
queue when you are asserting that a job was dispatched rather than that it ran.
|
|
69
|
+
`fake()` / `restore()` from `@stacksjs/queue` exist for that last one.
|
|
70
|
+
|
|
71
|
+
## Anti-patterns
|
|
72
|
+
|
|
73
|
+
- **Implementation-coupled**: mocks internal collaborators, tests private
|
|
74
|
+
methods, or verifies through a side channel (querying the database with raw
|
|
75
|
+
SQL instead of reading back through the model). The tell: the test breaks when
|
|
76
|
+
you refactor but behaviour has not changed.
|
|
77
|
+
- **Tautological**: the assertion recomputes the expected value the way the code
|
|
78
|
+
does, so it passes by construction and can never disagree with the code.
|
|
79
|
+
Expected values must come from an independent source of truth: a known-good
|
|
80
|
+
literal, a worked example, the spec.
|
|
81
|
+
- **Horizontal slicing**: writing all the tests first, then all the
|
|
82
|
+
implementation. Bulk tests verify *imagined* behaviour. You test the shape of
|
|
83
|
+
things rather than user-facing behaviour, the tests go insensitive to real
|
|
84
|
+
changes, and you commit to a test structure before understanding the
|
|
85
|
+
implementation. Work in **vertical slices** instead: one test, one
|
|
86
|
+
implementation, repeat. Each test is a **tracer bullet** that responds to what
|
|
87
|
+
the last cycle taught you.
|
|
88
|
+
- **Leaking state between files**: `refreshDatabase()` drops every table, and
|
|
89
|
+
`fake()` mutates global queue state. Both belong in setup and teardown, never
|
|
90
|
+
mid-test.
|
|
91
|
+
|
|
92
|
+
## Rules of the loop
|
|
93
|
+
|
|
94
|
+
- **Red before green.** Write the failing test first, then only enough code to
|
|
95
|
+
pass it. Do not anticipate future tests or add speculative features.
|
|
96
|
+
- **One slice at a time.** One seam, one test, one minimal implementation per
|
|
97
|
+
cycle.
|
|
98
|
+
- **Run the narrow thing during the loop.** `bun test tests/feature/articles.test.ts`
|
|
99
|
+
is the loop. `buddy test` is the gate you run once at the end. Passing a path
|
|
100
|
+
to `bun test` filters, it does not scope, so keep the path narrow while you
|
|
101
|
+
iterate.
|
|
102
|
+
- **Typecheck alongside.** `./buddy typecheck` for `app/`, `config/`,
|
|
103
|
+
`resources/` and `routes/`. It runs on tsgo and finishes in seconds, so there
|
|
104
|
+
is no reason to save it for the end.
|
|
105
|
+
- **Refactoring is not part of the loop.** It belongs to review. Run
|
|
106
|
+
`/stacks-review` once the slice is green.
|
|
107
|
+
|
|
108
|
+
## Model-first order
|
|
109
|
+
|
|
110
|
+
A vertical slice in Stacks cuts through the model, the migration, the action, the
|
|
111
|
+
route and the test. Migrations are derived from models here, so the loop has one
|
|
112
|
+
extra beat compared to other frameworks:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
model change → buddy generate:migrations → review the SQL → buddy migrate → red test → green
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Skipping the review step is how a wrong column type reaches every downstream
|
|
119
|
+
environment. See `stacks-new-feature` for the full slice and
|
|
120
|
+
`stacks-migrations` for the generation rules.
|
|
121
|
+
|
|
122
|
+
## Downstream
|
|
123
|
+
|
|
124
|
+
> Green? Run `/stacks-review` for the two-axis review, then `/stacks-browse` if
|
|
125
|
+
> the slice has a UI.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-testing
|
|
3
|
-
description: Use when writing or running tests in Stacks
|
|
3
|
+
description: Use when writing or running tests in Stacks - test setup, database test utilities (setup, refresh, truncate), DynamoDB testing, feature test patterns, the test CLI commands, test configuration in bunfig.toml, or test environment setup. Covers @stacksjs/testing and tests/.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -10,6 +10,11 @@ allowed-tools: Read Edit Write Bash Grep Glob
|
|
|
10
10
|
|
|
11
11
|
Uses Bun's built-in test runner with Stacks-specific test utilities.
|
|
12
12
|
|
|
13
|
+
This skill is the **mechanics**: the utilities, the setup, the CLI, the gotchas.
|
|
14
|
+
`stacks-tdd` is the **discipline**: the red-green loop, which seam a test belongs
|
|
15
|
+
at, and the anti-patterns that make a test worse than no test. Read that one
|
|
16
|
+
before deciding what to test, and this one for how.
|
|
17
|
+
|
|
13
18
|
## Key Paths
|
|
14
19
|
- Core package: `storage/framework/core/testing/src/`
|
|
15
20
|
- Test directory: `tests/`
|
|
@@ -122,8 +127,13 @@ preload = ["./tests/setup.ts"]
|
|
|
122
127
|
- Uses Bun's native test runner, NOT Jest or Vitest
|
|
123
128
|
- Test preload runs `tests/setup.ts` before each test file
|
|
124
129
|
- SQLite testing database is at `database/stacks_testing.sqlite`
|
|
125
|
-
- `refreshDatabase()` drops ALL tables
|
|
130
|
+
- `refreshDatabase()` drops ALL tables - use in test setup only
|
|
126
131
|
- DynamoDB Local must be installed for DynamoDB tests
|
|
127
|
-
- Queue testing uses `fake()`/`restore()` pattern
|
|
132
|
+
- Queue testing uses `fake()`/`restore()` pattern - affects global state
|
|
128
133
|
- `@stacksjs/faker` provides test data generation
|
|
129
134
|
- Coverage reports with `bun run test:coverage`
|
|
135
|
+
|
|
136
|
+
## Downstream
|
|
137
|
+
|
|
138
|
+
> Deciding what to test, or where? `/stacks-tdd`. Reviewing someone else's
|
|
139
|
+
> tests? `/stacks-review` audits coverage as its third pass.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-tunnel
|
|
3
|
-
description: Use when setting up tunnels in Stacks
|
|
3
|
+
description: Use when setting up tunnels in Stacks - local development tunnels for webhook testing, custom cloud tunnel deployment to AWS EC2, tunnel event callbacks (onConnect, onRequest, onResponse, onError), subdomain configuration, or the buddy share command. Covers @stacksjs/tunnel.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-types
|
|
3
|
-
description: Use when working with TypeScript type definitions in a Stacks application
|
|
3
|
+
description: Use when working with TypeScript type definitions in a Stacks application - model types, request types, environment variables, event types, billing types, attribute types, or auto-imported globals. Covers storage/framework/types/ and storage/framework/core/types/src/.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-ui
|
|
3
|
-
description: Use when working with UI in a Stacks application
|
|
3
|
+
description: Use when working with UI in a Stacks application - components, composables, reactivity (refs/watch/computed), Craft native components, Crosswind CSS, Crosswind utility framework, accessibility, or the STX templating engine. Covers @stacksjs/ui, @stacksjs/stx, and related UI tooling.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-utils
|
|
3
|
-
description: Use when needing general utility functions in Stacks
|
|
3
|
+
description: Use when needing general utility functions in Stacks - deep merge, debounce/throttle, color output, byte formatting, markdown tables, YAML parsing, Pipeline class, ResizeObserver, Macroable, project initialization, indentation detection, or the comprehensive utility toolkit. Covers @stacksjs/utils.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-validation
|
|
3
|
-
description: Use when implementing validation in Stacks
|
|
3
|
+
description: Use when implementing validation in Stacks - type guards (isString, isNumber, isBoolean, isObject, isArray, isFunction, etc.), numeric checks (isPositive, isEven, isInteger), the schema builder for model attribute validation, or request validation. Covers @stacksjs/validation.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: stacks-whois
|
|
3
|
-
description: Use when performing WHOIS lookups in Stacks
|
|
3
|
+
description: Use when performing WHOIS lookups in Stacks - domain queries, batch lookups, SOCKS proxy support, TLD server discovery, response parsing, the WhoIsParser class, or the built-in SocksClient. Covers @stacksjs/whois.
|
|
4
4
|
license: MIT
|
|
5
5
|
compatibility: Bun >= 1.3.0, TypeScript
|
|
6
6
|
allowed-tools: Read Edit Write Bash Grep Glob
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stacks-wizard
|
|
3
|
+
description: Use when a procedure needs a human in the loop and the agent has hit a wall it cannot pass alone - provisioning cloud credentials, verifying a sending domain, setting CI secrets, clicking through a registrar or third-party dashboard, or running a one-off cutover. Generates an interactive bash wizard that opens each URL, captures each value, and writes it into .env and GitHub secrets.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Bun >= 1.3.0, TypeScript, bash
|
|
6
|
+
allowed-tools: Read Edit Write Bash Grep Glob
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Wizard
|
|
10
|
+
|
|
11
|
+
A **wizard** is a bash script that walks a human, step by step, through a manual
|
|
12
|
+
procedure that is tedious to do by hand and tedious to re-explain to an agent
|
|
13
|
+
every time. It opens each URL, says exactly what to click and copy, captures the
|
|
14
|
+
values, writes them where they belong, confirms before anything irreversible, and
|
|
15
|
+
shows how many stages are left.
|
|
16
|
+
|
|
17
|
+
The UX is already solved by [scripts/template.sh](scripts/template.sh):
|
|
18
|
+
stage-by-stage progress, confirmation gates, cross-platform URL opening including
|
|
19
|
+
WSL, hidden entry for secrets, idempotent `.env` upserts, `gh secret` and
|
|
20
|
+
`gh variable` writes, and a closing summary. **Your job is only to scope the
|
|
21
|
+
procedure and author its stages.** Everything above the `STAGES` marker is
|
|
22
|
+
identical in every wizard, and that consistency is the point. Never hand-edit it.
|
|
23
|
+
|
|
24
|
+
A wizard is ephemeral by default: built for one run, saved to a scratch path or
|
|
25
|
+
`scripts/`, deleted when the job is done. Commit it only when the user wants a
|
|
26
|
+
repeatable setup path that should live in the repo.
|
|
27
|
+
|
|
28
|
+
Credit: adapted from Matt Pocock's `wizard` skill (MIT),
|
|
29
|
+
<https://github.com/mattpocock/skills>. The template library is his, unchanged
|
|
30
|
+
except for the example stage.
|
|
31
|
+
|
|
32
|
+
## When this is the right tool
|
|
33
|
+
|
|
34
|
+
Reach for it the moment you hit a step only the human can take. In a Stacks
|
|
35
|
+
project that is a short and predictable list:
|
|
36
|
+
|
|
37
|
+
- **AWS access** for `buddy deploy` and `buddy cloud`, and the IAM permissions
|
|
38
|
+
behind them.
|
|
39
|
+
- **Domains and DNS**: `buddy domains:purchase`, registrar nameserver changes,
|
|
40
|
+
the delegation that has to happen at the registrar rather than in Route53.
|
|
41
|
+
- **Email**: SES domain verification, DKIM records, moving out of the sandbox,
|
|
42
|
+
the port 25 request.
|
|
43
|
+
- **CI secrets**: every `secrets.*` and `vars.*` reference in
|
|
44
|
+
`.github/workflows/*` is a value the wizard should produce.
|
|
45
|
+
- **Server provisioning**: a Hetzner or other provider token, an SSH key added to
|
|
46
|
+
the account, the first-boot steps.
|
|
47
|
+
- **Payments**: Stripe keys and webhook endpoints.
|
|
48
|
+
|
|
49
|
+
If the agent could just do it itself, it should. This is for where a human is
|
|
50
|
+
genuinely in the loop.
|
|
51
|
+
|
|
52
|
+
## Process
|
|
53
|
+
|
|
54
|
+
### 1. Scope the procedure
|
|
55
|
+
|
|
56
|
+
Work out every manual step the human must take and every value captured along the
|
|
57
|
+
way. Read the repo first, do not ask cold:
|
|
58
|
+
|
|
59
|
+
- `.env`, `.env.example`, `.env.*`, and `config/services.ts` for what the app
|
|
60
|
+
already expects.
|
|
61
|
+
- `config/cloud.ts`, `config/dns.ts`, `config/email.ts` for what the deploy
|
|
62
|
+
targets.
|
|
63
|
+
- `.github/workflows/*` for every secret and variable CI reads.
|
|
64
|
+
- The relevant skill (`stacks-deploy`, `stacks-cloud`, `stacks-dns`,
|
|
65
|
+
`stacks-email`) for which steps the CLI already automates, so the wizard covers
|
|
66
|
+
only the gap.
|
|
67
|
+
|
|
68
|
+
Then show the user the ordered list of stages and the values each produces, and
|
|
69
|
+
confirm. They may add, drop or reorder.
|
|
70
|
+
|
|
71
|
+
**Done when** every stage is named in order, and for each captured value you know
|
|
72
|
+
(a) where the human gets it, (b) where it is written (`.env`, a GitHub secret,
|
|
73
|
+
both, or nowhere, since some stages are pure actions), and (c) whether it is
|
|
74
|
+
secret and so needs hidden entry.
|
|
75
|
+
|
|
76
|
+
### 2. Map each stage's journey
|
|
77
|
+
|
|
78
|
+
For each stage, write the precise path a human follows: which URL to open, what
|
|
79
|
+
to do there, where the value is shown, which variable it fills. For example
|
|
80
|
+
"Route53 console, Hosted zones, pick the domain, copy the four NS records".
|
|
81
|
+
|
|
82
|
+
Where you do not know the current UI or the exact command, say so and ask the
|
|
83
|
+
user or check the docs. Never invent steps that may not exist.
|
|
84
|
+
|
|
85
|
+
**Done when** every stage traces to concrete instructions a stranger could
|
|
86
|
+
follow.
|
|
87
|
+
|
|
88
|
+
### 3. Author the wizard
|
|
89
|
+
|
|
90
|
+
Copy `scripts/template.sh` to the target path. Replace the example stage with one
|
|
91
|
+
`stage` per step, in dependency order. Set `TOTAL_STAGES` to the number you
|
|
92
|
+
wrote. Use the library helpers: `stage`, `say`, `step`, `note`, `warn`,
|
|
93
|
+
`open_url`, `ask`, `ask_secret`, `write_env`, `set_secret`, `set_var`, `pause`,
|
|
94
|
+
`confirm`.
|
|
95
|
+
|
|
96
|
+
Hold the bar the template sets:
|
|
97
|
+
|
|
98
|
+
- Open the URL before asking for its value.
|
|
99
|
+
- `ask_secret` for anything secret.
|
|
100
|
+
- `write_env` every persisted value.
|
|
101
|
+
- `set_secret` only the values CI actually needs.
|
|
102
|
+
- `confirm` before anything irreversible.
|
|
103
|
+
- One focused task per `stage`, because each stage clears the screen and anything
|
|
104
|
+
the human still needs must not have scrolled away.
|
|
105
|
+
|
|
106
|
+
In a Stacks project, finish with a stage that encrypts what you just wrote:
|
|
107
|
+
`./buddy env:encrypt`, and for a production file the matching
|
|
108
|
+
`buddy env:keypair` / `buddy env:rotate` step. A wizard that leaves plaintext
|
|
109
|
+
credentials in `.env.production` has done half a job. `buddy env:check` is the
|
|
110
|
+
verification line for the closing stage.
|
|
111
|
+
|
|
112
|
+
### 4. Verify and hand off
|
|
113
|
+
|
|
114
|
+
- `bash -n <script>`, and `shellcheck` if it is available.
|
|
115
|
+
- `chmod +x <script>`.
|
|
116
|
+
- Do not run it end to end yourself. It opens browsers and blocks on human input.
|
|
117
|
+
Trace it statically instead: every value from step 1 is captured and lands
|
|
118
|
+
where step 1 said, and every `set_secret` name matches a `secrets.*` reference
|
|
119
|
+
in CI exactly.
|
|
120
|
+
- Tell the user how to run it. If it is a repeatable setup path, commit it under
|
|
121
|
+
`scripts/` and link it from the README so the next person runs the script
|
|
122
|
+
instead of asking an agent.
|
|
123
|
+
|
|
124
|
+
## Downstream
|
|
125
|
+
|
|
126
|
+
> Credentials in place? `/stacks-deploy` for the deploy workflow itself, and
|
|
127
|
+
> `/stacks-guard` before anything touches production.
|