agenttwin 0.3.3 → 0.3.5
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/dist/api.js +91 -5
- package/dist/cli.js +15 -15
- package/dist/dashboard/assets/dashboard/agent-home.css +12 -9
- package/dist/dashboard/assets/dashboard/dashboard.css +4 -0
- package/dist/dashboard/assets/dashboard/inventory.json +1 -1
- package/dist/dashboard/assets/dashboard/runs.json +1 -1
- package/dist/dashboard/assets/next/static/It81cabE0Vc-SUEO_z8CQ/_buildManifest.js +1 -0
- package/dist/dashboard/assets/next/static/It81cabE0Vc-SUEO_z8CQ/_ssgManifest.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/255-09fb0d129bb12f51.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/4bd1b696-c023c6e3521b1417.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/772-85561381eedc95da.js +67 -0
- package/dist/dashboard/assets/next/static/chunks/app/_not-found/page-5dc6a60918e8652d.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/app/dashboard/layout-fa1f6ba56d7af38a.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/app/dashboard/page-9b4372b1e47bc3bc.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/app/demo/page-760a47a5e4dee43f.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/app/docs/[[...slug]]/page-80a0c2c82d5b4efd.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/app/layout-1a40c59e535513d4.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/app/page-de4735052adab906.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/app/pricing/page-7703fc31d6dff0f7.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/app/sitemap.xml/route-ef5a216a578eb7a8.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/framework-292291387d6b2e39.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/main-aea6e71289384293.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/main-app-99295a8cc37e8a47.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/pages/_app-7d307437aca18ad4.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/pages/_error-cb2a52f75f2162e2.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/dashboard/assets/next/static/chunks/webpack-330c9b9dd99c0d55.js +1 -0
- package/dist/dashboard/assets/next/static/css/1323d7da89b3fa5e.css +1 -0
- package/dist/dashboard/assets/next/static/css/45513ebc8c6ae800.css +1 -0
- package/dist/dashboard/assets/next/static/css/61ec74d503f353d4.css +1 -0
- package/dist/dashboard/assets/next/static/css/62e3209163fa5e55.css +1 -0
- package/dist/dashboard/assets/next/static/css/9282330a2fd1ab73.css +1 -0
- package/dist/dashboard/assets/next/static/css/c5ac36ef5726e746.css +1 -0
- package/dist/dashboard/assets/next/static/media/inter-var.e4af272c.woff2 +0 -0
- package/dist/dashboard/assets/next/static/media/moonlit-coast.bbe901a1.png +0 -0
- package/dist/dashboard/assets/next/static/media/plexmono-400.d3ebbfd6.woff2 +0 -0
- package/dist/dashboard/index.html +1 -140
- package/dist/gateway.js +91 -5
- package/package.json +1 -1
- package/dist/dashboard/assets/dashboard/agent-home.js +0 -264
- package/dist/dashboard/assets/dashboard/dashboard.js +0 -436
- package/dist/dashboard/assets/dashboard/hosted.js +0 -89
- package/dist/dashboard/assets/dashboard/workflows.js +0 -39
- package/dist/dashboard/assets/vendor/dompurify.LICENSE +0 -202
- package/dist/dashboard/assets/vendor/marked.LICENSE +0 -44
- package/dist/dashboard/assets/vendor/marked.js +0 -82
- package/dist/dashboard/assets/vendor/purify.min.js +0 -7
package/dist/api.js
CHANGED
|
@@ -938,7 +938,13 @@ async function launchSession(cwd) {
|
|
|
938
938
|
});
|
|
939
939
|
}
|
|
940
940
|
async function loadDashboardDiscovery(cwd, inventory) {
|
|
941
|
-
|
|
941
|
+
let previousHead;
|
|
942
|
+
try {
|
|
943
|
+
previousHead = JSON.parse(await readFile6(join6(cwd, ".agenttwin/git.json"), "utf8")).head;
|
|
944
|
+
} catch {
|
|
945
|
+
}
|
|
946
|
+
const git = await captureGit(cwd, previousHead);
|
|
947
|
+
const base = discoveryTransfer({ ...dashboardInventory(cwd, inventory), ...git ? { git } : {} });
|
|
942
948
|
let raw;
|
|
943
949
|
try {
|
|
944
950
|
raw = await readFile6(join6(cwd, ".agenttwin/agent-discovery.json"), "utf8");
|
|
@@ -960,6 +966,7 @@ async function loadDashboardDiscovery(cwd, inventory) {
|
|
|
960
966
|
var init_session = __esm({
|
|
961
967
|
"src/commands/session.ts"() {
|
|
962
968
|
"use strict";
|
|
969
|
+
init_git();
|
|
963
970
|
init_project_products();
|
|
964
971
|
init_dashboard_transfer();
|
|
965
972
|
init_dashboard();
|
|
@@ -974,6 +981,28 @@ import { mkdir as mkdir3, readFile as readFile8, writeFile as writeFile4, rename
|
|
|
974
981
|
import { resolve as resolve2, join as join8, dirname as dirname2, extname } from "path";
|
|
975
982
|
import { tmpdir as tmpdir2 } from "os";
|
|
976
983
|
|
|
984
|
+
// src/runtime/transcription.ts
|
|
985
|
+
var transcriptionConfiguration = () => ({ available: Boolean(process.env.OPENAI_API_KEY), model: "gpt-4o-mini-transcribe" });
|
|
986
|
+
var formats = { "audio/webm": "webm", "audio/mp4": "mp4", "audio/ogg": "ogg", "audio/wav": "wav", "audio/mpeg": "mp3" };
|
|
987
|
+
function transcriptionAudio(input) {
|
|
988
|
+
if (typeof input.audio !== "string" || typeof input.mimeType !== "string" || !formats[input.mimeType]) throw new Error("Unsupported recording format");
|
|
989
|
+
const bytes = Buffer.from(input.audio, "base64");
|
|
990
|
+
if (!bytes.length || bytes.length > 4 * 1024 * 1024 || bytes.toString("base64") !== input.audio) throw new Error("Recording must be valid base64 and at most 4 MiB");
|
|
991
|
+
return { bytes, mimeType: input.mimeType, extension: formats[input.mimeType] };
|
|
992
|
+
}
|
|
993
|
+
async function transcribeAudio(audio, signal) {
|
|
994
|
+
if (!transcriptionConfiguration().available) throw new Error("transcription_not_configured");
|
|
995
|
+
const form = new FormData();
|
|
996
|
+
form.set("model", "gpt-4o-mini-transcribe");
|
|
997
|
+
form.set("response_format", "json");
|
|
998
|
+
form.set("file", new Blob([new Uint8Array(audio.bytes)], { type: audio.mimeType }), `recording.${audio.extension}`);
|
|
999
|
+
const response = await fetch("https://api.openai.com/v1/audio/transcriptions", { method: "POST", redirect: "error", signal, headers: { authorization: `Bearer ${process.env.OPENAI_API_KEY}` }, body: form });
|
|
1000
|
+
if (!response.ok) throw new Error(`transcription_request_failed_${response.status}`);
|
|
1001
|
+
const data = await response.json();
|
|
1002
|
+
if (typeof data.text !== "string" || !data.text.trim() || data.text.length > 16e3) throw new Error("transcription_returned_no_text");
|
|
1003
|
+
return data.text.trim();
|
|
1004
|
+
}
|
|
1005
|
+
|
|
977
1006
|
// src/runtime/chat.ts
|
|
978
1007
|
function chatConfiguration() {
|
|
979
1008
|
return { available: Boolean(process.env.OPENAI_API_KEY && process.env.AGENTTWIN_CHAT_MODEL), provider: "openai", model: process.env.AGENTTWIN_CHAT_MODEL ?? null };
|
|
@@ -1621,12 +1650,12 @@ function uploadPath(path) {
|
|
|
1621
1650
|
if (!path || path.startsWith("/") || path.includes("\\") || path.includes("\0") || path.split("/").some((p) => !p || p === "." || p === ".." || /^(\.env.*|\.git|\.ssh|\.aws|\.azure|\.config|\.npmrc|\.netrc|credentials.*)$/i.test(p)) || /\.(pem|key|p12|pfx)$/i.test(path)) throw new Error("Unsafe uploaded file path");
|
|
1622
1651
|
return path;
|
|
1623
1652
|
}
|
|
1624
|
-
async function body(req) {
|
|
1653
|
+
async function body(req, limit = 28 * 1024 * 1024) {
|
|
1625
1654
|
const chunks = [];
|
|
1626
1655
|
let bytes = 0;
|
|
1627
1656
|
for await (const chunk of req) {
|
|
1628
1657
|
bytes += chunk.length;
|
|
1629
|
-
if (bytes >
|
|
1658
|
+
if (bytes > limit) throw new Error("Request exceeds size limit");
|
|
1630
1659
|
chunks.push(Buffer.from(chunk));
|
|
1631
1660
|
}
|
|
1632
1661
|
return JSON.parse(Buffer.concat(chunks).toString("utf8"));
|
|
@@ -1649,6 +1678,7 @@ async function startGateway(opts) {
|
|
|
1649
1678
|
const controllers = /* @__PURE__ */ new Map();
|
|
1650
1679
|
const chatTasks = /* @__PURE__ */ new Set();
|
|
1651
1680
|
const chatControllers = /* @__PURE__ */ new Map();
|
|
1681
|
+
const voiceControllers = /* @__PURE__ */ new Map();
|
|
1652
1682
|
const directory = resolve2(opts.directory);
|
|
1653
1683
|
await mkdir3(directory, { recursive: true, mode: 448 });
|
|
1654
1684
|
const storePath = join8(directory, "state.json");
|
|
@@ -2027,7 +2057,63 @@ async function startGateway(opts) {
|
|
|
2027
2057
|
if (path === "/v1/chat" && req.method === "GET") {
|
|
2028
2058
|
const project = selectedInventory?.name ?? null;
|
|
2029
2059
|
const thread = store.chats?.find((t) => t.accountId === account.id && t.project === project);
|
|
2030
|
-
send(res, 200, { ...chatConfiguration(), project, thread: thread ?? null, busy: chatControllers.has(account.id) });
|
|
2060
|
+
send(res, 200, { ...chatConfiguration(), transcription: transcriptionConfiguration(), project, thread: thread ?? null, busy: chatControllers.has(account.id) });
|
|
2061
|
+
return;
|
|
2062
|
+
}
|
|
2063
|
+
if (path === "/v1/transcriptions" && req.method === "POST") {
|
|
2064
|
+
if (stopping) {
|
|
2065
|
+
send(res, 503, { error: "stopping" });
|
|
2066
|
+
return;
|
|
2067
|
+
}
|
|
2068
|
+
if (!transcriptionConfiguration().available) {
|
|
2069
|
+
send(res, 503, { error: "transcription_not_configured", message: "Voice input is unavailable on this server." });
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
if (voiceControllers.has(account.id) || voiceControllers.size >= 4) {
|
|
2073
|
+
send(res, 429, { error: "transcription_busy" });
|
|
2074
|
+
return;
|
|
2075
|
+
}
|
|
2076
|
+
const audio = transcriptionAudio(await body(req, 6 * 1024 * 1024));
|
|
2077
|
+
if (!account.active) {
|
|
2078
|
+
send(res, 401, { error: "unauthorized" });
|
|
2079
|
+
return;
|
|
2080
|
+
}
|
|
2081
|
+
if (voiceControllers.has(account.id) || voiceControllers.size >= 4) {
|
|
2082
|
+
send(res, 429, { error: "transcription_busy" });
|
|
2083
|
+
return;
|
|
2084
|
+
}
|
|
2085
|
+
const day = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2086
|
+
const usage = account.voiceUsageDay === day ? account.voiceRequests ?? 0 : 0;
|
|
2087
|
+
if (usage >= 50) {
|
|
2088
|
+
send(res, 429, { error: "daily_voice_limit" });
|
|
2089
|
+
return;
|
|
2090
|
+
}
|
|
2091
|
+
const controller = new AbortController();
|
|
2092
|
+
voiceControllers.set(account.id, controller);
|
|
2093
|
+
const timeout = setTimeout(() => controller.abort(), 3e4);
|
|
2094
|
+
let finish;
|
|
2095
|
+
const task = new Promise((done) => {
|
|
2096
|
+
finish = done;
|
|
2097
|
+
});
|
|
2098
|
+
chatTasks.add(task);
|
|
2099
|
+
try {
|
|
2100
|
+
account.voiceUsageDay = day;
|
|
2101
|
+
account.voiceRequests = usage + 1;
|
|
2102
|
+
await save();
|
|
2103
|
+
const text = await transcribeAudio(audio, controller.signal);
|
|
2104
|
+
if (!account.active) {
|
|
2105
|
+
send(res, 401, { error: "unauthorized" });
|
|
2106
|
+
return;
|
|
2107
|
+
}
|
|
2108
|
+
send(res, 200, { text });
|
|
2109
|
+
} catch {
|
|
2110
|
+
send(res, 502, { error: "transcription_failed", message: "Could not transcribe this recording. Please try again or type your message." });
|
|
2111
|
+
} finally {
|
|
2112
|
+
clearTimeout(timeout);
|
|
2113
|
+
voiceControllers.delete(account.id);
|
|
2114
|
+
chatTasks.delete(task);
|
|
2115
|
+
finish();
|
|
2116
|
+
}
|
|
2031
2117
|
return;
|
|
2032
2118
|
}
|
|
2033
2119
|
if (path === "/v1/chat" && req.method === "POST") {
|
|
@@ -2180,7 +2266,7 @@ async function startGateway(opts) {
|
|
|
2180
2266
|
});
|
|
2181
2267
|
return { server, async close() {
|
|
2182
2268
|
stopping = true;
|
|
2183
|
-
for (const controller of chatControllers.values()) controller.abort();
|
|
2269
|
+
for (const controller of [...chatControllers.values(), ...voiceControllers.values()]) controller.abort();
|
|
2184
2270
|
server.close();
|
|
2185
2271
|
await Promise.allSettled([...workers, ...chatTasks]);
|
|
2186
2272
|
await writes;
|
package/dist/cli.js
CHANGED
|
@@ -897,17 +897,17 @@ async function writeDashboard(cwd, inventory) {
|
|
|
897
897
|
try {
|
|
898
898
|
await readFile4(join4(bundle, "index.html"));
|
|
899
899
|
} catch {
|
|
900
|
-
bundle = fileURLToPath(new URL("
|
|
900
|
+
bundle = fileURLToPath(new URL("../../dist/dashboard/", import.meta.url));
|
|
901
901
|
}
|
|
902
902
|
await mkdir(join4(directory, "assets", "dashboard"), { recursive: true });
|
|
903
|
-
const html = await readFile4(join4(bundle,
|
|
904
|
-
for (const folder of ["dashboard", "icons", "logo", "fonts", "
|
|
903
|
+
const html = await readFile4(join4(bundle, "index.html"), "utf8");
|
|
904
|
+
for (const folder of ["dashboard", "icons", "logo", "fonts", "next"]) {
|
|
905
905
|
await cp(join4(bundle, "assets", folder), join4(directory, "assets", folder), { recursive: true });
|
|
906
906
|
}
|
|
907
907
|
await cp(join4(bundle, "assets", "brand.css"), join4(directory, "assets", "brand.css"));
|
|
908
908
|
const data = await loadDashboardDiscovery(cwd, inventory);
|
|
909
909
|
const payload = JSON.stringify(data).replace(/</g, "\\u003c");
|
|
910
|
-
const page2 = html.
|
|
910
|
+
const page2 = html.replace("</head>", `<script id="agenttwin-discovery" type="application/json">${payload}</script></head>`).replace(/href="index.html"/g, 'href="../report.html"').replace(/href="docs\/"/g, 'href="../report.html"').replace("Docs \u2197", "Discovery report \u2197").replace("Runtime documentation \u2197", "Coverage report \u2197").replace("Back to website \u2197", "Discovery report \u2197");
|
|
911
911
|
await writeFile(join4(directory, "index.html"), page2, "utf8");
|
|
912
912
|
await writeFile(join4(directory, "assets", "dashboard", "inventory.json"), JSON.stringify(data), "utf8");
|
|
913
913
|
await writeFile(join4(directory, "assets", "dashboard", "runs.json"), '{"runs":[]}', "utf8");
|
|
@@ -971,7 +971,13 @@ async function launchSession(cwd) {
|
|
|
971
971
|
});
|
|
972
972
|
}
|
|
973
973
|
async function loadDashboardDiscovery(cwd, inventory) {
|
|
974
|
-
|
|
974
|
+
let previousHead;
|
|
975
|
+
try {
|
|
976
|
+
previousHead = JSON.parse(await readFile5(join5(cwd, ".agenttwin/git.json"), "utf8")).head;
|
|
977
|
+
} catch {
|
|
978
|
+
}
|
|
979
|
+
const git = await captureGit(cwd, previousHead);
|
|
980
|
+
const base = discoveryTransfer({ ...dashboardInventory(cwd, inventory), ...git ? { git } : {} });
|
|
975
981
|
let raw;
|
|
976
982
|
try {
|
|
977
983
|
raw = await readFile5(join5(cwd, ".agenttwin/agent-discovery.json"), "utf8");
|
|
@@ -993,6 +999,7 @@ async function loadDashboardDiscovery(cwd, inventory) {
|
|
|
993
999
|
var init_session = __esm({
|
|
994
1000
|
"src/commands/session.ts"() {
|
|
995
1001
|
"use strict";
|
|
1002
|
+
init_git();
|
|
996
1003
|
init_project_products();
|
|
997
1004
|
init_dashboard_transfer();
|
|
998
1005
|
init_dashboard();
|
|
@@ -1048,7 +1055,6 @@ import { fileURLToPath as fileURLToPath3 } from "url";
|
|
|
1048
1055
|
import { parseArgs } from "util";
|
|
1049
1056
|
|
|
1050
1057
|
// src/commands/sync.ts
|
|
1051
|
-
init_git();
|
|
1052
1058
|
import { readFile as readFile6, writeFile as writeFile3 } from "fs/promises";
|
|
1053
1059
|
import { join as join6 } from "path";
|
|
1054
1060
|
|
|
@@ -1200,19 +1206,13 @@ async function runSync(cwd) {
|
|
|
1200
1206
|
const base = apiBase(process.env.AGENTTWIN_API_URL || "https://agenttwin-api.212.56.40.125.sslip.io");
|
|
1201
1207
|
const inventory = JSON.parse(await readFile6(join6(cwd, ".agenttwin/inventory.json"), "utf8"));
|
|
1202
1208
|
const payload = await loadDashboardDiscovery(cwd, inventory);
|
|
1203
|
-
|
|
1204
|
-
try {
|
|
1205
|
-
previousHead = JSON.parse(await readFile6(join6(cwd, ".agenttwin/git.json"), "utf8")).head;
|
|
1206
|
-
} catch {
|
|
1207
|
-
}
|
|
1208
|
-
const git = await captureGit(cwd, previousHead);
|
|
1209
|
-
Object.assign(payload, git ? { git } : {});
|
|
1209
|
+
const git = payload.git;
|
|
1210
1210
|
const response = await fetch(base + "/v1/discovery", { method: "POST", headers: { authorization: "Bearer " + token, "content-type": "application/json" }, body: JSON.stringify(payload), redirect: "error", signal: AbortSignal.timeout(2e4) });
|
|
1211
1211
|
const result = await response.json();
|
|
1212
1212
|
if (!response.ok) throw new Error(result.error || "Discovery sync failed: " + response.status);
|
|
1213
1213
|
if (git) await writeFile3(join6(cwd, ".agenttwin/git.json"), JSON.stringify(git) + "\n", { mode: 384 });
|
|
1214
1214
|
const receipts = await syncReceipts(cwd, base, token);
|
|
1215
|
-
return { receipts, synced: true, tools: payload.tools.length, workflows: payload.workflows.length, dashboard: "https://agenttwin.si/
|
|
1215
|
+
return { receipts, synced: true, tools: payload.tools.length, workflows: payload.workflows.length, dashboard: "https://agenttwin.si/dashboard/", uploaded: "discovery, Git metadata and run evidence; no application source or credentials" };
|
|
1216
1216
|
}
|
|
1217
1217
|
|
|
1218
1218
|
// src/commands/prepare.ts
|
|
@@ -5677,7 +5677,7 @@ async function runInit(opts) {
|
|
|
5677
5677
|
await launchSession(opts.cwd);
|
|
5678
5678
|
await writeDashboard(opts.cwd, finalInventory);
|
|
5679
5679
|
}
|
|
5680
|
-
if (opts.sync) {
|
|
5680
|
+
if (opts.sync || !opts.json && process.env.AGENTTWIN_TOKEN) {
|
|
5681
5681
|
const synced = await runSync(opts.cwd);
|
|
5682
5682
|
if (!opts.json) ok(`Synced ${synced.workflows} candidates: ${synced.dashboard}`);
|
|
5683
5683
|
} else if (!opts.json) info("Send reviewed discovery to your account: npx agenttwin sync (requires AGENTTWIN_TOKEN).");
|
|
@@ -377,13 +377,6 @@ body.view-home #api-message:not(:empty){position:absolute;top:58px;right:20px;ma
|
|
|
377
377
|
.home-widgets .widget h2{font-size:12px;font-weight:500;color:#d9dce2}
|
|
378
378
|
.home-widgets .widget .w-empty{font-size:11px;line-height:1.6;color:#90949f;margin:0}
|
|
379
379
|
.home-widgets .w-head-meta{font-size:10px;color:#9398a4}
|
|
380
|
-
.home-widgets #widget-receipts{grid-column:2;grid-row:1 / span 2}
|
|
381
|
-
.home-widgets #widget-project{grid-column:1;grid-row:1}
|
|
382
|
-
.home-widgets #widget-git{grid-column:1;grid-row:2}
|
|
383
|
-
.home-widgets #widget-working{grid-column:1;grid-row:3}
|
|
384
|
-
.home-widgets #widget-services{grid-column:2;grid-row:3 / span 2}
|
|
385
|
-
.home-widgets #widget-sandbox{grid-column:1;grid-row:4}
|
|
386
|
-
.home-widgets #widget-failures{grid-column:1 / -1;grid-row:5}
|
|
387
380
|
.review-row{grid-template-columns:16px minmax(0,1fr) auto;gap:8px;padding:9px 0}
|
|
388
381
|
.review-row .ref{grid-column:2;font-size:10px}.review-row .r-time{display:none}
|
|
389
382
|
.review-row strong{font-size:12px;font-weight:450}.review-row .r-status{font-size:10px}
|
|
@@ -400,6 +393,16 @@ body.view-home #api-message:not(:empty){position:absolute;top:58px;right:20px;ma
|
|
|
400
393
|
body.view-home #api-message:not(:empty){position:relative;top:auto;right:auto;margin:8px 20px;text-align:left;max-width:none}
|
|
401
394
|
.home-hero{min-height:310px;padding:162px 20px 24px}.home-hero #home-sky{height:410px!important;background-size:auto 410px;background-position:23% top}
|
|
402
395
|
.home-overview-title{font-size:21px}.home-body{padding:0 16px 28px}.home-body .home-action{flex-direction:row;padding:12px;gap:12px}.home-action p{display:none}
|
|
403
|
-
.home-widgets{grid-template-columns:minmax(0,1fr)}.home-widgets #widget-project,.home-widgets #widget-working,.home-widgets #widget-receipts,.home-widgets #widget-git,.home-widgets #widget-services,.home-widgets #widget-sandbox
|
|
404
|
-
#assistant-dock-panel{max-height:410px}.home-assistant-bottom{bottom:auto}.home-grid-head{margin-top:0}
|
|
396
|
+
.home-widgets{grid-template-columns:minmax(0,1fr)}.home-widgets #widget-project,.home-widgets #widget-working,.home-widgets #widget-receipts,.home-widgets #widget-git,.home-widgets #widget-services,.home-widgets #widget-sandbox, #assistant-dock-panel{max-height:410px}.home-assistant-bottom{bottom:auto}.home-grid-head{margin-top:0}
|
|
405
397
|
}
|
|
398
|
+
|
|
399
|
+
/* Dotted coast fades into the workspace; voice sits inside the input pill. */
|
|
400
|
+
.home-hero #home-sky{background-image:radial-gradient(circle,#11172388 .65px,transparent .95px),url('moonlit-coast.png');background-size:3px 3px,100% auto;background-position:center top;background-repeat:repeat,no-repeat;mask-image:linear-gradient(#000 0%,#000 40%,#0009 61%,transparent 94%)}
|
|
401
|
+
.assistant-entry{display:flex;align-items:center;gap:8px;padding:5px 7px 5px 4px;border:1px solid #ffffff20;border-radius:32px;background:#1b1e25d9;backdrop-filter:blur(18px);box-shadow:0 10px 40px #080a1040}.assistant-entry #assistant-dock-toggle{flex:1;width:auto;min-width:0;padding:12px 14px;border:0;border-radius:28px;background:transparent;box-shadow:none;backdrop-filter:none}.home-assistant-bottom:has(#assistant-dock-panel:not([hidden])) .assistant-entry{display:none}.home-assistant-bottom .home-composer{border-radius:26px}.voice-button{display:grid;place-items:center;flex:none;width:36px;height:36px;min-height:36px;padding:8px;border-radius:50%;border:1px solid #ffffff14;background:#ffffff08;color:#c9d1df}.voice-button svg{width:18px;height:18px}.voice-button:hover{background:#ffffff14}.voice-button.recording{color:#ffb6b6;background:#662c3c;border-color:#b46777}.voice-button:disabled{opacity:.45}.composer-row .assistant-send-hint{flex:1;min-width:0}.composer-send{border-radius:22px}
|
|
402
|
+
@media(max-width:600px){.home-hero #home-sky{background-size:3px 3px,auto 410px;background-position:center top,23% top}.assistant-entry #assistant-dock-toggle{font-size:12px}.assistant-send-hint{font-size:10px}}
|
|
403
|
+
|
|
404
|
+
/* Each column packs its own cards; short and hidden cards reserve no rows. */
|
|
405
|
+
.home-widgets>.widget-column{display:flex;flex-direction:column;gap:10px;min-width:0}
|
|
406
|
+
.home-widgets>.widget-column:not(:has(>.widget:not([hidden]))){display:none}
|
|
407
|
+
.home-widgets:has(>.widget-column:not(:has(>.widget:not([hidden])))){grid-template-columns:minmax(0,1fr)}
|
|
408
|
+
@media(max-width:600px){.home-widgets>.widget-column{display:contents}.home-widgets #widget-project{order:0}.home-widgets #widget-receipts{order:1}.home-widgets #widget-git{order:2}.home-widgets #widget-working{order:3}.home-widgets #widget-services{order:4}.home-widgets #widget-sandbox{order:5}.home-widgets #widget-failures{order:6}}
|
|
@@ -189,3 +189,7 @@ button,.upload{background:#202329;border-color:#353944;color:var(--ink);border-r
|
|
|
189
189
|
#environment-workflows{max-height:320px;overflow:auto}.discovery-onboarding .terminal-boundary code{overflow-wrap:anywhere}
|
|
190
190
|
|
|
191
191
|
.sidebar-workflow-group{margin:4px 0 12px}.sidebar-workflow-group summary{cursor:pointer;color:var(--text-muted,#93949f);padding:8px 10px;font-size:12px;display:flex;justify-content:space-between}.sidebar-workflow-group summary span{opacity:.65}.sidebar-workflow-group .sidebar-workflow{padding-left:20px;line-height:1.5;white-space:normal;text-align:left}.sidebar-workflow-group summary:hover{color:var(--text,#eee)}
|
|
192
|
+
|
|
193
|
+
/* Actionable resource coverage and focused setup. */
|
|
194
|
+
button.resource-badge{min-height:26px;border:1px solid currentColor;cursor:pointer;text-align:left;white-space:normal}button.resource-badge:hover{filter:brightness(1.2)}button.resource-badge:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
|
|
195
|
+
.resource-setup{width:min(600px,calc(100vw - 32px));max-height:calc(100dvh - 40px);overflow:auto;margin:auto;padding:26px;color:var(--ink);background:#16181c;border:1px solid var(--line);border-radius:16px;box-shadow:0 24px 80px #0008}.resource-setup::backdrop{background:#0009;backdrop-filter:blur(5px)}.resource-setup header{display:flex;justify-content:space-between;align-items:start;margin-bottom:24px;gap:16px}.resource-setup header button{min-width:36px;font-size:20px}.resource-setup h2{font-size:24px;margin-top:4px}.resource-setup h3{font-size:15px;margin:18px 0 8px}.resource-setup p,.resource-setup li{font-size:13px;line-height:1.7;color:var(--muted)}.resource-setup ol{padding-left:20px;margin:16px 0}.resource-setup .actions{flex-wrap:wrap}.resource-setup section{border-top:1px solid var(--line);margin-top:22px;padding-top:4px}.resource-setup-workflows{display:grid;gap:8px;max-height:220px;overflow:auto;margin:12px 0 20px}.resource-setup-workflows button{display:flex;justify-content:space-between;gap:16px;text-align:left;font-size:13px}.resource-setup-workflows button span{white-space:nowrap;color:var(--muted)}#resource-task-status:empty{display:none}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"schema":"company-inventory/v1","name":"Your project","tools":[],"workflows":[]}
|
|
1
|
+
{"schema": "company-inventory/v1", "name": "Your project", "tools": [], "workflows": []}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"runs":[]}
|
|
1
|
+
{"runs": []}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
self.__BUILD_MANIFEST=function(e,r,t,_){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},__routerFilterStatic:{numItems:6,errorRate:1e-4,numBits:116,numHashes:14,bitArray:[1,1,0,0,r,r,e,e,e,e,r,e,r,r,r,e,r,r,e,e,e,e,r,r,r,e,e,r,e,r,e,r,e,e,r,e,e,e,e,e,r,e,e,e,e,r,r,r,e,r,r,e,e,r,r,r,e,e,e,e,e,e,r,e,r,r,e,e,r,e,e,e,e,r,r,e,e,r,e,r,e,e,r,r,r,r,r,e,e,e,r,e,e,r,r,r,r,e,r,r,r,e,e,e,r,e,e,e,r,e,r,e,r,r,e,r]},__routerFilterDynamic:{numItems:e,errorRate:1e-4,numBits:20,numHashes:14,bitArray:[r,r,e,e,r,r,e,e,e,e,r,r,e,e,r,e,r,e,e,r]},"/_error":["static/chunks/pages/_error-cb2a52f75f2162e2.js"],sortedPages:["/_app","/_error"]}}(1,0,1e-4,14),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
self.__SSG_MANIFEST=new Set(["\u002Fdocs\u002F[[...slug]]"]);self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()
|