@gallopsystems/agent-skills 1.1.0 → 1.4.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.
Files changed (24) hide show
  1. package/README.md +57 -0
  2. package/commands/contribute-skill.md +65 -0
  3. package/package.json +2 -1
  4. package/plugins/copier-template/.claude-plugin/plugin.json +8 -0
  5. package/plugins/copier-template/skills/copier-template/SKILL.md +74 -0
  6. package/plugins/copier-template/skills/copier-template/applying-updates.md +87 -0
  7. package/plugins/copier-template/skills/copier-template/template-authoring.md +89 -0
  8. package/plugins/doctl/.claude-plugin/plugin.json +2 -2
  9. package/plugins/doctl/skills/doctl/SKILL.md +80 -48
  10. package/plugins/doctl/skills/doctl/other-services.md +56 -0
  11. package/plugins/doctl/skills/doctl/spec-management.md +74 -0
  12. package/plugins/git-github/.claude-plugin/plugin.json +8 -0
  13. package/plugins/git-github/skills/git-github/SKILL.md +91 -0
  14. package/plugins/git-github/skills/git-github/actions-debugging.md +102 -0
  15. package/plugins/git-github/skills/git-github/external-review.md +39 -0
  16. package/plugins/git-github/skills/git-github/getting-unstuck.md +106 -0
  17. package/plugins/git-github/skills/git-github/gh-api-recipes.md +73 -0
  18. package/plugins/git-github/skills/git-github/releases.md +53 -0
  19. package/plugins/kysely-postgres/skills/kysely-postgres/SKILL.md +6 -0
  20. package/plugins/linear/skills/linear/SKILL.md +6 -0
  21. package/plugins/nitro-testing/skills/nitro-testing/SKILL.md +6 -0
  22. package/plugins/nuxt-nitro-api/skills/nuxt-nitro-api/SKILL.md +7 -0
  23. package/plugins/nuxt-nitro-api/skills/nuxt-nitro-api/composables-utils.md +5 -0
  24. package/plugins/nuxt-nitro-api/skills/nuxt-nitro-api/formatters.md +139 -0
@@ -25,6 +25,7 @@ For detailed patterns, see these topic-focused reference files:
25
25
  - [auth-patterns.md](./auth-patterns.md) - nuxt-auth-utils, OAuth, WebAuthn, middleware
26
26
  - [page-structure.md](./page-structure.md) - Keep pages thin, components do the work
27
27
  - [composables-utils.md](./composables-utils.md) - When to use composables vs utils
28
+ - [formatters.md](./formatters.md) - Centralize currency/date/number formatters in useFormatters, never inline
28
29
  - [ssr-client.md](./ssr-client.md) - SSR + localStorage, hydration, VueUse
29
30
  - [deep-linking.md](./deep-linking.md) - URL params sync with filters and useFetch
30
31
  - [nitro-tasks.md](./nitro-tasks.md) - Background jobs, scheduled tasks, job queues
