@appsforgood/next-supabase-kit 0.1.8 → 0.2.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/BEST_PRACTICE_EVIDENCE.md +1 -1
- package/CHANGELOG.md +13 -0
- package/DOGFOOD.md +2 -1
- package/README.md +431 -335
- package/REPOSITORY_SETTINGS.md +12 -6
- package/SECURITY.md +14 -0
- package/SUPPLY_CHAIN.md +15 -14
- package/UPGRADE.md +14 -4
- package/assistant-adapters/README.md +3 -0
- package/assistant-adapters/antigravity.md +2 -0
- package/assistant-adapters/claude-code-subagents.md +1 -0
- package/assistant-adapters/codex-agents.md +2 -0
- package/assistant-adapters/cursor-agent-kit.mdc +2 -0
- package/assistant-adapters/cursor-planner.mdc +1 -1
- package/assistant-adapters/orchestrator-runtime.md +39 -0
- package/checklists/frontend-quality.md +1 -0
- package/checklists/ui-detectors.md +6 -0
- package/dist/index.js +1723 -688
- package/dist/index.js.map +1 -1
- package/dist/studio/office/assets/office.css +138 -7
- package/dist/studio/office/assets/office.js +200 -2
- package/dist/studio/wizard/assets/wizard.js +7 -1
- package/examples/next-supabase-installed/.agent-kit/manifest.json +187 -14
- package/examples/next-supabase-installed/audit-output.json +405 -380
- package/package.json +25 -4
- package/prompts/frontend-design-review.md +6 -0
- package/prompts/screenshot-review.md +2 -1
- package/schemas/audit-report-v2.schema.json +71 -0
- package/schemas/audit-report.schema.json +16 -16
- package/schemas/orchestrator.schema.json +167 -0
- package/schemas/runtime-event.schema.json +66 -0
- package/schemas/runtime-run.schema.json +58 -0
- package/schemas/session-event.schema.json +2 -0
- package/templates/next-supabase/.agent-kit/orchestrator.json +48 -0
- package/templates/next-supabase/.agent-kit/runtime/gitignore.template +2 -0
- package/templates/next-supabase/AGENTS.md +2 -0
- package/templates/next-supabase/ASSISTANT_ADAPTERS.md +20 -0
- package/templates/next-supabase/DECISIONS.md +14 -0
- package/templates/next-supabase/DEPLOYMENT.md +4 -0
- package/templates/next-supabase/DESIGN.md +6 -0
- package/templates/next-supabase/DOCS.md +8 -0
- package/templates/next-supabase/MODEL_ROUTING.md +9 -0
- package/templates/next-supabase/QUALITY_GATES.md +5 -1
- package/templates/next-supabase/SECURITY.md +10 -0
- package/templates/next-supabase/SPEC.md +3 -1
- package/templates/next-supabase/STYLE_GUIDE.md +15 -0
- package/templates/next-supabase/TESTING.md +6 -0
- package/templates/next-supabase/UPGRADE.md +1 -0
|
@@ -566,6 +566,10 @@ body {
|
|
|
566
566
|
display: none !important;
|
|
567
567
|
}
|
|
568
568
|
|
|
569
|
+
[hidden] {
|
|
570
|
+
display: none !important;
|
|
571
|
+
}
|
|
572
|
+
|
|
569
573
|
code {
|
|
570
574
|
font-family: ui-monospace, Menlo, Consolas, monospace;
|
|
571
575
|
font-size: 12px;
|
|
@@ -600,6 +604,39 @@ code {
|
|
|
600
604
|
max-height: calc(100vh - 64px);
|
|
601
605
|
}
|
|
602
606
|
|
|
607
|
+
.studio-tabs {
|
|
608
|
+
display: grid;
|
|
609
|
+
grid-template-columns: 1fr 1fr;
|
|
610
|
+
margin-bottom: 12px;
|
|
611
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
612
|
+
border-radius: 6px;
|
|
613
|
+
overflow: hidden;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
.studio-tab {
|
|
617
|
+
min-height: 34px;
|
|
618
|
+
border: 0;
|
|
619
|
+
border-right: 1px solid rgba(255, 255, 255, 0.12);
|
|
620
|
+
background: #0f172a;
|
|
621
|
+
color: #94a3b8;
|
|
622
|
+
font: inherit;
|
|
623
|
+
cursor: pointer;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
.studio-tab:last-child {
|
|
627
|
+
border-right: 0;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
.studio-tab.active {
|
|
631
|
+
background: #334155;
|
|
632
|
+
color: #f8fafc;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
.studio-tab:focus-visible {
|
|
636
|
+
outline: 2px solid #fbbf24;
|
|
637
|
+
outline-offset: -2px;
|
|
638
|
+
}
|
|
639
|
+
|
|
603
640
|
.studio-controls {
|
|
604
641
|
display: grid;
|
|
605
642
|
gap: 10px;
|
|
@@ -620,7 +657,9 @@ code {
|
|
|
620
657
|
|
|
621
658
|
.studio-note-form input,
|
|
622
659
|
.studio-note-form select,
|
|
623
|
-
#session-picker
|
|
660
|
+
#session-picker,
|
|
661
|
+
#runtime-picker,
|
|
662
|
+
#runtime-goal {
|
|
624
663
|
width: 100%;
|
|
625
664
|
padding: 8px 10px;
|
|
626
665
|
border-radius: 8px;
|
|
@@ -630,13 +669,95 @@ code {
|
|
|
630
669
|
font-size: 13px;
|
|
631
670
|
}
|
|
632
671
|
|
|
672
|
+
#runtime-goal {
|
|
673
|
+
min-height: 82px;
|
|
674
|
+
resize: vertical;
|
|
675
|
+
line-height: 1.4;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
.runtime-start-form,
|
|
679
|
+
.runtime-toolbar {
|
|
680
|
+
display: grid;
|
|
681
|
+
gap: 8px;
|
|
682
|
+
padding-bottom: 12px;
|
|
683
|
+
margin-bottom: 12px;
|
|
684
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
.runtime-check {
|
|
688
|
+
display: flex;
|
|
689
|
+
align-items: center;
|
|
690
|
+
gap: 8px;
|
|
691
|
+
font-size: 12px;
|
|
692
|
+
color: #cbd5e1;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.runtime-check input {
|
|
696
|
+
width: 16px;
|
|
697
|
+
height: 16px;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
.runtime-summary {
|
|
701
|
+
margin: 0 0 12px;
|
|
702
|
+
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
.runtime-summary div {
|
|
706
|
+
display: grid;
|
|
707
|
+
grid-template-columns: 72px minmax(0, 1fr);
|
|
708
|
+
gap: 8px;
|
|
709
|
+
padding: 7px 0;
|
|
710
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
711
|
+
font-size: 12px;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
.runtime-summary dt {
|
|
715
|
+
color: #94a3b8;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
.runtime-summary dd {
|
|
719
|
+
margin: 0;
|
|
720
|
+
color: #f8fafc;
|
|
721
|
+
overflow-wrap: anywhere;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.runtime-approval {
|
|
725
|
+
padding: 10px;
|
|
726
|
+
margin-bottom: 10px;
|
|
727
|
+
border: 1px solid rgba(251, 191, 36, 0.32);
|
|
728
|
+
border-radius: 6px;
|
|
729
|
+
background: rgba(251, 191, 36, 0.08);
|
|
730
|
+
color: #f8fafc;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.runtime-approval p {
|
|
734
|
+
margin: 6px 0 10px;
|
|
735
|
+
color: #cbd5e1;
|
|
736
|
+
font-size: 12px;
|
|
737
|
+
line-height: 1.4;
|
|
738
|
+
white-space: pre-wrap;
|
|
739
|
+
overflow-wrap: anywhere;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
.runtime-actions {
|
|
743
|
+
display: grid;
|
|
744
|
+
grid-template-columns: 1fr 1fr;
|
|
745
|
+
gap: 8px;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
.runtime-cancel {
|
|
749
|
+
width: 100%;
|
|
750
|
+
margin-bottom: 12px;
|
|
751
|
+
}
|
|
752
|
+
|
|
633
753
|
.transcript-panel h2 {
|
|
634
754
|
margin: 0 0 8px;
|
|
635
755
|
font-size: 14px;
|
|
636
756
|
color: #f8fafc;
|
|
637
757
|
}
|
|
638
758
|
|
|
639
|
-
#transcript-list
|
|
759
|
+
#transcript-list,
|
|
760
|
+
#runtime-event-list {
|
|
640
761
|
list-style: none;
|
|
641
762
|
margin: 0;
|
|
642
763
|
padding: 0;
|
|
@@ -645,7 +766,8 @@ code {
|
|
|
645
766
|
font-size: 12px;
|
|
646
767
|
}
|
|
647
768
|
|
|
648
|
-
#transcript-list li
|
|
769
|
+
#transcript-list li,
|
|
770
|
+
#runtime-event-list li {
|
|
649
771
|
padding: 8px;
|
|
650
772
|
border-radius: 8px;
|
|
651
773
|
background: rgba(255, 255, 255, 0.04);
|
|
@@ -692,11 +814,20 @@ code {
|
|
|
692
814
|
@media (max-width: 900px) {
|
|
693
815
|
.office-main.studio-layout {
|
|
694
816
|
grid-template-columns: 1fr;
|
|
817
|
+
grid-template-areas:
|
|
818
|
+
"activity"
|
|
819
|
+
"office";
|
|
820
|
+
}
|
|
821
|
+
.office-main.studio-layout > .canvas-wrap {
|
|
822
|
+
grid-area: office;
|
|
695
823
|
}
|
|
696
824
|
.transcript-panel {
|
|
697
|
-
|
|
825
|
+
grid-area: activity;
|
|
826
|
+
height: min(640px, 72vh);
|
|
827
|
+
max-height: none;
|
|
698
828
|
border-left: 0;
|
|
699
|
-
border-top:
|
|
829
|
+
border-top: 0;
|
|
830
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
700
831
|
}
|
|
701
832
|
}
|
|
702
833
|
|
|
@@ -732,8 +863,8 @@ code {
|
|
|
732
863
|
padding: 6px 10px;
|
|
733
864
|
background: #fff;
|
|
734
865
|
color: var(--ink);
|
|
735
|
-
border:
|
|
736
|
-
border-radius:
|
|
866
|
+
border: 1px solid #cbd5e1;
|
|
867
|
+
border-radius: 8px;
|
|
737
868
|
font-size: 11px;
|
|
738
869
|
line-height: 1.3;
|
|
739
870
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
|
@@ -36,6 +36,9 @@
|
|
|
36
36
|
studioSessionId: boot.activeSessionId || "",
|
|
37
37
|
studioEvents: [],
|
|
38
38
|
studioEventSource: null,
|
|
39
|
+
runtimeRuns: [],
|
|
40
|
+
runtimeRunId: "",
|
|
41
|
+
runtimeEvents: [],
|
|
39
42
|
speechBubbles: [],
|
|
40
43
|
agenticLevel: null
|
|
41
44
|
};
|
|
@@ -77,7 +80,25 @@
|
|
|
77
80
|
studioNoteForm: document.getElementById("studio-note-form"),
|
|
78
81
|
studioNoteAgent: document.getElementById("studio-note-agent"),
|
|
79
82
|
studioNoteText: document.getElementById("studio-note-text"),
|
|
80
|
-
studioRenderBtn: document.getElementById("studio-render-btn")
|
|
83
|
+
studioRenderBtn: document.getElementById("studio-render-btn"),
|
|
84
|
+
studioCouncilTab: document.getElementById("studio-council-tab"),
|
|
85
|
+
studioRuntimeTab: document.getElementById("studio-runtime-tab"),
|
|
86
|
+
studioCouncilView: document.getElementById("studio-council-view"),
|
|
87
|
+
studioRuntimeView: document.getElementById("studio-runtime-view"),
|
|
88
|
+
runtimeStartForm: document.getElementById("runtime-start-form"),
|
|
89
|
+
runtimeStartBtn: document.getElementById("runtime-start-btn"),
|
|
90
|
+
runtimeGoal: document.getElementById("runtime-goal"),
|
|
91
|
+
runtimeDirtyBase: document.getElementById("runtime-dirty-base"),
|
|
92
|
+
runtimePicker: document.getElementById("runtime-picker"),
|
|
93
|
+
runtimeRefreshBtn: document.getElementById("runtime-refresh-btn"),
|
|
94
|
+
runtimeSummary: document.getElementById("runtime-summary"),
|
|
95
|
+
runtimeApproval: document.getElementById("runtime-approval"),
|
|
96
|
+
runtimeApprovalTitle: document.getElementById("runtime-approval-title"),
|
|
97
|
+
runtimeApprovalDetail: document.getElementById("runtime-approval-detail"),
|
|
98
|
+
runtimeApproveBtn: document.getElementById("runtime-approve-btn"),
|
|
99
|
+
runtimeRejectBtn: document.getElementById("runtime-reject-btn"),
|
|
100
|
+
runtimeCancelBtn: document.getElementById("runtime-cancel-btn"),
|
|
101
|
+
runtimeEventList: document.getElementById("runtime-event-list")
|
|
81
102
|
};
|
|
82
103
|
|
|
83
104
|
const ctx = els.canvas?.getContext("2d");
|
|
@@ -175,7 +196,13 @@
|
|
|
175
196
|
}
|
|
176
197
|
|
|
177
198
|
async function api(path, options) {
|
|
178
|
-
const
|
|
199
|
+
const requestOptions = options ? { ...options } : {};
|
|
200
|
+
const method = String(requestOptions.method || "GET").toUpperCase();
|
|
201
|
+
if (!["GET", "HEAD", "OPTIONS"].includes(method)) {
|
|
202
|
+
const token = document.querySelector('meta[name="agent-kit-csrf-token"]')?.getAttribute("content") || "";
|
|
203
|
+
requestOptions.headers = { ...(requestOptions.headers || {}), "Content-Type": "application/json", "X-Agent-Kit-CSRF": token };
|
|
204
|
+
}
|
|
205
|
+
const response = await fetch(path, requestOptions);
|
|
179
206
|
const data = await response.json();
|
|
180
207
|
if (!response.ok) throw new Error(data.error || "Request failed");
|
|
181
208
|
return data;
|
|
@@ -230,6 +257,7 @@
|
|
|
230
257
|
window.setTimeout(() => els.officeHint?.classList.add("hidden"), 6000);
|
|
231
258
|
}
|
|
232
259
|
connectStudioStream();
|
|
260
|
+
await loadRuntimeRuns().catch((error) => renderRuntimeUnavailable(error.message));
|
|
233
261
|
}
|
|
234
262
|
|
|
235
263
|
function populateSessionPicker(sessions, selectedId) {
|
|
@@ -257,7 +285,123 @@
|
|
|
257
285
|
: '<option value="planner">Planner</option>';
|
|
258
286
|
}
|
|
259
287
|
|
|
288
|
+
function switchStudioView(view) {
|
|
289
|
+
const runtime = view === "runtime";
|
|
290
|
+
if (els.studioCouncilView) els.studioCouncilView.hidden = runtime;
|
|
291
|
+
if (els.studioRuntimeView) els.studioRuntimeView.hidden = !runtime;
|
|
292
|
+
els.studioCouncilTab?.classList.toggle("active", !runtime);
|
|
293
|
+
els.studioRuntimeTab?.classList.toggle("active", runtime);
|
|
294
|
+
els.studioCouncilTab?.setAttribute("aria-selected", String(!runtime));
|
|
295
|
+
els.studioRuntimeTab?.setAttribute("aria-selected", String(runtime));
|
|
296
|
+
if (runtime) void loadRuntimeRuns().catch((error) => renderRuntimeUnavailable(error.message));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function populateRuntimePicker() {
|
|
300
|
+
if (!els.runtimePicker) return;
|
|
301
|
+
els.runtimePicker.innerHTML = state.runtimeRuns.length
|
|
302
|
+
? state.runtimeRuns
|
|
303
|
+
.map(
|
|
304
|
+
(run) =>
|
|
305
|
+
'<option value="' +
|
|
306
|
+
escapeHtml(run.runId) +
|
|
307
|
+
'"' +
|
|
308
|
+
(run.runId === state.runtimeRunId ? " selected" : "") +
|
|
309
|
+
">" +
|
|
310
|
+
escapeHtml(run.runId.slice(0, 30) + " · " + run.status) +
|
|
311
|
+
"</option>"
|
|
312
|
+
)
|
|
313
|
+
.join("")
|
|
314
|
+
: '<option value="">No runs</option>';
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async function loadRuntimeRuns() {
|
|
318
|
+
const response = await api("/api/runtime/runs");
|
|
319
|
+
const runtimeEnabled = response.enabled === true;
|
|
320
|
+
if (els.runtimeStartBtn) els.runtimeStartBtn.disabled = !runtimeEnabled;
|
|
321
|
+
state.runtimeRuns = Array.isArray(response.runs) ? response.runs : [];
|
|
322
|
+
if (!state.runtimeRunId || !state.runtimeRuns.some((run) => run.runId === state.runtimeRunId)) {
|
|
323
|
+
state.runtimeRunId = state.runtimeRuns[0]?.runId || "";
|
|
324
|
+
}
|
|
325
|
+
populateRuntimePicker();
|
|
326
|
+
if (state.runtimeRunId) await loadRuntimeRun(state.runtimeRunId);
|
|
327
|
+
else if (runtimeEnabled) renderRuntimeRun(null, []);
|
|
328
|
+
else renderRuntimeUnavailable("Runtime is disabled in .agent-kit/orchestrator.json.");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
async function loadRuntimeRun(runId) {
|
|
332
|
+
if (!runId) {
|
|
333
|
+
renderRuntimeRun(null, []);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const response = await api("/api/runtime/runs/" + encodeURIComponent(runId));
|
|
337
|
+
state.runtimeRunId = runId;
|
|
338
|
+
state.runtimeEvents = response.events || [];
|
|
339
|
+
const index = state.runtimeRuns.findIndex((run) => run.runId === runId);
|
|
340
|
+
if (index >= 0) state.runtimeRuns[index] = response.run;
|
|
341
|
+
else state.runtimeRuns.unshift(response.run);
|
|
342
|
+
populateRuntimePicker();
|
|
343
|
+
renderRuntimeRun(response.run, state.runtimeEvents);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function renderRuntimeUnavailable(message) {
|
|
347
|
+
if (els.runtimeStartBtn) els.runtimeStartBtn.disabled = true;
|
|
348
|
+
if (els.runtimeSummary) els.runtimeSummary.innerHTML = "<div><dt>Status</dt><dd>" + escapeHtml(message) + "</dd></div>";
|
|
349
|
+
if (els.runtimeEventList) els.runtimeEventList.innerHTML = "";
|
|
350
|
+
if (els.runtimeApproval) els.runtimeApproval.hidden = true;
|
|
351
|
+
if (els.runtimeCancelBtn) els.runtimeCancelBtn.hidden = true;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function renderRuntimeRun(run, events) {
|
|
355
|
+
if (els.runtimeSummary) {
|
|
356
|
+
const items = run
|
|
357
|
+
? [
|
|
358
|
+
["Status", run.status],
|
|
359
|
+
["Workflow", run.workflowId],
|
|
360
|
+
["Agent", run.activeAgentId || "—"],
|
|
361
|
+
["Commit", run.commit ? run.commit.slice(0, 12) : "—"]
|
|
362
|
+
]
|
|
363
|
+
: [["Status", "No runs"]];
|
|
364
|
+
els.runtimeSummary.innerHTML = items.map(([label, value]) => "<div><dt>" + escapeHtml(label) + "</dt><dd>" + escapeHtml(value) + "</dd></div>").join("");
|
|
365
|
+
}
|
|
366
|
+
const pending = run?.pendingApproval;
|
|
367
|
+
if (els.runtimeApproval) els.runtimeApproval.hidden = !pending;
|
|
368
|
+
if (els.runtimeApprovalTitle) els.runtimeApprovalTitle.textContent = pending?.title || "";
|
|
369
|
+
if (els.runtimeApprovalDetail) els.runtimeApprovalDetail.textContent = pending?.detail || "";
|
|
370
|
+
const terminal = !run || ["complete", "failed", "cancelled"].includes(run.status);
|
|
371
|
+
if (els.runtimeCancelBtn) els.runtimeCancelBtn.hidden = terminal;
|
|
372
|
+
if (els.runtimeEventList) {
|
|
373
|
+
els.runtimeEventList.innerHTML = (events || [])
|
|
374
|
+
.slice(-100)
|
|
375
|
+
.map(
|
|
376
|
+
(event) =>
|
|
377
|
+
'<li><span class="tx-time">' +
|
|
378
|
+
escapeHtml((event.createdAt || "").slice(11, 19)) +
|
|
379
|
+
"</span> <strong>" +
|
|
380
|
+
escapeHtml(event.agentId || "run") +
|
|
381
|
+
"</strong> " +
|
|
382
|
+
escapeHtml(eventLabel(event)) +
|
|
383
|
+
"</li>"
|
|
384
|
+
)
|
|
385
|
+
.join("");
|
|
386
|
+
els.runtimeEventList.scrollTop = els.runtimeEventList.scrollHeight;
|
|
387
|
+
}
|
|
388
|
+
if (run && els.sessionPill && !els.studioRuntimeView?.hidden) els.sessionPill.textContent = run.runId.slice(0, 24);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
async function decideRuntime(decision) {
|
|
392
|
+
if (!state.runtimeRunId) return;
|
|
393
|
+
const response = await api("/api/runtime/runs/" + encodeURIComponent(state.runtimeRunId) + "/decision", {
|
|
394
|
+
method: "POST",
|
|
395
|
+
body: JSON.stringify({ decision, actor: "studio-operator" })
|
|
396
|
+
});
|
|
397
|
+
state.runtimeEvents = response.events || [];
|
|
398
|
+
renderRuntimeRun(response.run, state.runtimeEvents);
|
|
399
|
+
await loadRuntimeRuns();
|
|
400
|
+
}
|
|
401
|
+
|
|
260
402
|
function bindStudioControls() {
|
|
403
|
+
els.studioCouncilTab?.addEventListener("click", () => switchStudioView("council"));
|
|
404
|
+
els.studioRuntimeTab?.addEventListener("click", () => switchStudioView("runtime"));
|
|
261
405
|
if (els.sessionPicker) {
|
|
262
406
|
els.sessionPicker.addEventListener("change", () => {
|
|
263
407
|
state.studioSessionId = els.sessionPicker.value;
|
|
@@ -309,6 +453,60 @@
|
|
|
309
453
|
}
|
|
310
454
|
});
|
|
311
455
|
}
|
|
456
|
+
if (els.runtimePicker) {
|
|
457
|
+
els.runtimePicker.addEventListener("change", () => {
|
|
458
|
+
state.runtimeRunId = els.runtimePicker.value;
|
|
459
|
+
void loadRuntimeRun(state.runtimeRunId).catch((error) => setStatus("error", error.message));
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
els.runtimeRefreshBtn?.addEventListener("click", () => {
|
|
463
|
+
void loadRuntimeRuns().catch((error) => setStatus("error", error.message));
|
|
464
|
+
});
|
|
465
|
+
if (els.runtimeStartForm) {
|
|
466
|
+
els.runtimeStartForm.addEventListener("submit", async (event) => {
|
|
467
|
+
event.preventDefault();
|
|
468
|
+
const goal = (els.runtimeGoal?.value || "").trim();
|
|
469
|
+
if (!goal) {
|
|
470
|
+
setStatus("error", "Enter a run goal.");
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
try {
|
|
474
|
+
const response = await api("/api/runtime/runs", {
|
|
475
|
+
method: "POST",
|
|
476
|
+
body: JSON.stringify({ goal, acknowledgeDirtyBase: Boolean(els.runtimeDirtyBase?.checked) })
|
|
477
|
+
});
|
|
478
|
+
state.runtimeRunId = response.run.runId;
|
|
479
|
+
state.runtimeEvents = response.events || [];
|
|
480
|
+
if (els.runtimeGoal) els.runtimeGoal.value = "";
|
|
481
|
+
await loadRuntimeRuns();
|
|
482
|
+
setStatus("ok", "Run started.");
|
|
483
|
+
} catch (error) {
|
|
484
|
+
setStatus("error", error.message);
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
els.runtimeApproveBtn?.addEventListener("click", () => {
|
|
489
|
+
void decideRuntime("approve").catch((error) => setStatus("error", error.message));
|
|
490
|
+
});
|
|
491
|
+
els.runtimeRejectBtn?.addEventListener("click", () => {
|
|
492
|
+
void decideRuntime("reject").catch((error) => setStatus("error", error.message));
|
|
493
|
+
});
|
|
494
|
+
els.runtimeCancelBtn?.addEventListener("click", async () => {
|
|
495
|
+
if (!state.runtimeRunId) return;
|
|
496
|
+
try {
|
|
497
|
+
const response = await api("/api/runtime/runs/" + encodeURIComponent(state.runtimeRunId) + "/cancel", { method: "POST" });
|
|
498
|
+
state.runtimeEvents = response.events || [];
|
|
499
|
+
renderRuntimeRun(response.run, state.runtimeEvents);
|
|
500
|
+
await loadRuntimeRuns();
|
|
501
|
+
} catch (error) {
|
|
502
|
+
setStatus("error", error.message);
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
window.setInterval(() => {
|
|
506
|
+
if (els.studioRuntimeView && !els.studioRuntimeView.hidden) {
|
|
507
|
+
void loadRuntimeRuns().catch(() => undefined);
|
|
508
|
+
}
|
|
509
|
+
}, 2500);
|
|
312
510
|
}
|
|
313
511
|
|
|
314
512
|
function connectStudioStream() {
|
|
@@ -59,7 +59,13 @@
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
async function api(path, options) {
|
|
62
|
-
const
|
|
62
|
+
const requestOptions = options ? { ...options } : {};
|
|
63
|
+
const method = String(requestOptions.method || "GET").toUpperCase();
|
|
64
|
+
if (!["GET", "HEAD", "OPTIONS"].includes(method)) {
|
|
65
|
+
const token = document.querySelector('meta[name="agent-kit-csrf-token"]')?.getAttribute("content") || "";
|
|
66
|
+
requestOptions.headers = { ...(requestOptions.headers || {}), "Content-Type": "application/json", "X-Agent-Kit-CSRF": token };
|
|
67
|
+
}
|
|
68
|
+
const response = await fetch(path, requestOptions);
|
|
63
69
|
const data = await response.json();
|
|
64
70
|
if (!response.ok) throw new Error(data.error || "Request failed");
|
|
65
71
|
return data;
|