@superblocksteam/cli 2.0.157-next.4 → 2.0.157-next.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/README.md +1 -1
- package/bin/dev.js +6 -0
- package/bin/run.js +6 -0
- package/dist/{acorn-WMA6L7P4.js → acorn-OZZ46WC6.js} +3 -3
- package/dist/{angular-4M32OMPP.js → angular-F3X4PU6H.js} +3 -3
- package/dist/{api-PWLWF2AO.js → api-LKM3KWDE.js} +4 -4
- package/dist/{babel-6NS2YDUA.js → babel-P2KZ44V4.js} +3 -3
- package/dist/{chunk-Z2X5CQMK.js → chunk-7FF5Q3TT.js} +3758 -157
- package/dist/chunk-7FF5Q3TT.js.map +1 -0
- package/dist/{chunk-BIOZGKJI.js → chunk-B7DU3NCK.js} +3 -3
- package/dist/{chunk-OK32IXZD.js → chunk-BOHZPNHE.js} +3 -3
- package/dist/{chunk-5FZQ7GKI.js → chunk-DXUQTJ2E.js} +3 -3
- package/dist/{chunk-HK6JH3R3.js → chunk-F5V42P6U.js} +3 -3
- package/dist/{chunk-MNVPTTZN.js → chunk-FIYNW3SU.js} +4 -4
- package/dist/{chunk-QMC3HPGT.js → chunk-FJXQDKZ2.js} +4 -4
- package/dist/{chunk-72HOGMVP.js → chunk-I4TBU2RS.js} +3 -3
- package/dist/{chunk-7G3SJRTY.js → chunk-IYSPUQ7M.js} +3 -3
- package/dist/{chunk-FLZB4YF5.js → chunk-LEBMSKJP.js} +8 -8
- package/dist/{chunk-Q6H6AYB3.js → chunk-LTWZXD76.js} +2 -2
- package/dist/{chunk-AMN5CPNU.js → chunk-NHR7FAPE.js} +3 -3
- package/dist/{chunk-3CHQLJTS.js → chunk-O4SXABRB.js} +3 -3
- package/dist/{chunk-2M6BYRVF.js → chunk-PAGW2Y3I.js} +4 -4
- package/dist/{chunk-IUATCEZY.js → chunk-Q2BWW5QV.js} +3 -3
- package/dist/{chunk-U4R6POH4.js → chunk-QVKSQHMA.js} +3 -3
- package/dist/{chunk-PSOBYRL5.js → chunk-RH52ZSDO.js} +5 -5
- package/dist/{chunk-LQB4PWSW.js → chunk-VPLRE4U5.js} +3 -3
- package/dist/{chunk-STWY7L44.js → chunk-YBAGYCX4.js} +4875 -2872
- package/dist/{chunk-STWY7L44.js.map → chunk-YBAGYCX4.js.map} +1 -1
- package/dist/{chunk-Y3RLIV4P.js → chunk-ZOQPSDKJ.js} +4 -4
- package/dist/{cli-truncate-OWUAGIPO.js → cli-truncate-JE6KXDNY.js} +5 -5
- package/dist/commands/dev-parent.js +3 -3
- package/dist/{dd-trace-EUCR6QVT.js → dd-trace-AQZGAF2E.js} +6 -6
- package/dist/{dist-2M5L5FNH.js → dist-NJHWXUHQ.js} +839 -200
- package/dist/dist-NJHWXUHQ.js.map +1 -0
- package/dist/{dist-QHYW4U6O.js → dist-ONFSHJBQ.js} +15 -15
- package/dist/{embedded-playwright-mcp-server-D4TETPXE.js → embedded-playwright-mcp-server-65RUBGLR.js} +3 -3
- package/dist/{enquirer-UD7IHY44.js → enquirer-6C55IUPI.js} +4 -4
- package/dist/{estree-JZ3UIJHT.js → estree-OUX276MJ.js} +3 -3
- package/dist/{flow-GSPIY4XU.js → flow-RNZL6EOQ.js} +3 -3
- package/dist/{getMachineId-bsd-36VZS47Z.js → getMachineId-bsd-SAYCT6BA.js} +5 -5
- package/dist/{getMachineId-darwin-7LZY45ZM.js → getMachineId-darwin-2BIZIQZ6.js} +5 -5
- package/dist/{getMachineId-linux-LX4NM644.js → getMachineId-linux-RTE4SKPS.js} +4 -4
- package/dist/{getMachineId-unsupported-7TJOPLYI.js → getMachineId-unsupported-4AJE3HZA.js} +4 -4
- package/dist/{getMachineId-win-M22WJ3MM.js → getMachineId-win-WCR2ELI3.js} +5 -5
- package/dist/{glimmer-UVO3BIBM.js → glimmer-ZSFJLGZS.js} +3 -3
- package/dist/{graphql-XLZ6JI47.js → graphql-6XBYVCIJ.js} +3 -3
- package/dist/{html-B4A6WYXT.js → html-VEAJ3MIN.js} +3 -3
- package/dist/{http-K3OYGWVL.js → http-VGB6FR7N.js} +14 -14
- package/dist/index.js +23 -23
- package/dist/{jiti-266YLMVX.js → jiti-NN2RRFEA.js} +3 -3
- package/dist/{log-update-YQK5AUYG.js → log-update-G37STD43.js} +6 -6
- package/dist/{markdown-JEOFIXUQ.js → markdown-Y4YLMHL3.js} +3 -3
- package/dist/{meriyah-QGCQSGGS.js → meriyah-4GQGGWUO.js} +3 -3
- package/dist/{postcss-KSFJ6EQS.js → postcss-ZFUKCQTL.js} +3 -3
- package/dist/{read-pkg-CZ4YTNKI.js → read-pkg-Q3NL2F2P.js} +4 -4
- package/dist/{spans-3C4P2IQ3.js → spans-XZD4N5LG.js} +4 -4
- package/dist/{src-XPHA3RUC.js → src-E7PNU35M.js} +3 -3
- package/dist/{token-BDGVUJER.js → token-MQA7XSGS.js} +5 -5
- package/dist/{token-util-5FML3764.js → token-util-VDHZFUFG.js} +5 -5
- package/dist/{typescript-22T2V3TY.js → typescript-LKK6LNWR.js} +3 -3
- package/dist/{v4-IHD3EOAU.js → v4-SQGBAYYV.js} +4 -4
- package/dist/{wrap-ansi-46TLWEUF.js → wrap-ansi-XEURB6IQ.js} +5 -5
- package/dist/{yaml-TG67GZWZ.js → yaml-GAKRLORX.js} +3 -3
- package/oclif.manifest.json +1 -1
- package/package.json +7 -7
- package/dist/chunk-Z2X5CQMK.js.map +0 -1
- package/dist/dist-2M5L5FNH.js.map +0 -1
- /package/dist/{acorn-WMA6L7P4.js.map → acorn-OZZ46WC6.js.map} +0 -0
- /package/dist/{angular-4M32OMPP.js.map → angular-F3X4PU6H.js.map} +0 -0
- /package/dist/{api-PWLWF2AO.js.map → api-LKM3KWDE.js.map} +0 -0
- /package/dist/{babel-6NS2YDUA.js.map → babel-P2KZ44V4.js.map} +0 -0
- /package/dist/{chunk-BIOZGKJI.js.map → chunk-B7DU3NCK.js.map} +0 -0
- /package/dist/{chunk-OK32IXZD.js.map → chunk-BOHZPNHE.js.map} +0 -0
- /package/dist/{chunk-5FZQ7GKI.js.map → chunk-DXUQTJ2E.js.map} +0 -0
- /package/dist/{chunk-HK6JH3R3.js.map → chunk-F5V42P6U.js.map} +0 -0
- /package/dist/{chunk-MNVPTTZN.js.map → chunk-FIYNW3SU.js.map} +0 -0
- /package/dist/{chunk-QMC3HPGT.js.map → chunk-FJXQDKZ2.js.map} +0 -0
- /package/dist/{chunk-72HOGMVP.js.map → chunk-I4TBU2RS.js.map} +0 -0
- /package/dist/{chunk-7G3SJRTY.js.map → chunk-IYSPUQ7M.js.map} +0 -0
- /package/dist/{chunk-FLZB4YF5.js.map → chunk-LEBMSKJP.js.map} +0 -0
- /package/dist/{chunk-Q6H6AYB3.js.map → chunk-LTWZXD76.js.map} +0 -0
- /package/dist/{chunk-AMN5CPNU.js.map → chunk-NHR7FAPE.js.map} +0 -0
- /package/dist/{chunk-3CHQLJTS.js.map → chunk-O4SXABRB.js.map} +0 -0
- /package/dist/{chunk-2M6BYRVF.js.map → chunk-PAGW2Y3I.js.map} +0 -0
- /package/dist/{chunk-IUATCEZY.js.map → chunk-Q2BWW5QV.js.map} +0 -0
- /package/dist/{chunk-U4R6POH4.js.map → chunk-QVKSQHMA.js.map} +0 -0
- /package/dist/{chunk-PSOBYRL5.js.map → chunk-RH52ZSDO.js.map} +0 -0
- /package/dist/{chunk-LQB4PWSW.js.map → chunk-VPLRE4U5.js.map} +0 -0
- /package/dist/{chunk-Y3RLIV4P.js.map → chunk-ZOQPSDKJ.js.map} +0 -0
- /package/dist/{cli-truncate-OWUAGIPO.js.map → cli-truncate-JE6KXDNY.js.map} +0 -0
- /package/dist/{dd-trace-EUCR6QVT.js.map → dd-trace-AQZGAF2E.js.map} +0 -0
- /package/dist/{dist-QHYW4U6O.js.map → dist-ONFSHJBQ.js.map} +0 -0
- /package/dist/{embedded-playwright-mcp-server-D4TETPXE.js.map → embedded-playwright-mcp-server-65RUBGLR.js.map} +0 -0
- /package/dist/{enquirer-UD7IHY44.js.map → enquirer-6C55IUPI.js.map} +0 -0
- /package/dist/{estree-JZ3UIJHT.js.map → estree-OUX276MJ.js.map} +0 -0
- /package/dist/{flow-GSPIY4XU.js.map → flow-RNZL6EOQ.js.map} +0 -0
- /package/dist/{getMachineId-bsd-36VZS47Z.js.map → getMachineId-bsd-SAYCT6BA.js.map} +0 -0
- /package/dist/{getMachineId-darwin-7LZY45ZM.js.map → getMachineId-darwin-2BIZIQZ6.js.map} +0 -0
- /package/dist/{getMachineId-linux-LX4NM644.js.map → getMachineId-linux-RTE4SKPS.js.map} +0 -0
- /package/dist/{getMachineId-unsupported-7TJOPLYI.js.map → getMachineId-unsupported-4AJE3HZA.js.map} +0 -0
- /package/dist/{getMachineId-win-M22WJ3MM.js.map → getMachineId-win-WCR2ELI3.js.map} +0 -0
- /package/dist/{glimmer-UVO3BIBM.js.map → glimmer-ZSFJLGZS.js.map} +0 -0
- /package/dist/{graphql-XLZ6JI47.js.map → graphql-6XBYVCIJ.js.map} +0 -0
- /package/dist/{html-B4A6WYXT.js.map → html-VEAJ3MIN.js.map} +0 -0
- /package/dist/{http-K3OYGWVL.js.map → http-VGB6FR7N.js.map} +0 -0
- /package/dist/{jiti-266YLMVX.js.map → jiti-NN2RRFEA.js.map} +0 -0
- /package/dist/{log-update-YQK5AUYG.js.map → log-update-G37STD43.js.map} +0 -0
- /package/dist/{markdown-JEOFIXUQ.js.map → markdown-Y4YLMHL3.js.map} +0 -0
- /package/dist/{meriyah-QGCQSGGS.js.map → meriyah-4GQGGWUO.js.map} +0 -0
- /package/dist/{postcss-KSFJ6EQS.js.map → postcss-ZFUKCQTL.js.map} +0 -0
- /package/dist/{read-pkg-CZ4YTNKI.js.map → read-pkg-Q3NL2F2P.js.map} +0 -0
- /package/dist/{spans-3C4P2IQ3.js.map → spans-XZD4N5LG.js.map} +0 -0
- /package/dist/{src-XPHA3RUC.js.map → src-E7PNU35M.js.map} +0 -0
- /package/dist/{token-BDGVUJER.js.map → token-MQA7XSGS.js.map} +0 -0
- /package/dist/{token-util-5FML3764.js.map → token-util-VDHZFUFG.js.map} +0 -0
- /package/dist/{typescript-22T2V3TY.js.map → typescript-LKK6LNWR.js.map} +0 -0
- /package/dist/{v4-IHD3EOAU.js.map → v4-SQGBAYYV.js.map} +0 -0
- /package/dist/{wrap-ansi-46TLWEUF.js.map → wrap-ansi-XEURB6IQ.js.map} +0 -0
- /package/dist/{yaml-TG67GZWZ.js.map → yaml-GAKRLORX.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
if (typeof process === 'object' && process !== null &&
|
|
2
2
|
process.env !== null && typeof process.env === 'object') {
|
|
3
3
|
process.env.DD_GIT_REPOSITORY_URL = 'https://token@github.com/superblocksteam/superblocks.git';
|
|
4
|
-
process.env.DD_GIT_COMMIT_SHA = '
|
|
4
|
+
process.env.DD_GIT_COMMIT_SHA = '35eb352f57c1fbed7b4c3e71ec22cd31d0c49921';
|
|
5
5
|
}
|
|
6
6
|
import { createRequire as $dd_createRequire } from 'module';
|
|
7
7
|
import { fileURLToPath as $dd_fileURLToPath } from 'url';
|
|
@@ -13,7 +13,7 @@ globalThis.__dirname ??= $dd_dirname(globalThis.__filename);
|
|
|
13
13
|
import {
|
|
14
14
|
McpServer,
|
|
15
15
|
StdioServerTransport
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-LEBMSKJP.js";
|
|
17
17
|
import {
|
|
18
18
|
CallToolResultSchema,
|
|
19
19
|
ContentBlockSchema,
|
|
@@ -27,30 +27,37 @@ import {
|
|
|
27
27
|
executeToolCall,
|
|
28
28
|
runWithAuthContext,
|
|
29
29
|
toolDefinitions
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-7FF5Q3TT.js";
|
|
31
31
|
import {
|
|
32
32
|
external_exports
|
|
33
|
-
} from "./chunk-
|
|
34
|
-
import "./chunk-
|
|
33
|
+
} from "./chunk-F5V42P6U.js";
|
|
34
|
+
import "./chunk-PAGW2Y3I.js";
|
|
35
35
|
import {
|
|
36
|
+
getDefaultPolicy,
|
|
37
|
+
import_shared,
|
|
36
38
|
import_websocket,
|
|
39
|
+
initNodeTelemetry,
|
|
40
|
+
parseDeploymentType,
|
|
37
41
|
require_dist
|
|
38
|
-
} from "./chunk-
|
|
39
|
-
import "./chunk-
|
|
40
|
-
import "./chunk-
|
|
41
|
-
import "./chunk-
|
|
42
|
-
import "./chunk-
|
|
43
|
-
import "./chunk-
|
|
44
|
-
import "./chunk-
|
|
42
|
+
} from "./chunk-YBAGYCX4.js";
|
|
43
|
+
import "./chunk-QVKSQHMA.js";
|
|
44
|
+
import "./chunk-I4TBU2RS.js";
|
|
45
|
+
import "./chunk-RH52ZSDO.js";
|
|
46
|
+
import "./chunk-VPLRE4U5.js";
|
|
47
|
+
import "./chunk-O4SXABRB.js";
|
|
48
|
+
import "./chunk-BOHZPNHE.js";
|
|
45
49
|
import {
|
|
50
|
+
SpanStatusCode,
|
|
51
|
+
context,
|
|
46
52
|
init_esm,
|
|
47
|
-
metrics
|
|
48
|
-
|
|
53
|
+
metrics,
|
|
54
|
+
trace
|
|
55
|
+
} from "./chunk-NHR7FAPE.js";
|
|
49
56
|
import {
|
|
50
57
|
__require,
|
|
51
58
|
__toESM,
|
|
52
59
|
init_cjs_shims
|
|
53
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-LTWZXD76.js";
|
|
54
61
|
|
|
55
62
|
// ../../../gateway/dist/index.js
|
|
56
63
|
init_cjs_shims();
|
|
@@ -232,7 +239,7 @@ function formatCaptureModeSummary(input) {
|
|
|
232
239
|
|
|
233
240
|
// ../../../gateway/dist/capabilities/lifecycle.js
|
|
234
241
|
init_cjs_shims();
|
|
235
|
-
var
|
|
242
|
+
var import_shared3 = __toESM(require_dist());
|
|
236
243
|
import { randomUUID } from "node:crypto";
|
|
237
244
|
import { readFile, realpath, stat } from "node:fs/promises";
|
|
238
245
|
import path2 from "node:path";
|
|
@@ -437,7 +444,7 @@ function buildOpenablePreviewUrls(input) {
|
|
|
437
444
|
|
|
438
445
|
// ../../../gateway/dist/server/client.js
|
|
439
446
|
init_cjs_shims();
|
|
440
|
-
var
|
|
447
|
+
var import_shared2 = __toESM(require_dist());
|
|
441
448
|
|
|
442
449
|
// ../../../gateway/dist/telemetry/metrics.js
|
|
443
450
|
init_cjs_shims();
|
|
@@ -841,7 +848,7 @@ var HttpSuperblocksServerClient = class {
|
|
|
841
848
|
}
|
|
842
849
|
async uploadAttachment(input) {
|
|
843
850
|
const mimeType = input.mimeType ?? "application/zip";
|
|
844
|
-
const response = await (0,
|
|
851
|
+
const response = await (0, import_shared2.uploadAttachmentToServerApi)({
|
|
845
852
|
applicationId: input.applicationId,
|
|
846
853
|
authorization: `Bearer ${input.apiKey}`,
|
|
847
854
|
baseUrl: this.baseUrl(),
|
|
@@ -888,10 +895,18 @@ var HttpSuperblocksServerClient = class {
|
|
|
888
895
|
*/
|
|
889
896
|
async issueScopedToken(input) {
|
|
890
897
|
const scope = input.scope ?? "apps:update";
|
|
891
|
-
const body = {
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
898
|
+
const body = { scope };
|
|
899
|
+
if (scope === "integrations:build") {
|
|
900
|
+
if (!input.integrationId?.trim()) {
|
|
901
|
+
throw new Error("integrations:build scoped tokens require an integrationId; the token authorizes exactly one integration");
|
|
902
|
+
}
|
|
903
|
+
body.integrationId = input.integrationId;
|
|
904
|
+
} else {
|
|
905
|
+
if (!input.applicationId?.trim()) {
|
|
906
|
+
throw new Error(`${scope} scoped tokens require an applicationId`);
|
|
907
|
+
}
|
|
908
|
+
body.applicationId = input.applicationId;
|
|
909
|
+
}
|
|
895
910
|
if (scope === "apps:preview") {
|
|
896
911
|
if (!input.commitId?.trim()) {
|
|
897
912
|
throw new Error("apps:preview scoped tokens require a commitId so the viewer can load that commit");
|
|
@@ -1831,37 +1846,37 @@ async function captureModeOf(ctx) {
|
|
|
1831
1846
|
});
|
|
1832
1847
|
}
|
|
1833
1848
|
function libraryCaptureInput(ctx, applicationId) {
|
|
1834
|
-
const
|
|
1835
|
-
if (!
|
|
1849
|
+
const context2 = ctx.sessionPeer.libraryBrowserContext?.(applicationId);
|
|
1850
|
+
if (!context2) {
|
|
1836
1851
|
return void 0;
|
|
1837
1852
|
}
|
|
1838
|
-
const auth =
|
|
1853
|
+
const auth = context2.initData.devServerAuthorization;
|
|
1839
1854
|
if (!auth) {
|
|
1840
1855
|
console.error("gateway live canvas skipped: missing_dev_server_authorization", { applicationId });
|
|
1841
1856
|
return void 0;
|
|
1842
1857
|
}
|
|
1843
1858
|
return {
|
|
1844
1859
|
bootstrapData: {
|
|
1845
|
-
accessToken:
|
|
1846
|
-
agents:
|
|
1847
|
-
...
|
|
1848
|
-
appId:
|
|
1860
|
+
accessToken: context2.bootstrapData.accessToken,
|
|
1861
|
+
agents: context2.bootstrapData.agents ?? [],
|
|
1862
|
+
...context2.bootstrapData.agentUrls ? { agentUrls: context2.bootstrapData.agentUrls } : {},
|
|
1863
|
+
appId: context2.bootstrapData.appId,
|
|
1849
1864
|
devServerAuthorization: auth,
|
|
1850
|
-
...
|
|
1851
|
-
...
|
|
1852
|
-
...
|
|
1853
|
-
token:
|
|
1854
|
-
...
|
|
1855
|
-
userId:
|
|
1856
|
-
...
|
|
1865
|
+
...context2.bootstrapData.featureFlags ? { featureFlags: context2.bootstrapData.featureFlags } : {},
|
|
1866
|
+
...context2.bootstrapData.orgId ? { orgId: context2.bootstrapData.orgId } : {},
|
|
1867
|
+
...context2.bootstrapData.profiles ? { profiles: context2.bootstrapData.profiles } : {},
|
|
1868
|
+
token: context2.bootstrapData.token,
|
|
1869
|
+
...context2.bootstrapData.userEmail ? { userEmail: context2.bootstrapData.userEmail } : {},
|
|
1870
|
+
userId: context2.bootstrapData.userId,
|
|
1871
|
+
...context2.bootstrapData.windowOriginUrl ? { windowOriginUrl: context2.bootstrapData.windowOriginUrl } : {}
|
|
1857
1872
|
},
|
|
1858
|
-
iframeBaseUrl:
|
|
1873
|
+
iframeBaseUrl: context2.iframeBaseUrl,
|
|
1859
1874
|
initData: {
|
|
1860
|
-
appId:
|
|
1875
|
+
appId: context2.initData.appId,
|
|
1861
1876
|
devServerAuthorization: auth,
|
|
1862
|
-
peerId:
|
|
1863
|
-
...
|
|
1864
|
-
...
|
|
1877
|
+
peerId: context2.initData.peerId,
|
|
1878
|
+
...context2.initData.userId ? { userId: context2.initData.userId } : {},
|
|
1879
|
+
...context2.initData.windowOriginUrl ? { windowOriginUrl: context2.initData.windowOriginUrl } : {}
|
|
1865
1880
|
}
|
|
1866
1881
|
};
|
|
1867
1882
|
}
|
|
@@ -1985,13 +2000,15 @@ function defaultAppName(prompt) {
|
|
|
1985
2000
|
async function ensurePrincipal(ctx) {
|
|
1986
2001
|
const { principal } = ctx;
|
|
1987
2002
|
if (principal.organizationId && principal.userId) {
|
|
2003
|
+
const resolved2 = {
|
|
2004
|
+
...principal,
|
|
2005
|
+
organizationId: principal.organizationId,
|
|
2006
|
+
userId: principal.userId
|
|
2007
|
+
};
|
|
2008
|
+
ctx.onPrincipalResolved?.(resolved2);
|
|
1988
2009
|
return {
|
|
1989
2010
|
kind: "ok",
|
|
1990
|
-
value:
|
|
1991
|
-
...principal,
|
|
1992
|
-
organizationId: principal.organizationId,
|
|
1993
|
-
userId: principal.userId
|
|
1994
|
-
}
|
|
2011
|
+
value: resolved2
|
|
1995
2012
|
};
|
|
1996
2013
|
}
|
|
1997
2014
|
let validated;
|
|
@@ -2021,14 +2038,16 @@ async function ensurePrincipal(ctx) {
|
|
|
2021
2038
|
message: "The Superblocks API rejected the credential issued for this caller."
|
|
2022
2039
|
};
|
|
2023
2040
|
}
|
|
2041
|
+
const resolved = {
|
|
2042
|
+
...principal,
|
|
2043
|
+
email: validated.email,
|
|
2044
|
+
organizationId: validated.organizationId,
|
|
2045
|
+
userId: validated.userId
|
|
2046
|
+
};
|
|
2047
|
+
ctx.onPrincipalResolved?.(resolved);
|
|
2024
2048
|
return {
|
|
2025
2049
|
kind: "ok",
|
|
2026
|
-
value:
|
|
2027
|
-
...principal,
|
|
2028
|
-
email: validated.email,
|
|
2029
|
-
organizationId: validated.organizationId,
|
|
2030
|
-
userId: validated.userId
|
|
2031
|
-
}
|
|
2050
|
+
value: resolved
|
|
2032
2051
|
};
|
|
2033
2052
|
}
|
|
2034
2053
|
async function nameWithClark(ctx, input) {
|
|
@@ -2221,7 +2240,7 @@ function turnSummary(turn) {
|
|
|
2221
2240
|
return "Superblocks is still working, but only the editor can show it \u2014 open the edit URL";
|
|
2222
2241
|
}
|
|
2223
2242
|
if (turn.generationStatus === "live_edit_terminated") {
|
|
2224
|
-
return "The Superblocks live-edit session terminated before anything was built \u2014 send the prompt again with edit_app";
|
|
2243
|
+
return turn.retryAction === "retry_import" ? "The Superblocks live-edit session terminated before anything was built \u2014 send the archive again with import_app" : "The Superblocks live-edit session terminated before anything was built \u2014 send the prompt again with edit_app";
|
|
2225
2244
|
}
|
|
2226
2245
|
if (turn.checkpointCommitId) {
|
|
2227
2246
|
return `Application ready \u2014 checkpoint saved. ${NEXT_STEPS}`;
|
|
@@ -2347,6 +2366,7 @@ async function forwardClarkPrompt(ctx, input) {
|
|
|
2347
2366
|
generationStatus: forward.generationStatus,
|
|
2348
2367
|
...forward.liveEditId ? { liveEditId: forward.liveEditId } : {},
|
|
2349
2368
|
...forward.recentRuns && forward.recentRuns.length > 0 ? { recentRuns: forward.recentRuns } : {},
|
|
2369
|
+
...forward.retryAction ? { retryAction: forward.retryAction } : {},
|
|
2350
2370
|
viewStatus: forward.viewStatus
|
|
2351
2371
|
}
|
|
2352
2372
|
};
|
|
@@ -2392,7 +2412,7 @@ function namingCreatedApplication(applicationId, capability, result) {
|
|
|
2392
2412
|
return namingApplication(applicationId, result);
|
|
2393
2413
|
}
|
|
2394
2414
|
function retryIfReplayable(attachments) {
|
|
2395
|
-
return attachments && attachments.length > 0 ?
|
|
2415
|
+
return attachments && attachments.length > 0 ? { pendingAction: "retry_import" } : { pendingAction: "retry_build" };
|
|
2396
2416
|
}
|
|
2397
2417
|
function liveEditUnavailable(error, attachments) {
|
|
2398
2418
|
return {
|
|
@@ -2413,7 +2433,8 @@ function rememberFailedStart(ctx, input) {
|
|
|
2413
2433
|
organizationId: input.principal.organizationId,
|
|
2414
2434
|
// Reaches the caller as the dead start's reply on its next poll, so it
|
|
2415
2435
|
// has to stand on its own there rather than lean on this call's error.
|
|
2416
|
-
reason: `The Superblocks live-edit session for application ${input.applicationId} never opened, so the prompt never reached Superblocks and nothing was built. Nothing is running for that application; send the same instruction again to retry it. (${cause})`,
|
|
2436
|
+
reason: input.reason ?? `The Superblocks live-edit session for application ${input.applicationId} never opened, so the prompt never reached Superblocks and nothing was built. Nothing is running for that application; send the same instruction again to retry it. (${cause})`,
|
|
2437
|
+
...input.retryAction ? { retryAction: input.retryAction } : {},
|
|
2417
2438
|
userId: input.principal.userId
|
|
2418
2439
|
});
|
|
2419
2440
|
} catch (error) {
|
|
@@ -2443,7 +2464,12 @@ async function promptNewApplication(ctx, args) {
|
|
|
2443
2464
|
organizationId: principal.organizationId
|
|
2444
2465
|
});
|
|
2445
2466
|
} catch (error) {
|
|
2446
|
-
rememberFailedStart(ctx, {
|
|
2467
|
+
rememberFailedStart(ctx, {
|
|
2468
|
+
applicationId,
|
|
2469
|
+
error,
|
|
2470
|
+
principal,
|
|
2471
|
+
...args.attachments?.length ? { retryAction: "retry_import" } : {}
|
|
2472
|
+
});
|
|
2447
2473
|
return liveEditUnavailable(error, args.attachments);
|
|
2448
2474
|
}
|
|
2449
2475
|
ctx.onProgress?.({
|
|
@@ -2638,7 +2664,7 @@ async function resolveImportArchive(input, searchDirs) {
|
|
|
2638
2664
|
if (bytes.byteLength > IMPORT_ZIP_MAX_BYTES) {
|
|
2639
2665
|
return tooLargeError(bytes.byteLength);
|
|
2640
2666
|
}
|
|
2641
|
-
const archiveType = (0,
|
|
2667
|
+
const archiveType = (0, import_shared3.detectAttachmentArchiveType)({ fileName });
|
|
2642
2668
|
if (archiveType === null) {
|
|
2643
2669
|
return {
|
|
2644
2670
|
kind: "error",
|
|
@@ -2680,14 +2706,15 @@ function normalizeImportSource(source) {
|
|
|
2680
2706
|
}
|
|
2681
2707
|
}
|
|
2682
2708
|
async function importApp(ctx, input) {
|
|
2709
|
+
const resumedApplicationId = input.applicationId?.trim();
|
|
2683
2710
|
const archiveResult = await resolveImportArchive(input, ctx.config.importSearchDirs);
|
|
2684
2711
|
if (archiveResult.kind !== "ok") {
|
|
2685
|
-
return archiveResult;
|
|
2712
|
+
return resumedApplicationId ? namingApplication(resumedApplicationId, archiveResult) : archiveResult;
|
|
2686
2713
|
}
|
|
2687
2714
|
const archive = archiveResult.value;
|
|
2688
2715
|
const principalResult = await ensurePrincipal(ctx);
|
|
2689
2716
|
if (principalResult.kind !== "ok") {
|
|
2690
|
-
return principalResult;
|
|
2717
|
+
return resumedApplicationId ? namingApplication(resumedApplicationId, principalResult) : principalResult;
|
|
2691
2718
|
}
|
|
2692
2719
|
const principal = principalResult.value;
|
|
2693
2720
|
const source = normalizeImportSource(input.source);
|
|
@@ -2698,23 +2725,26 @@ async function importApp(ctx, input) {
|
|
|
2698
2725
|
});
|
|
2699
2726
|
const explicitName = input.name?.trim();
|
|
2700
2727
|
const name = explicitName || defaultAppName(migrationPrompt);
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2728
|
+
let applicationId = resumedApplicationId;
|
|
2729
|
+
if (!applicationId) {
|
|
2730
|
+
ctx.onProgress?.({
|
|
2731
|
+
message: "Creating application for import",
|
|
2732
|
+
type: "progress"
|
|
2733
|
+
});
|
|
2734
|
+
const created = await createApplicationForPrompt(ctx, {
|
|
2735
|
+
apiKey: principal.apiKey,
|
|
2736
|
+
name,
|
|
2737
|
+
organizationId: principal.organizationId,
|
|
2738
|
+
templateName: "app-fullstack"
|
|
2739
|
+
});
|
|
2740
|
+
if (created.kind !== "ok") {
|
|
2741
|
+
return created;
|
|
2742
|
+
}
|
|
2743
|
+
applicationId = created.value.id;
|
|
2713
2744
|
}
|
|
2714
|
-
|
|
2715
|
-
await
|
|
2716
|
-
|
|
2717
|
-
applicationId: app.id,
|
|
2745
|
+
await rememberApplication(ctx, principal, applicationId);
|
|
2746
|
+
const result = await migrateArchiveIntoApplication(ctx, {
|
|
2747
|
+
applicationId,
|
|
2718
2748
|
archive,
|
|
2719
2749
|
explicitName,
|
|
2720
2750
|
input,
|
|
@@ -2722,7 +2752,8 @@ async function importApp(ctx, input) {
|
|
|
2722
2752
|
name,
|
|
2723
2753
|
principal,
|
|
2724
2754
|
source
|
|
2725
|
-
})
|
|
2755
|
+
});
|
|
2756
|
+
return resumedApplicationId ? namingApplication(applicationId, result) : namingCreatedApplication(applicationId, "import_app", result);
|
|
2726
2757
|
}
|
|
2727
2758
|
async function migrateArchiveIntoApplication(ctx, args) {
|
|
2728
2759
|
const { applicationId, archive, principal } = args;
|
|
@@ -2741,10 +2772,18 @@ async function migrateArchiveIntoApplication(ctx, args) {
|
|
|
2741
2772
|
});
|
|
2742
2773
|
} catch (error) {
|
|
2743
2774
|
const message = error instanceof Error ? error.message : String(error);
|
|
2775
|
+
rememberFailedStart(ctx, {
|
|
2776
|
+
applicationId,
|
|
2777
|
+
error,
|
|
2778
|
+
principal,
|
|
2779
|
+
reason: `The archive for application ${applicationId} could not be uploaded, so the migration never started and nothing was built. Send the same archive again with import_app to retry it. (${message})`,
|
|
2780
|
+
retryAction: "retry_import"
|
|
2781
|
+
});
|
|
2744
2782
|
return {
|
|
2745
2783
|
kind: "error",
|
|
2746
2784
|
code: "import_upload_failed",
|
|
2747
|
-
message
|
|
2785
|
+
message,
|
|
2786
|
+
pendingAction: "retry_import"
|
|
2748
2787
|
};
|
|
2749
2788
|
}
|
|
2750
2789
|
return promptNewApplication(ctx, {
|
|
@@ -2829,7 +2868,7 @@ async function checkAppProgress(ctx, input) {
|
|
|
2829
2868
|
}
|
|
2830
2869
|
const applicationId = resolved.value;
|
|
2831
2870
|
if (ctx.signal?.aborted) {
|
|
2832
|
-
return cancelled("check_app_progress");
|
|
2871
|
+
return namingApplication(applicationId, cancelled("check_app_progress"));
|
|
2833
2872
|
}
|
|
2834
2873
|
const cursorKey2 = cursorKeyFor(ctx, principal, applicationId);
|
|
2835
2874
|
const stored = cursorKey2 ? await ctx.progressCursors?.getCursor(cursorKey2) : void 0;
|
|
@@ -2841,7 +2880,7 @@ async function checkAppProgress(ctx, input) {
|
|
|
2841
2880
|
waitMs: hostCallBudgetMs(ctx, ctx.config.clarkProgressWaitMs)
|
|
2842
2881
|
});
|
|
2843
2882
|
if (ctx.signal?.aborted) {
|
|
2844
|
-
return cancelled("check_app_progress");
|
|
2883
|
+
return namingApplication(applicationId, cancelled("check_app_progress"));
|
|
2845
2884
|
}
|
|
2846
2885
|
const snapshot = await readSnapshot(ctx, {
|
|
2847
2886
|
applicationId,
|
|
@@ -2915,6 +2954,7 @@ async function checkAppProgress(ctx, input) {
|
|
|
2915
2954
|
reply: update.reply,
|
|
2916
2955
|
...update.decision ? { decision: update.decision } : {},
|
|
2917
2956
|
generationStatus: update.generationStatus,
|
|
2957
|
+
...update.retryAction && emptyTurnStatus(update.generationStatus) ? { pendingAction: update.retryAction } : {},
|
|
2918
2958
|
status,
|
|
2919
2959
|
viewStatus: update.viewStatus
|
|
2920
2960
|
}
|
|
@@ -3336,7 +3376,11 @@ function localUnbuiltReason(turn, pending) {
|
|
|
3336
3376
|
return void 0;
|
|
3337
3377
|
}
|
|
3338
3378
|
const status = emptyTurnStatus(turn.generationStatus);
|
|
3339
|
-
return status ? {
|
|
3379
|
+
return status ? {
|
|
3380
|
+
kind: "empty_turn",
|
|
3381
|
+
retryAction: turn.retryAction ?? "retry_build",
|
|
3382
|
+
status
|
|
3383
|
+
} : void 0;
|
|
3340
3384
|
}
|
|
3341
3385
|
async function persistedUnbuiltReason(ctx, principal, applicationId) {
|
|
3342
3386
|
let snapshot;
|
|
@@ -3379,6 +3423,8 @@ function persistedTurnEnd(status) {
|
|
|
3379
3423
|
// plain question and cannot be approved.
|
|
3380
3424
|
case "needs_decision":
|
|
3381
3425
|
return { kind: "awaiting_decision" };
|
|
3426
|
+
// The stream never recorded whether the prompt carried an archive, so
|
|
3427
|
+
// this path cannot pick retry_build vs retry_import. Omit rather than guess.
|
|
3382
3428
|
case "live_edit_terminated":
|
|
3383
3429
|
return { kind: "empty_turn", status };
|
|
3384
3430
|
// A `cancelled` in the tail may still have a real app behind it: the
|
|
@@ -3437,7 +3483,11 @@ async function unbuiltApp(ctx, principal, applicationId) {
|
|
|
3437
3483
|
if (reason.kind === "empty_turn") {
|
|
3438
3484
|
return {
|
|
3439
3485
|
kind: "ok",
|
|
3440
|
-
value: {
|
|
3486
|
+
value: {
|
|
3487
|
+
...app,
|
|
3488
|
+
...reason.retryAction ? { pendingAction: reason.retryAction } : {},
|
|
3489
|
+
status: reason.status
|
|
3490
|
+
}
|
|
3441
3491
|
};
|
|
3442
3492
|
}
|
|
3443
3493
|
return {
|
|
@@ -3539,7 +3589,7 @@ async function waitForBuild(ctx, input) {
|
|
|
3539
3589
|
let started = false;
|
|
3540
3590
|
for (; ; ) {
|
|
3541
3591
|
if (ctx.signal?.aborted) {
|
|
3542
|
-
return cancelled("get_app");
|
|
3592
|
+
return namingApplication(input.applicationId, cancelled("get_app"));
|
|
3543
3593
|
}
|
|
3544
3594
|
if (nowMs(ctx) >= deadline) {
|
|
3545
3595
|
return { kind: "ok", value: { built: false } };
|
|
@@ -4193,7 +4243,7 @@ async function createStores() {
|
|
|
4193
4243
|
// ../../../gateway/dist/sabs/websocket-session-peer.js
|
|
4194
4244
|
init_cjs_shims();
|
|
4195
4245
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
4196
|
-
var
|
|
4246
|
+
var import_shared6 = __toESM(require_dist());
|
|
4197
4247
|
|
|
4198
4248
|
// ../../../gateway/dist/agents/resolve-orchestrator-url.js
|
|
4199
4249
|
init_cjs_shims();
|
|
@@ -4514,15 +4564,15 @@ var HttpOrchestratorClient = class {
|
|
|
4514
4564
|
|
|
4515
4565
|
// ../../../gateway/dist/sabs/browser-context.js
|
|
4516
4566
|
init_cjs_shims();
|
|
4517
|
-
var
|
|
4567
|
+
var import_shared4 = __toESM(require_dist());
|
|
4518
4568
|
function toProfile(row) {
|
|
4519
|
-
return new
|
|
4569
|
+
return new import_shared4.Profile({
|
|
4520
4570
|
allowedInEditor: row.allowedInEditor,
|
|
4521
4571
|
description: "",
|
|
4522
4572
|
displayName: row.displayName ?? row.key,
|
|
4523
4573
|
id: row.id ?? row.key,
|
|
4524
4574
|
key: row.key,
|
|
4525
|
-
type:
|
|
4575
|
+
type: import_shared4.ProfileType.RESERVED
|
|
4526
4576
|
});
|
|
4527
4577
|
}
|
|
4528
4578
|
function selectProfiles(input) {
|
|
@@ -4586,7 +4636,7 @@ function buildBrowserContext(input) {
|
|
|
4586
4636
|
|
|
4587
4637
|
// ../../../gateway/dist/sabs/editor-client-methods.js
|
|
4588
4638
|
init_cjs_shims();
|
|
4589
|
-
var
|
|
4639
|
+
var import_shared5 = __toESM(require_dist());
|
|
4590
4640
|
|
|
4591
4641
|
// ../../../gateway/dist/integrations/map.js
|
|
4592
4642
|
init_cjs_shims();
|
|
@@ -4741,7 +4791,7 @@ function sanitizeAgentFacingValue(value) {
|
|
|
4741
4791
|
}
|
|
4742
4792
|
|
|
4743
4793
|
// ../../../gateway/dist/sabs/editor-client-methods.js
|
|
4744
|
-
var ADMIN_MCP_SETUP_MESSAGE = "Integrations CRUD is available on this Superblocks MCP via create_integration, update_integration, and list_integrations (same connector as start_app). Use those Admin tools, then continue with edit_app. The headless editor session cannot open the Integrations UI.";
|
|
4794
|
+
var ADMIN_MCP_SETUP_MESSAGE = "Integrations CRUD is available on this Superblocks MCP via get_integration_config_schema, create_integration, update_integration, and list_integrations (same connector as start_app). Call get_integration_config_schema before create_integration. Use those Admin tools, then continue with edit_app. The headless editor session cannot open the Integrations UI.";
|
|
4745
4795
|
var HEADLESS_AUTO_APPROVED_TOOLS = /* @__PURE__ */ new Set([
|
|
4746
4796
|
"build_deleteFile",
|
|
4747
4797
|
"build_installPackages",
|
|
@@ -4827,27 +4877,27 @@ function clarifySdkExecutionErrorMessage(message) {
|
|
|
4827
4877
|
}
|
|
4828
4878
|
return sanitizeAgentFacingText(clarified);
|
|
4829
4879
|
}
|
|
4830
|
-
async function executeRequestToIntegrationViaOrchestrator(
|
|
4880
|
+
async function executeRequestToIntegrationViaOrchestrator(context2, payload) {
|
|
4831
4881
|
let pluginId = payload.integrationHint?.type;
|
|
4832
4882
|
let integrationName = payload.integrationHint?.displayName ?? payload.integrationHint?.name ?? "Integration";
|
|
4833
4883
|
if (!pluginId) {
|
|
4834
4884
|
let row;
|
|
4835
4885
|
try {
|
|
4836
|
-
row = await
|
|
4837
|
-
apiKey:
|
|
4886
|
+
row = await context2.server.getIntegration({
|
|
4887
|
+
apiKey: context2.apiKey,
|
|
4838
4888
|
integrationId: payload.integrationId
|
|
4839
4889
|
});
|
|
4840
4890
|
if (!row) {
|
|
4841
|
-
const rows = await
|
|
4842
|
-
apiKey:
|
|
4843
|
-
applicationId:
|
|
4844
|
-
organizationId:
|
|
4891
|
+
const rows = await context2.server.getSupersetIntegrations({
|
|
4892
|
+
apiKey: context2.apiKey,
|
|
4893
|
+
applicationId: context2.applicationId,
|
|
4894
|
+
organizationId: context2.organizationId
|
|
4845
4895
|
});
|
|
4846
4896
|
row = rows.find((candidate) => candidate.id === payload.integrationId);
|
|
4847
4897
|
}
|
|
4848
4898
|
} catch (error) {
|
|
4849
4899
|
console.warn("gateway failed to resolve integration for execute", {
|
|
4850
|
-
applicationId:
|
|
4900
|
+
applicationId: context2.applicationId,
|
|
4851
4901
|
integrationId: payload.integrationId,
|
|
4852
4902
|
message: error instanceof Error ? error.message : String(error)
|
|
4853
4903
|
});
|
|
@@ -4860,7 +4910,7 @@ async function executeRequestToIntegrationViaOrchestrator(context, payload) {
|
|
|
4860
4910
|
pluginId = row.pluginId;
|
|
4861
4911
|
integrationName = row.name || integrationName;
|
|
4862
4912
|
}
|
|
4863
|
-
const pluginIdForStep = (0,
|
|
4913
|
+
const pluginIdForStep = (0, import_shared5.getBasePluginId)(pluginId);
|
|
4864
4914
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4865
4915
|
const inlineApiId = `ai-inline-${payload.integrationId}-${Date.now()}`;
|
|
4866
4916
|
const definition = {
|
|
@@ -4876,14 +4926,14 @@ async function executeRequestToIntegrationViaOrchestrator(context, payload) {
|
|
|
4876
4926
|
metadata: {
|
|
4877
4927
|
id: inlineApiId,
|
|
4878
4928
|
name: `${integrationName} AI Query`,
|
|
4879
|
-
organization:
|
|
4929
|
+
organization: context2.organizationId,
|
|
4880
4930
|
timestamps: { created: now, updated: now }
|
|
4881
4931
|
},
|
|
4882
4932
|
trigger: { application: {} }
|
|
4883
4933
|
};
|
|
4884
4934
|
try {
|
|
4885
|
-
const result = await
|
|
4886
|
-
apiKey:
|
|
4935
|
+
const result = await context2.orchestrator.executeV2Api({
|
|
4936
|
+
apiKey: context2.apiKey,
|
|
4887
4937
|
body: {
|
|
4888
4938
|
definition: { api: definition },
|
|
4889
4939
|
inputs: {},
|
|
@@ -4894,10 +4944,10 @@ async function executeRequestToIntegrationViaOrchestrator(context, payload) {
|
|
|
4894
4944
|
isAiTriggered: true,
|
|
4895
4945
|
suppressTracking: true
|
|
4896
4946
|
},
|
|
4897
|
-
...
|
|
4947
|
+
...context2.profileKey ? { profile: { name: context2.profileKey } } : {}
|
|
4898
4948
|
},
|
|
4899
|
-
profileKey:
|
|
4900
|
-
scopedToken:
|
|
4949
|
+
profileKey: context2.profileKey,
|
|
4950
|
+
scopedToken: context2.sessionToken
|
|
4901
4951
|
});
|
|
4902
4952
|
if (result && typeof result === "object" && "systemError" in result) {
|
|
4903
4953
|
const systemError = String(result.systemError ?? "Integration execution failed");
|
|
@@ -4933,11 +4983,11 @@ async function executeRequestToIntegrationViaOrchestrator(context, payload) {
|
|
|
4933
4983
|
return { error: clarifySdkExecutionErrorMessage(message) };
|
|
4934
4984
|
}
|
|
4935
4985
|
}
|
|
4936
|
-
async function loadIntegrationsForPrompt(
|
|
4937
|
-
const rows = await
|
|
4938
|
-
apiKey:
|
|
4939
|
-
applicationId:
|
|
4940
|
-
organizationId:
|
|
4986
|
+
async function loadIntegrationsForPrompt(context2) {
|
|
4987
|
+
const rows = await context2.server.getSupersetIntegrations({
|
|
4988
|
+
apiKey: context2.apiKey,
|
|
4989
|
+
applicationId: context2.applicationId,
|
|
4990
|
+
organizationId: context2.organizationId
|
|
4941
4991
|
});
|
|
4942
4992
|
return listIntegrationsForClark(rows);
|
|
4943
4993
|
}
|
|
@@ -5082,10 +5132,9 @@ function createEditorClientMethods(getListener, onInbound, deps) {
|
|
|
5082
5132
|
],
|
|
5083
5133
|
updateApiInputs: ack,
|
|
5084
5134
|
updateScope: ack,
|
|
5085
|
-
// No browser tab means no viewport to photograph.
|
|
5086
|
-
//
|
|
5087
|
-
//
|
|
5088
|
-
// instead of reporting that it cannot see the app it just built.
|
|
5135
|
+
// No browser tab means no viewport to photograph. viewportUnavailable
|
|
5136
|
+
// marks this as a refusal, not a failed capture. The screenshot tool
|
|
5137
|
+
// does not read that flag; MCP turns omit the tool via disabledTools.
|
|
5089
5138
|
aiCaptureScreenshot: [
|
|
5090
5139
|
async () => ({
|
|
5091
5140
|
error: "the headless gateway session has no browser viewport",
|
|
@@ -5097,13 +5146,13 @@ function createEditorClientMethods(getListener, onInbound, deps) {
|
|
|
5097
5146
|
aiDeleteIntegration: setupUnavailable,
|
|
5098
5147
|
aiExecuteRequestToIntegration: [
|
|
5099
5148
|
async (payload) => {
|
|
5100
|
-
const
|
|
5101
|
-
if (!
|
|
5149
|
+
const context2 = deps?.getContext();
|
|
5150
|
+
if (!context2) {
|
|
5102
5151
|
return {
|
|
5103
5152
|
error: "the headless gateway session cannot execute integration requests without an active prompt session"
|
|
5104
5153
|
};
|
|
5105
5154
|
}
|
|
5106
|
-
const result = await executeRequestToIntegrationViaOrchestrator(
|
|
5155
|
+
const result = await executeRequestToIntegrationViaOrchestrator(context2, payload);
|
|
5107
5156
|
const name = payload.integrationHint?.name || payload.integrationId || "integration";
|
|
5108
5157
|
deps?.onToolRun?.({
|
|
5109
5158
|
detail: result,
|
|
@@ -5116,8 +5165,8 @@ function createEditorClientMethods(getListener, onInbound, deps) {
|
|
|
5116
5165
|
],
|
|
5117
5166
|
aiExecuteSdkApi: [
|
|
5118
5167
|
async (payload) => {
|
|
5119
|
-
const
|
|
5120
|
-
if (!
|
|
5168
|
+
const context2 = deps?.getContext();
|
|
5169
|
+
if (!context2) {
|
|
5121
5170
|
throw missingSessionError("execute SDK APIs");
|
|
5122
5171
|
}
|
|
5123
5172
|
if (!payload.entryPoint) {
|
|
@@ -5137,7 +5186,7 @@ function createEditorClientMethods(getListener, onInbound, deps) {
|
|
|
5137
5186
|
return missing;
|
|
5138
5187
|
}
|
|
5139
5188
|
try {
|
|
5140
|
-
const inSync = await
|
|
5189
|
+
const inSync = await context2.waitUntilFilesSynced();
|
|
5141
5190
|
if (!inSync) {
|
|
5142
5191
|
const syncing = {
|
|
5143
5192
|
success: false,
|
|
@@ -5154,15 +5203,15 @@ function createEditorClientMethods(getListener, onInbound, deps) {
|
|
|
5154
5203
|
});
|
|
5155
5204
|
return syncing;
|
|
5156
5205
|
}
|
|
5157
|
-
const response = await
|
|
5158
|
-
apiKey:
|
|
5159
|
-
applicationId:
|
|
5160
|
-
branchName:
|
|
5206
|
+
const response = await context2.orchestrator.executeSdkApiV3({
|
|
5207
|
+
apiKey: context2.apiKey,
|
|
5208
|
+
applicationId: context2.applicationId,
|
|
5209
|
+
branchName: context2.branchName,
|
|
5161
5210
|
entryPoint: payload.entryPoint,
|
|
5162
5211
|
exportName: payload.exportName,
|
|
5163
5212
|
inputs: payload.input ?? {},
|
|
5164
|
-
profileKey:
|
|
5165
|
-
scopedToken:
|
|
5213
|
+
profileKey: context2.profileKey,
|
|
5214
|
+
scopedToken: context2.sessionToken
|
|
5166
5215
|
});
|
|
5167
5216
|
const mapped = mapSdkExecutionResponse(response);
|
|
5168
5217
|
deps?.onToolRun?.({
|
|
@@ -5192,8 +5241,8 @@ function createEditorClientMethods(getListener, onInbound, deps) {
|
|
|
5192
5241
|
],
|
|
5193
5242
|
aiExecuteV2Api: [
|
|
5194
5243
|
async (payload) => {
|
|
5195
|
-
const
|
|
5196
|
-
if (!
|
|
5244
|
+
const context2 = deps?.getContext();
|
|
5245
|
+
if (!context2) {
|
|
5197
5246
|
throw missingSessionError("execute V2 APIs");
|
|
5198
5247
|
}
|
|
5199
5248
|
if (payload.api.type === "fetch") {
|
|
@@ -5206,14 +5255,14 @@ function createEditorClientMethods(getListener, onInbound, deps) {
|
|
|
5206
5255
|
...payload.api.definition,
|
|
5207
5256
|
metadata: {
|
|
5208
5257
|
...payload.api.definition.metadata ?? {},
|
|
5209
|
-
organization:
|
|
5258
|
+
organization: context2.organizationId,
|
|
5210
5259
|
timestamps: { created: now, updated: now }
|
|
5211
5260
|
},
|
|
5212
5261
|
trigger: { application: {} }
|
|
5213
5262
|
};
|
|
5214
5263
|
try {
|
|
5215
|
-
const result = await
|
|
5216
|
-
apiKey:
|
|
5264
|
+
const result = await context2.orchestrator.executeV2Api({
|
|
5265
|
+
apiKey: context2.apiKey,
|
|
5217
5266
|
body: {
|
|
5218
5267
|
definition: { api: definition },
|
|
5219
5268
|
inputs: payload.inputs ?? {},
|
|
@@ -5224,10 +5273,10 @@ function createEditorClientMethods(getListener, onInbound, deps) {
|
|
|
5224
5273
|
isAiTriggered: true,
|
|
5225
5274
|
suppressTracking: true
|
|
5226
5275
|
},
|
|
5227
|
-
...
|
|
5276
|
+
...context2.profileKey ? { profile: { name: context2.profileKey } } : {}
|
|
5228
5277
|
},
|
|
5229
|
-
profileKey:
|
|
5230
|
-
scopedToken:
|
|
5278
|
+
profileKey: context2.profileKey,
|
|
5279
|
+
scopedToken: context2.sessionToken
|
|
5231
5280
|
});
|
|
5232
5281
|
if (result && typeof result === "object" && "systemError" in result) {
|
|
5233
5282
|
return result;
|
|
@@ -5249,27 +5298,27 @@ function createEditorClientMethods(getListener, onInbound, deps) {
|
|
|
5249
5298
|
],
|
|
5250
5299
|
aiGetIntegration: [
|
|
5251
5300
|
async (payload) => {
|
|
5252
|
-
const
|
|
5253
|
-
if (!
|
|
5301
|
+
const context2 = deps?.getContext();
|
|
5302
|
+
if (!context2) {
|
|
5254
5303
|
throw missingSessionError("provide integration metadata");
|
|
5255
5304
|
}
|
|
5256
5305
|
let row;
|
|
5257
5306
|
try {
|
|
5258
|
-
row = await
|
|
5259
|
-
apiKey:
|
|
5307
|
+
row = await context2.server.getIntegration({
|
|
5308
|
+
apiKey: context2.apiKey,
|
|
5260
5309
|
integrationId: payload.integrationId
|
|
5261
5310
|
});
|
|
5262
5311
|
if (!row) {
|
|
5263
|
-
const rows = await
|
|
5264
|
-
apiKey:
|
|
5265
|
-
applicationId:
|
|
5266
|
-
organizationId:
|
|
5312
|
+
const rows = await context2.server.getSupersetIntegrations({
|
|
5313
|
+
apiKey: context2.apiKey,
|
|
5314
|
+
applicationId: context2.applicationId,
|
|
5315
|
+
organizationId: context2.organizationId
|
|
5267
5316
|
});
|
|
5268
5317
|
row = rows.find((candidate) => candidate.id === payload.integrationId);
|
|
5269
5318
|
}
|
|
5270
5319
|
} catch (error) {
|
|
5271
5320
|
console.warn("gateway failed to load integration for Clark", {
|
|
5272
|
-
applicationId:
|
|
5321
|
+
applicationId: context2.applicationId,
|
|
5273
5322
|
integrationId: payload.integrationId,
|
|
5274
5323
|
message: error instanceof Error ? error.message : String(error)
|
|
5275
5324
|
});
|
|
@@ -5285,11 +5334,11 @@ function createEditorClientMethods(getListener, onInbound, deps) {
|
|
|
5285
5334
|
}
|
|
5286
5335
|
let metadata = {};
|
|
5287
5336
|
try {
|
|
5288
|
-
metadata = await
|
|
5289
|
-
apiKey:
|
|
5337
|
+
metadata = await context2.orchestrator.getMetadata({
|
|
5338
|
+
apiKey: context2.apiKey,
|
|
5290
5339
|
integrationId: payload.integrationId,
|
|
5291
|
-
profileKey:
|
|
5292
|
-
scopedToken:
|
|
5340
|
+
profileKey: context2.profileKey,
|
|
5341
|
+
scopedToken: context2.sessionToken
|
|
5293
5342
|
});
|
|
5294
5343
|
} catch {
|
|
5295
5344
|
metadata = {};
|
|
@@ -5311,15 +5360,15 @@ function createEditorClientMethods(getListener, onInbound, deps) {
|
|
|
5311
5360
|
],
|
|
5312
5361
|
aiGetIntegrations: [
|
|
5313
5362
|
async () => {
|
|
5314
|
-
const
|
|
5315
|
-
if (!
|
|
5363
|
+
const context2 = deps?.getContext();
|
|
5364
|
+
if (!context2) {
|
|
5316
5365
|
return [];
|
|
5317
5366
|
}
|
|
5318
5367
|
try {
|
|
5319
|
-
return await loadIntegrationsForPrompt(
|
|
5368
|
+
return await loadIntegrationsForPrompt(context2);
|
|
5320
5369
|
} catch (error) {
|
|
5321
5370
|
console.warn("gateway failed to list integrations for Clark", {
|
|
5322
|
-
applicationId:
|
|
5371
|
+
applicationId: context2.applicationId,
|
|
5323
5372
|
message: error instanceof Error ? error.message : String(error)
|
|
5324
5373
|
});
|
|
5325
5374
|
return [];
|
|
@@ -5420,6 +5469,7 @@ function truncate(text, max = RECENT_TOOL_RUN_SUMMARY_MAX) {
|
|
|
5420
5469
|
var GENERATE_METHOD = "editor.aiGenerateWithQueue";
|
|
5421
5470
|
var ACCEPT_DRAFT_METHOD = "editor.aiAcceptDraft";
|
|
5422
5471
|
var RELOAD_CHAT_METHOD = "editor.aiChatGetMessages";
|
|
5472
|
+
var RELEASE_TURN_LOCK_METHOD = "editor.releaseTurnLock";
|
|
5423
5473
|
var RESPOND_TOOL_PERMISSION_METHOD = "editor.aiRespondToToolPermission";
|
|
5424
5474
|
var PING_METHOD = "editor.ping";
|
|
5425
5475
|
var DEFAULT_TIMEOUT_MS3 = 12e4;
|
|
@@ -5761,6 +5811,7 @@ var WebSocketSessionPeer = class {
|
|
|
5761
5811
|
this.failedStarts.set(input, {
|
|
5762
5812
|
generationStatus: "live_edit_terminated",
|
|
5763
5813
|
reply: input.reason,
|
|
5814
|
+
...input.retryAction ? { retryAction: input.retryAction } : {},
|
|
5764
5815
|
// Nothing ran, so nothing is viewable. Reporting "ready" here is how a
|
|
5765
5816
|
// caller comes to show the untouched starter template as the app.
|
|
5766
5817
|
viewStatus: "unknown"
|
|
@@ -5793,7 +5844,11 @@ var WebSocketSessionPeer = class {
|
|
|
5793
5844
|
}
|
|
5794
5845
|
const failed = this.failedStarts.get(input);
|
|
5795
5846
|
if (failed) {
|
|
5796
|
-
return {
|
|
5847
|
+
return {
|
|
5848
|
+
generationStatus: failed.generationStatus,
|
|
5849
|
+
phase: "finished",
|
|
5850
|
+
...failed.retryAction ? { retryAction: failed.retryAction } : {}
|
|
5851
|
+
};
|
|
5797
5852
|
}
|
|
5798
5853
|
if (!turn?.finished) {
|
|
5799
5854
|
return void 0;
|
|
@@ -5801,7 +5856,8 @@ var WebSocketSessionPeer = class {
|
|
|
5801
5856
|
return {
|
|
5802
5857
|
...turn.finished.checkpointCommitId ? { checkpointCommitId: turn.finished.checkpointCommitId } : {},
|
|
5803
5858
|
generationStatus: turn.finished.generationStatus,
|
|
5804
|
-
phase: "finished"
|
|
5859
|
+
phase: "finished",
|
|
5860
|
+
...turn.retryAction ? { retryAction: turn.retryAction } : {}
|
|
5805
5861
|
};
|
|
5806
5862
|
}
|
|
5807
5863
|
clearPendingPlan(applicationId) {
|
|
@@ -5947,6 +6003,7 @@ var WebSocketSessionPeer = class {
|
|
|
5947
6003
|
normalized: void 0,
|
|
5948
6004
|
recentRuns: [],
|
|
5949
6005
|
reconnects: 0,
|
|
6006
|
+
...input.attachments?.length ? { retryAction: "retry_import" } : {},
|
|
5950
6007
|
startedAt: Date.now(),
|
|
5951
6008
|
turnId: randomUUID3(),
|
|
5952
6009
|
unsubscribe: () => void 0,
|
|
@@ -6007,6 +6064,7 @@ var WebSocketSessionPeer = class {
|
|
|
6007
6064
|
jwt: input.sessionToken,
|
|
6008
6065
|
llmConfig: {
|
|
6009
6066
|
coreModel: this.options.coreModel ?? DEFAULT_LLM.coreModel,
|
|
6067
|
+
disabledTools: ["build_captureScreenshot", "build_navigatePreview"],
|
|
6010
6068
|
// The ai-service gates Clark's testing tools on this flag *and* a
|
|
6011
6069
|
// browser context, so the two travel together or not at all.
|
|
6012
6070
|
...browserContext ? { flags: { isTestingEnabled: true } } : {},
|
|
@@ -6112,6 +6170,7 @@ var WebSocketSessionPeer = class {
|
|
|
6112
6170
|
elapsedMs,
|
|
6113
6171
|
status: "finished",
|
|
6114
6172
|
...turn.finished,
|
|
6173
|
+
...turn.retryAction ? { retryAction: turn.retryAction } : {},
|
|
6115
6174
|
...recentRuns ? { recentRuns } : {}
|
|
6116
6175
|
};
|
|
6117
6176
|
}
|
|
@@ -6252,6 +6311,15 @@ var WebSocketSessionPeer = class {
|
|
|
6252
6311
|
collector.dispose();
|
|
6253
6312
|
const stillMapped = this.turns.get(input.applicationId) === turn;
|
|
6254
6313
|
if (stillMapped) {
|
|
6314
|
+
try {
|
|
6315
|
+
await turn.held.client.requestWithTracing(RELEASE_TURN_LOCK_METHOD, this.turnCorrelator(turn.turnId), {}, `Bearer ${input.sessionToken}`);
|
|
6316
|
+
} catch (error) {
|
|
6317
|
+
console.warn("gateway could not release the live-edit turn lock", {
|
|
6318
|
+
applicationId: input.applicationId,
|
|
6319
|
+
message: describeSocketError(error),
|
|
6320
|
+
turnId: turn.turnId
|
|
6321
|
+
});
|
|
6322
|
+
}
|
|
6255
6323
|
if (turn.finished?.generationStatus === "needs_decision") {
|
|
6256
6324
|
this.armIdle(turn.held);
|
|
6257
6325
|
} else {
|
|
@@ -6668,7 +6736,7 @@ var WebSocketSessionPeer = class {
|
|
|
6668
6736
|
const heldRef = {
|
|
6669
6737
|
current: void 0
|
|
6670
6738
|
};
|
|
6671
|
-
const socket = new
|
|
6739
|
+
const socket = new import_shared6.ISocket(ws, createEditorClientMethods(() => {
|
|
6672
6740
|
const listeners = heldRef.current?.listeners;
|
|
6673
6741
|
if (!listeners || listeners.size === 0) {
|
|
6674
6742
|
return void 0;
|
|
@@ -6745,7 +6813,7 @@ var WebSocketSessionPeer = class {
|
|
|
6745
6813
|
noResponseTimeoutInSeconds: (this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS3) / 1e3
|
|
6746
6814
|
}
|
|
6747
6815
|
});
|
|
6748
|
-
const client = (0,
|
|
6816
|
+
const client = (0, import_shared6.createISocketClient)(socket);
|
|
6749
6817
|
const heartbeat = this.buildHeartbeat(heldRef);
|
|
6750
6818
|
const held = {
|
|
6751
6819
|
applicationId: input.applicationId,
|
|
@@ -6781,7 +6849,7 @@ var WebSocketSessionPeer = class {
|
|
|
6781
6849
|
* who to tell.
|
|
6782
6850
|
*/
|
|
6783
6851
|
buildHeartbeat(heldRef) {
|
|
6784
|
-
return new
|
|
6852
|
+
return new import_shared6.SocketHeartbeat({
|
|
6785
6853
|
beat: async () => {
|
|
6786
6854
|
const held = heldRef.current;
|
|
6787
6855
|
if (!held?.sessionToken) {
|
|
@@ -7308,6 +7376,233 @@ var WebSocketSessionPeer = class {
|
|
|
7308
7376
|
}
|
|
7309
7377
|
};
|
|
7310
7378
|
|
|
7379
|
+
// ../../../gateway/dist/telemetry/runtime.js
|
|
7380
|
+
init_cjs_shims();
|
|
7381
|
+
|
|
7382
|
+
// ../../../gateway/dist/telemetry/mcp-client.js
|
|
7383
|
+
init_cjs_shims();
|
|
7384
|
+
init_esm();
|
|
7385
|
+
function bounded(value, maxLength) {
|
|
7386
|
+
return value.slice(0, maxLength);
|
|
7387
|
+
}
|
|
7388
|
+
function stringProperty(value, key2) {
|
|
7389
|
+
if (typeof value !== "object" || value === null || !(key2 in value)) {
|
|
7390
|
+
return void 0;
|
|
7391
|
+
}
|
|
7392
|
+
const property = Reflect.get(value, key2);
|
|
7393
|
+
return typeof property === "string" ? property : void 0;
|
|
7394
|
+
}
|
|
7395
|
+
var McpClientTelemetry = class {
|
|
7396
|
+
tracer;
|
|
7397
|
+
ended = false;
|
|
7398
|
+
hadError = false;
|
|
7399
|
+
organizationId;
|
|
7400
|
+
sessionContext;
|
|
7401
|
+
sessionSpan;
|
|
7402
|
+
constructor(tracer) {
|
|
7403
|
+
this.tracer = tracer;
|
|
7404
|
+
this.sessionSpan = tracer.startSpan("gen_ai.request", {
|
|
7405
|
+
attributes: {
|
|
7406
|
+
"gen_ai.operation.name": "invoke_agent"
|
|
7407
|
+
}
|
|
7408
|
+
});
|
|
7409
|
+
this.sessionContext = trace.setSpan(context.active(), this.sessionSpan);
|
|
7410
|
+
}
|
|
7411
|
+
setOrganizationId(organizationId) {
|
|
7412
|
+
this.organizationId = organizationId;
|
|
7413
|
+
this.sessionSpan.setAttribute("organization.id", organizationId);
|
|
7414
|
+
}
|
|
7415
|
+
async runTool(call, operation) {
|
|
7416
|
+
const attributes = {
|
|
7417
|
+
"gen_ai.operation.name": "execute_tool",
|
|
7418
|
+
...call.client ? {
|
|
7419
|
+
"mcp.client.name": bounded(call.client.name, 80),
|
|
7420
|
+
...call.client.version ? {
|
|
7421
|
+
"mcp.client.version": bounded(call.client.version, 40)
|
|
7422
|
+
} : {}
|
|
7423
|
+
} : {},
|
|
7424
|
+
...this.organizationId ? { "organization.id": this.organizationId } : {},
|
|
7425
|
+
"tool.name": bounded(call.toolName, 80)
|
|
7426
|
+
};
|
|
7427
|
+
if (call.client) {
|
|
7428
|
+
this.sessionSpan.setAttributes({
|
|
7429
|
+
"mcp.client.name": bounded(call.client.name, 80),
|
|
7430
|
+
...call.client.version ? { "mcp.client.version": bounded(call.client.version, 40) } : {}
|
|
7431
|
+
});
|
|
7432
|
+
}
|
|
7433
|
+
let span;
|
|
7434
|
+
try {
|
|
7435
|
+
span = this.tracer.startSpan("gen_ai.tool_call", { attributes }, this.sessionContext);
|
|
7436
|
+
} catch {
|
|
7437
|
+
return operation();
|
|
7438
|
+
}
|
|
7439
|
+
const startedAt = Date.now();
|
|
7440
|
+
try {
|
|
7441
|
+
const result = await context.with(trace.setSpan(this.sessionContext, span), operation);
|
|
7442
|
+
span.setAttribute("tool.duration_ms", Date.now() - startedAt);
|
|
7443
|
+
if (this.organizationId) {
|
|
7444
|
+
span.setAttribute("organization.id", this.organizationId);
|
|
7445
|
+
}
|
|
7446
|
+
if (result.kind === "error") {
|
|
7447
|
+
this.hadError = true;
|
|
7448
|
+
span.setAttributes({
|
|
7449
|
+
...result.applicationId ? { "application.id": result.applicationId } : {},
|
|
7450
|
+
"mcp.error.code": bounded(result.code, 80),
|
|
7451
|
+
"tool.error_category": result.code === "cancelled" ? "timeout" : "execution_error",
|
|
7452
|
+
"tool.status": "error"
|
|
7453
|
+
});
|
|
7454
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
7455
|
+
} else if (result.kind === "auth_required") {
|
|
7456
|
+
this.hadError = true;
|
|
7457
|
+
span.setAttributes({
|
|
7458
|
+
"mcp.result.status": "auth_required",
|
|
7459
|
+
"tool.error_category": "permission_denied",
|
|
7460
|
+
"tool.status": "error"
|
|
7461
|
+
});
|
|
7462
|
+
} else {
|
|
7463
|
+
const applicationId = stringProperty(result.value, "applicationId");
|
|
7464
|
+
const resultStatus = stringProperty(result.value, "status");
|
|
7465
|
+
span.setAttributes({
|
|
7466
|
+
...applicationId ? { "application.id": applicationId } : {},
|
|
7467
|
+
...resultStatus ? { "mcp.result.status": bounded(resultStatus, 80) } : {},
|
|
7468
|
+
"tool.error_category": "none",
|
|
7469
|
+
"tool.status": "success"
|
|
7470
|
+
});
|
|
7471
|
+
}
|
|
7472
|
+
return result;
|
|
7473
|
+
} catch (error) {
|
|
7474
|
+
this.hadError = true;
|
|
7475
|
+
span.setAttributes({
|
|
7476
|
+
"tool.duration_ms": Date.now() - startedAt,
|
|
7477
|
+
"tool.error_category": "execution_error",
|
|
7478
|
+
"tool.status": "error"
|
|
7479
|
+
});
|
|
7480
|
+
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
7481
|
+
throw error;
|
|
7482
|
+
} finally {
|
|
7483
|
+
span.end();
|
|
7484
|
+
}
|
|
7485
|
+
}
|
|
7486
|
+
endSession() {
|
|
7487
|
+
if (this.ended) {
|
|
7488
|
+
return;
|
|
7489
|
+
}
|
|
7490
|
+
this.ended = true;
|
|
7491
|
+
this.sessionSpan.setAttribute("gen_ai.request.status", this.hadError ? "error" : "success");
|
|
7492
|
+
this.sessionSpan.end();
|
|
7493
|
+
}
|
|
7494
|
+
};
|
|
7495
|
+
|
|
7496
|
+
// ../../../gateway/dist/telemetry/runtime.js
|
|
7497
|
+
var TELEMETRY_SHUTDOWN_MS = 2e3;
|
|
7498
|
+
function logToStderr(first, message) {
|
|
7499
|
+
if (message === void 0) {
|
|
7500
|
+
console.error(first);
|
|
7501
|
+
return;
|
|
7502
|
+
}
|
|
7503
|
+
console.error(first, message);
|
|
7504
|
+
}
|
|
7505
|
+
var stderrLogger = {
|
|
7506
|
+
error: logToStderr,
|
|
7507
|
+
info: logToStderr,
|
|
7508
|
+
warn: logToStderr
|
|
7509
|
+
};
|
|
7510
|
+
function telemetryBaseUrl(serverUrl) {
|
|
7511
|
+
try {
|
|
7512
|
+
const url = new URL(serverUrl);
|
|
7513
|
+
url.hash = "";
|
|
7514
|
+
url.pathname = `${url.pathname.replace(/\/$/u, "")}/api`;
|
|
7515
|
+
url.search = "";
|
|
7516
|
+
return url.toString().replace(/\/$/u, "");
|
|
7517
|
+
} catch {
|
|
7518
|
+
console.error("gateway telemetry skipped: server URL is not parseable");
|
|
7519
|
+
return void 0;
|
|
7520
|
+
}
|
|
7521
|
+
}
|
|
7522
|
+
function environmentName(config) {
|
|
7523
|
+
if (config.deploymentEnvironmentName !== "unknown") {
|
|
7524
|
+
return config.deploymentEnvironmentName;
|
|
7525
|
+
}
|
|
7526
|
+
try {
|
|
7527
|
+
return environmentFromHostname(new URL(config.serverUrl).hostname);
|
|
7528
|
+
} catch {
|
|
7529
|
+
return "unknown";
|
|
7530
|
+
}
|
|
7531
|
+
}
|
|
7532
|
+
function environmentFromHostname(hostname) {
|
|
7533
|
+
if (hostname.match(/^app\.superblocks(?:hq)?\.com$/u)) {
|
|
7534
|
+
return "prod";
|
|
7535
|
+
}
|
|
7536
|
+
if (hostname.match(/^eu\.superblocks(?:hq)?\.com$/u)) {
|
|
7537
|
+
return "prod-eu";
|
|
7538
|
+
}
|
|
7539
|
+
if (hostname.match(/^staging\.superblocks(?:hq)?\.com$/u)) {
|
|
7540
|
+
return "staging";
|
|
7541
|
+
}
|
|
7542
|
+
if (hostname.match(/^dev\.superblocks(?:hq)?\.com$/u)) {
|
|
7543
|
+
return "dev";
|
|
7544
|
+
}
|
|
7545
|
+
if (hostname.match(/^pr-[0-9]+\.superblocks(?:hq)?\.dev$/u)) {
|
|
7546
|
+
return "ephemeral";
|
|
7547
|
+
}
|
|
7548
|
+
if (hostname === "localhost" || hostname === "127.0.0.1") {
|
|
7549
|
+
return "local";
|
|
7550
|
+
}
|
|
7551
|
+
return "other";
|
|
7552
|
+
}
|
|
7553
|
+
function deploymentTypeFor(config) {
|
|
7554
|
+
if (config.localAgentMode) {
|
|
7555
|
+
return import_shared.DeploymentTypeEnum.CLOUD_PREM;
|
|
7556
|
+
}
|
|
7557
|
+
try {
|
|
7558
|
+
return parseDeploymentType(process.env.SUPERBLOCKS_DEPLOYMENT_TYPE);
|
|
7559
|
+
} catch {
|
|
7560
|
+
return import_shared.DeploymentTypeEnum.CLOUD;
|
|
7561
|
+
}
|
|
7562
|
+
}
|
|
7563
|
+
async function settleWithin(work, timeoutMs) {
|
|
7564
|
+
let timer;
|
|
7565
|
+
try {
|
|
7566
|
+
await Promise.race([
|
|
7567
|
+
work,
|
|
7568
|
+
new Promise((resolve) => {
|
|
7569
|
+
timer = setTimeout(resolve, timeoutMs);
|
|
7570
|
+
})
|
|
7571
|
+
]);
|
|
7572
|
+
} finally {
|
|
7573
|
+
if (timer !== void 0) {
|
|
7574
|
+
clearTimeout(timer);
|
|
7575
|
+
}
|
|
7576
|
+
}
|
|
7577
|
+
}
|
|
7578
|
+
function startGatewayTelemetry(input) {
|
|
7579
|
+
const otlpUrl = telemetryBaseUrl(input.config.serverUrl);
|
|
7580
|
+
const telemetry = initNodeTelemetry({
|
|
7581
|
+
environment: environmentName(input.config),
|
|
7582
|
+
logger: stderrLogger,
|
|
7583
|
+
logsEnabled: false,
|
|
7584
|
+
// Counters in metrics.ts are created at import time, before this SDK
|
|
7585
|
+
// starts, so they stay no-ops. Do not turn metrics on until those
|
|
7586
|
+
// instruments are created after init.
|
|
7587
|
+
metricsEnabled: false,
|
|
7588
|
+
otlpHeaders: { Authorization: `Bearer ${input.apiKey}` },
|
|
7589
|
+
...otlpUrl ? { otlpUrl } : {},
|
|
7590
|
+
serviceName: "gateway",
|
|
7591
|
+
serviceVersion: "0.0.1"
|
|
7592
|
+
}, getDefaultPolicy(deploymentTypeFor(input.config)));
|
|
7593
|
+
const mcpTelemetry = new McpClientTelemetry(telemetry.getTracer("gateway.mcp"));
|
|
7594
|
+
return {
|
|
7595
|
+
mcpTelemetry,
|
|
7596
|
+
shutdown: async () => {
|
|
7597
|
+
try {
|
|
7598
|
+
mcpTelemetry.endSession();
|
|
7599
|
+
} finally {
|
|
7600
|
+
await settleWithin(telemetry.shutdown(), TELEMETRY_SHUTDOWN_MS);
|
|
7601
|
+
}
|
|
7602
|
+
}
|
|
7603
|
+
};
|
|
7604
|
+
}
|
|
7605
|
+
|
|
7311
7606
|
// ../../../gateway/dist/transports/mcp/mount.js
|
|
7312
7607
|
init_cjs_shims();
|
|
7313
7608
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
@@ -7407,6 +7702,150 @@ function N3(Z, $, J, X, V) {
|
|
|
7407
7702
|
return Z.registerResource($, J, { mimeType: p, ...X }, V);
|
|
7408
7703
|
}
|
|
7409
7704
|
|
|
7705
|
+
// ../../../gateway/dist/capabilities/integration-metadata.js
|
|
7706
|
+
init_cjs_shims();
|
|
7707
|
+
var DEFAULT_LIMIT = 100;
|
|
7708
|
+
function labelPart(value) {
|
|
7709
|
+
return typeof value === "string" ? value.trim().replaceAll(/[.[\]]/g, "_") : "";
|
|
7710
|
+
}
|
|
7711
|
+
function arrayEntryLabel(value, index) {
|
|
7712
|
+
if (value && typeof value === "object") {
|
|
7713
|
+
const row = value;
|
|
7714
|
+
const name = labelPart(row.name);
|
|
7715
|
+
if (name) {
|
|
7716
|
+
const schema = labelPart(row.schema);
|
|
7717
|
+
return schema ? `${schema}.${name}` : name;
|
|
7718
|
+
}
|
|
7719
|
+
}
|
|
7720
|
+
return String(index);
|
|
7721
|
+
}
|
|
7722
|
+
function metadataEntries(value, path3 = "", entries = []) {
|
|
7723
|
+
if (value === null || typeof value === "boolean" || typeof value === "number" || typeof value === "string") {
|
|
7724
|
+
entries.push({ path: path3, value });
|
|
7725
|
+
return entries;
|
|
7726
|
+
}
|
|
7727
|
+
if (Array.isArray(value)) {
|
|
7728
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7729
|
+
value.forEach((entry, index) => {
|
|
7730
|
+
const label = arrayEntryLabel(entry, index);
|
|
7731
|
+
const unique = seen.has(label) ? `${label}#${index}` : label;
|
|
7732
|
+
seen.add(unique);
|
|
7733
|
+
metadataEntries(entry, `${path3}[${unique}]`, entries);
|
|
7734
|
+
});
|
|
7735
|
+
return entries;
|
|
7736
|
+
}
|
|
7737
|
+
if (value && typeof value === "object") {
|
|
7738
|
+
for (const [key2, entry] of Object.entries(value)) {
|
|
7739
|
+
metadataEntries(entry, path3 ? `${path3}.${key2}` : key2, entries);
|
|
7740
|
+
}
|
|
7741
|
+
}
|
|
7742
|
+
return entries;
|
|
7743
|
+
}
|
|
7744
|
+
async function getIntegrationMetadata(context2, input) {
|
|
7745
|
+
const principal = await ensurePrincipal(context2);
|
|
7746
|
+
if (principal.kind !== "ok") {
|
|
7747
|
+
return principal;
|
|
7748
|
+
}
|
|
7749
|
+
let applicationId;
|
|
7750
|
+
let label = sanitizeAgentFacingText(input.integrationId);
|
|
7751
|
+
try {
|
|
7752
|
+
const resolved = await resolveApplicationId(context2, principal.value, input.applicationId);
|
|
7753
|
+
applicationId = resolved.kind === "ok" ? resolved.value : void 0;
|
|
7754
|
+
const rows = await context2.server.getSupersetIntegrations({
|
|
7755
|
+
apiKey: principal.value.apiKey,
|
|
7756
|
+
...applicationId && { applicationId },
|
|
7757
|
+
organizationId: principal.value.organizationId
|
|
7758
|
+
});
|
|
7759
|
+
const integration = rows.find((row) => row.id === input.integrationId);
|
|
7760
|
+
if (!integration) {
|
|
7761
|
+
return {
|
|
7762
|
+
...applicationId && { applicationId },
|
|
7763
|
+
kind: "error",
|
|
7764
|
+
code: "integration_not_accessible",
|
|
7765
|
+
message: `Integration ${label} was not found or is not accessible.`
|
|
7766
|
+
};
|
|
7767
|
+
}
|
|
7768
|
+
const integrationName = sanitizeAgentFacingText(integration.name);
|
|
7769
|
+
const pluginId = sanitizeAgentFacingText(integration.pluginId);
|
|
7770
|
+
label = integrationName;
|
|
7771
|
+
if (!hasBuildPermission(integration)) {
|
|
7772
|
+
return {
|
|
7773
|
+
...applicationId && { applicationId },
|
|
7774
|
+
kind: "error",
|
|
7775
|
+
code: "integration_not_permitted",
|
|
7776
|
+
message: `You do not have build permission on ${integrationName}.`
|
|
7777
|
+
};
|
|
7778
|
+
}
|
|
7779
|
+
if (!integrationIsToolSupported(integration.pluginId)) {
|
|
7780
|
+
return {
|
|
7781
|
+
...applicationId && { applicationId },
|
|
7782
|
+
kind: "error",
|
|
7783
|
+
code: "integration_not_supported",
|
|
7784
|
+
message: `${integrationName} is a ${pluginId} integration, which this tool cannot inspect.`
|
|
7785
|
+
};
|
|
7786
|
+
}
|
|
7787
|
+
const profiles = await context2.server.getOrganizationProfiles({
|
|
7788
|
+
apiKey: principal.value.apiKey,
|
|
7789
|
+
organizationId: principal.value.organizationId
|
|
7790
|
+
});
|
|
7791
|
+
const profileKey = pickEditorProfileKey(context2.config.profileKey, profiles);
|
|
7792
|
+
const inventory = await context2.server.getAgentInventory({
|
|
7793
|
+
apiKey: principal.value.apiKey,
|
|
7794
|
+
organizationId: principal.value.organizationId
|
|
7795
|
+
});
|
|
7796
|
+
const orchestratorUrl = pickOrchestratorBaseUrl({
|
|
7797
|
+
agentType: inventory.agentType,
|
|
7798
|
+
agents: inventory.agents,
|
|
7799
|
+
profileKey
|
|
7800
|
+
});
|
|
7801
|
+
const scopedToken = await context2.server.issueScopedToken(applicationId ? {
|
|
7802
|
+
apiKey: principal.value.apiKey,
|
|
7803
|
+
applicationId,
|
|
7804
|
+
scope: "apps:update"
|
|
7805
|
+
} : {
|
|
7806
|
+
apiKey: principal.value.apiKey,
|
|
7807
|
+
integrationId: input.integrationId,
|
|
7808
|
+
scope: "integrations:build"
|
|
7809
|
+
});
|
|
7810
|
+
const metadata = await new HttpOrchestratorClient(orchestratorUrl).getMetadata({
|
|
7811
|
+
apiKey: principal.value.apiKey,
|
|
7812
|
+
integrationId: input.integrationId,
|
|
7813
|
+
profileKey,
|
|
7814
|
+
scopedToken
|
|
7815
|
+
});
|
|
7816
|
+
const sanitized = sanitizeAgentFacingValue(metadata);
|
|
7817
|
+
const search = input.search?.trim().toLowerCase();
|
|
7818
|
+
const matched = metadataEntries(sanitized).filter((entry) => !search || entry.path.toLowerCase().includes(search) || String(entry.value).toLowerCase().includes(search));
|
|
7819
|
+
const limit = input.limit ?? DEFAULT_LIMIT;
|
|
7820
|
+
const offset = input.offset ?? 0;
|
|
7821
|
+
const entries = matched.slice(offset, offset + limit);
|
|
7822
|
+
const nextOffset = offset + entries.length < matched.length ? offset + entries.length : null;
|
|
7823
|
+
return {
|
|
7824
|
+
kind: "ok",
|
|
7825
|
+
value: {
|
|
7826
|
+
...applicationId && { applicationId },
|
|
7827
|
+
entries,
|
|
7828
|
+
hasMore: nextOffset !== null,
|
|
7829
|
+
integrationId: integration.id,
|
|
7830
|
+
integrationName,
|
|
7831
|
+
nextOffset,
|
|
7832
|
+
offset,
|
|
7833
|
+
pluginId,
|
|
7834
|
+
returnedCount: entries.length,
|
|
7835
|
+
totalCount: matched.length
|
|
7836
|
+
}
|
|
7837
|
+
};
|
|
7838
|
+
} catch (error) {
|
|
7839
|
+
const detail = sanitizeAgentFacingText(error instanceof Error ? error.message : "Unknown metadata error").replaceAll("\u2014", "-");
|
|
7840
|
+
return {
|
|
7841
|
+
...applicationId && { applicationId },
|
|
7842
|
+
kind: "error",
|
|
7843
|
+
code: "integration_metadata_unavailable",
|
|
7844
|
+
message: `Could not load metadata for ${label}: ${detail}`
|
|
7845
|
+
};
|
|
7846
|
+
}
|
|
7847
|
+
}
|
|
7848
|
+
|
|
7410
7849
|
// ../../../gateway/dist/capture/browser-instructions.js
|
|
7411
7850
|
init_cjs_shims();
|
|
7412
7851
|
var BROWSER_DRIVER_INSTRUCTIONS = `Browser capture (MUST):
|
|
@@ -8068,6 +8507,16 @@ function resolveToken(options, auth) {
|
|
|
8068
8507
|
function superblocksProductCopy(text) {
|
|
8069
8508
|
return text.replaceAll(/\bClark AI Apps\b/g, "Superblocks AI Apps").replaceAll(/\bClark\b/g, "Superblocks");
|
|
8070
8509
|
}
|
|
8510
|
+
function completeToolAnnotations(annotations) {
|
|
8511
|
+
const readOnlyHint = annotations?.readOnlyHint ?? false;
|
|
8512
|
+
return {
|
|
8513
|
+
...annotations,
|
|
8514
|
+
destructiveHint: annotations?.destructiveHint ?? (readOnlyHint ? false : true),
|
|
8515
|
+
idempotentHint: annotations?.idempotentHint ?? readOnlyHint,
|
|
8516
|
+
openWorldHint: annotations?.openWorldHint ?? true,
|
|
8517
|
+
readOnlyHint
|
|
8518
|
+
};
|
|
8519
|
+
}
|
|
8071
8520
|
function registerAdminTools(server, options) {
|
|
8072
8521
|
const registry = buildToolRegistry(toolDefinitions, "customer", {
|
|
8073
8522
|
requireEntitledPlan: options.localAgentMode !== true
|
|
@@ -8078,7 +8527,7 @@ function registerAdminTools(server, options) {
|
|
|
8078
8527
|
}
|
|
8079
8528
|
const definition = toolDefinitions.find((d2) => d2.name === tool.name);
|
|
8080
8529
|
server.registerTool(tool.name, {
|
|
8081
|
-
annotations: tool.annotations,
|
|
8530
|
+
annotations: completeToolAnnotations(tool.annotations),
|
|
8082
8531
|
description: superblocksProductCopy(tool.description ?? ""),
|
|
8083
8532
|
inputSchema: gatewayAdminInputShape(tool.inputSchema),
|
|
8084
8533
|
title: tool.title ?? definition?.title
|
|
@@ -8119,7 +8568,7 @@ function registerAdminTools(server, options) {
|
|
|
8119
8568
|
|
|
8120
8569
|
// ../../../gateway/dist/transports/mcp/app-status-html.js
|
|
8121
8570
|
init_cjs_shims();
|
|
8122
|
-
var APP_STATUS_RESOURCE_URI = "ui://gateway/app-status-
|
|
8571
|
+
var APP_STATUS_RESOURCE_URI = "ui://gateway/app-status-v8.html";
|
|
8123
8572
|
var APP_STATUS_HTML = `<!DOCTYPE html>
|
|
8124
8573
|
<html lang="en">
|
|
8125
8574
|
<head>
|
|
@@ -8233,11 +8682,29 @@ var APP_STATUS_HTML = `<!DOCTYPE html>
|
|
|
8233
8682
|
<script>
|
|
8234
8683
|
(() => {
|
|
8235
8684
|
const PROTOCOL_VERSION = "2026-01-26";
|
|
8685
|
+
// Statuses get_app reports when the app is still the empty starter
|
|
8686
|
+
// template. "building" is deliberately absent: the card only hears a
|
|
8687
|
+
// build finished if a new result arrives, so a stale badge would strand
|
|
8688
|
+
// the button.
|
|
8689
|
+
const UNBUILT_STATUSES = [
|
|
8690
|
+
"cancelled",
|
|
8691
|
+
"live_edit_terminated",
|
|
8692
|
+
"needs_decision",
|
|
8693
|
+
"no_changes",
|
|
8694
|
+
"timeout",
|
|
8695
|
+
];
|
|
8696
|
+
const BLOCKED_ACTIONS = [
|
|
8697
|
+
"answer_question",
|
|
8698
|
+
"approve_plan",
|
|
8699
|
+
"retry_build",
|
|
8700
|
+
"retry_import",
|
|
8701
|
+
];
|
|
8236
8702
|
let nextId = 1;
|
|
8237
8703
|
const pending = new Map();
|
|
8238
8704
|
let applicationId = "";
|
|
8239
8705
|
let appName = "";
|
|
8240
8706
|
let commitId = "";
|
|
8707
|
+
let pendingAction = "";
|
|
8241
8708
|
let editUrl = "";
|
|
8242
8709
|
let previewUrl = "";
|
|
8243
8710
|
let publishUrl = "";
|
|
@@ -8245,6 +8712,13 @@ var APP_STATUS_HTML = `<!DOCTYPE html>
|
|
|
8245
8712
|
let canCallTools = false;
|
|
8246
8713
|
let publishing = false;
|
|
8247
8714
|
let lastHeight = 0;
|
|
8715
|
+
let refreshInFlight = false;
|
|
8716
|
+
let refreshTimer = 0;
|
|
8717
|
+
let refreshGeneration = 0;
|
|
8718
|
+
let refreshAttempts = 0;
|
|
8719
|
+
let pollAfterMs = 2000;
|
|
8720
|
+
const MIN_POLL_MS = 2000;
|
|
8721
|
+
const MAX_REFRESH_ATTEMPTS = 40;
|
|
8248
8722
|
|
|
8249
8723
|
function post(message) {
|
|
8250
8724
|
window.parent.postMessage(message, "*");
|
|
@@ -8334,6 +8808,31 @@ var APP_STATUS_HTML = `<!DOCTYPE html>
|
|
|
8334
8808
|
}
|
|
8335
8809
|
}
|
|
8336
8810
|
|
|
8811
|
+
/**
|
|
8812
|
+
* True when publishing would deploy the empty starter template.
|
|
8813
|
+
* pendingAction is the server's own "nothing to preview" signal;
|
|
8814
|
+
* wait_for_build is the building exception. Status is only a fallback
|
|
8815
|
+
* when the payload omitted pendingAction. loading/waiting with no
|
|
8816
|
+
* preview fail closed so Publish is not clickable before get_app
|
|
8817
|
+
* returns.
|
|
8818
|
+
*/
|
|
8819
|
+
function nothingToPublish() {
|
|
8820
|
+
if (previewUrl || publishUrl) {
|
|
8821
|
+
return false;
|
|
8822
|
+
}
|
|
8823
|
+
if (pendingAction === "wait_for_build") {
|
|
8824
|
+
return false;
|
|
8825
|
+
}
|
|
8826
|
+
if (BLOCKED_ACTIONS.indexOf(pendingAction) !== -1) {
|
|
8827
|
+
return true;
|
|
8828
|
+
}
|
|
8829
|
+
const badge = element("status").textContent;
|
|
8830
|
+
if (!badge || badge === "loading" || badge === "waiting") {
|
|
8831
|
+
return true;
|
|
8832
|
+
}
|
|
8833
|
+
return UNBUILT_STATUSES.indexOf(badge) !== -1;
|
|
8834
|
+
}
|
|
8835
|
+
|
|
8337
8836
|
/**
|
|
8338
8837
|
* Keep URLs in memory for openLink \u2014 never print them (preview JWTs are
|
|
8339
8838
|
* huge and ugly in the card).
|
|
@@ -8348,7 +8847,10 @@ var APP_STATUS_HTML = `<!DOCTYPE html>
|
|
|
8348
8847
|
: "Publish app";
|
|
8349
8848
|
element("publishApp").disabled = publishUrl
|
|
8350
8849
|
? !canOpenLinks
|
|
8351
|
-
: !applicationId ||
|
|
8850
|
+
: !applicationId ||
|
|
8851
|
+
!canCallTools ||
|
|
8852
|
+
publishing ||
|
|
8853
|
+
nothingToPublish();
|
|
8352
8854
|
// Only warn about what is actually broken. Hosts that do open links
|
|
8353
8855
|
// handle local http fine; if one refuses, refused() says so then.
|
|
8354
8856
|
if (!canOpenLinks && (editUrl || previewUrl) && !publishUrl) {
|
|
@@ -8420,6 +8922,11 @@ var APP_STATUS_HTML = `<!DOCTYPE html>
|
|
|
8420
8922
|
if (typeof value.commitId === "string") {
|
|
8421
8923
|
commitId = value.commitId;
|
|
8422
8924
|
}
|
|
8925
|
+
if (typeof value.pendingAction === "string") {
|
|
8926
|
+
pendingAction = value.pendingAction;
|
|
8927
|
+
} else if (typeof value.status === "string") {
|
|
8928
|
+
pendingAction = "";
|
|
8929
|
+
}
|
|
8423
8930
|
if (typeof value.screenshotBase64 === "string") {
|
|
8424
8931
|
showScreenshot(value.screenshotBase64, "image/jpeg");
|
|
8425
8932
|
}
|
|
@@ -8432,6 +8939,9 @@ var APP_STATUS_HTML = `<!DOCTYPE html>
|
|
|
8432
8939
|
if (typeof value.publishUrl === "string") {
|
|
8433
8940
|
publishUrl = webUrl(value.publishUrl);
|
|
8434
8941
|
}
|
|
8942
|
+
if (typeof value.nextPollAfterMs === "number") {
|
|
8943
|
+
pollAfterMs = value.nextPollAfterMs;
|
|
8944
|
+
}
|
|
8435
8945
|
// Hosts that deliver URLs without a status left the badge on the HTML
|
|
8436
8946
|
// default ("loading") even after the app was built.
|
|
8437
8947
|
const badge = element("status").textContent;
|
|
@@ -8446,29 +8956,91 @@ var APP_STATUS_HTML = `<!DOCTYPE html>
|
|
|
8446
8956
|
}
|
|
8447
8957
|
|
|
8448
8958
|
/**
|
|
8449
|
-
*
|
|
8450
|
-
*
|
|
8451
|
-
*
|
|
8959
|
+
* Re-ask get_app when the host gave us no result, or while status is
|
|
8960
|
+
* still building. wait:false and ensurePreview:false so polls only
|
|
8961
|
+
* ask for status. Honor nextPollAfterMs; 0 means stop.
|
|
8452
8962
|
*/
|
|
8963
|
+
function clearRefreshTimer() {
|
|
8964
|
+
if (refreshTimer) {
|
|
8965
|
+
clearTimeout(refreshTimer);
|
|
8966
|
+
refreshTimer = 0;
|
|
8967
|
+
}
|
|
8968
|
+
}
|
|
8969
|
+
|
|
8970
|
+
function retryDelay() {
|
|
8971
|
+
return Math.max(MIN_POLL_MS, pollAfterMs || MIN_POLL_MS);
|
|
8972
|
+
}
|
|
8973
|
+
|
|
8974
|
+
function scheduleRefresh(delayMs) {
|
|
8975
|
+
clearRefreshTimer();
|
|
8976
|
+
if (refreshAttempts >= MAX_REFRESH_ATTEMPTS) {
|
|
8977
|
+
note("Stopped checking whether the app is still building.");
|
|
8978
|
+
return;
|
|
8979
|
+
}
|
|
8980
|
+
refreshTimer = setTimeout(() => {
|
|
8981
|
+
refreshTimer = 0;
|
|
8982
|
+
refreshFromServer();
|
|
8983
|
+
}, delayMs);
|
|
8984
|
+
}
|
|
8985
|
+
|
|
8453
8986
|
function refreshFromServer() {
|
|
8454
|
-
|
|
8987
|
+
clearRefreshTimer();
|
|
8988
|
+
if (!canCallTools || !applicationId || refreshInFlight) {
|
|
8989
|
+
return;
|
|
8990
|
+
}
|
|
8991
|
+
if (typeof document.hidden === "boolean" && document.hidden) {
|
|
8992
|
+
scheduleRefresh(retryDelay());
|
|
8993
|
+
return;
|
|
8994
|
+
}
|
|
8995
|
+
const badge = element("status").textContent;
|
|
8996
|
+
if (editUrl && badge !== "building") {
|
|
8997
|
+
return;
|
|
8998
|
+
}
|
|
8999
|
+
if (refreshAttempts >= MAX_REFRESH_ATTEMPTS) {
|
|
9000
|
+
note("Stopped checking whether the app is still building.");
|
|
8455
9001
|
return;
|
|
8456
9002
|
}
|
|
9003
|
+
refreshAttempts += 1;
|
|
9004
|
+
const generation = refreshGeneration;
|
|
9005
|
+
refreshInFlight = true;
|
|
8457
9006
|
request("tools/call", {
|
|
8458
9007
|
name: "get_app",
|
|
8459
|
-
arguments: {
|
|
9008
|
+
arguments: {
|
|
9009
|
+
applicationId,
|
|
9010
|
+
ensurePreview: false,
|
|
9011
|
+
wait: false,
|
|
9012
|
+
},
|
|
8460
9013
|
})
|
|
8461
9014
|
.then((result) => {
|
|
9015
|
+
refreshInFlight = false;
|
|
9016
|
+
if (generation !== refreshGeneration) {
|
|
9017
|
+
if (element("status").textContent === "building") {
|
|
9018
|
+
scheduleRefresh(retryDelay());
|
|
9019
|
+
}
|
|
9020
|
+
return;
|
|
9021
|
+
}
|
|
8462
9022
|
if (!result || result.isError) {
|
|
9023
|
+
scheduleRefresh(retryDelay());
|
|
8463
9024
|
return;
|
|
8464
9025
|
}
|
|
8465
9026
|
applyPayload(result);
|
|
8466
9027
|
if (result.structuredContent) {
|
|
8467
9028
|
applyPayload(result.structuredContent);
|
|
8468
9029
|
}
|
|
9030
|
+
if (element("status").textContent !== "building") {
|
|
9031
|
+
return;
|
|
9032
|
+
}
|
|
9033
|
+
if (pollAfterMs === 0) {
|
|
9034
|
+
return;
|
|
9035
|
+
}
|
|
9036
|
+
scheduleRefresh(retryDelay());
|
|
8469
9037
|
})
|
|
8470
9038
|
.catch(() => {
|
|
8471
|
-
|
|
9039
|
+
refreshInFlight = false;
|
|
9040
|
+
if (generation !== refreshGeneration) {
|
|
9041
|
+
return;
|
|
9042
|
+
}
|
|
9043
|
+
scheduleRefresh(retryDelay());
|
|
8472
9044
|
});
|
|
8473
9045
|
}
|
|
8474
9046
|
|
|
@@ -8521,6 +9093,10 @@ var APP_STATUS_HTML = `<!DOCTYPE html>
|
|
|
8521
9093
|
if (!applicationId || !canCallTools || publishing) {
|
|
8522
9094
|
return;
|
|
8523
9095
|
}
|
|
9096
|
+
if (nothingToPublish()) {
|
|
9097
|
+
note("Nothing to publish yet: this turn did not build the app.");
|
|
9098
|
+
return;
|
|
9099
|
+
}
|
|
8524
9100
|
publishing = true;
|
|
8525
9101
|
renderActions();
|
|
8526
9102
|
note("Publishing\u2026");
|
|
@@ -8604,6 +9180,10 @@ var APP_STATUS_HTML = `<!DOCTYPE html>
|
|
|
8604
9180
|
if (params.structuredContent) {
|
|
8605
9181
|
applyPayload(params.structuredContent);
|
|
8606
9182
|
}
|
|
9183
|
+
refreshGeneration += 1;
|
|
9184
|
+
if (element("status").textContent === "building") {
|
|
9185
|
+
refreshFromServer();
|
|
9186
|
+
}
|
|
8607
9187
|
}
|
|
8608
9188
|
if (method === "ui/notifications/tool-input" && params.arguments) {
|
|
8609
9189
|
applyPayload(params.arguments);
|
|
@@ -8933,6 +9513,24 @@ function createProgressNotifier(extra) {
|
|
|
8933
9513
|
}
|
|
8934
9514
|
|
|
8935
9515
|
// ../../../gateway/dist/transports/mcp/mount.js
|
|
9516
|
+
var DESTRUCTIVE_TOOL_ANNOTATIONS = {
|
|
9517
|
+
destructiveHint: true,
|
|
9518
|
+
idempotentHint: false,
|
|
9519
|
+
openWorldHint: true,
|
|
9520
|
+
readOnlyHint: false
|
|
9521
|
+
};
|
|
9522
|
+
var NON_DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS = {
|
|
9523
|
+
destructiveHint: false,
|
|
9524
|
+
idempotentHint: false,
|
|
9525
|
+
openWorldHint: true,
|
|
9526
|
+
readOnlyHint: false
|
|
9527
|
+
};
|
|
9528
|
+
var READ_ONLY_TOOL_ANNOTATIONS = {
|
|
9529
|
+
destructiveHint: false,
|
|
9530
|
+
idempotentHint: true,
|
|
9531
|
+
openWorldHint: true,
|
|
9532
|
+
readOnlyHint: true
|
|
9533
|
+
};
|
|
8936
9534
|
var eventCursorInputSchema = external_exports.object({
|
|
8937
9535
|
streams: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
|
|
8938
9536
|
version: external_exports.unknown().optional()
|
|
@@ -8953,10 +9551,11 @@ Name the builder "Superblocks" in every word you write. Users sometimes call it
|
|
|
8953
9551
|
Use these tools whenever the user asks to build, change, import, or ship an app, whichever of those names they reach for.
|
|
8954
9552
|
|
|
8955
9553
|
- start_app: create a new application and hand a prompt to Superblocks. Returns as soon as Superblocks accepts, with status "building". Superblocks names it unless a name is given.
|
|
8956
|
-
- import_app: import an existing app from a ZIP (or .tgz/.gz) into Superblocks and start a Superblocks migration. Pass the archive's file name as zipPath \u2014 the gateway opens the file on this machine itself. Archives larger than 1 MB are rejected \u2014 they almost certainly include node_modules; re-export without install artifacts. Optional prompt carries extra intent (e.g. "make it more secure"). Returns like start_app with status "building".
|
|
9554
|
+
- import_app: import an existing app from a ZIP (or .tgz/.gz) into Superblocks and start a Superblocks migration. Pass the archive's file name as zipPath \u2014 the gateway opens the file on this machine itself. Archives larger than 1 MB are rejected \u2014 they almost certainly include node_modules; re-export without install artifacts. Optional prompt carries extra intent (e.g. "make it more secure"). Returns like start_app with status "building". Pass applicationId only when retrying a failed import into the application that call already created.
|
|
8957
9555
|
- edit_app: send a follow-up prompt (including the answer when Superblocks asked a question) for an existing application. Also returns at status "building". Defaults to the most recent app, so an applicationId is only needed to target a different app.
|
|
8958
9556
|
- check_app_progress: wait for the next thing Superblocks does and return it. It returns the moment Superblocks says anything, and after ~10 seconds of silence at the latest. "activity" holds Superblocks' own words since the previous call, in order; a quiet poll still returns a short heartbeat with elapsedSeconds.
|
|
8959
|
-
- get_app: return editor and preview URLs for the recent or specified app (builds a private preview when needed). Prefer this after status "ready" so the user can open the live app. Hosts that support MCP Apps show the status card (Open editor / Open preview) on this call \u2014 not on check_app_progress or preview_app \u2014 so only one card opens. When Superblocks has written code the tool includes a screenshot: the live Vite canvas (library peer) if a held session exists, otherwise the signed-in preview. Never open canvas.doNotOpen (the edit URL) to take that screenshot. It refuses to build a preview of an app Superblocks has not written yet: while a plan or question is outstanding it returns status "needs_decision" with "pendingAction", while a turn is running it returns status "building", and when the last turn ended without writing anything it returns that turn's status ("timeout", "live_edit_terminated", "no_changes" or "cancelled") with pendingAction "retry_build". In each case there are no preview URLs and no screenshot \u2014 do the pendingAction first rather than calling get_app again.
|
|
9557
|
+
- get_app: return editor and preview URLs for the recent or specified app (builds a private preview when needed). Prefer this after status "ready" so the user can open the live app. Hosts that support MCP Apps show the status card (Open editor / Open preview) on this call \u2014 not on check_app_progress or preview_app \u2014 so only one card opens. When Superblocks has written code the tool includes a screenshot: the live Vite canvas (library peer) if a held session exists, otherwise the signed-in preview. Never open canvas.doNotOpen (the edit URL) to take that screenshot. It refuses to build a preview of an app Superblocks has not written yet: while a plan or question is outstanding it returns status "needs_decision" with "pendingAction", while a turn is running it returns status "building", and when the last turn ended without writing anything it returns that turn's status ("timeout", "live_edit_terminated", "no_changes" or "cancelled") with pendingAction "retry_build" for ordinary prompts or pendingAction "retry_import" for imports. In each case there are no preview URLs and no screenshot \u2014 do the pendingAction first rather than calling get_app again.
|
|
9558
|
+
- get_integration_metadata: inspect the tables, columns, and types in a connected integration. It needs no application and never executes an integration action, so do not call start_app or hunt through list_applications to satisfy it. Pass applicationId only for an integration that belongs to one application, such as a Native DB. Use search, limit, and offset to page large results. get_integration_config_schema is the JSON form for create_integration; it does not inspect connected data.
|
|
8960
9559
|
- preview_app: build the application's current work and return a URL that runs it, without deploying it \u2014 the editor's Preview button. Nobody else can reach a preview. Text/markdown only (no MCP Apps widget); use get_app instead when you want the status card.
|
|
8961
9560
|
- publish_app: deploy an application and wait until it is live. It commits the current work first, so a commitId is only needed to publish an earlier commit.
|
|
8962
9561
|
|
|
@@ -8964,21 +9563,25 @@ A build takes two to four minutes, and start_app/edit_app/import_app return with
|
|
|
8964
9563
|
|
|
8965
9564
|
The user sees nothing at all while a tool call is outstanding, so between two calls always write out the new "activity" lines as a short message in your own reply \u2014 quote or paraphrase them, oldest first, before calling check_app_progress again. Do not batch them up for a summary at the end, and do not go two calls in a row without writing something: the point of the loop is that the user watches the build happen. When a call comes back with only a heartbeat (no new Superblocks words), say Superblocks is still working and how long it has been going, then poll again.
|
|
8966
9565
|
|
|
8967
|
-
status "ready" means the turn finished: report the "reply" field, then call get_app (not preview_app as well \u2014 calling both used to open two widgets) so the user gets Open preview / an https link or a screenshot. status "needs_decision" means Superblocks is waiting \u2014 often with a plan \u2014 so stop polling and put the decision to the user. When "decision.kind" is "plan", show the plan markdown, then invite them to build it as written or say what to change \u2014 the same fork the editor's Build-it button offers. Ask that as an ordinary closing question in your own words; do not turn it into a numbered or bulleted menu, and do not wrap the choices in quotation marks. When they say "Build it", "approve", "looks good", or "go ahead", you MUST call edit_app with planAction "approve" and omit prompt (do not re-send the plan, and do not put "approve" or "Build it" in the prompt field \u2014 that is refine feedback to Superblocks, not the editor Build-it path). When they want changes, call edit_app with planAction "refine" and their feedback as prompt. When "decision.kind" is "multi_choice", relay the question and options and send their answer with edit_app. Do not claim the app is built while status is "needs_decision". status "no_changes" means the Superblocks job ended without building anything: relay reply, say no app was built, and do not present the edit URL as a finished app. status "live_edit_terminated" means the live-edit session that was to run the turn died before it built anything, or never opened at all \u2014
|
|
9566
|
+
status "ready" means the turn finished: report the "reply" field, then call get_app (not preview_app as well \u2014 calling both used to open two widgets) so the user gets Open preview / an https link or a screenshot. status "needs_decision" means Superblocks is waiting \u2014 often with a plan \u2014 so stop polling and put the decision to the user. When "decision.kind" is "plan", show the plan markdown, then invite them to build it as written or say what to change \u2014 the same fork the editor's Build-it button offers. Ask that as an ordinary closing question in your own words; do not turn it into a numbered or bulleted menu, and do not wrap the choices in quotation marks. When they say "Build it", "approve", "looks good", or "go ahead", you MUST call edit_app with planAction "approve" and omit prompt (do not re-send the plan, and do not put "approve" or "Build it" in the prompt field \u2014 that is refine feedback to Superblocks, not the editor Build-it path). When they want changes, call edit_app with planAction "refine" and their feedback as prompt. When "decision.kind" is "multi_choice", relay the question and options and send their answer with edit_app. Do not claim the app is built while status is "needs_decision". status "no_changes" means the Superblocks job ended without building anything: relay reply, say no app was built, and do not present the edit URL as a finished app. status "live_edit_terminated" means the live-edit session that was to run the turn died before it built anything, or never opened at all \u2014 relay reply, tell the user the session did not survive, and follow its pendingAction to retry with edit_app or import_app. status "detached" means Superblocks is still working but the gateway can no longer see it \u2014 usually because the app is open in a browser editor, which takes over Superblocks updates. Stop polling, say so, and point the user at the edit URL. status "unknown" means nothing is in flight for that app. A checkpointCommitId means Superblocks work is saved and the edit URL opens the finished app; when viewStatus is unknown, say the app may still be finishing in the editor.
|
|
9567
|
+
|
|
9568
|
+
When get_app returns a screenshot, inspect it yourself before reporting that the app looks correct. If it shows skeletons, spinners, empty tables or charts, or "Loading...", call get_app again a few seconds later instead of treating that as a defect. If it shows a problem the user would plainly recognize as wrong, call edit_app once with a concrete correction, follow that turn to completion, and inspect the next get_app screenshot. Otherwise describe what you see and ask the user whether to fix it.
|
|
8968
9569
|
|
|
8969
9570
|
start_app, edit_app, and import_app default to Plan mode (Superblocks proposes a plan before writing). Pass mode "BUILD" only when the user asks to skip planning and build immediately. Approving a plan after start_app or import_app is always a follow-up edit_app with planAction "approve" \u2014 never a second start_app/import_app with prompt "approve". Once the app has run in Build mode, later edit_app calls stay in Build mode on their own: you do not need to re-send mode "BUILD", and a new instruction is not a fresh planning round. Send mode "PLAN" only when the user explicitly asks to plan again before building. Every start_app / edit_app / import_app result reports the "mode" the turn ran in, so you can tell the user whether Superblocks is planning or building rather than guessing \u2014 and if a result comes back "PLAN" after a long gap, the build session was recycled rather than the user asking to plan, so pass mode "BUILD" again to carry on building. editUrl / previewUrl / publishUrl may appear in structured JSON for openLink buttons \u2014 do not dump raw URLs (especially preview JWTs) into the chat. Prefer the MCP Apps Open editor / Open preview buttons from get_app. Claude Desktop can only openLink https URLs; when previewUrl is http, say so briefly and rely on any screenshot image the tool returned rather than pasting the URL.
|
|
8970
9571
|
|
|
8971
9572
|
Once a build reaches "ready", call get_app so the user can open the app, then offer publish_app to deploy for their organization when they ask. Prefer get_app over preview_app after a build \u2014 get_app already ensures a private preview and is the only tool that opens the MCP Apps status card. Only publish when the user asks. If preview_app or get_app comes back with status "building", the URL is already correct; tell the user it is still building and call again to check.
|
|
8972
9573
|
|
|
8973
|
-
There is nothing to preview until Superblocks has written code, so get_app is not the way out of a plan, a question, or a turn that failed. When it answers status "needs_decision" (pendingAction "approve_plan" or "answer_question"), the app is still the empty starter template: put the decision to the user, send their answer with edit_app, and only call get_app once a turn has finished. When it answers "timeout", "live_edit_terminated", "no_changes" or "cancelled" with pendingAction "retry_build", that turn built nothing: tell the user so plainly, and send the instruction again with edit_app if they want to retry. Repeating get_app instead opens another status card and tells the user nothing new.
|
|
9574
|
+
There is nothing to preview until Superblocks has written code, so get_app is not the way out of a plan, a question, or a turn that failed. When it answers status "needs_decision" (pendingAction "approve_plan" or "answer_question"), the app is still the empty starter template: put the decision to the user, send their answer with edit_app, and only call get_app once a turn has finished. When it answers "timeout", "live_edit_terminated", "no_changes" or "cancelled" with pendingAction "retry_build", that turn built nothing: tell the user so plainly, and send the instruction again with edit_app if they want to retry. For pendingAction "retry_import", call import_app again with the same archive and applicationId. One of those statuses can arrive with no pendingAction at all, which means the gateway knows the turn wrote nothing but not how it was started: say so, and pick the retry from what this conversation already knows \u2014 import_app with the archive and applicationId for an app you imported, edit_app with the same prompt otherwise. Repeating get_app instead opens another status card and tells the user nothing new.
|
|
8974
9575
|
|
|
8975
9576
|
Superblocks tests what it builds: it opens the app in a browser and runs its APIs, and the test run arrives as ordinary "activity" lines ("Testing the orders page", "Test passed: \u2026", "Tests failed: \u2026"). Relay those lines like any other activity, and say which cases passed and which failed \u2014 a test run is the only evidence the user has that the app actually works. A failing test is a build signal, not an auth problem: it means the app has a bug Superblocks is about to work on, so keep polling and never tell the user to sign in again or re-enter credentials over one.
|
|
8976
9577
|
|
|
8977
|
-
A failed call still names the application it was working on. start_app and import_app create the application before the build can start, so an error from either one leaves an application that exists and belongs to this conversation, and the error says which: read the "applicationId" field, never a UUID out of the message text. Never take an error to mean nothing happened. Do not answer a failed start_app with a second start_app \u2014 that abandons the app you already have and creates a duplicate. When the error carries pendingAction "retry_build" \u2014 a "live_edit_unavailable" session that would not open, or a turn that ran out of budget \u2014 send the same prompt again with edit_app and that applicationId.
|
|
9578
|
+
A failed call still names the application it was working on. start_app and import_app create the application before the build can start, so an error from either one leaves an application that exists and belongs to this conversation, and the error says which: read the "applicationId" field, never a UUID out of the message text. Never take an error to mean nothing happened. Do not answer a failed start_app with a second start_app \u2014 that abandons the app you already have and creates a duplicate. When the error carries pendingAction "retry_build" \u2014 a "live_edit_unavailable" session that would not open, or a turn that ran out of budget \u2014 send the same prompt again with edit_app and that applicationId. When import_app returns pendingAction "retry_import", call import_app again with the same archive and applicationId so it resumes the existing app instead of creating another one. Every edit_app error names its applicationId too, which is the one place to see which app a call that omitted the id actually ran on.
|
|
9579
|
+
|
|
9580
|
+
A cancelled call does not stop the build, and it is not permission to start over. Cancelling only ends the waiting \u2014 Superblocks carries on, and the "cancelled" error names the application it was driving in "applicationId". Read that id, call check_app_progress or get_app on it, and act on what comes back. When the user then asks to redo, retry, or resume an import, that is a request to finish the application you already have: never answer it with an import_app that omits applicationId, which builds a second app and strands the first. The same holds when no pendingAction is in front of you \u2014 after a cancel, or in a later session. If the app came from an import, the way back in is import_app with the same archive and that applicationId; if you cannot tell which application the user means, ask rather than create one.
|
|
8978
9581
|
|
|
8979
9582
|
Prompts are forwarded to Superblocks verbatim \u2014 pass the user's wording rather than a summary.
|
|
8980
9583
|
|
|
8981
|
-
This connector is the single Superblocks MCP: Builder tools (start_app, import_app, edit_app, check_app_progress, get_app, preview_app, publish_app) and Admin tools (integrations, apps, users, folders, deploy_application, and the rest of the customer Admin surface) share this endpoint. Prefer create_integration / update_integration / list_integrations here when Superblocks needs a missing Postgres, REST, or other datasource \u2014 do not send the user to a second MCP. create_integration is Admin CRUD for org datasources; start_app creates a new application and hands a prompt to Superblocks. deploy_application is Admin deploy of an existing commit; publish_app is the Builder path that commits current work and waits until the app is live. Omit base_url on Admin tools unless targeting a different control plane \u2014 the gateway injects its configured Server URL. checkout_application is not exposed on this network surface (host filesystem writes); use the CLI/workspace checkout path instead.
|
|
9584
|
+
This connector is the single Superblocks MCP: Builder tools (start_app, import_app, edit_app, check_app_progress, get_app, get_integration_metadata, preview_app, publish_app) and Admin tools (integrations, apps, users, folders, deploy_application, and the rest of the customer Admin surface) share this endpoint. Prefer create_integration / update_integration / list_integrations here when Superblocks needs a missing Postgres, REST, or other datasource \u2014 do not send the user to a second MCP. Call get_integration_config_schema with the plugin_id before create_integration, then pass name, plugin_id, and configuration \u2014 never the raw integrations API envelope. create_integration is Admin CRUD for org datasources; start_app creates a new application and hands a prompt to Superblocks. deploy_application is Admin deploy of an existing commit; publish_app is the Builder path that commits current work and waits until the app is live. Omit base_url on Admin tools unless targeting a different control plane \u2014 the gateway injects its configured Server URL. checkout_application is not exposed on this network surface (host filesystem writes); use the CLI/workspace checkout path instead.
|
|
8982
9585
|
|
|
8983
9586
|
This connection is already authenticated and already pointed at one Superblocks Server, so there is no setup, login, or auth-status call to make first. Call the tool that does the job \u2014 list_integrations to see the org's datasources, start_app to create an application \u2014 and read its error if something is genuinely wrong. Do not look for a tool that reports credentials or environments; there is none, and asking for one costs the user a turn.
|
|
8984
9587
|
|
|
@@ -8988,7 +9591,7 @@ For import_app, the archive never travels through you. A file the user attached
|
|
|
8988
9591
|
|
|
8989
9592
|
${BROWSER_DRIVER_INSTRUCTIONS}`;
|
|
8990
9593
|
function createMcpServer(deps) {
|
|
8991
|
-
const
|
|
9594
|
+
const context2 = async (progress, notify, signal) => ({
|
|
8992
9595
|
caller: callerFrom(),
|
|
8993
9596
|
captureLibraryScreenshot: captureLibraryScreenshotWithPlaywright,
|
|
8994
9597
|
capturePreviewScreenshot: capturePreviewScreenshotWithPlaywright,
|
|
@@ -8998,6 +9601,9 @@ function createMcpServer(deps) {
|
|
|
8998
9601
|
progress.push(event);
|
|
8999
9602
|
notify?.(event.message);
|
|
9000
9603
|
},
|
|
9604
|
+
onPrincipalResolved: (principal) => {
|
|
9605
|
+
deps.mcpTelemetry?.setOrganizationId(principal.organizationId);
|
|
9606
|
+
},
|
|
9001
9607
|
principal: principalFrom(deps),
|
|
9002
9608
|
progressCursors: deps.progressCursors,
|
|
9003
9609
|
recentApps: deps.recentApps,
|
|
@@ -9010,22 +9616,22 @@ function createMcpServer(deps) {
|
|
|
9010
9616
|
gatewayDebugStack("tool started", { "tool.name": toolName });
|
|
9011
9617
|
const progress = [];
|
|
9012
9618
|
const notify = createProgressNotifier(extra);
|
|
9013
|
-
|
|
9014
|
-
|
|
9015
|
-
|
|
9016
|
-
|
|
9017
|
-
|
|
9018
|
-
|
|
9019
|
-
|
|
9020
|
-
|
|
9021
|
-
|
|
9022
|
-
|
|
9023
|
-
|
|
9024
|
-
|
|
9619
|
+
const execute = async () => {
|
|
9620
|
+
if (!deps.cliApiKey) {
|
|
9621
|
+
gatewayDebug("tool short-circuited", {
|
|
9622
|
+
"tool.name": toolName,
|
|
9623
|
+
"tool.reason": "missing_cli_session"
|
|
9624
|
+
});
|
|
9625
|
+
return {
|
|
9626
|
+
kind: "error",
|
|
9627
|
+
code: "unauthenticated",
|
|
9628
|
+
message: "This Gateway has no CLI session. Run: superblocks login"
|
|
9629
|
+
};
|
|
9630
|
+
}
|
|
9025
9631
|
try {
|
|
9026
9632
|
const signal = extra?.signal;
|
|
9027
|
-
const capabilityContext = await
|
|
9028
|
-
|
|
9633
|
+
const capabilityContext = await context2(progress, notify, signal);
|
|
9634
|
+
return await capability(capabilityContext, () => {
|
|
9029
9635
|
for (let index = progress.length - 1; index >= 0; index -= 1) {
|
|
9030
9636
|
if (progress[index]?.type === "completed") {
|
|
9031
9637
|
progress.splice(index, 1);
|
|
@@ -9034,13 +9640,23 @@ function createMcpServer(deps) {
|
|
|
9034
9640
|
});
|
|
9035
9641
|
} catch (error) {
|
|
9036
9642
|
console.error("gateway capability failed", error);
|
|
9037
|
-
|
|
9643
|
+
return {
|
|
9038
9644
|
kind: "error",
|
|
9039
9645
|
code: "capability_failed",
|
|
9040
9646
|
message: error instanceof Error ? error.message : "The gateway failed for an unknown reason."
|
|
9041
9647
|
};
|
|
9042
9648
|
}
|
|
9043
|
-
}
|
|
9649
|
+
};
|
|
9650
|
+
const client = server.server.getClientVersion();
|
|
9651
|
+
const result = deps.mcpTelemetry ? await deps.mcpTelemetry.runTool({
|
|
9652
|
+
...client ? {
|
|
9653
|
+
client: {
|
|
9654
|
+
name: client.name,
|
|
9655
|
+
version: client.version
|
|
9656
|
+
}
|
|
9657
|
+
} : {},
|
|
9658
|
+
toolName
|
|
9659
|
+
}, execute) : await execute();
|
|
9044
9660
|
const resultStatus = result.kind === "ok" && result.value && typeof result.value === "object" && "status" in result.value && typeof result.value.status === "string" ? result.value.status : void 0;
|
|
9045
9661
|
gatewayDebug("tool finished", {
|
|
9046
9662
|
"progress.event_count": progress.length,
|
|
@@ -9066,12 +9682,12 @@ function createMcpServer(deps) {
|
|
|
9066
9682
|
title: "Superblocks",
|
|
9067
9683
|
version: "0.0.1"
|
|
9068
9684
|
}, { instructions: SERVER_INSTRUCTIONS });
|
|
9069
|
-
const progressWithDecisionForm = async (
|
|
9685
|
+
const progressWithDecisionForm = async (context3, input, extra, forgetFinishedTurn) => {
|
|
9070
9686
|
gatewayDebug("progress decision flow started", {
|
|
9071
9687
|
"application.id": input.applicationId,
|
|
9072
9688
|
"progress.cursor_provided": Boolean(input.cursor)
|
|
9073
9689
|
});
|
|
9074
|
-
const result = await checkAppProgress(
|
|
9690
|
+
const result = await checkAppProgress(context3, input);
|
|
9075
9691
|
const decision = pendingDecision(result);
|
|
9076
9692
|
if (!decision) {
|
|
9077
9693
|
gatewayDebug("progress decision flow finished", {
|
|
@@ -9091,7 +9707,7 @@ function createMcpServer(deps) {
|
|
|
9091
9707
|
const resolved = await resolveDecisionByElicitation({
|
|
9092
9708
|
apply: (answer) => {
|
|
9093
9709
|
forgetFinishedTurn();
|
|
9094
|
-
return editApp(
|
|
9710
|
+
return editApp(context3, {
|
|
9095
9711
|
applicationId: input.applicationId,
|
|
9096
9712
|
idempotencyKey: `mcp-decision:${randomUUID4()}`,
|
|
9097
9713
|
wait: "ack",
|
|
@@ -9123,7 +9739,20 @@ function createMcpServer(deps) {
|
|
|
9123
9739
|
});
|
|
9124
9740
|
}
|
|
9125
9741
|
function registerBuilderTools() {
|
|
9742
|
+
server.registerTool("get_integration_metadata", {
|
|
9743
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
9744
|
+
description: "Inspect the tables, columns, and types in a connected Superblocks integration. Needs no application and never executes an integration action. Pass integrationId, which list_integrations returns. A large result comes back paged: narrow it with search, take more or fewer entries with limit, and continue from nextOffset with offset. Requires build permission on the integration. Do not use this to learn how to create an integration; that is get_integration_config_schema.",
|
|
9745
|
+
inputSchema: {
|
|
9746
|
+
applicationId: external_exports.string().uuid().optional().describe("Only for an integration owned by a single application, such as a Native DB. Leave unset otherwise; do not go looking for an application to supply."),
|
|
9747
|
+
integrationId: external_exports.string().uuid(),
|
|
9748
|
+
limit: external_exports.number().int().min(1).max(200).optional(),
|
|
9749
|
+
offset: external_exports.number().int().min(0).optional(),
|
|
9750
|
+
search: external_exports.string().min(1).optional()
|
|
9751
|
+
},
|
|
9752
|
+
title: "Get Integration Metadata"
|
|
9753
|
+
}, async (input, extra) => run("get_integration_metadata", (context3) => getIntegrationMetadata(context3, input), extra));
|
|
9126
9754
|
server.registerTool("start_app", {
|
|
9755
|
+
annotations: NON_DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS,
|
|
9127
9756
|
description: 'Create a Superblocks application and hand a prompt to Superblocks in Plan mode by default. Returns as soon as Superblocks accepts, with status "building" and an edit URL; follow with check_app_progress until status is no longer "building". When Superblocks returns needs_decision with a plan and the user says "Build it", call edit_app with planAction "approve" (omit prompt) \u2014 do not call start_app again with prompt "approve". Pass mode "BUILD" to skip planning. Superblocks names the application unless name is given. An error from this tool does not mean nothing happened: the application is created before the build starts, so the error names it in "applicationId". Retry that app with edit_app rather than calling start_app another time, which would leave the first one abandoned.',
|
|
9128
9757
|
inputSchema: {
|
|
9129
9758
|
branch: external_exports.string().optional(),
|
|
@@ -9136,7 +9765,7 @@ function createMcpServer(deps) {
|
|
|
9136
9765
|
// the tool name: a host that ranks tools by title has to be able to find
|
|
9137
9766
|
// this one from the request.
|
|
9138
9767
|
title: "Create Superblocks App"
|
|
9139
|
-
}, async ({ branch, idempotencyKey, mode, name, prompt }, extra) => run("start_app", (
|
|
9768
|
+
}, async ({ branch, idempotencyKey, mode, name, prompt }, extra) => run("start_app", (context3) => startApp(context3, {
|
|
9140
9769
|
branch,
|
|
9141
9770
|
idempotencyKey: idempotencyKey ?? `mcp-start:${randomUUID4()}`,
|
|
9142
9771
|
mode,
|
|
@@ -9148,8 +9777,10 @@ function createMcpServer(deps) {
|
|
|
9148
9777
|
wait: "ack"
|
|
9149
9778
|
}), extra));
|
|
9150
9779
|
server.registerTool("import_app", {
|
|
9151
|
-
|
|
9780
|
+
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
9781
|
+
description: `Import an existing app from a ZIP/.tgz/.gz archive into Superblocks and start a Superblocks migration. Pass the archive's file name (or its full path on this machine) as zipPath: the gateway reads the file itself, so a path from your own sandbox is fine as long as the name matches the file the user has. Never encode the archive as base64 \u2014 zipBase64 only carries test fixtures. Archives larger than 1 MB are rejected \u2014 exclude node_modules. Optional prompt adds intent such as hardening security. Returns status "building"; follow with check_app_progress. Defaults to Plan mode \u2014 when Superblocks returns a plan and the user says "Build it", call edit_app with planAction "approve" (omit prompt); do not call import_app again with prompt "approve". An error from this tool does not mean nothing happened: the application is created before the migration starts, so the error names it in "applicationId". When it returns pendingAction "retry_import", call import_app again with the same archive and applicationId to resume that application instead of creating another one.`,
|
|
9152
9782
|
inputSchema: {
|
|
9783
|
+
applicationId: external_exports.string().uuid().optional(),
|
|
9153
9784
|
branch: external_exports.string().optional(),
|
|
9154
9785
|
idempotencyKey: external_exports.string().optional(),
|
|
9155
9786
|
mode: external_exports.enum(["BUILD", "PLAN"]).optional(),
|
|
@@ -9169,7 +9800,8 @@ function createMcpServer(deps) {
|
|
|
9169
9800
|
zipPath: external_exports.string().min(1).optional()
|
|
9170
9801
|
},
|
|
9171
9802
|
title: "Import App"
|
|
9172
|
-
}, async ({ branch, idempotencyKey, mode, name, prompt, source, zipBase64, zipPath }, extra) => run("import_app", (
|
|
9803
|
+
}, async ({ applicationId, branch, idempotencyKey, mode, name, prompt, source, zipBase64, zipPath }, extra) => run("import_app", (context3) => importApp(context3, {
|
|
9804
|
+
applicationId,
|
|
9173
9805
|
branch,
|
|
9174
9806
|
idempotencyKey: idempotencyKey ?? `mcp-import:${randomUUID4()}`,
|
|
9175
9807
|
mode,
|
|
@@ -9181,6 +9813,7 @@ function createMcpServer(deps) {
|
|
|
9181
9813
|
zipPath
|
|
9182
9814
|
}), extra));
|
|
9183
9815
|
server.registerTool("edit_app", {
|
|
9816
|
+
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
9184
9817
|
description: 'Forward a prompt to Superblocks for the recent or specified application. Defaults to Plan mode until the app has run in Build mode; after that later edits keep building directly \u2014 you do not need to pass mode again. Pass mode "PLAN" only when the user explicitly asks to plan before building. The result reports the "mode" the turn ran in; a "PLAN" result after a long gap means the build session was recycled, so pass mode "BUILD" again rather than treating it as a new planning round. When status was needs_decision with a plan and the user says "Build it" / approve / go ahead, call edit_app with planAction "approve" and omit prompt \u2014 do not put "approve" or "Build it" in prompt (that is refine feedback, not the Build-it path). Use planAction "refine" with their feedback as prompt to change the plan. Also use edit_app to answer multi_choice questions. Returns status "building"; follow with check_app_progress.',
|
|
9185
9818
|
inputSchema: {
|
|
9186
9819
|
applicationId: external_exports.string().uuid().optional(),
|
|
@@ -9191,7 +9824,7 @@ function createMcpServer(deps) {
|
|
|
9191
9824
|
prompt: external_exports.string().min(1).optional()
|
|
9192
9825
|
},
|
|
9193
9826
|
title: "Edit App"
|
|
9194
|
-
}, async ({ applicationId, branch, idempotencyKey, mode, planAction, prompt }, extra) => run("edit_app", (
|
|
9827
|
+
}, async ({ applicationId, branch, idempotencyKey, mode, planAction, prompt }, extra) => run("edit_app", (context3) => editApp(context3, {
|
|
9195
9828
|
applicationId,
|
|
9196
9829
|
branch,
|
|
9197
9830
|
idempotencyKey: idempotencyKey ?? `mcp-edit:${randomUUID4()}`,
|
|
@@ -9201,24 +9834,26 @@ function createMcpServer(deps) {
|
|
|
9201
9834
|
wait: "ack"
|
|
9202
9835
|
}), extra));
|
|
9203
9836
|
server.registerTool("check_app_progress", {
|
|
9837
|
+
annotations: NON_DESTRUCTIVE_WRITE_TOOL_ANNOTATIONS,
|
|
9204
9838
|
description: `Wait for the next thing Superblocks does on the recent or specified application and return it: "activity" carries Superblocks' words since the previous call (or a short heartbeat when Superblocks is quiet), and status is "building" while the app is still being generated. Returns as soon as Superblocks says anything, and after ~10 seconds of silence at the latest. Call within about 10 seconds of start_app, import_app, or edit_app so a plan or question surfaces quickly. Once the plan is approved and Superblocks is building, space later polls about 30 seconds apart (honor "nextPollAfterMs" when present) until status is no longer "building" \u2014 a 10-second cadence on a multi-minute build burns through the host's tool-call budget. Relay each new activity line to the user between calls. When status becomes "needs_decision", stop polling and put the decision to the user \u2014 for a plan, show it and ask whether to build it or say what to change; for multi_choice, relay the question and options. Hosts that support form elicitation get a native picker instead, and this tool then returns the answered turn. When status becomes "ready", follow with get_app so the user can open the preview. Progress is text-only (no MCP Apps widget) so each poll does not reopen a blank card. Optional "cursor" from a prior result resumes from that composite position (per producer, no global sequence); omit it to use the gateway's stored place for this caller.`,
|
|
9205
9839
|
inputSchema: {
|
|
9206
9840
|
applicationId: external_exports.string().uuid().optional(),
|
|
9207
9841
|
cursor: eventCursorInputSchema.optional()
|
|
9208
9842
|
},
|
|
9209
9843
|
title: "Check App Progress"
|
|
9210
|
-
}, async ({ applicationId, cursor }, extra) => run("check_app_progress", (
|
|
9844
|
+
}, async ({ applicationId, cursor }, extra) => run("check_app_progress", (context3, forgetFinishedTurn) => {
|
|
9211
9845
|
const parsed = cursor === void 0 ? void 0 : parseEventCursor(cursor);
|
|
9212
9846
|
gatewayDebug("progress cursor parsed", {
|
|
9213
9847
|
"progress.cursor_provided": cursor !== void 0,
|
|
9214
9848
|
"progress.cursor_valid": Boolean(parsed)
|
|
9215
9849
|
});
|
|
9216
|
-
return progressWithDecisionForm(
|
|
9850
|
+
return progressWithDecisionForm(context3, {
|
|
9217
9851
|
applicationId,
|
|
9218
9852
|
...parsed ? { cursor: parsed } : {}
|
|
9219
9853
|
}, extra, forgetFinishedTurn);
|
|
9220
9854
|
}, extra));
|
|
9221
9855
|
K3(server, "get_app", {
|
|
9856
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
9222
9857
|
description: 'Return editor and preview URLs for the recent or specified Superblocks application. Ensures a private preview build by default (same as preview_app), but only once Superblocks has something to show: while a plan or question is outstanding it returns status "needs_decision" with the "decision" and a "pendingAction" of "approve_plan" or "answer_question", while a turn is running it returns status "building", and when the last turn ended without writing anything it returns "timeout", "live_edit_terminated", "no_changes" or "cancelled" with pendingAction "retry_build" \u2014 no preview URLs and no screenshot in any of those cases, because the app is still the empty starter template. Act on "pendingAction" through edit_app instead of calling this again. Prefer this after check_app_progress reaches status "ready". Also the right call when you do not know where a build stands \u2014 after a reconnect, when no turn of yours is running, or when the conversation moved to another channel: pass wait false and read "status" and "cursor" from the result rather than guessing. Hosts that support MCP Apps show Open editor / Open preview buttons. When Superblocks has written code the result includes a screenshot of the live Vite canvas if a held session exists, otherwise the signed-in preview \u2014 never the edit URL.',
|
|
9223
9858
|
inputSchema: {
|
|
9224
9859
|
applicationId: external_exports.string().uuid().optional(),
|
|
@@ -9230,15 +9865,16 @@ function createMcpServer(deps) {
|
|
|
9230
9865
|
_meta: {
|
|
9231
9866
|
ui: { resourceUri: APP_STATUS_RESOURCE_URI }
|
|
9232
9867
|
}
|
|
9233
|
-
}, async ({ applicationId, branch, ensurePreview, wait }, extra) => run("get_app", (
|
|
9868
|
+
}, async ({ applicationId, branch, ensurePreview, wait }, extra) => run("get_app", (context3) => getApp(context3, { applicationId, branch, ensurePreview, wait }), extra));
|
|
9234
9869
|
server.registerTool("preview_app", {
|
|
9870
|
+
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
9235
9871
|
description: `Build the recent or specified Superblocks application's current work and return a URL that runs it, without deploying it \u2014 the same thing the editor's Preview button does. Only the user can open it. Status "ready" means the URL works now; "building" means the build is still running and calling again resumes watching it. Prefer get_app when you want the MCP Apps status card (Open editor / Open preview); this tool returns the same URLs as text/markdown without opening a second widget.`,
|
|
9236
9872
|
inputSchema: {
|
|
9237
9873
|
applicationId: external_exports.string().uuid().optional(),
|
|
9238
9874
|
branch: external_exports.string().optional()
|
|
9239
9875
|
},
|
|
9240
9876
|
title: "Preview App"
|
|
9241
|
-
}, async ({ applicationId, branch }, extra) => run("preview_app", (
|
|
9877
|
+
}, async ({ applicationId, branch }, extra) => run("preview_app", (context3) => previewApp(context3, { applicationId, branch }), extra));
|
|
9242
9878
|
const uiCsp = { csp: { frameDomains: [] } };
|
|
9243
9879
|
N3(server, "Gateway app status", APP_STATUS_RESOURCE_URI, {
|
|
9244
9880
|
description: "Status card with Open editor / Open preview / Publish app",
|
|
@@ -9255,6 +9891,7 @@ function createMcpServer(deps) {
|
|
|
9255
9891
|
]
|
|
9256
9892
|
}));
|
|
9257
9893
|
server.registerTool("publish_app", {
|
|
9894
|
+
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
9258
9895
|
description: "Publish/deploy the recent or specified Superblocks application and wait until it is live. Commits the application's current work first, so commitId is only needed to publish an earlier commit.",
|
|
9259
9896
|
inputSchema: {
|
|
9260
9897
|
applicationId: external_exports.string().uuid().optional(),
|
|
@@ -9264,7 +9901,7 @@ function createMcpServer(deps) {
|
|
|
9264
9901
|
prompt: external_exports.string().min(1)
|
|
9265
9902
|
},
|
|
9266
9903
|
title: "Publish App"
|
|
9267
|
-
}, async ({ applicationId, branch, commitId, idempotencyKey, prompt }, extra) => run("publish_app", (
|
|
9904
|
+
}, async ({ applicationId, branch, commitId, idempotencyKey, prompt }, extra) => run("publish_app", (context3) => publishApp(context3, {
|
|
9268
9905
|
applicationId,
|
|
9269
9906
|
branch,
|
|
9270
9907
|
commitId,
|
|
@@ -9284,6 +9921,7 @@ function createMcpServer(deps) {
|
|
|
9284
9921
|
async function createRuntime(apiKey) {
|
|
9285
9922
|
const config = loadConfig();
|
|
9286
9923
|
const stores = await createStores();
|
|
9924
|
+
const telemetry = startGatewayTelemetry({ apiKey, config });
|
|
9287
9925
|
const serverClient = new HttpSuperblocksServerClient(config.serverUrl);
|
|
9288
9926
|
const sessionPeer = new WebSocketSessionPeer({
|
|
9289
9927
|
beatLostGraceMs: config.beatLostGraceMs,
|
|
@@ -9301,6 +9939,7 @@ async function createRuntime(apiKey) {
|
|
|
9301
9939
|
cliApiKey: apiKey,
|
|
9302
9940
|
config,
|
|
9303
9941
|
events: stores.events,
|
|
9942
|
+
mcpTelemetry: telemetry.mcpTelemetry,
|
|
9304
9943
|
progressCursors: stores.progressCursors,
|
|
9305
9944
|
recentApps: stores.recentApps,
|
|
9306
9945
|
server: serverClient,
|
|
@@ -9312,7 +9951,7 @@ async function createRuntime(apiKey) {
|
|
|
9312
9951
|
deps,
|
|
9313
9952
|
close: async () => {
|
|
9314
9953
|
sessionPeer.closeAll();
|
|
9315
|
-
await stores.close();
|
|
9954
|
+
await Promise.allSettled([stores.close(), telemetry.shutdown()]);
|
|
9316
9955
|
}
|
|
9317
9956
|
};
|
|
9318
9957
|
}
|
|
@@ -9358,4 +9997,4 @@ export {
|
|
|
9358
9997
|
startApp,
|
|
9359
9998
|
startStdioGateway
|
|
9360
9999
|
};
|
|
9361
|
-
//# sourceMappingURL=dist-
|
|
10000
|
+
//# sourceMappingURL=dist-NJHWXUHQ.js.map
|