@appsforgood/next-supabase-kit 0.1.6 → 0.1.8
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/CHANGELOG.md +15 -0
- package/DOGFOOD.md +41 -0
- package/README.md +209 -42
- package/antigravity/commands/review.toml +16 -0
- package/antigravity/commands/spec.toml +17 -0
- package/antigravity/commands/test.toml +17 -0
- package/antigravity/plugin.json +4 -1
- package/assistant-adapters/antigravity.md +7 -0
- package/dist/index.js +96 -28
- package/dist/index.js.map +1 -1
- package/dist/studio/office/assets/office.css +30 -0
- package/dist/studio/office/assets/office.js +99 -3
- package/examples/next-supabase-installed/.agent-kit/agent-roster.json +46 -11
- package/examples/next-supabase-installed/.agent-kit/manifest.json +2 -2
- package/examples/next-supabase-installed/audit-output.json +380 -380
- package/package.json +3 -1
- package/prompts/lifecycle-command-index.md +180 -0
- package/rosters/next-supabase-default-council.json +16 -2
|
@@ -600,6 +600,36 @@ code {
|
|
|
600
600
|
max-height: calc(100vh - 64px);
|
|
601
601
|
}
|
|
602
602
|
|
|
603
|
+
.studio-controls {
|
|
604
|
+
display: grid;
|
|
605
|
+
gap: 10px;
|
|
606
|
+
margin-bottom: 12px;
|
|
607
|
+
padding-bottom: 12px;
|
|
608
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
.studio-label {
|
|
612
|
+
font-size: 12px;
|
|
613
|
+
color: #94a3b8;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
.studio-note-form {
|
|
617
|
+
display: grid;
|
|
618
|
+
gap: 8px;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
.studio-note-form input,
|
|
622
|
+
.studio-note-form select,
|
|
623
|
+
#session-picker {
|
|
624
|
+
width: 100%;
|
|
625
|
+
padding: 8px 10px;
|
|
626
|
+
border-radius: 8px;
|
|
627
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
628
|
+
background: #0f172a;
|
|
629
|
+
color: #e2e8f0;
|
|
630
|
+
font-size: 13px;
|
|
631
|
+
}
|
|
632
|
+
|
|
603
633
|
.transcript-panel h2 {
|
|
604
634
|
margin: 0 0 8px;
|
|
605
635
|
font-size: 14px;
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
handoffPulse: null,
|
|
36
36
|
studioSessionId: boot.activeSessionId || "",
|
|
37
37
|
studioEvents: [],
|
|
38
|
+
studioEventSource: null,
|
|
38
39
|
speechBubbles: [],
|
|
39
40
|
agenticLevel: null
|
|
40
41
|
};
|
|
@@ -71,7 +72,12 @@
|
|
|
71
72
|
bubbleLayer: document.getElementById("bubble-layer"),
|
|
72
73
|
officeHint: document.getElementById("office-hint"),
|
|
73
74
|
canvasWrap: document.querySelector(".canvas-wrap"),
|
|
74
|
-
transcriptList: document.getElementById("transcript-list")
|
|
75
|
+
transcriptList: document.getElementById("transcript-list"),
|
|
76
|
+
sessionPicker: document.getElementById("session-picker"),
|
|
77
|
+
studioNoteForm: document.getElementById("studio-note-form"),
|
|
78
|
+
studioNoteAgent: document.getElementById("studio-note-agent"),
|
|
79
|
+
studioNoteText: document.getElementById("studio-note-text"),
|
|
80
|
+
studioRenderBtn: document.getElementById("studio-render-btn")
|
|
75
81
|
};
|
|
76
82
|
|
|
77
83
|
const ctx = els.canvas?.getContext("2d");
|
|
@@ -210,11 +216,15 @@
|
|
|
210
216
|
|
|
211
217
|
async function loadStudioState() {
|
|
212
218
|
const sessionsRes = await api("/api/sessions");
|
|
213
|
-
|
|
219
|
+
const sessions = sessionsRes.sessions || [];
|
|
220
|
+
state.studioSessionId = sessionsRes.activeSessionId || boot.activeSessionId || sessions[0]?.sessionId || "";
|
|
221
|
+
populateSessionPicker(sessions, state.studioSessionId);
|
|
222
|
+
populateStudioAgents();
|
|
214
223
|
if (els.sessionPill) {
|
|
215
224
|
els.sessionPill.textContent = state.studioSessionId ? state.studioSessionId.slice(0, 24) : "No session";
|
|
216
225
|
}
|
|
217
|
-
|
|
226
|
+
const activeSession = sessions.find((s) => s.sessionId === state.studioSessionId);
|
|
227
|
+
if (els.projectName) els.projectName.textContent = activeSession?.title || "Council session";
|
|
218
228
|
if (els.officeHint) {
|
|
219
229
|
els.officeHint.classList.remove("hidden");
|
|
220
230
|
window.setTimeout(() => els.officeHint?.classList.add("hidden"), 6000);
|
|
@@ -222,10 +232,94 @@
|
|
|
222
232
|
connectStudioStream();
|
|
223
233
|
}
|
|
224
234
|
|
|
235
|
+
function populateSessionPicker(sessions, selectedId) {
|
|
236
|
+
if (!els.sessionPicker) return;
|
|
237
|
+
els.sessionPicker.innerHTML = sessions.length
|
|
238
|
+
? sessions
|
|
239
|
+
.map(
|
|
240
|
+
(s) =>
|
|
241
|
+
'<option value="' +
|
|
242
|
+
escapeHtml(s.sessionId) +
|
|
243
|
+
'"' +
|
|
244
|
+
(s.sessionId === selectedId ? " selected" : "") +
|
|
245
|
+
">" +
|
|
246
|
+
escapeHtml((s.title || s.sessionId).slice(0, 48)) +
|
|
247
|
+
"</option>"
|
|
248
|
+
)
|
|
249
|
+
.join("")
|
|
250
|
+
: '<option value="">No sessions</option>';
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function populateStudioAgents() {
|
|
254
|
+
if (!els.studioNoteAgent) return;
|
|
255
|
+
els.studioNoteAgent.innerHTML = state.agents.length
|
|
256
|
+
? state.agents.map((a) => '<option value="' + escapeHtml(a.id) + '">' + escapeHtml(a.name || a.id) + "</option>").join("")
|
|
257
|
+
: '<option value="planner">Planner</option>';
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function bindStudioControls() {
|
|
261
|
+
if (els.sessionPicker) {
|
|
262
|
+
els.sessionPicker.addEventListener("change", () => {
|
|
263
|
+
state.studioSessionId = els.sessionPicker.value;
|
|
264
|
+
if (els.sessionPill) {
|
|
265
|
+
els.sessionPill.textContent = state.studioSessionId ? state.studioSessionId.slice(0, 24) : "No session";
|
|
266
|
+
}
|
|
267
|
+
connectStudioStream();
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
if (els.studioNoteForm) {
|
|
271
|
+
els.studioNoteForm.addEventListener("submit", async (event) => {
|
|
272
|
+
event.preventDefault();
|
|
273
|
+
if (!state.studioSessionId) {
|
|
274
|
+
setStatus("error", "Select a session first.");
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const agent = els.studioNoteAgent?.value || "planner";
|
|
278
|
+
const text = (els.studioNoteText?.value || "").trim();
|
|
279
|
+
if (!text) {
|
|
280
|
+
setStatus("error", "Enter note text.");
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
try {
|
|
284
|
+
await api("/api/sessions/" + encodeURIComponent(state.studioSessionId) + "/note", {
|
|
285
|
+
method: "POST",
|
|
286
|
+
headers: { "Content-Type": "application/json" },
|
|
287
|
+
body: JSON.stringify({ agent, text })
|
|
288
|
+
});
|
|
289
|
+
if (els.studioNoteText) els.studioNoteText.value = "";
|
|
290
|
+
setStatus("ok", "Note recorded.");
|
|
291
|
+
} catch (error) {
|
|
292
|
+
setStatus("error", error.message);
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
if (els.studioRenderBtn) {
|
|
297
|
+
els.studioRenderBtn.addEventListener("click", async () => {
|
|
298
|
+
if (!state.studioSessionId) {
|
|
299
|
+
setStatus("error", "Select a session first.");
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
try {
|
|
303
|
+
const result = await api("/api/sessions/" + encodeURIComponent(state.studioSessionId) + "/render", {
|
|
304
|
+
method: "POST"
|
|
305
|
+
});
|
|
306
|
+
setStatus("ok", "Rendered " + (result.files?.length || 0) + " markdown files.");
|
|
307
|
+
} catch (error) {
|
|
308
|
+
setStatus("error", error.message);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
225
314
|
function connectStudioStream() {
|
|
226
315
|
if (!state.studioSessionId) return;
|
|
316
|
+
if (state.studioEventSource) {
|
|
317
|
+
state.studioEventSource.close();
|
|
318
|
+
state.studioEventSource = null;
|
|
319
|
+
}
|
|
227
320
|
const url = "/api/events/stream?sessionId=" + encodeURIComponent(state.studioSessionId);
|
|
228
321
|
const source = new EventSource(url);
|
|
322
|
+
state.studioEventSource = source;
|
|
229
323
|
source.addEventListener("snapshot", (ev) => {
|
|
230
324
|
try {
|
|
231
325
|
const payload = JSON.parse(ev.data);
|
|
@@ -249,6 +343,7 @@
|
|
|
249
343
|
});
|
|
250
344
|
source.onerror = () => {
|
|
251
345
|
source.close();
|
|
346
|
+
if (state.studioEventSource === source) state.studioEventSource = null;
|
|
252
347
|
};
|
|
253
348
|
}
|
|
254
349
|
|
|
@@ -1119,6 +1214,7 @@
|
|
|
1119
1214
|
}
|
|
1120
1215
|
|
|
1121
1216
|
loop();
|
|
1217
|
+
if (isStudio) bindStudioControls();
|
|
1122
1218
|
loadState().catch((error) => setStatus("error", error.message));
|
|
1123
1219
|
window.addEventListener("resize", () => {
|
|
1124
1220
|
renderNameplates();
|
|
@@ -96,13 +96,7 @@
|
|
|
96
96
|
"voice-tone",
|
|
97
97
|
"pricing-copy"
|
|
98
98
|
],
|
|
99
|
-
"skills": [
|
|
100
|
-
"positioning-messaging",
|
|
101
|
-
"conversion-copywriting",
|
|
102
|
-
"landing-page-copy",
|
|
103
|
-
"product-voice-tone",
|
|
104
|
-
"onboarding-empty-state-copy"
|
|
105
|
-
],
|
|
99
|
+
"skills": ["positioning-messaging", "conversion-copywriting", "landing-page-copy", "product-voice-tone", "onboarding-empty-state-copy"],
|
|
106
100
|
"handsOffTo": ["frontend-design-lead", "nextjs-engineer", "qa-engineer", "docs-maintainer"]
|
|
107
101
|
},
|
|
108
102
|
{
|
|
@@ -117,7 +111,7 @@
|
|
|
117
111
|
"id": "qa-engineer",
|
|
118
112
|
"name": "QA Engineer",
|
|
119
113
|
"file": ".agent-kit/agents/qa-engineer.md",
|
|
120
|
-
"defaultFor": ["testing", "regression", "smoke", "acceptance-evidence"],
|
|
114
|
+
"defaultFor": ["testing", "regression", "smoke", "acceptance-evidence", "test", "review", "code-review"],
|
|
121
115
|
"skills": ["testing-qa", "best-practice-maturity-review", "visual-regression-qa", "accessibility-wcag"],
|
|
122
116
|
"handsOffTo": ["docs-maintainer", "deployment-observability-engineer"]
|
|
123
117
|
},
|
|
@@ -141,14 +135,26 @@
|
|
|
141
135
|
"workflows": [
|
|
142
136
|
{
|
|
143
137
|
"id": "planning",
|
|
144
|
-
"triggers": ["plan", "roadmap", "phase", "scope", "what should we do", "break this down"],
|
|
138
|
+
"triggers": ["plan", "roadmap", "phase", "scope", "spec", "specification", "acceptance criteria", "what should we do", "break this down"],
|
|
145
139
|
"sequence": ["planner", "lead-architect", "qa-engineer", "docs-maintainer"],
|
|
146
140
|
"council": ["planner", "lead-architect"],
|
|
147
141
|
"requiredOutputs": ["phased checklist", "maturity target", "affected layers", "preserved capabilities", "verification plan", "docs impact"]
|
|
148
142
|
},
|
|
149
143
|
{
|
|
150
144
|
"id": "core-change",
|
|
151
|
-
"triggers": [
|
|
145
|
+
"triggers": [
|
|
146
|
+
"schema",
|
|
147
|
+
"auth",
|
|
148
|
+
"rls",
|
|
149
|
+
"api",
|
|
150
|
+
"route handler",
|
|
151
|
+
"server action",
|
|
152
|
+
"dependency",
|
|
153
|
+
"upgrade",
|
|
154
|
+
"release workflow",
|
|
155
|
+
"package behavior",
|
|
156
|
+
"cross-layer"
|
|
157
|
+
],
|
|
152
158
|
"sequence": [
|
|
153
159
|
"planner",
|
|
154
160
|
"lead-architect",
|
|
@@ -195,7 +201,22 @@
|
|
|
195
201
|
},
|
|
196
202
|
{
|
|
197
203
|
"id": "marketing-copy",
|
|
198
|
-
"triggers": [
|
|
204
|
+
"triggers": [
|
|
205
|
+
"copy",
|
|
206
|
+
"copywriting",
|
|
207
|
+
"marketing",
|
|
208
|
+
"positioning",
|
|
209
|
+
"messaging",
|
|
210
|
+
"value prop",
|
|
211
|
+
"value proposition",
|
|
212
|
+
"landing page",
|
|
213
|
+
"headline",
|
|
214
|
+
"cta",
|
|
215
|
+
"conversion",
|
|
216
|
+
"onboarding",
|
|
217
|
+
"empty state",
|
|
218
|
+
"pricing"
|
|
219
|
+
],
|
|
199
220
|
"sequence": ["planner", "marketing-copy-lead", "frontend-design-lead", "qa-engineer", "docs-maintainer"],
|
|
200
221
|
"council": ["marketing-copy-lead", "frontend-design-lead"],
|
|
201
222
|
"requiredOutputs": [
|
|
@@ -209,6 +230,20 @@
|
|
|
209
230
|
"handoff notes for design and implementation"
|
|
210
231
|
]
|
|
211
232
|
},
|
|
233
|
+
{
|
|
234
|
+
"id": "testing",
|
|
235
|
+
"triggers": ["test", "tests", "unit test", "regression test", "smoke test", "playwright", "acceptance test"],
|
|
236
|
+
"sequence": ["qa-engineer", "docs-maintainer"],
|
|
237
|
+
"council": ["qa-engineer"],
|
|
238
|
+
"requiredOutputs": ["test plan", "commands run", "pass/fail summary", "coverage gaps", "skipped-test rationale"]
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
"id": "code-review",
|
|
242
|
+
"triggers": ["review", "code review", "pre-merge", "pr review", "merge review"],
|
|
243
|
+
"sequence": ["qa-engineer", "security-reviewer", "docs-maintainer"],
|
|
244
|
+
"council": ["qa-engineer", "security-reviewer"],
|
|
245
|
+
"requiredOutputs": ["reviewed scope", "findings by severity", "required fixes", "security notes when applicable", "merge recommendation"]
|
|
246
|
+
},
|
|
212
247
|
{
|
|
213
248
|
"id": "security-review",
|
|
214
249
|
"triggers": ["security", "owasp", "secret", "token", "permission", "ssrf", "idor", "dependency"],
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"packageName": "@appsforgood/next-supabase-kit",
|
|
3
|
-
"packageVersion": "0.1.
|
|
3
|
+
"packageVersion": "0.1.8",
|
|
4
4
|
"stack": "next-supabase",
|
|
5
|
-
"installedAt": "2026-
|
|
5
|
+
"installedAt": "2026-07-04T01:32:06.844Z",
|
|
6
6
|
"docs": [
|
|
7
7
|
"AGENTS.md",
|
|
8
8
|
"AGENT_ROSTER.md",
|