@lifeaitools/rdc-skills 0.8.7

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 (97) hide show
  1. package/.claude/settings.json +15 -0
  2. package/.claude-plugin/marketplace.json +21 -0
  3. package/.claude-plugin/plugin.json +11 -0
  4. package/.github/workflows/publish.yml +25 -0
  5. package/.github/workflows/self-test.yml +53 -0
  6. package/CHANGELOG.md +246 -0
  7. package/LICENSE +21 -0
  8. package/MANIFEST.md +190 -0
  9. package/README.md +188 -0
  10. package/README.sandbox.md +3 -0
  11. package/assets/watcher/viewer.html +164 -0
  12. package/commands/build.md +183 -0
  13. package/commands/collab.md +180 -0
  14. package/commands/deploy.md +138 -0
  15. package/commands/fixit.md +112 -0
  16. package/commands/handoff.md +173 -0
  17. package/commands/help.md +88 -0
  18. package/commands/overnight.md +220 -0
  19. package/commands/plan.md +158 -0
  20. package/commands/preplan.md +131 -0
  21. package/commands/prototype.md +145 -0
  22. package/commands/release.md +159 -0
  23. package/commands/report.md +99 -0
  24. package/commands/review.md +120 -0
  25. package/commands/self-test.md +107 -0
  26. package/commands/status.md +86 -0
  27. package/commands/watch.md +92 -0
  28. package/commands/workitems.md +132 -0
  29. package/guides/.gitkeep +0 -0
  30. package/guides/agent-bootstrap.md +191 -0
  31. package/guides/agents/backend.md +104 -0
  32. package/guides/agents/content.md +94 -0
  33. package/guides/agents/cs2.md +56 -0
  34. package/guides/agents/data.md +87 -0
  35. package/guides/agents/design.md +77 -0
  36. package/guides/agents/frontend.md +92 -0
  37. package/guides/agents/infrastructure.md +81 -0
  38. package/guides/agents/setup.md +279 -0
  39. package/guides/agents/verify.md +132 -0
  40. package/guides/agents/viz.md +106 -0
  41. package/guides/backend.md +146 -0
  42. package/guides/content.md +147 -0
  43. package/guides/cs2.md +190 -0
  44. package/guides/data.md +123 -0
  45. package/guides/design.md +116 -0
  46. package/guides/frontend.md +151 -0
  47. package/guides/infrastructure.md +179 -0
  48. package/guides/output-contract.md +98 -0
  49. package/hooks/no-stop-open-epics.js +125 -0
  50. package/package.json +31 -0
  51. package/rules/work-items-rpc.md +399 -0
  52. package/scripts/install-rdc-skills.js +559 -0
  53. package/scripts/install.ps1 +165 -0
  54. package/scripts/install.sh +132 -0
  55. package/scripts/lib/assertions.mjs +264 -0
  56. package/scripts/lib/manifest-schema.mjs +607 -0
  57. package/scripts/lib/runner.mjs +429 -0
  58. package/scripts/lib/sandbox.mjs +435 -0
  59. package/scripts/self-test.mjs +1108 -0
  60. package/scripts/uninstall.ps1 +77 -0
  61. package/scripts/uninstall.sh +69 -0
  62. package/scripts/update.ps1 +43 -0
  63. package/scripts/update.sh +43 -0
  64. package/scripts/watch-init.mjs +100 -0
  65. package/skills/.gitkeep +0 -0
  66. package/skills/build/SKILL.md +238 -0
  67. package/skills/collab/SKILL.md +218 -0
  68. package/skills/deploy/SKILL.md +144 -0
  69. package/skills/fixit/SKILL.md +112 -0
  70. package/skills/handoff/SKILL.md +175 -0
  71. package/skills/help/SKILL.md +101 -0
  72. package/skills/overnight/SKILL.md +220 -0
  73. package/skills/plan/SKILL.md +96 -0
  74. package/skills/preplan/SKILL.md +87 -0
  75. package/skills/prototype/SKILL.md +151 -0
  76. package/skills/release/SKILL.md +221 -0
  77. package/skills/report/SKILL.md +101 -0
  78. package/skills/review/SKILL.md +120 -0
  79. package/skills/self-test/SKILL.md +127 -0
  80. package/skills/status/SKILL.md +86 -0
  81. package/skills/tests/README.md +29 -0
  82. package/skills/tests/rdc-build.test.json +22 -0
  83. package/skills/tests/rdc-deploy.test.json +15 -0
  84. package/skills/tests/rdc-fixit.test.json +21 -0
  85. package/skills/tests/rdc-handoff.test.json +14 -0
  86. package/skills/tests/rdc-overnight.test.json +21 -0
  87. package/skills/tests/rdc-plan.test.json +14 -0
  88. package/skills/tests/rdc-preplan.test.json +15 -0
  89. package/skills/tests/rdc-prototype.test.json +14 -0
  90. package/skills/tests/rdc-release.test.json +15 -0
  91. package/skills/tests/rdc-report.test.json +14 -0
  92. package/skills/tests/rdc-review.test.json +14 -0
  93. package/skills/tests/rdc-status.test.json +16 -0
  94. package/skills/tests/rdc-workitems.test.json +15 -0
  95. package/skills/watch/SKILL.md +92 -0
  96. package/skills/workitems/SKILL.md +147 -0
  97. package/tests/validate-skills.js +183 -0
