@massu/core 0.4.1 → 0.5.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.
@@ -0,0 +1,125 @@
1
+ ---
2
+ name: massu-scaffold-router
3
+ description: "When user wants to create a new tRPC router, API endpoint, or backend procedure — scaffolds router file, registers in root.ts, adds Zod schemas"
4
+ allowed-tools: Bash(*), Read(*), Write(*), Edit(*), Grep(*), Glob(*)
5
+ ---
6
+
7
+ # Scaffold New tRPC Router
8
+
9
+ > **Shared rules apply.** Read `.claude/commands/_shared-preamble.md` before proceeding.
10
+
11
+ Creates a complete tRPC router following all project database and auth patterns.
12
+
13
+ ## What Gets Created
14
+
15
+ | File | Purpose |
16
+ |------|---------|
17
+ | `src/server/api/routers/[name].ts` | Router with procedures |
18
+ | Registration in `src/server/api/root.ts` | Import + add to appRouter |
19
+
20
+ ## Template
21
+
22
+ ```typescript
23
+ import { z } from 'zod';
24
+ import { createTRPCRouter, protectedProcedure } from '@/server/api/trpc';
25
+
26
+ export const myEntityRouter = createTRPCRouter({
27
+ getAll: protectedProcedure
28
+ .query(async ({ ctx }) => {
29
+ const items = await ctx.db.my_table.findMany({
30
+ orderBy: { created_at: 'desc' },
31
+ });
32
+ return items;
33
+ }),
34
+
35
+ getById: protectedProcedure
36
+ .input(z.object({ id: z.string().uuid() }))
37
+ .query(async ({ ctx, input }) => {
38
+ const item = await ctx.db.my_table.findUnique({
39
+ where: { id: input.id },
40
+ });
41
+ if (!item) throw new Error('Not found');
42
+ return item;
43
+ }),
44
+
45
+ create: protectedProcedure
46
+ .input(z.object({
47
+ name: z.string().min(1),
48
+ // Add fields here
49
+ }))
50
+ .mutation(async ({ ctx, input }) => {
51
+ return ctx.db.my_table.create({
52
+ data: {
53
+ ...input,
54
+ created_by: ctx.session.user.id,
55
+ },
56
+ });
57
+ }),
58
+
59
+ update: protectedProcedure
60
+ .input(z.object({
61
+ id: z.string().uuid(),
62
+ name: z.string().min(1).optional(),
63
+ }))
64
+ .mutation(async ({ ctx, input }) => {
65
+ const { id, ...data } = input;
66
+ return ctx.db.my_table.update({
67
+ where: { id },
68
+ data,
69
+ });
70
+ }),
71
+ });
72
+ ```
73
+
74
+ ## 3-Step Query Pattern (for relations)
75
+
76
+ ```typescript
77
+ // Step 1: Base query
78
+ const items = await ctx.db.my_table.findMany({ where: { status: 'active' } });
79
+
80
+ // Step 2: Relation query with IN
81
+ const relatedIds = items.map(i => i.related_id).filter(Boolean);
82
+ const related = relatedIds.length > 0
83
+ ? await ctx.db.related_table.findMany({ where: { id: { in: relatedIds } } })
84
+ : [];
85
+
86
+ // Step 3: Map combine
87
+ const relatedMap = new Map(related.map(r => [r.id, r]));
88
+ return items.map(item => ({
89
+ ...item,
90
+ related: item.related_id ? relatedMap.get(item.related_id) : null,
91
+ }));
92
+ ```
93
+
94
+ ## Registration in root.ts
95
+
96
+ ```typescript
97
+ import { myEntityRouter } from './routers/my-entity';
98
+
99
+ export const appRouter = createTRPCRouter({
100
+ // ... existing routers
101
+ myEntity: myEntityRouter,
102
+ });
103
+ ```
104
+
105
+ ## Gotchas
106
+
107
+ - **ctx.db NOT ctx.prisma** — hybrid client requires ctx.db
108
+ - **protectedProcedure for ALL mutations** — never publicProcedure
109
+ - **No `include:`** — hybrid DB ignores include statements; use 3-step query
110
+ - **user_profiles NOT users** — `ctx.db.user_profiles` (auth.users not exposed)
111
+ - **BigInt**: convert to `Number()` on return, NEVER use `BigInt()` in INSERT
112
+ - **New tables**: add to `src/lib/db.ts` DatabaseClient BEFORE using in routers
113
+ - **Split-commit**: NEVER add import to root.ts before router file exists
114
+
115
+ ## Process
116
+
117
+ 1. Ask user: What entity? What operations (CRUD, custom)?
118
+ 2. Run VR-SCHEMA-PRE to verify table columns exist
119
+ 3. Create router file with proper patterns
120
+ 4. Register in root.ts
121
+ 5. Run `npx tsc --noEmit` to verify types
122
+
123
+ ## START NOW
124
+
125
+ Ask the user what entity/table the router is for and what procedures it needs.
@@ -0,0 +1,101 @@
1
+ ---
2
+ name: massu-squirrels
3
+ description: "When user has a tangential idea mid-task that should be parked — 'squirrel this', 'park this idea', 'remind me later about'"
4
+ allowed-tools: Bash(*), Read(*), Write(*), Edit(*), Grep(*), Glob(*)
5
+ ---
6
+ name: massu-squirrels
7
+
8
+ # Massu Squirrels: Idea Parking Lot Manager
9
+
10
+ > **Shared rules apply.** Read `.claude/commands/_shared-preamble.md` before proceeding.
11
+
12
+ ---
13
+
14
+ ## Purpose
15
+
16
+ Manage `.claude/session-state/squirrels.md` — a parking lot for stray ideas that come up mid-session. These are thoughts worth capturing but not worth derailing the current task for.
17
+
18
+ **This is NOT a backlog.** It's a scratchpad. Ideas here are unvetted, unscoped, and may be irrelevant. The value is in not losing them.
19
+
20
+ ---
21
+
22
+ ## ARGUMENTS
23
+
24
+ ```
25
+ /massu-squirrels # Show current squirrels list
26
+ /massu-squirrels add [idea] # Park a new idea
27
+ /massu-squirrels review # Review all ideas, grouped by age
28
+ /massu-squirrels promote [N] # Promote idea #N to a plan or task
29
+ /massu-squirrels clean # Remove stale/irrelevant ideas
30
+ ```
31
+
32
+ **Arguments from command**: `{{ARGUMENTS}}`
33
+
34
+ ---
35
+
36
+ ## Actions
37
+
38
+ ### No argument / `review` — Show current squirrels
39
+
40
+ 1. Read `.claude/session-state/squirrels.md`
41
+ 2. If empty (no ideas below the divider): say "No parked squirrels." and stop
42
+ 3. If ideas exist, display them grouped by age:
43
+ - **Fresh** (today or yesterday)
44
+ - **This week** (2-7 days old)
45
+ - **Aging** (> 7 days — consider promoting or cleaning)
46
+ 4. Show count: "N squirrels parked (X fresh, Y aging)"
47
+
48
+ ### `add` — Park a new idea
49
+
50
+ 1. Determine the idea from `{{ARGUMENTS}}` (everything after "add")
51
+ 2. Determine current context from `session-state/CURRENT.md` (what task is active)
52
+ 3. Append to `.claude/session-state/squirrels.md`:
53
+ ```
54
+ - YYYY-MM-DD: [idea] (context: [current task summary])
55
+ ```
56
+ 4. Confirm: "Parked: [idea]"
57
+ 5. Return to current work — do NOT expand on the idea or start working on it
58
+
59
+ ### `promote [N]` — Promote an idea
60
+
61
+ 1. Read squirrels.md, number the ideas (1-based, top to bottom)
62
+ 2. Display idea #N and ask: "Promote this to a plan, a task, or a session-state item?"
63
+ 3. Based on response:
64
+ - **Plan**: Create a plan stub in `.claude/plans/`
65
+ - **Task**: Add to CURRENT.md as an open item
66
+ - **Session-state**: Add to CURRENT.md as context
67
+ 4. Remove the idea from squirrels.md
68
+ 5. Confirm: "Promoted squirrel #N to [destination]"
69
+
70
+ ### `clean` — Clean stale ideas
71
+
72
+ 1. Read squirrels.md, display ALL ideas with numbers
73
+ 2. Ask user which to remove (by number, or "all aging" for ideas > 7 days old)
74
+ 3. Remove selected ideas
75
+ 4. Confirm: "Cleaned N squirrels. M remaining."
76
+
77
+ ---
78
+
79
+ ## Integration Points
80
+
81
+ - `/massu-bearings` reads squirrels.md and surfaces the count + list
82
+ - `/massu-recap` surfaces any squirrels added during the session
83
+ - Squirrels are NOT automatically promoted — they require explicit user action
84
+ - Squirrels are NOT persisted to memory/ — they are ephemeral by design
85
+
86
+ ---
87
+
88
+ ## Edge Cases
89
+
90
+ - If `squirrels.md` doesn't exist: create it with the standard header format
91
+ - If `CURRENT.md` doesn't exist when adding context: use "no active task" as context
92
+ - If promote target #N doesn't exist: show the list and ask again
93
+
94
+ ---
95
+
96
+ ## START NOW
97
+
98
+ 1. Parse `{{ARGUMENTS}}` to determine action (show/add/review/promote/clean)
99
+ 2. Read `.claude/session-state/squirrels.md`
100
+ 3. Execute the appropriate action
101
+ 4. Return to current work without expanding on the idea