@appsforgood/next-supabase-kit 0.1.7 → 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 +8 -0
- package/DOGFOOD.md +10 -0
- package/README.md +3 -3
- package/antigravity/plugin.json +1 -1
- package/dist/index.js +93 -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/manifest.json +1 -1
- package/examples/next-supabase-installed/audit-output.json +1 -1
- package/package.json +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.8
|
|
4
|
+
|
|
5
|
+
- Added `tests/setup-server-api.test.ts` for full setup-server API route coverage (PATCH state, context import, checklists, design/messaging drafts, apply, agentic-level refresh, oversized body, 404) plus wizard draft edge cases.
|
|
6
|
+
- Moved `readJsonBody` to `src/studio/shared.ts` for reuse; setup-server validates invalid `completeSection` ids with 400.
|
|
7
|
+
- Added Playwright UI screenshot smoke (`scripts/smoke-ui-screens.mjs`, `npm run smoke:ui-screens`, Playwright 1.55.1) with dedicated Ubuntu CI job uploading `artifacts/ui-screens/` (not in `release:check`).
|
|
8
|
+
- Completed Agent Studio Milestone 8: `POST /api/sessions/:id/note` and `/render` on studio serve, session picker, note form, and render button in live office UI; SSE broadcast for notes.
|
|
9
|
+
- Updated `TESTING.md`, `QUALITY_GATES.md`, `DOCS.md`, `ROADMAP.md`, and `DECISIONS.md` for studio serve endpoints, UI smoke, and runtime adapter references.
|
|
10
|
+
|
|
3
11
|
## 0.1.7
|
|
4
12
|
|
|
5
13
|
- Added **Workflow Commands** section to README and docs site: lifecycle diagram, 12 core + 8 UI slash commands, council table, skills-by-phase grouping, and explicit separation from package CLI commands.
|
package/DOGFOOD.md
CHANGED
|
@@ -34,6 +34,16 @@ Mode: read-only audit; no downstream files were modified.
|
|
|
34
34
|
- Assistant adapters and upgrade lifecycle still need real activation/dogfood evidence after publication.
|
|
35
35
|
- Reference-led design critique still needs a real UI change dogfood pass with screenshots or equivalent visual evidence.
|
|
36
36
|
|
|
37
|
+
## 2026-07-04 Publish @0.1.8 Snapshot
|
|
38
|
+
|
|
39
|
+
Date: 2026-07-04
|
|
40
|
+
CLI source: local `dist/index.js` after `npm run release:check`
|
|
41
|
+
|
|
42
|
+
- Setup-server API route coverage (`tests/setup-server-api.test.ts`), Playwright UI screenshot smoke (`smoke:ui-screens`, Playwright 1.55.1), and Agent Studio Milestone 8 completion (note/render POST endpoints, session picker, live office controls).
|
|
43
|
+
- `readJsonBody` shared between setup and studio servers; oversized bodies return 400 without dropping the connection; studio SSE broadcasts notes.
|
|
44
|
+
- Dedicated Ubuntu CI job for UI screenshots; not part of `release:check` matrix.
|
|
45
|
+
- Local verification: `release:check` green (150 tests, setup-server.ts 86% statements), `smoke:ui-screens` produced 4 PNGs.
|
|
46
|
+
|
|
37
47
|
## 2026-07-04 Publish @0.1.7 Snapshot
|
|
38
48
|
|
|
39
49
|
Date: 2026-07-04
|
package/README.md
CHANGED
|
@@ -20,10 +20,10 @@ It also includes a local Agent Studio workflow: project context, durable human c
|
|
|
20
20
|
|
|
21
21
|
## Quick Start
|
|
22
22
|
|
|
23
|
-
Use this in a Next.js + Supabase project (latest: **v0.1.
|
|
23
|
+
Use this in a Next.js + Supabase project (latest: **v0.1.8** on npm):
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
npx @appsforgood/next-supabase-kit@0.1.
|
|
26
|
+
npx @appsforgood/next-supabase-kit@0.1.8 init --stack next-supabase --setup --open
|
|
27
27
|
npx @appsforgood/next-supabase-kit audit
|
|
28
28
|
npx @appsforgood/next-supabase-kit audit --min-readiness baseline-setup
|
|
29
29
|
```
|
|
@@ -458,7 +458,7 @@ Release expectations:
|
|
|
458
458
|
- Dependency Review, CodeQL, OpenSSF Scorecard, Dependabot, SBOM validation, and SBOM attestation.
|
|
459
459
|
- Post-publish verification with `npm run publish:verify`.
|
|
460
460
|
|
|
461
|
-
The package is published to public npm under `@appsforgood/next-supabase-kit@0.1.
|
|
461
|
+
The package is published to public npm under `@appsforgood/next-supabase-kit@0.1.8`. Every release must pass `npm run release:check` before publish and `npm run publish:verify` after (registry visibility, clean `npx` doctor/init/audit). Post-publish verification last passed **2026-07-04** against the live registry: `@0.1.7` doctor, clean init, and `audit --min-readiness baseline-setup` with zero failures.
|
|
462
462
|
|
|
463
463
|
## Repository Health
|
|
464
464
|
|
package/antigravity/plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"name": "agent-kit-next-supabase",
|
|
4
4
|
"displayName": "Agent Kit Next/Supabase",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.8",
|
|
6
6
|
"description": "Runtime commands and portable skills for the Agent Kit Next/Supabase council workflow.",
|
|
7
7
|
"homepage": "https://github.com/lukey662/agentsandskills",
|
|
8
8
|
"sourceOfTruth": [
|
package/dist/index.js
CHANGED
|
@@ -150,7 +150,7 @@ import { join as join12, normalize } from "path";
|
|
|
150
150
|
|
|
151
151
|
// src/config/defaults.ts
|
|
152
152
|
var PACKAGE_NAME = "@appsforgood/next-supabase-kit";
|
|
153
|
-
var PACKAGE_VERSION = "0.1.
|
|
153
|
+
var PACKAGE_VERSION = "0.1.8";
|
|
154
154
|
var DEFAULT_CONFIG = {
|
|
155
155
|
stack: "next-supabase",
|
|
156
156
|
projectType: "saas",
|
|
@@ -362,6 +362,34 @@ function listMarkdown(items) {
|
|
|
362
362
|
function unique(values) {
|
|
363
363
|
return [...new Set(values.filter(Boolean))].sort();
|
|
364
364
|
}
|
|
365
|
+
function readJsonBody(request) {
|
|
366
|
+
return new Promise((resolve3, reject) => {
|
|
367
|
+
const chunks = [];
|
|
368
|
+
let bodyTooLarge = false;
|
|
369
|
+
request.on("data", (chunk) => {
|
|
370
|
+
if (bodyTooLarge) return;
|
|
371
|
+
chunks.push(chunk);
|
|
372
|
+
if (chunks.reduce((total, item) => total + item.length, 0) > 256e3) {
|
|
373
|
+
bodyTooLarge = true;
|
|
374
|
+
reject(new Error("Request body too large."));
|
|
375
|
+
}
|
|
376
|
+
});
|
|
377
|
+
request.on("end", () => {
|
|
378
|
+
if (bodyTooLarge) return;
|
|
379
|
+
const raw = Buffer.concat(chunks).toString("utf8").trim();
|
|
380
|
+
if (!raw) {
|
|
381
|
+
resolve3({});
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
try {
|
|
385
|
+
resolve3(JSON.parse(raw));
|
|
386
|
+
} catch {
|
|
387
|
+
reject(new Error("Request body must be valid JSON."));
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
request.on("error", reject);
|
|
391
|
+
});
|
|
392
|
+
}
|
|
365
393
|
|
|
366
394
|
// src/install/audit.ts
|
|
367
395
|
import { existsSync as existsSync11, readFileSync as readFileSync9, statSync } from "fs";
|
|
@@ -4548,7 +4576,10 @@ function redactEvent(event) {
|
|
|
4548
4576
|
};
|
|
4549
4577
|
}
|
|
4550
4578
|
function recordNote(cwd, agentId, text) {
|
|
4551
|
-
return
|
|
4579
|
+
return recordSessionNote(cwd, getActiveSessionId(cwd), agentId, text);
|
|
4580
|
+
}
|
|
4581
|
+
function recordSessionNote(cwd, sessionId, agentId, text) {
|
|
4582
|
+
return appendSessionEvent(cwd, sessionId, { type: "agent_message", createdAt: nowIso(), agentId, text });
|
|
4552
4583
|
}
|
|
4553
4584
|
function recordDecision(cwd, agentId, decision, risk) {
|
|
4554
4585
|
return appendSessionEvent(cwd, getActiveSessionId(cwd), {
|
|
@@ -5709,7 +5740,7 @@ function renderOfficeHtml(boot, mode) {
|
|
|
5709
5740
|
<div id="nameplate-layer" class="nameplate-layer" aria-hidden="true"></div>
|
|
5710
5741
|
<div id="office-hint" class="office-hint hidden" role="status">${isStudio ? "Watching council session events\u2026" : "Click a desk or zone to brief your agent team."}</div>
|
|
5711
5742
|
</div>
|
|
5712
|
-
${isStudio ? '<aside class="transcript-panel" id="transcript-panel" aria-label="Session transcript"><h2>Transcript</h2><ol id="transcript-list"></ol></aside>' : ""}
|
|
5743
|
+
${isStudio ? '<aside class="transcript-panel" id="transcript-panel" aria-label="Session transcript"><div class="studio-controls" id="studio-controls"><label class="studio-label" for="session-picker">Session</label><select id="session-picker" aria-label="Council session"></select><form id="studio-note-form" class="studio-note-form"><select id="studio-note-agent" aria-label="Agent for note"></select><input id="studio-note-text" type="text" maxlength="3999" placeholder="Add council note\u2026" /><button type="submit" class="btn secondary">Add note</button></form><button type="button" class="btn primary" id="studio-render-btn">Render markdown</button></div><h2>Transcript</h2><ol id="transcript-list"></ol></aside>' : ""}
|
|
5713
5744
|
</main>
|
|
5714
5745
|
<div id="status" class="status" role="status" aria-live="polite"></div>
|
|
5715
5746
|
<div id="depth-modal" class="modal modal-blur" hidden>
|
|
@@ -6164,31 +6195,6 @@ function invalidateAgenticLevelCache(cwd) {
|
|
|
6164
6195
|
// src/studio/setup-server.ts
|
|
6165
6196
|
var DEFAULT_PORT = 9321;
|
|
6166
6197
|
var DEFAULT_HOST = "127.0.0.1";
|
|
6167
|
-
function readJsonBody(request) {
|
|
6168
|
-
return new Promise((resolve3, reject) => {
|
|
6169
|
-
const chunks = [];
|
|
6170
|
-
request.on("data", (chunk) => {
|
|
6171
|
-
chunks.push(chunk);
|
|
6172
|
-
if (chunks.reduce((total, item) => total + item.length, 0) > 256e3) {
|
|
6173
|
-
reject(new Error("Request body too large."));
|
|
6174
|
-
request.destroy();
|
|
6175
|
-
}
|
|
6176
|
-
});
|
|
6177
|
-
request.on("end", () => {
|
|
6178
|
-
const raw = Buffer.concat(chunks).toString("utf8").trim();
|
|
6179
|
-
if (!raw) {
|
|
6180
|
-
resolve3({});
|
|
6181
|
-
return;
|
|
6182
|
-
}
|
|
6183
|
-
try {
|
|
6184
|
-
resolve3(JSON.parse(raw));
|
|
6185
|
-
} catch {
|
|
6186
|
-
reject(new Error("Request body must be valid JSON."));
|
|
6187
|
-
}
|
|
6188
|
-
});
|
|
6189
|
-
request.on("error", reject);
|
|
6190
|
-
});
|
|
6191
|
-
}
|
|
6192
6198
|
function sendJson(response, statusCode, payload) {
|
|
6193
6199
|
response.writeHead(statusCode, {
|
|
6194
6200
|
"Content-Type": "application/json; charset=utf-8",
|
|
@@ -6276,6 +6282,9 @@ async function handleRequest(cwd, request, response) {
|
|
|
6276
6282
|
try {
|
|
6277
6283
|
const body = await readJsonBody(request);
|
|
6278
6284
|
if (typeof body.completeSection === "string") {
|
|
6285
|
+
if (!(body.completeSection in SECTION_LABELS)) {
|
|
6286
|
+
throw new Error("Invalid section id.");
|
|
6287
|
+
}
|
|
6279
6288
|
markSectionComplete(cwd, body.completeSection);
|
|
6280
6289
|
}
|
|
6281
6290
|
const patch = {};
|
|
@@ -6544,6 +6553,11 @@ function safeSessionId(raw) {
|
|
|
6544
6553
|
return raw;
|
|
6545
6554
|
}
|
|
6546
6555
|
function handleRequest2(cwd, request, response) {
|
|
6556
|
+
handleRequestAsync(cwd, request, response).catch((error) => {
|
|
6557
|
+
sendJson2(response, 500, { error: error instanceof Error ? error.message : String(error) });
|
|
6558
|
+
});
|
|
6559
|
+
}
|
|
6560
|
+
async function handleRequestAsync(cwd, request, response) {
|
|
6547
6561
|
const url = new URL(request.url ?? "/", "http://127.0.0.1");
|
|
6548
6562
|
if (request.method === "GET" && (url.pathname === "/" || url.pathname === "/office")) {
|
|
6549
6563
|
sendHtml2(response, renderLiveStudioHtmlWithContext(cwd));
|
|
@@ -6618,6 +6632,57 @@ data: ${JSON.stringify({ sessionId: activeId, events: [] })}
|
|
|
6618
6632
|
});
|
|
6619
6633
|
return;
|
|
6620
6634
|
}
|
|
6635
|
+
const noteMatch = url.pathname.match(/^\/api\/sessions\/([^/]+)\/note$/);
|
|
6636
|
+
if (request.method === "POST" && noteMatch) {
|
|
6637
|
+
const sessionId = safeSessionId(noteMatch[1] ?? "");
|
|
6638
|
+
if (!sessionId) {
|
|
6639
|
+
sendJson2(response, 400, { error: "Invalid session id." });
|
|
6640
|
+
return;
|
|
6641
|
+
}
|
|
6642
|
+
try {
|
|
6643
|
+
const body = await readJsonBody(request);
|
|
6644
|
+
const agent = typeof body.agent === "string" ? body.agent.trim() : "";
|
|
6645
|
+
const text = typeof body.text === "string" ? body.text.trim() : "";
|
|
6646
|
+
if (!agent) {
|
|
6647
|
+
sendJson2(response, 400, { error: "agent is required." });
|
|
6648
|
+
return;
|
|
6649
|
+
}
|
|
6650
|
+
if (!text) {
|
|
6651
|
+
sendJson2(response, 400, { error: "text is required." });
|
|
6652
|
+
return;
|
|
6653
|
+
}
|
|
6654
|
+
if (text.length >= 4e3) {
|
|
6655
|
+
sendJson2(response, 400, { error: "text must be under 4000 characters." });
|
|
6656
|
+
return;
|
|
6657
|
+
}
|
|
6658
|
+
const event = recordSessionNote(cwd, sessionId, agent, text);
|
|
6659
|
+
broadcastSse("event", { sessionId, event, total: readSessionEvents(cwd, sessionId).length });
|
|
6660
|
+
sendJson2(response, 200, { event });
|
|
6661
|
+
} catch (error) {
|
|
6662
|
+
sendJson2(response, 404, { error: error instanceof Error ? error.message : String(error) });
|
|
6663
|
+
}
|
|
6664
|
+
return;
|
|
6665
|
+
}
|
|
6666
|
+
const renderMatch = url.pathname.match(/^\/api\/sessions\/([^/]+)\/render$/);
|
|
6667
|
+
if (request.method === "POST" && renderMatch) {
|
|
6668
|
+
const sessionId = safeSessionId(renderMatch[1] ?? "");
|
|
6669
|
+
if (!sessionId) {
|
|
6670
|
+
sendJson2(response, 400, { error: "Invalid session id." });
|
|
6671
|
+
return;
|
|
6672
|
+
}
|
|
6673
|
+
try {
|
|
6674
|
+
const result = renderSession(cwd, sessionId);
|
|
6675
|
+
sendJson2(response, 200, {
|
|
6676
|
+
rendered: true,
|
|
6677
|
+
sessionId: result.sessionId,
|
|
6678
|
+
sessionPath: result.sessionPath,
|
|
6679
|
+
files: [`${result.sessionPath}/index.md`, `${result.sessionPath}/transcript.md`]
|
|
6680
|
+
});
|
|
6681
|
+
} catch (error) {
|
|
6682
|
+
sendJson2(response, 404, { error: error instanceof Error ? error.message : String(error) });
|
|
6683
|
+
}
|
|
6684
|
+
return;
|
|
6685
|
+
}
|
|
6621
6686
|
sendJson2(response, 404, { error: "Not found." });
|
|
6622
6687
|
}
|
|
6623
6688
|
function listen2(server, host, port) {
|