@gallopsystems/agent-skills 1.25.1 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gallopsystems/agent-skills",
3
- "version": "1.25.1",
3
+ "version": "1.26.0",
4
4
  "description": "Gallop Systems agent skills, symlinked into .claude/skills (Claude Code) and .agents/skills (Codex) on install.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -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
+
@@ -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 "../assets/css/main.css"; /* ✅ exposes YOUR tokens; path is relative to the file */
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