@yottagraph-app/aether-instructions 1.0.1
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/README.md +52 -0
- package/commands/aether_broadchurch_setup.md +163 -0
- package/commands/aether_build_my_app.md +148 -0
- package/commands/aether_configure_query_server.md +90 -0
- package/commands/aether_deploy_agent.md +153 -0
- package/commands/aether_deploy_mcp.md +163 -0
- package/commands/aether_update_branding.md +123 -0
- package/commands/aether_update_instructions.md +183 -0
- package/commands/aether_vercel_deploy.md +278 -0
- package/commands/aether_vercel_setup.md +528 -0
- package/package.json +26 -0
- package/rules/aether_aether.mdc +21 -0
- package/rules/aether_agents.mdc +166 -0
- package/rules/aether_api.mdc +211 -0
- package/rules/aether_architecture.mdc +141 -0
- package/rules/aether_branding.mdc +43 -0
- package/rules/aether_cookbook.mdc +489 -0
- package/rules/aether_design.mdc +48 -0
- package/rules/aether_git-support.mdc +48 -0
- package/rules/aether_instructions_warning.mdc +48 -0
- package/rules/aether_mcp-servers.mdc +108 -0
- package/rules/aether_pref.mdc +123 -0
- package/rules/aether_server.mdc +99 -0
- package/rules/aether_something-broke.mdc +73 -0
- package/rules/aether_ui.mdc +76 -0
- package/skills/aether_test-api-queries/SKILL.md +63 -0
- package/skills/aether_test-api-queries/query-api.js +175 -0
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Copy-paste UI patterns for common pages: entity search, data table, form, chart, master-detail. Read when building new pages or features."
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# UI Pattern Cookbook
|
|
7
|
+
|
|
8
|
+
Copy-paste patterns using the project's actual composables and Vuetify components. Adapt to your needs.
|
|
9
|
+
|
|
10
|
+
## 1. Entity Search Page
|
|
11
|
+
|
|
12
|
+
Search for entities by name and display results.
|
|
13
|
+
|
|
14
|
+
```vue
|
|
15
|
+
<template>
|
|
16
|
+
<div class="d-flex flex-column fill-height pa-4">
|
|
17
|
+
<h1 class="text-h5 mb-4">Entity Search</h1>
|
|
18
|
+
<v-text-field
|
|
19
|
+
v-model="query"
|
|
20
|
+
label="Search entities"
|
|
21
|
+
prepend-inner-icon="mdi-magnify"
|
|
22
|
+
variant="outlined"
|
|
23
|
+
@keyup.enter="search"
|
|
24
|
+
:loading="loading"
|
|
25
|
+
/>
|
|
26
|
+
<v-alert v-if="error" type="error" variant="tonal" class="mt-2" closable>
|
|
27
|
+
{{ error }}
|
|
28
|
+
</v-alert>
|
|
29
|
+
<v-list v-if="results.length" class="mt-4">
|
|
30
|
+
<v-list-item
|
|
31
|
+
v-for="(neid, i) in results"
|
|
32
|
+
:key="neid"
|
|
33
|
+
:title="names[i] || neid"
|
|
34
|
+
:subtitle="neid"
|
|
35
|
+
/>
|
|
36
|
+
</v-list>
|
|
37
|
+
<v-empty-state
|
|
38
|
+
v-else-if="searched && !loading"
|
|
39
|
+
headline="No results"
|
|
40
|
+
icon="mdi-magnify-remove-outline"
|
|
41
|
+
/>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
|
|
45
|
+
<script setup lang="ts">
|
|
46
|
+
import { useElementalClient } from '@yottagraph-app/elemental-api/client';
|
|
47
|
+
|
|
48
|
+
const client = useElementalClient();
|
|
49
|
+
const query = ref('');
|
|
50
|
+
const results = ref<string[]>([]);
|
|
51
|
+
const names = ref<string[]>([]);
|
|
52
|
+
const loading = ref(false);
|
|
53
|
+
const error = ref<string | null>(null);
|
|
54
|
+
const searched = ref(false);
|
|
55
|
+
|
|
56
|
+
async function search() {
|
|
57
|
+
if (!query.value.trim()) return;
|
|
58
|
+
loading.value = true;
|
|
59
|
+
error.value = null;
|
|
60
|
+
searched.value = true;
|
|
61
|
+
try {
|
|
62
|
+
const res = await client.getNEID({
|
|
63
|
+
entityName: query.value.trim(),
|
|
64
|
+
maxResults: 10,
|
|
65
|
+
includeNames: true,
|
|
66
|
+
});
|
|
67
|
+
results.value = res.neids || [];
|
|
68
|
+
names.value = res.names || [];
|
|
69
|
+
} catch (e: any) {
|
|
70
|
+
error.value = e.message || 'Search failed';
|
|
71
|
+
results.value = [];
|
|
72
|
+
} finally {
|
|
73
|
+
loading.value = false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
</script>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 2. Data Table Page
|
|
80
|
+
|
|
81
|
+
Sortable table with loading, empty, and error states.
|
|
82
|
+
|
|
83
|
+
```vue
|
|
84
|
+
<template>
|
|
85
|
+
<div class="d-flex flex-column fill-height pa-4">
|
|
86
|
+
<h1 class="text-h5 mb-4">Data Table</h1>
|
|
87
|
+
<v-alert v-if="error" type="error" variant="tonal" class="mb-4" closable>
|
|
88
|
+
{{ error }}
|
|
89
|
+
</v-alert>
|
|
90
|
+
<v-data-table
|
|
91
|
+
:headers="headers"
|
|
92
|
+
:items="items"
|
|
93
|
+
:loading="loading"
|
|
94
|
+
density="comfortable"
|
|
95
|
+
hover
|
|
96
|
+
>
|
|
97
|
+
<template v-slot:item.actions="{ item }">
|
|
98
|
+
<v-btn icon size="small" variant="text" @click="onView(item)">
|
|
99
|
+
<v-icon>mdi-eye</v-icon>
|
|
100
|
+
</v-btn>
|
|
101
|
+
</template>
|
|
102
|
+
<template v-slot:no-data>
|
|
103
|
+
<v-empty-state headline="No data" icon="mdi-database-off" />
|
|
104
|
+
</template>
|
|
105
|
+
</v-data-table>
|
|
106
|
+
</div>
|
|
107
|
+
</template>
|
|
108
|
+
|
|
109
|
+
<script setup lang="ts">
|
|
110
|
+
const headers = [
|
|
111
|
+
{ title: 'Name', key: 'name', sortable: true },
|
|
112
|
+
{ title: 'Type', key: 'type', sortable: true },
|
|
113
|
+
{ title: 'Updated', key: 'updatedAt', sortable: true },
|
|
114
|
+
{ title: '', key: 'actions', sortable: false, width: 60 },
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
const items = ref<any[]>([]);
|
|
118
|
+
const loading = ref(false);
|
|
119
|
+
const error = ref<string | null>(null);
|
|
120
|
+
|
|
121
|
+
function onView(item: any) {
|
|
122
|
+
// Handle row action
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
onMounted(async () => {
|
|
126
|
+
loading.value = true;
|
|
127
|
+
try {
|
|
128
|
+
// items.value = await fetchData();
|
|
129
|
+
} catch (e: any) {
|
|
130
|
+
error.value = e.message || 'Failed to load';
|
|
131
|
+
} finally {
|
|
132
|
+
loading.value = false;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
</script>
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## 3. Form with Validation
|
|
139
|
+
|
|
140
|
+
Form with field validation, submit handler, and user feedback.
|
|
141
|
+
|
|
142
|
+
```vue
|
|
143
|
+
<template>
|
|
144
|
+
<v-container class="py-6" style="max-width: 600px">
|
|
145
|
+
<h1 class="text-h5 mb-4">Settings</h1>
|
|
146
|
+
<v-form ref="formRef" v-model="valid" @submit.prevent="submit">
|
|
147
|
+
<v-text-field
|
|
148
|
+
v-model="form.name"
|
|
149
|
+
label="Name"
|
|
150
|
+
:rules="[rules.required]"
|
|
151
|
+
variant="outlined"
|
|
152
|
+
class="mb-3"
|
|
153
|
+
/>
|
|
154
|
+
<v-text-field
|
|
155
|
+
v-model="form.email"
|
|
156
|
+
label="Email"
|
|
157
|
+
:rules="[rules.required, rules.email]"
|
|
158
|
+
variant="outlined"
|
|
159
|
+
class="mb-3"
|
|
160
|
+
/>
|
|
161
|
+
<v-select
|
|
162
|
+
v-model="form.role"
|
|
163
|
+
:items="['Admin', 'Editor', 'Viewer']"
|
|
164
|
+
label="Role"
|
|
165
|
+
variant="outlined"
|
|
166
|
+
class="mb-3"
|
|
167
|
+
/>
|
|
168
|
+
<v-btn type="submit" color="primary" :loading="saving" :disabled="!valid">
|
|
169
|
+
Save
|
|
170
|
+
</v-btn>
|
|
171
|
+
</v-form>
|
|
172
|
+
</v-container>
|
|
173
|
+
</template>
|
|
174
|
+
|
|
175
|
+
<script setup lang="ts">
|
|
176
|
+
import { useNotification } from '~/composables/useNotification';
|
|
177
|
+
|
|
178
|
+
const { showSuccess, showError } = useNotification();
|
|
179
|
+
const formRef = ref();
|
|
180
|
+
const valid = ref(false);
|
|
181
|
+
const saving = ref(false);
|
|
182
|
+
|
|
183
|
+
const form = reactive({ name: '', email: '', role: 'Viewer' });
|
|
184
|
+
|
|
185
|
+
const rules = {
|
|
186
|
+
required: (v: string) => !!v || 'Required',
|
|
187
|
+
email: (v: string) => /.+@.+\..+/.test(v) || 'Invalid email',
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
async function submit() {
|
|
191
|
+
const { valid: isValid } = await formRef.value.validate();
|
|
192
|
+
if (!isValid) return;
|
|
193
|
+
saving.value = true;
|
|
194
|
+
try {
|
|
195
|
+
// await saveSettings(form);
|
|
196
|
+
showSuccess('Settings saved');
|
|
197
|
+
} catch (e: any) {
|
|
198
|
+
showError(e.message || 'Failed to save');
|
|
199
|
+
} finally {
|
|
200
|
+
saving.value = false;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
</script>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## 4. Chart Page
|
|
207
|
+
|
|
208
|
+
Chart.js chart with dark theme colors.
|
|
209
|
+
|
|
210
|
+
```vue
|
|
211
|
+
<template>
|
|
212
|
+
<div class="d-flex flex-column fill-height pa-4">
|
|
213
|
+
<h1 class="text-h5 mb-4">Analytics</h1>
|
|
214
|
+
<v-card class="flex-grow-1 pa-4">
|
|
215
|
+
<canvas ref="chartCanvas" />
|
|
216
|
+
</v-card>
|
|
217
|
+
</div>
|
|
218
|
+
</template>
|
|
219
|
+
|
|
220
|
+
<script setup lang="ts">
|
|
221
|
+
import { Chart, registerables } from 'chart.js';
|
|
222
|
+
Chart.register(...registerables);
|
|
223
|
+
|
|
224
|
+
const chartCanvas = ref<HTMLCanvasElement | null>(null);
|
|
225
|
+
let chart: Chart | null = null;
|
|
226
|
+
|
|
227
|
+
onMounted(() => {
|
|
228
|
+
if (!chartCanvas.value) return;
|
|
229
|
+
chart = new Chart(chartCanvas.value, {
|
|
230
|
+
type: 'line',
|
|
231
|
+
data: {
|
|
232
|
+
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
|
|
233
|
+
datasets: [
|
|
234
|
+
{
|
|
235
|
+
label: 'Mentions',
|
|
236
|
+
data: [12, 19, 3, 5, 2, 15],
|
|
237
|
+
borderColor: '#3fea00',
|
|
238
|
+
backgroundColor: 'rgba(63, 234, 0, 0.1)',
|
|
239
|
+
fill: true,
|
|
240
|
+
tension: 0.3,
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
},
|
|
244
|
+
options: {
|
|
245
|
+
responsive: true,
|
|
246
|
+
maintainAspectRatio: false,
|
|
247
|
+
scales: {
|
|
248
|
+
x: { ticks: { color: '#999' }, grid: { color: '#222' } },
|
|
249
|
+
y: { ticks: { color: '#999' }, grid: { color: '#222' } },
|
|
250
|
+
},
|
|
251
|
+
plugins: {
|
|
252
|
+
legend: { labels: { color: '#e5e5e5' } },
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
onUnmounted(() => chart?.destroy());
|
|
259
|
+
</script>
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Note: `chart.js` must be installed (`npm install chart.js`). Use the brand colors: `#3fea00` (green), `#003bff` (blue), `#ff5c00` (orange).
|
|
263
|
+
|
|
264
|
+
## 5. Dialog
|
|
265
|
+
|
|
266
|
+
Confirmation or form dialog. The global `VCard` default is `variant: 'outlined'` (transparent background), but `nuxt.config.ts` sets a nested `VDialog > VCard` default of `variant: 'flat'` so dialog cards get a solid background automatically. No manual override needed.
|
|
267
|
+
|
|
268
|
+
```vue
|
|
269
|
+
<template>
|
|
270
|
+
<v-dialog v-model="open" max-width="500" persistent>
|
|
271
|
+
<v-card>
|
|
272
|
+
<v-card-title class="d-flex align-center">
|
|
273
|
+
<span>Confirm Action</span>
|
|
274
|
+
<v-spacer />
|
|
275
|
+
<v-btn icon variant="text" @click="open = false">
|
|
276
|
+
<v-icon>mdi-close</v-icon>
|
|
277
|
+
</v-btn>
|
|
278
|
+
</v-card-title>
|
|
279
|
+
<v-divider />
|
|
280
|
+
<v-card-text>
|
|
281
|
+
Are you sure you want to proceed? This action cannot be undone.
|
|
282
|
+
</v-card-text>
|
|
283
|
+
<v-divider />
|
|
284
|
+
<v-card-actions>
|
|
285
|
+
<v-spacer />
|
|
286
|
+
<v-btn variant="text" @click="open = false">Cancel</v-btn>
|
|
287
|
+
<v-btn color="primary" :loading="loading" @click="confirm">Confirm</v-btn>
|
|
288
|
+
</v-card-actions>
|
|
289
|
+
</v-card>
|
|
290
|
+
</v-dialog>
|
|
291
|
+
</template>
|
|
292
|
+
|
|
293
|
+
<script setup lang="ts">
|
|
294
|
+
const open = defineModel<boolean>({ default: false });
|
|
295
|
+
const emit = defineEmits<{ confirmed: [] }>();
|
|
296
|
+
const loading = ref(false);
|
|
297
|
+
|
|
298
|
+
async function confirm() {
|
|
299
|
+
loading.value = true;
|
|
300
|
+
try {
|
|
301
|
+
emit('confirmed');
|
|
302
|
+
open.value = false;
|
|
303
|
+
} finally {
|
|
304
|
+
loading.value = false;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
</script>
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## 6. Master-Detail View
|
|
311
|
+
|
|
312
|
+
Two-column layout with selectable list and detail panel.
|
|
313
|
+
|
|
314
|
+
```vue
|
|
315
|
+
<template>
|
|
316
|
+
<div class="d-flex fill-height">
|
|
317
|
+
<!-- List panel -->
|
|
318
|
+
<v-card class="flex-shrink-0" style="width: 320px; overflow-y: auto" flat>
|
|
319
|
+
<v-list density="compact" nav>
|
|
320
|
+
<v-list-item
|
|
321
|
+
v-for="item in items"
|
|
322
|
+
:key="item.id"
|
|
323
|
+
:title="item.name"
|
|
324
|
+
:subtitle="item.type"
|
|
325
|
+
:active="selected?.id === item.id"
|
|
326
|
+
@click="selected = item"
|
|
327
|
+
/>
|
|
328
|
+
</v-list>
|
|
329
|
+
<v-empty-state
|
|
330
|
+
v-if="!items.length"
|
|
331
|
+
headline="No items"
|
|
332
|
+
icon="mdi-playlist-remove"
|
|
333
|
+
density="compact"
|
|
334
|
+
/>
|
|
335
|
+
</v-card>
|
|
336
|
+
|
|
337
|
+
<v-divider vertical />
|
|
338
|
+
|
|
339
|
+
<!-- Detail panel -->
|
|
340
|
+
<div class="flex-grow-1 overflow-y-auto pa-4">
|
|
341
|
+
<template v-if="selected">
|
|
342
|
+
<h2 class="text-h5 mb-2">{{ selected.name }}</h2>
|
|
343
|
+
<v-chip class="mb-4">{{ selected.type }}</v-chip>
|
|
344
|
+
<p>{{ selected.description }}</p>
|
|
345
|
+
</template>
|
|
346
|
+
<v-empty-state
|
|
347
|
+
v-else
|
|
348
|
+
headline="Select an item"
|
|
349
|
+
text="Choose from the list to see details"
|
|
350
|
+
icon="mdi-arrow-left"
|
|
351
|
+
/>
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
354
|
+
</template>
|
|
355
|
+
|
|
356
|
+
<script setup lang="ts">
|
|
357
|
+
interface Item {
|
|
358
|
+
id: string;
|
|
359
|
+
name: string;
|
|
360
|
+
type: string;
|
|
361
|
+
description: string;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const items = ref<Item[]>([]);
|
|
365
|
+
const selected = ref<Item | null>(null);
|
|
366
|
+
|
|
367
|
+
onMounted(async () => {
|
|
368
|
+
// items.value = await fetchItems();
|
|
369
|
+
});
|
|
370
|
+
</script>
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
## 7. Get Filings for a Company
|
|
374
|
+
|
|
375
|
+
Fetch Edgar filings (or any relationship-linked documents) for an organization.
|
|
376
|
+
|
|
377
|
+
**Important:** `getLinkedEntities` only supports graph node types (person,
|
|
378
|
+
organization, location). Documents, filings, articles, and other types are
|
|
379
|
+
NOT supported — use `getPropertyValues` with the relationship PID instead.
|
|
380
|
+
|
|
381
|
+
```vue
|
|
382
|
+
<template>
|
|
383
|
+
<div class="d-flex flex-column fill-height pa-4">
|
|
384
|
+
<h1 class="text-h5 mb-4">Company Filings</h1>
|
|
385
|
+
<v-text-field
|
|
386
|
+
v-model="query"
|
|
387
|
+
label="Company name"
|
|
388
|
+
prepend-inner-icon="mdi-magnify"
|
|
389
|
+
@keyup.enter="search"
|
|
390
|
+
:loading="loading"
|
|
391
|
+
/>
|
|
392
|
+
<v-alert v-if="error" type="error" variant="tonal" class="mt-2" closable>
|
|
393
|
+
{{ error }}
|
|
394
|
+
</v-alert>
|
|
395
|
+
<v-data-table
|
|
396
|
+
v-if="filings.length"
|
|
397
|
+
:headers="headers"
|
|
398
|
+
:items="filings"
|
|
399
|
+
:loading="loading"
|
|
400
|
+
density="comfortable"
|
|
401
|
+
hover
|
|
402
|
+
class="mt-4"
|
|
403
|
+
/>
|
|
404
|
+
<v-empty-state
|
|
405
|
+
v-else-if="searched && !loading"
|
|
406
|
+
headline="No filings found"
|
|
407
|
+
icon="mdi-file-document-off"
|
|
408
|
+
/>
|
|
409
|
+
</div>
|
|
410
|
+
</template>
|
|
411
|
+
|
|
412
|
+
<script setup lang="ts">
|
|
413
|
+
import { useElementalClient } from '@yottagraph-app/elemental-api/client';
|
|
414
|
+
|
|
415
|
+
const client = useElementalClient();
|
|
416
|
+
const query = ref('');
|
|
417
|
+
const filings = ref<{ neid: string; name: string }[]>([]);
|
|
418
|
+
const loading = ref(false);
|
|
419
|
+
const error = ref<string | null>(null);
|
|
420
|
+
const searched = ref(false);
|
|
421
|
+
|
|
422
|
+
const headers = [
|
|
423
|
+
{ title: 'NEID', key: 'neid', sortable: true },
|
|
424
|
+
{ title: 'Name', key: 'name', sortable: true },
|
|
425
|
+
];
|
|
426
|
+
|
|
427
|
+
async function getPropertyPidMap(client: ReturnType<typeof useElementalClient>) {
|
|
428
|
+
const schemaRes = await client.getSchema();
|
|
429
|
+
const properties = schemaRes.schema?.properties ?? (schemaRes as any).properties ?? [];
|
|
430
|
+
return new Map(properties.map((p: any) => [p.name, p.pid]));
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
async function search() {
|
|
434
|
+
if (!query.value.trim()) return;
|
|
435
|
+
loading.value = true;
|
|
436
|
+
error.value = null;
|
|
437
|
+
searched.value = true;
|
|
438
|
+
try {
|
|
439
|
+
const lookup = await client.getNEID({
|
|
440
|
+
entityName: query.value.trim(),
|
|
441
|
+
maxResults: 1,
|
|
442
|
+
includeNames: true,
|
|
443
|
+
});
|
|
444
|
+
if (!lookup.neids?.length) {
|
|
445
|
+
filings.value = [];
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
const orgNeid = lookup.neids[0];
|
|
449
|
+
|
|
450
|
+
const pidMap = await getPropertyPidMap(client);
|
|
451
|
+
const filedPid = pidMap.get('filed');
|
|
452
|
+
if (!filedPid) {
|
|
453
|
+
error.value = '"filed" relationship not found in schema';
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const res = await client.getPropertyValues({
|
|
458
|
+
eids: JSON.stringify([orgNeid]),
|
|
459
|
+
pids: JSON.stringify([filedPid]),
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
const docNeids = res.values.map((v: any) =>
|
|
463
|
+
String(v.value).padStart(20, '0'),
|
|
464
|
+
);
|
|
465
|
+
|
|
466
|
+
const names = await Promise.all(
|
|
467
|
+
docNeids.map(async (neid: string) => {
|
|
468
|
+
try {
|
|
469
|
+
const r = await client.getNamedEntityReport(neid);
|
|
470
|
+
return r.name || neid;
|
|
471
|
+
} catch {
|
|
472
|
+
return neid;
|
|
473
|
+
}
|
|
474
|
+
}),
|
|
475
|
+
);
|
|
476
|
+
|
|
477
|
+
filings.value = docNeids.map((neid: string, i: number) => ({
|
|
478
|
+
neid,
|
|
479
|
+
name: names[i],
|
|
480
|
+
}));
|
|
481
|
+
} catch (e: any) {
|
|
482
|
+
error.value = e.message || 'Failed to load filings';
|
|
483
|
+
filings.value = [];
|
|
484
|
+
} finally {
|
|
485
|
+
loading.value = false;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
</script>
|
|
489
|
+
```
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "DESIGN.md workflow, feature docs, starter app is placeholder. Read when starting work, planning features, or updating project design."
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Design
|
|
7
|
+
|
|
8
|
+
Read `DESIGN.md` before starting any work. It is the source of truth for project vision, architecture, and current implementation status.
|
|
9
|
+
|
|
10
|
+
Update `DESIGN.md` when you add, remove, or change the design or implementation status of a feature.
|
|
11
|
+
|
|
12
|
+
`DESIGN.md` serves as a record of the current state of the project. Do not include checklists, working plans, or documentation of changes or previous implementation details.
|
|
13
|
+
|
|
14
|
+
The sections of the design doc are flexible and you should add or remove sections to fit the needs of the project.
|
|
15
|
+
|
|
16
|
+
# Starter App is a Placeholder
|
|
17
|
+
|
|
18
|
+
The default UI that ships with this template (home page, chat page, entity
|
|
19
|
+
lookup) is **placeholder content** meant to demonstrate capabilities. When
|
|
20
|
+
building from a project brief or user request, feel free to:
|
|
21
|
+
|
|
22
|
+
- **Replace** `pages/index.vue` with the app's real home page
|
|
23
|
+
- **Remove** example pages (`entity-lookup.vue`, `chat.vue`, `mcp.vue`)
|
|
24
|
+
if the app doesn't need them
|
|
25
|
+
- **Restructure** the navigation, layout, and branding entirely
|
|
26
|
+
- **Keep** only the infrastructure: `composables/`, `server/api/kv/`,
|
|
27
|
+
`agents/`, and `pages/chat.vue` (if the app uses agent chat)
|
|
28
|
+
|
|
29
|
+
Do NOT treat the existing UI as something to preserve. Build what the
|
|
30
|
+
user described, using the template's infrastructure and patterns but not
|
|
31
|
+
its placeholder content. The only exception is if the user explicitly
|
|
32
|
+
asks to keep specific parts.
|
|
33
|
+
|
|
34
|
+
# Project Brief
|
|
35
|
+
|
|
36
|
+
If `DESIGN.md` has a `## Vision` section, it contains the project creator's original description of what they want to build — written during project setup in the Broadchurch Portal.
|
|
37
|
+
|
|
38
|
+
When a user opens the project for the first time and hasn't started building yet (the `## Status` section says "Run `/build-my-app`"), suggest running that command. If they ask "what should I build?" or similar, read the Vision section of DESIGN.md first.
|
|
39
|
+
|
|
40
|
+
# Feature docs
|
|
41
|
+
|
|
42
|
+
Feature docs are used as working documents to help a user and agent collaborate on feature implementation. A feature can be whatever size you need -- an entire page, a shared composable, or a single component.
|
|
43
|
+
|
|
44
|
+
When a user starts working on implementing a change, if they are using a feature doc, read the relevant feature doc before starting work. Then update the feature doc with every change you make. Be sure to create checklists as you plan work, and check off the checklists as the work is completed. Document design choices and open questions.
|
|
45
|
+
|
|
46
|
+
If the user is implementing a change that has no feature doc, encourage them to work with you to create one before starting work. A new feature doc should be created by copying `design/feature_template.md` to a new file in `design`, giving it an appropriate name, and editing it from there.
|
|
47
|
+
|
|
48
|
+
It is a good practice to close out one feature doc and start a new one as the focus of the work shifts. It is acceptable to be working with multiple feature docs at once, if the user is working on multiple unconnected or loosely connected features. The sections of the feature doc are flexible and you should add or remove sections to fit the needs of the project.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Git commit workflow and conventions. Apply when finishing implementation work, making commits, or troubleshooting git/pre-commit failures."
|
|
3
|
+
alwaysApply: false
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Git Workflow
|
|
7
|
+
|
|
8
|
+
This rule applies both when an agent is committing its own work and when helping a user commit theirs.
|
|
9
|
+
|
|
10
|
+
## Committing
|
|
11
|
+
|
|
12
|
+
Commit when you finish a meaningful unit of work — a feature, a fix, a refactor, or a coherent set of related changes. Do **not** commit after every individual edit. If you're making several related changes (e.g. updating references across multiple files for the same reason), bundle them into a single commit. If the user changes focus and starts working on something different, commit before starting the new work focus.
|
|
13
|
+
|
|
14
|
+
### Steps
|
|
15
|
+
|
|
16
|
+
1. **Run formatting first** — this is required or the commit will fail:
|
|
17
|
+
```bash
|
|
18
|
+
npm run format
|
|
19
|
+
```
|
|
20
|
+
2. **Stage all files** — always use `git add -A`.
|
|
21
|
+
3. **Commit** with the message format below.
|
|
22
|
+
4. **Verify the commit succeeded** with `git status`. If it failed, see Pre-commit Failure Troubleshooting below. Do not proceed until the commit is confirmed.
|
|
23
|
+
5. **Inform the user** that you made a commit.
|
|
24
|
+
|
|
25
|
+
### Commit Message Format
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
[Agent commit] {work summary}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
- The work summary should be 1–3 lines.
|
|
32
|
+
- Reuse checklist item language from the source doc when it fits; otherwise write a single concise description.
|
|
33
|
+
|
|
34
|
+
### Pre-commit Failure Troubleshooting
|
|
35
|
+
|
|
36
|
+
If a commit fails with `✖ prettier --check [FAILED]` or `pre-commit script failed`, the fix is:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm run format
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Do **not** run Prettier directly — always use `npm run format`. After formatting, run `git add -A` again and retry the commit.
|
|
43
|
+
|
|
44
|
+
If a user asks about this error, explain the `npm run format` requirement.
|
|
45
|
+
|
|
46
|
+
## Post-Feature: Encourage Push
|
|
47
|
+
|
|
48
|
+
After a feature is fully implemented and committed, use `AskQuestion` to encourage the user to push their branch.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Warns users not to modify aether_ prefixed files in .cursor/
|
|
3
|
+
globs:
|
|
4
|
+
- .cursor/**/aether_*
|
|
5
|
+
alwaysApply: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Aether Instructions Warning
|
|
9
|
+
|
|
10
|
+
**You are editing a file managed by the `@yottagraph-app/aether-instructions` package.**
|
|
11
|
+
|
|
12
|
+
Files prefixed with `aether_` are automatically installed and updated by the
|
|
13
|
+
Aether instructions system. They will be **overwritten** when you run
|
|
14
|
+
`/aether_update_instructions`.
|
|
15
|
+
|
|
16
|
+
## Do Not
|
|
17
|
+
|
|
18
|
+
- Modify existing `aether_*` files directly (changes will be lost on update)
|
|
19
|
+
- Create new files with the `aether_` prefix (they will be deleted on update)
|
|
20
|
+
|
|
21
|
+
## To Customize
|
|
22
|
+
|
|
23
|
+
If you need to modify the behavior of an `aether_*` rule or command:
|
|
24
|
+
|
|
25
|
+
1. **Copy** the file to a new name **without** the `aether_` prefix
|
|
26
|
+
2. Make your changes to the copy
|
|
27
|
+
3. Your copy will not be affected by instruction updates
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Copy the rule you want to customize
|
|
33
|
+
cp .cursor/rules/aether_api.mdc .cursor/rules/api_custom.mdc
|
|
34
|
+
|
|
35
|
+
# Edit your copy
|
|
36
|
+
# Your customizations in api_custom.mdc are preserved across updates
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Why This Matters
|
|
40
|
+
|
|
41
|
+
The `aether_` prefix creates a clear namespace:
|
|
42
|
+
- **`aether_*` files** = Package-managed, updated automatically
|
|
43
|
+
- **Other files** = Your custom rules/commands, never touched
|
|
44
|
+
|
|
45
|
+
This allows you to:
|
|
46
|
+
- Receive rule updates without losing your customizations
|
|
47
|
+
- Know at a glance which files are yours vs. package-provided
|
|
48
|
+
- Safely extend the system without conflicts
|