@@ -258,3 +259,9 @@ const activeProjects = computed(() =>
258
259
  ```
259
260
 
260
261
  This ensures your frontend types stay in sync with your API - if the endpoint return type changes, TypeScript will catch mismatches.
262
+
263
+ ## Contributing Back
264
+
265
+ This skill grows by capturing what it missed. If you just worked through something in this domain that this skill did not cover — an error you had to figure out, a behavior that contradicts what is documented above, a workflow knot — ask the user: **"Want me to contribute this back to the nuxt-nitro-api skill?"**
266
+
267
+ If yes, run `/contribute-skill`. If that command is not available, do the equivalent inline: distill the generic lesson (placeholders only — no project names, IDs, domains, or secrets), then branch or fork [gallop-systems/agent-skills](https://github.com/gallop-systems/agent-skills) and open a PR editing this skill.
@@ -79,6 +79,11 @@ export const usePermissions = () => {
79
79
  - Data transformations, formatting, parsing
80
80
  - NO `use` prefix
81
81
 
82
+ > **Formatters belong in one shared place.** The examples below show util *placement*,
83
+ > not where to call formatters from. Never define a currency/date/number formatter inline
84
+ > at the call site — centralize them in `useFormatters` or a shared util, and prefer
85
+ > VueUse / date-fns over hand-rolling. See [formatters.md](./formatters.md).
86
+
82
87
  ```typescript
83
88
  // utils/formatting.ts
84
89
  export const formatDate = (date: string) => {
@@ -0,0 +1,139 @@
1
+ # Formatters (Currency, Dates, Numbers)
2
+
3
+ ## Rule: Never define a formatter inline
4
+
5
+ Whenever you need to format a value — currency, dates, times, numbers, percentages,
6
+ file sizes, relative time, etc. — **do not define the formatter inline at the call site.**
7
+
8
+ Before writing any new formatting logic:
9
+
10
+ 1. **Check if a shared formatter already exists.** Look for a `useFormatters`
11
+ composable (`/composables/useFormatters.ts`) or a formatting util
12
+ (`/utils/formatters.ts`, `/shared/utils/format.ts`). If a formatter for the value
13
+ you need is already there, **use it.**
14
+ 2. **If none exists, create one** in the appropriate shared location, then use it.
15
+ Do not scatter a one-off `Intl.NumberFormat(...)` or `new Date(...).toLocaleString(...)`
16
+ at the call site.
17
+
18
+ This keeps formatting consistent across the app (one source of truth for locale,
19
+ currency, date style) and makes a future change — switching locale, adding a currency,
20
+ tweaking date format — a single edit instead of a hunt-and-replace.
21
+
22
+ ```typescript
23
+ // WRONG - inline formatter at the call site
24
+ <template>
25
+ <span>{{ new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" }).format(total) }}</span>
26
+ <span>{{ new Date(order.createdAt).toLocaleDateString("en-US", { dateStyle: "medium" }) }}</span>
27
+ </template>
28
+
29
+ // RIGHT - use the shared formatter
30
+ <script setup lang="ts">
31
+ const { formatCurrency, formatDate } = useFormatters();
32
+ </script>
33
+ <template>
34
+ <span>{{ formatCurrency(total) }}</span>
35
+ <span>{{ formatDate(order.createdAt) }}</span>
36
+ </template>
37
+ ```
38
+
39
+ ## Reach for existing libraries before hand-rolling
40
+
41
+ Two libraries are almost always already available — prefer them over writing formatting
42
+ or date logic by hand:
43
+
44
+ - **VueUse** ships a broad set of formatting/reactive helpers out of the box (auto-imported
45
+ in Nuxt). Before building your own, check for one of these:
46
+ - `useDateFormat(date, "YYYY-MM-DD HH:mm")` — reactive date formatting
47
+ - `useTimeAgo(date)` — reactive "3 minutes ago" relative time
48
+ - `useNow()` / `useTimestamp()` — reactive current time to drive the above
49
+ - `formatTimeAgo()` — the non-reactive function form
50
+ Wrap these in `useFormatters` when you want a single app-wide configuration point,
51
+ rather than calling them ad hoc at each site.
52
+
53
+ - **date-fns is the preferred way to work with dates.** Do **not** parse, compare, add,
54
+ or diff dates by hand (no manual `string.split("-")`, no `new Date(a) - new Date(b)`
55
+ arithmetic, no hand-rolled "is same day"). Use `date-fns`:
56
+
57
+ ```typescript
58
+ import { format, parseISO, formatDistanceToNow, differenceInDays, isSameDay } from "date-fns";
59
+
60
+ format(parseISO(order.createdAt), "MMM d, yyyy"); // "Jun 12, 2026"
61
+ formatDistanceToNow(parseISO(order.createdAt)); // "about 2 hours"
62
+ differenceInDays(parseISO(end), parseISO(start)); // 5
63
+ ```
64
+
65
+ ```typescript
66
+ // WRONG - parsing/diffing dates by hand
67
+ const [y, m, d] = order.createdAt.split("T")[0].split("-");
68
+ const daysLeft = Math.floor((new Date(end) - new Date(start)) / 86400000);
69
+ ```
70
+
71
+ Still route date-fns calls through `useFormatters` (or a shared util) rather than
72
+ importing and calling them inline everywhere — same single-source-of-truth reason.
73
+
74
+ ## Where to put the formatters
75
+
76
+ Pick the location by what the formatter needs (see [composables-utils.md](./composables-utils.md)):
77
+
78
+ - **Needs Nuxt/Vue context** (e.g. reads locale/currency from `useRuntimeConfig()`,
79
+ `useI18n()`, or user preferences) → **composable** `useFormatters` in
80
+ `/composables/useFormatters.ts`.
81
+ - **Pure, client-only** → **util** in `/utils/formatters.ts`.
82
+ - **Used on both client and server** (e.g. an invoice rendered in SSR *and* in a
83
+ server API response) → **shared util** in `/shared/utils/format.ts`.
84
+
85
+ When in doubt and the formatters are pure, prefer `useFormatters` as a composable so
86
+ there is one obvious, discoverable place to look — and so it can later pull locale
87
+ from context without moving every call site.
88
+
89
+ ### Composable form (`useFormatters`)
90
+
91
+ ```typescript
92
+ // composables/useFormatters.ts
93
+ export const useFormatters = () => {
94
+ const config = useRuntimeConfig();
95
+ const locale = config.public.locale ?? "en-US";
96
+ const currency = config.public.currency ?? "USD";
97
+
98
+ const currencyFmt = new Intl.NumberFormat(locale, { style: "currency", currency });
99
+ const dateFmt = new Intl.DateTimeFormat(locale, { dateStyle: "medium" });
100
+ const dateTimeFmt = new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeStyle: "short" });
101
+ const numberFmt = new Intl.NumberFormat(locale);
102
+ const percentFmt = new Intl.NumberFormat(locale, { style: "percent", maximumFractionDigits: 1 });
103
+
104
+ return {
105
+ formatCurrency: (amount: number) => currencyFmt.format(amount),
106
+ formatDate: (date: string | Date) => dateFmt.format(new Date(date)),
107
+ formatDateTime: (date: string | Date) => dateTimeFmt.format(new Date(date)),
108
+ formatNumber: (n: number) => numberFmt.format(n),
109
+ formatPercent: (n: number) => percentFmt.format(n),
110
+ };
111
+ };
112
+ ```
113
+
114
+ > **Reuse the `Intl.*` instances.** Construct each formatter once (as above), not on
115
+ > every call. `Intl.NumberFormat`/`Intl.DateTimeFormat` construction is comparatively
116
+ > expensive, so building a new one inside a render or a loop is wasteful.
117
+
118
+ ### Pure util / shared form
119
+
120
+ If no Nuxt context is needed, the same functions live as plain exports:
121
+
122
+ ```typescript
123
+ // shared/utils/format.ts (or utils/formatters.ts for client-only)
124
+ const currencyFmt = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" });
125
+ const dateFmt = new Intl.DateTimeFormat("en-US", { dateStyle: "medium" });
126
+
127
+ export const formatCurrency = (amount: number) => currencyFmt.format(amount);
128
+ export const formatDate = (date: string | Date) => dateFmt.format(new Date(date));
129
+ ```
130
+
131
+ ## Checklist before adding a formatter
132
+
133
+ - [ ] Searched for an existing `useFormatters` / `formatters` / `format` util?
134
+ - [ ] Reusing it if a matching formatter exists?
135
+ - [ ] Checked for a VueUse helper (`useDateFormat`, `useTimeAgo`, …) before hand-rolling?
136
+ - [ ] Using `date-fns` for any date parsing/formatting/math — not hand-parsing strings?
137
+ - [ ] If creating, placed it in the right shared location (composable vs util vs shared)?
138
+ - [ ] Constructed the `Intl.*` instance once, not per call?
139
+ - [ ] Replaced the inline formatting at the call site with the shared function?