@@ -0,0 +1,399 @@
1
+ # Work Items RPC Reference
2
+
3
+ > Complete reference for work_items table operations via Supabase RPC functions.
4
+ > Use these functions for ALL CRUD operations. Never write raw INSERT/UPDATE/SELECT against work_items.
5
+
6
+ ---
7
+
8
+ ## Core Rule
9
+
10
+ **Always use RPC functions.** They handle defaults, check constraints, timestamps, sorting, and return structured JSONB.
11
+
12
+ Exception: Ad-hoc analytics queries (e.g., `SELECT count(*)`) are acceptable as raw SQL.
13
+
14
+ ---
15
+
16
+ ## Valid Enum Values
17
+
18
+ | Column | Allowed Values |
19
+ |--------|---|
20
+ | `status` | `todo` · `in_progress` · `blocked` · `review` · `done` · `archived` |
21
+ | `priority` | `urgent` · `high` · `normal` · `low` |
22
+ | `item_type` | `epic` · `task` · `subtask` · `bug` · `spike` |
23
+
24
+ ---
25
+
26
+ ## RPC Functions
27
+
28
+ ### 1. get_open_epics — List open epics
29
+
30
+ Returns all non-done/archived epics sorted by priority, then created_at.
31
+
32
+ **Supabase SQL:**
33
+ ```sql
34
+ SELECT get_open_epics();
35
+ SELECT get_open_epics('urgent');
36
+ SELECT get_open_epics(p_label_filter := 'feature-x');
37
+ SELECT get_open_epics('high', 'backend');
38
+ ```
39
+
40
+ **Supabase JS Client:**
41
+ ```ts
42
+ const { data } = await supabase.rpc('get_open_epics');
43
+ const { data } = await supabase.rpc('get_open_epics', {
44
+ p_priority_filter: 'urgent'
45
+ });
46
+ const { data } = await supabase.rpc('get_open_epics', {
47
+ p_label_filter: 'cs2'
48
+ });
49
+ ```
50
+
51
+ **Parameters:**
52
+
53
+ | Name | Type | Required | Notes |
54
+ |------|------|----------|-------|
55
+ | `p_priority_filter` | text | no | NULL = all priorities. One of: `urgent`, `high`, `normal`, `low` |
56
+ | `p_label_filter` | text | no | NULL = all labels. Uses array containment (`@>`) for matching |
57
+
58
+ **Returns:**
59
+ - JSONB array of epic objects (sorted by priority then created_at)
60
+ - Empty `[]` if none found
61
+ - Each epic has: `id`, `title`, `status`, `priority`, `item_type`, `labels`, `created_at`, `updated_at`
62
+
63
+ ---
64
+
65
+ ### 2. insert_work_item — Create a work item
66
+
67
+ Create a new task, epic, subtask, bug, or spike.
68
+
69
+ **Supabase SQL:**
70
+ ```sql
71
+ SELECT insert_work_item(
72
+ p_title := 'Build user authentication',
73
+ p_description := 'Implement OAuth2 flow...',
74
+ p_status := 'todo',
75
+ p_priority := 'high',
76
+ p_item_type := 'task',
77
+ p_parent_id := 'epic-uuid'::uuid,
78
+ p_labels := ARRAY['backend', 'auth'],
79
+ p_source := 'agent'
80
+ );
81
+ ```
82
+
83
+ **Supabase JS Client:**
84
+ ```ts
85
+ const { data } = await supabase.rpc('insert_work_item', {
86
+ p_title: 'Build user authentication',
87
+ p_description: 'Implement OAuth2 flow...',
88
+ p_status: 'todo',
89
+ p_priority: 'high',
90
+ p_item_type: 'task',
91
+ p_parent_id: epicId,
92
+ p_labels: ['backend', 'auth'],
93
+ p_source: 'agent'
94
+ });
95
+ ```
96
+
97
+ **All Parameters:**
98
+
99
+ | Name | Type | Default | Notes |
100
+ |------|------|---------|-------|
101
+ | `p_title` | text | *required* | Work item name (max 255 chars) |
102
+ | `p_description` | text | NULL | Long-form description |
103
+ | `p_status` | text | `'todo'` | One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
104
+ | `p_priority` | text | `'normal'` | One of: `urgent`, `high`, `normal`, `low` |
105
+ | `p_item_type` | text | `'task'` | One of: `epic`, `task`, `subtask`, `bug`, `spike` |
106
+ | `p_parent_id` | uuid | NULL | Parent epic UUID for hierarchy (for subtasks) |
107
+ | `p_company_id` | uuid | NULL | Foreign key to companies table |
108
+ | `p_customer_id` | uuid | NULL | Foreign key to customers table |
109
+ | `p_campaign_id` | uuid | NULL | Foreign key to campaigns table |
110
+ | `p_contact_id` | uuid | NULL | Foreign key to contacts table |
111
+ | `p_project_id` | uuid | NULL | Project identifier (project-specific) |
112
+ | `p_assignee` | text | NULL | Assigned person name or email |
113
+ | `p_assigned_to` | text | NULL | Same as assignee (alternate field) |
114
+ | `p_due_date` | date | NULL | Due date for the task |
115
+ | `p_tags` | text[] | `'{}'` | Array of tags |
116
+ | `p_labels` | text[] | `'{}'` | Array of labels (used for filtering) |
117
+ | `p_linked_table` | text | NULL | Name of external table to link (if any) |
118
+ | `p_linked_id` | uuid | NULL | ID in linked_table |
119
+ | `p_created_by` | text | NULL | Who created this item |
120
+ | `p_estimated_hours` | numeric | NULL | Time estimate in hours |
121
+ | `p_notes` | jsonb | `'[]'` | Array of note objects `[{ text, author, timestamp }]` |
122
+ | `p_session_id` | text | NULL | Session UUID (for audit trail) |
123
+ | `p_package` | text | NULL | Package/module name (e.g., '@regen/ui') |
124
+ | `p_source` | text | `'manual'` | How was this created: `manual`, `agent`, `api`, `import` |
125
+
126
+ **Returns:**
127
+ - Full inserted work_item row as JSONB
128
+ - Includes auto-generated `id`, `created_at`, `updated_at`
129
+
130
+ ---
131
+
132
+ ### 3. update_work_item_status — Change status
133
+
134
+ Transition a work item's status. Auto-manages `completed_at`.
135
+
136
+ **Supabase SQL:**
137
+ ```sql
138
+ SELECT update_work_item_status(
139
+ 'work-item-uuid'::uuid,
140
+ 'in_progress'
141
+ );
142
+
143
+ SELECT update_work_item_status(
144
+ 'work-item-uuid'::uuid,
145
+ 'done',
146
+ '["Completed by agent session xyz"]'::jsonb
147
+ );
148
+ ```
149
+
150
+ **Supabase JS Client:**
151
+ ```ts
152
+ const { data } = await supabase.rpc('update_work_item_status', {
153
+ p_id: itemId,
154
+ p_status: 'in_progress'
155
+ });
156
+
157
+ const { data } = await supabase.rpc('update_work_item_status', {
158
+ p_id: itemId,
159
+ p_status: 'done',
160
+ p_notes_append: ['Completed by agent session xyz']
161
+ });
162
+ ```
163
+
164
+ **Parameters:**
165
+
166
+ | Name | Type | Required | Notes |
167
+ |------|------|----------|-------|
168
+ | `p_id` | uuid | yes | work_item ID |
169
+ | `p_status` | text | yes | One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
170
+ | `p_notes_append` | jsonb | no | Array of strings appended to existing notes |
171
+
172
+ **Behavior:**
173
+ - Setting `done` auto-sets `completed_at = now()`
174
+ - Setting `todo`, `in_progress`, `blocked`, or `review` clears `completed_at`
175
+ - `updated_at` always refreshed to current timestamp
176
+ - Raises exception if ID not found
177
+
178
+ **Returns:**
179
+ - Full updated work_item row as JSONB
180
+
181
+ ---
182
+
183
+ ### 4. get_work_items_by_epic — Fetch epic + children
184
+
185
+ Get an epic and all its child tasks/subtasks, sorted by priority.
186
+
187
+ **Supabase SQL:**
188
+ ```sql
189
+ SELECT get_work_items_by_epic('epic-uuid'::uuid);
190
+ SELECT get_work_items_by_epic('epic-uuid'::uuid, 'todo');
191
+ ```
192
+
193
+ **Supabase JS Client:**
194
+ ```ts
195
+ const { data } = await supabase.rpc('get_work_items_by_epic', {
196
+ p_epic_id: epicId
197
+ });
198
+
199
+ const { data } = await supabase.rpc('get_work_items_by_epic', {
200
+ p_epic_id: epicId,
201
+ p_status_filter: 'todo'
202
+ });
203
+ ```
204
+
205
+ **Parameters:**
206
+
207
+ | Name | Type | Required | Notes |
208
+ |------|------|----------|-------|
209
+ | `p_epic_id` | uuid | yes | The epic's work_item ID |
210
+ | `p_status_filter` | text | no | NULL = all statuses. One of: `todo`, `in_progress`, `blocked`, `review`, `done`, `archived` |
211
+
212
+ **Returns:**
213
+ - JSONB array with parent epic first, then children
214
+ - Sorted by: priority (urgent > high > normal > low), then created_at
215
+ - Each item has same structure as returned from insert_work_item
216
+
217
+ ---
218
+
219
+ ### 5. bump_epic_version — Version with history
220
+
221
+ Snapshot an epic's current state and assign a version number.
222
+
223
+ **Supabase SQL:**
224
+ ```sql
225
+ SELECT bump_epic_version(
226
+ 'epic-uuid'::uuid,
227
+ '0.2.0',
228
+ 'Added async task execution',
229
+ 'agent'
230
+ );
231
+ ```
232
+
233
+ **Supabase JS Client:**
234
+ ```ts
235
+ const { data } = await supabase.rpc('bump_epic_version', {
236
+ p_epic_id: epicId,
237
+ p_version: '0.2.0',
238
+ p_change_summary: 'Added async task execution',
239
+ p_changed_by: 'agent'
240
+ });
241
+ ```
242
+
243
+ **Parameters:**
244
+
245
+ | Name | Type | Required | Notes |
246
+ |------|------|----------|-------|
247
+ | `p_epic_id` | uuid | yes | Must be item_type = `'epic'` |
248
+ | `p_version` | text | yes | Semantic version string (e.g., `'0.1.0'`, `'1.0.0'`) |
249
+ | `p_change_summary` | text | no | What changed in this version |
250
+ | `p_changed_by` | text | no | Who bumped the version |
251
+
252
+ **Behavior:**
253
+ - Snapshots the epic's current state into work_item_versions table
254
+ - Updates the epic's `version` column
255
+ - Raises exception if item is not an epic (item_type != 'epic')
256
+
257
+ **Returns:**
258
+ - JSONB object: `{ epic_id, version, version_record_id, change_summary, changed_by, bumped_at }`
259
+
260
+ ---
261
+
262
+ ## Common Patterns
263
+
264
+ ### Create an Epic + Child Tasks
265
+
266
+ ```ts
267
+ // 1. Create epic
268
+ const { data: epic } = await supabase.rpc('insert_work_item', {
269
+ p_title: 'Implement feature X',
270
+ p_item_type: 'epic',
271
+ p_status: 'todo',
272
+ p_priority: 'high',
273
+ p_source: 'agent'
274
+ });
275
+ const epicId = epic[0].id;
276
+
277
+ // 2. Create child tasks
278
+ for (const task of tasks) {
279
+ await supabase.rpc('insert_work_item', {
280
+ p_title: task.title,
281
+ p_item_type: 'task',
282
+ p_priority: task.priority,
283
+ p_parent_id: epicId,
284
+ p_source: 'agent'
285
+ });
286
+ }
287
+ ```
288
+
289
+ ### Fetch Epic Tree, Filter by Status, Update Each
290
+
291
+ ```ts
292
+ const { data: tree } = await supabase.rpc('get_work_items_by_epic', {
293
+ p_epic_id: epicId,
294
+ p_status_filter: 'todo'
295
+ });
296
+
297
+ for (const item of tree) {
298
+ if (item.item_type === 'epic') continue; // skip parent
299
+
300
+ await supabase.rpc('update_work_item_status', {
301
+ p_id: item.id,
302
+ p_status: 'in_progress'
303
+ });
304
+ }
305
+ ```
306
+
307
+ ### Mark Epic Done with Notes
308
+
309
+ ```ts
310
+ const { data } = await supabase.rpc('update_work_item_status', {
311
+ p_id: epicId,
312
+ p_status: 'done',
313
+ p_notes_append: [
314
+ 'All child tasks completed',
315
+ 'Code reviewed and merged to main',
316
+ 'Deployed to production'
317
+ ]
318
+ });
319
+ ```
320
+
321
+ ### List All Open Work, Filter by Priority
322
+
323
+ ```ts
324
+ const { data: epics } = await supabase.rpc('get_open_epics', {
325
+ p_priority_filter: 'urgent'
326
+ });
327
+
328
+ for (const epic of epics) {
329
+ const { data: items } = await supabase.rpc('get_work_items_by_epic', {
330
+ p_epic_id: epic.id
331
+ });
332
+ // process items...
333
+ }
334
+ ```
335
+
336
+ ---
337
+
338
+ ## Supabase Project Reference
339
+
340
+ In production, you'll need:
341
+
342
+ **Environment variables (in .env.local):**
343
+ ```bash
344
+ NEXT_PUBLIC_SUPABASE_URL=https://<project-ref>.supabase.co
345
+ NEXT_PUBLIC_SUPABASE_ANON_KEY=<anon-key>
346
+ SUPABASE_SERVICE_ROLE_KEY=<service-role-key> # Server-side only
347
+ ```
348
+
349
+ Replace `<project-ref>` with your actual Supabase project reference (e.g., `uvojezuorjgqzmhhgluu`).
350
+
351
+ **Project-specific data (from docs/guides/agent-bootstrap.md):**
352
+ - SUPABASE_PROJECT_ID (if required by your project)
353
+ - Any custom schema names (if work_items lives in non-public schema)
354
+ - Related table names (companies, customers, contacts, campaigns, etc.)
355
+
356
+ ---
357
+
358
+ ## Error Handling
359
+
360
+ ### RPC Not Found
361
+ If `get_open_epics` returns a 404, the function doesn't exist on your Supabase instance.
362
+ Run migration to add the function, or contact your DBA.
363
+
364
+ ### Invalid UUID
365
+ ```ts
366
+ // Wrong — string passed directly
367
+ p_id: "item-id"
368
+
369
+ // Correct — cast to uuid
370
+ p_id: itemId
371
+ ```
372
+
373
+ ### Status Not in Enum
374
+ Check `p_status` against allowed values. Will raise a constraint error if invalid.
375
+
376
+ ### Item Not Found
377
+ `update_work_item_status` and `bump_epic_version` will raise an exception if ID doesn't exist.
378
+ Always catch or check first:
379
+ ```ts
380
+ const { data: items } = await supabase.rpc('get_work_items_by_epic', { p_epic_id: id });
381
+ if (!items || items.length === 0) {
382
+ // Epic not found
383
+ }
384
+ ```
385
+
386
+ ---
387
+
388
+ ## Analytics (Raw SQL)
389
+
390
+ Direct SELECT is acceptable for read-only analytics:
391
+
392
+ ```sql
393
+ SELECT status, count(*) as cnt FROM work_items GROUP BY status;
394
+ SELECT priority, count(*) FROM work_items WHERE labels @> ARRAY['urgent'] GROUP BY priority;
395
+ SELECT avg(EXTRACT(EPOCH FROM (completed_at - created_at))/3600)::numeric(10,2) as avg_hours
396
+ FROM work_items WHERE status = 'done' AND item_type = 'task';
397
+ ```
398
+
399
+ For INSERT/UPDATE/DELETE: always use the RPC functions above.