@gallopsystems/agent-skills 1.25.0 → 1.26.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/package.json +1 -1
- package/plugins/frontend-design/skills/frontend-design/SKILL.md +10 -0
- package/plugins/kysely-postgres/skills/kysely-postgres/SKILL.md +1 -0
- package/plugins/kysely-postgres/skills/kysely-postgres/references/migrations-and-codegen.md +59 -0
- package/plugins/linear/skills/linear/SKILL.md +5 -0
- package/plugins/tailwind-v4/skills/tailwind-v4/gotchas.md +9 -1
package/package.json
CHANGED
|
@@ -199,6 +199,16 @@ The first three are the foundational lenses — every other principle and rule s
|
|
|
199
199
|
- **Why:** This is core to the tool-like feel. Persistent action buttons next to every value make lists feel cluttered and form-like; inline edit + hover actions keep the surface calm and let content dominate.
|
|
200
200
|
- **How to apply:** For editable fields on detail pages and rows, prefer click-to-edit. For bulk row actions, use a hover-revealed action group or a per-row `…` (kebab) menu. Reserve always-visible buttons for the one or two primary actions of the surface.
|
|
201
201
|
|
|
202
|
+
#### Entering edit mode must not shift the layout
|
|
203
|
+
|
|
204
|
+
- **Rule:** Toggling a row or field between read and edit must not move anything around it. The read-out keeps its exact footprint, aligned columns (numeric value columns especially) stay put, and neighboring rows don't reflow. The classic offender is swapping a row's right-hand cells (the value/metric readout) for inputs — inputs have different widths, so the value column jumps and every other row's alignment breaks the instant one row opens.
|
|
205
|
+
- **Why:** A layout that lurches when you click "edit" reads as broken, and in a dense ledger/table it destroys the scannability that made the read view useful — the eye loses the column it was tracking. Stability is what makes inline editing feel native rather than like a bolted-on form.
|
|
206
|
+
- **How to apply:**
|
|
207
|
+
- Reveal the edit affordance (a pencil/kebab) with **absolute positioning** so it consumes no layout space — float it in the row's whitespace with `opacity-0 group-hover:opacity-100` (also reveal on `focus-visible`). Adding a real per-row action *column* pushes content and, unless you add the identical gutter to every row including headers/totals, misaligns the value column — absolute positioning sidesteps that entirely.
|
|
208
|
+
- For anything wider than the value it replaces (multiple inputs, unit×qty, a rate + suffix), **expand an editor strip below the row** rather than replacing the cells in place. The row above stays frozen showing the current value for context; the editor gets arbitrary width with zero horizontal shift. Animate the expand with a height/opacity transition (e.g. `v-auto-animate` / auto-height), never by animating siblings.
|
|
209
|
+
- Drop the row's bottom divider while it's being edited so the row and its editor strip read as one unit, not two stacked rows.
|
|
210
|
+
- One editor open at a time; autofocus the first input; **Enter** saves, **Esc** cancels. On save, patch → return to read-only → let the recomputed value settle back into the unchanged row.
|
|
211
|
+
|
|
202
212
|
#### Every interaction gets immediate visible feedback
|
|
203
213
|
|
|
204
214
|
- **Rule:** The moment a user acts, the UI must respond — within the same frame if possible. Pressed states on buttons (slight darken or scale, not just color), hover states on every clickable surface, optimistic UI updates for ordinary mutations (toggling a checkbox, renaming a field), an inline check or subtle highlight when a save completes. If a network call takes more than ~200ms, show a quiet inline spinner or skeleton in the affected region — not a global loading bar.
|
|
@@ -52,6 +52,7 @@ Runnable, copy-pasteable query examples live alongside as `.ts` files:
|
|
|
52
52
|
1. **Always use Kysely's query builder — never reach for raw `sql`**: Almost anything expressible in SQL is expressible type-safely through Kysely's methods and the ExpressionBuilder (`eb`); raw `sql`` throws away the type safety this stack depends on. Treat it as a true last resort — only when Kysely genuinely cannot express the query (and type the template literal when you must). Being unsure how to do something is the cue to check the reference guides above, **not** to drop to raw SQL.
|
|
53
53
|
2. **Use the ExpressionBuilder (eb)**: The `eb` parameter in callbacks is the foundation of type-safe query building
|
|
54
54
|
3. **Let TypeScript guide you**: If it compiles, it's likely correct SQL
|
|
55
|
+
4. **Document schema in the database, and read it before you touch a table**: Keep table/column/index/constraint notes as Postgres COMMENTs (not just migration source), surface them in the generated `db.d.ts`, and update them in the same migration that changes how something works. Consult that JSDoc to gather context before querying or altering a table — see [migrations-and-codegen.md](references/migrations-and-codegen.md#schema-comments--document-in-the-db-not-just-in-migration-source).
|
|
55
56
|
|
|
56
57
|
## Contributing Back
|
|
57
58
|
|
|
@@ -147,6 +147,46 @@ with `ifExists`, so re-applying it after the others is a safe no-op). Verify the
|
|
|
147
147
|
ledger is a contiguous prefix after the DELETE, and prefer letting the deploy's own
|
|
148
148
|
migrate job re-apply rather than running migrations from a laptop against prod.
|
|
149
149
|
|
|
150
|
+
## Schema Comments — Document in the DB, Not Just in Migration Source
|
|
151
|
+
|
|
152
|
+
Design notes written as `//` comments in a migration file are invisible the moment
|
|
153
|
+
the migration runs: they don't reach a live database and they don't reach the
|
|
154
|
+
generated types. **Put the documentation in the database itself** as Postgres
|
|
155
|
+
COMMENTs so it survives, stays queryable (`\d+`, `obj_description`, any GUI), and —
|
|
156
|
+
via codegen below — lands in the generated `db.d.ts` as JSDoc.
|
|
157
|
+
|
|
158
|
+
Comment every object that carries intent, not just tables and columns:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
await sql`COMMENT ON TABLE ${sql.ref("invoice")} IS ${sql.lit(
|
|
162
|
+
"A billed invoice. status is DERIVED from payments, never stored.",
|
|
163
|
+
)}`.execute(db);
|
|
164
|
+
await sql`COMMENT ON COLUMN ${sql.ref("invoice.void_reason")} IS ${sql.lit(
|
|
165
|
+
"Set only when status='void'; null otherwise.",
|
|
166
|
+
)}`.execute(db);
|
|
167
|
+
await sql`COMMENT ON INDEX ${sql.ref("uq_invoice_current_number")} IS ${sql.lit(
|
|
168
|
+
"One live number per org — partial unique WHERE void_at IS NULL.",
|
|
169
|
+
)}`.execute(db);
|
|
170
|
+
await sql`COMMENT ON CONSTRAINT ${sql.ref("invoice_status_check")} ON ${sql.ref("invoice")} IS ${sql.lit(
|
|
171
|
+
"status must be one of draft/sent/paid/void.",
|
|
172
|
+
)}`.execute(db);
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Use `sql.ref()` for identifiers and `sql.lit()` for the text (it escapes the
|
|
176
|
+
literal; `COMMENT` does not accept bound parameters). To reverse, set the comment
|
|
177
|
+
to `NULL`. Centralizing all comments in one data-driven migration (maps of
|
|
178
|
+
table/column/index/constraint → text, applied in `up`, nulled in `down`) keeps them
|
|
179
|
+
in one place and makes the `down` trivial.
|
|
180
|
+
|
|
181
|
+
**Keep comments in sync with behavior.** When a migration changes *how something
|
|
182
|
+
works* — a column's meaning, what a partial index enforces, a new CHECK — update
|
|
183
|
+
its comment in that same migration. A stale comment is worse than none.
|
|
184
|
+
|
|
185
|
+
**Gather context from these comments.** Before querying or changing a table, read
|
|
186
|
+
its JSDoc in the generated `db.d.ts` (see below) — the table/column/index/constraint
|
|
187
|
+
notes are the schema's own explanation of intent, invariants, and "derived, not
|
|
188
|
+
stored" rules. Prefer them over re-deriving intent from the raw column list.
|
|
189
|
+
|
|
150
190
|
## Type Generation
|
|
151
191
|
|
|
152
192
|
Use `kysely-codegen` to generate types from your database:
|
|
@@ -160,3 +200,22 @@ Generated types use:
|
|
|
160
200
|
- `ColumnType<Select, Insert, Update>` for different operation types
|
|
161
201
|
- `Timestamp` for timestamptz columns
|
|
162
202
|
|
|
203
|
+
### Surfacing schema comments in the generated types
|
|
204
|
+
|
|
205
|
+
`kysely-codegen` emits **column** comments as JSDoc automatically, but drops
|
|
206
|
+
**table**, **index**, and **constraint** comments (kysely #1368 / kysely-codegen
|
|
207
|
+
#316, unmerged as of 0.20.0 — indexes and constraints also have no symbol of their
|
|
208
|
+
own in the output). Recover them with a post-codegen step: a small script reads
|
|
209
|
+
`obj_description` for tables/indexes/constraints and injects each table's comment
|
|
210
|
+
plus `Indexes:` / `Constraints:` sections as JSDoc above its `export interface`.
|
|
211
|
+
Chain it into the codegen command:
|
|
212
|
+
|
|
213
|
+
```jsonc
|
|
214
|
+
"db:codegen": "kysely-codegen --url $DATABASE_URL --out-file src/db/db.d.ts --dialect postgres --date-parser string && node scripts/inject-table-comments.mjs $DATABASE_URL src/db/db.d.ts"
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The result is a `db.d.ts` where each table interface is prefaced by its full design
|
|
218
|
+
note — the documentation surface an agent should consult first. (Ship the
|
|
219
|
+
`inject-table-comments.mjs` script and this wired-up `db:codegen` in your project
|
|
220
|
+
template so every scaffolded repo gets it out of the box.)
|
|
221
|
+
|
|
@@ -391,6 +391,11 @@ node linear.mjs current-cycle-id # Current active cycle UUID
|
|
|
391
391
|
- **No domain prefix** (e.g., ~~UI:~~, ~~API:~~) — labels (`frontend`, `backend`) already cover this.
|
|
392
392
|
- Titles should be concise and describe the feature/fix directly (e.g., "Add provider create form", "Fix login redirect on Safari").
|
|
393
393
|
|
|
394
|
+
### Issue Body Conventions
|
|
395
|
+
|
|
396
|
+
- **Do NOT list or link an issue's sub-issues in the parent body** (no "Sub-issues" section, no bulleted child links). Linear renders an issue's children natively — a manual list just clutters the description and goes stale as children are added or removed. A parent body should carry the objective, any single-source-of-truth pointer, and acceptance criteria — nothing that restates the hierarchy.
|
|
397
|
+
- **No timestamped or dated section headers** (e.g. `## Data model — corrected (2025-05-01)`). State the current spec cleanly; issue history already records the "when." Dated "correction" sections accumulate as noise.
|
|
398
|
+
|
|
394
399
|
### Client Feature Request — Frontend
|
|
395
400
|
|
|
396
401
|
> **Important:** Do NOT guess which pages/components need updating. Check the client's repo (`app/pages/`, `app/components/`) to identify the correct files and routes. If the repo is not accessible, add a **## To Determine** section listing what needs to be verified before work begins (e.g., "Which page renders the jobs list? Check repo.").
|
|
@@ -13,10 +13,18 @@ but your custom `@theme` tokens fail with *"Cannot apply unknown utility class."
|
|
|
13
13
|
|
|
14
14
|
```css
|
|
15
15
|
/* ❌ @reference "tailwindcss"; → @apply text-fg fails */
|
|
16
|
-
@reference "
|
|
16
|
+
@reference "~/assets/css/main.css"; /* ✅ exposes YOUR tokens */
|
|
17
17
|
.prose :where(h2) { @apply text-fg; }
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
Prefer the bundler alias (`~/` in Nuxt, or your Vite alias) over a relative
|
|
21
|
+
path — `@tailwindcss/vite` resolves aliases in `@reference` fine, and the alias
|
|
22
|
+
survives file moves. A relative path (`"../assets/css/main.css"`) is depth-
|
|
23
|
+
sensitive: move the file a directory deeper (e.g. a route-namespace refactor)
|
|
24
|
+
and the production build fails with
|
|
25
|
+
`[@tailwindcss/vite:generate:build] Can't resolve '../assets/css/main.css'` —
|
|
26
|
+
typecheck, tests, and dev can all stay green; only the real build catches it.
|
|
27
|
+
|
|
20
28
|
Better still in scoped styles: skip `@apply` and consume the generated CSS
|
|
21
29
|
variables directly — `color: var(--color-fg)` always works with no `@reference`.
|
|
22
30
|
|