@inspecto-dev/plugin 0.3.9 → 0.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/astro.cjs +268 -100
- package/dist/astro.cjs.map +1 -1
- package/dist/astro.d.cts +1 -1
- package/dist/astro.d.ts +1 -1
- package/dist/astro.js +237 -68
- package/dist/astro.js.map +1 -1
- package/dist/index.cjs +255 -97
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +224 -65
- package/dist/index.js.map +1 -1
- package/dist/legacy/rspack/index.cjs +225 -88
- package/dist/legacy/rspack/index.cjs.map +1 -1
- package/dist/legacy/rspack/index.js +195 -57
- package/dist/legacy/rspack/index.js.map +1 -1
- package/dist/legacy/rspack/loader.cjs +1 -1
- package/dist/legacy/rspack/loader.cjs.map +1 -1
- package/dist/legacy/webpack4/index.cjs +225 -88
- package/dist/legacy/webpack4/index.cjs.map +1 -1
- package/dist/legacy/webpack4/index.js +195 -57
- package/dist/legacy/webpack4/index.js.map +1 -1
- package/dist/legacy/webpack4/loader.cjs +1 -1
- package/dist/legacy/webpack4/loader.cjs.map +1 -1
- package/dist/rollup.cjs +255 -97
- package/dist/rollup.cjs.map +1 -1
- package/dist/rollup.js +224 -65
- package/dist/rollup.js.map +1 -1
- package/dist/rspack.cjs +255 -97
- package/dist/rspack.cjs.map +1 -1
- package/dist/rspack.js +224 -65
- package/dist/rspack.js.map +1 -1
- package/dist/vite.cjs +255 -97
- package/dist/vite.cjs.map +1 -1
- package/dist/vite.js +224 -65
- package/dist/vite.js.map +1 -1
- package/dist/webpack.cjs +255 -97
- package/dist/webpack.cjs.map +1 -1
- package/dist/webpack.js +224 -65
- package/dist/webpack.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -43,7 +43,7 @@ __export(src_exports, {
|
|
|
43
43
|
});
|
|
44
44
|
module.exports = __toCommonJS(src_exports);
|
|
45
45
|
|
|
46
|
-
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.
|
|
46
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.7.0_postcss@8.5.14_typescript@5.9.3_yaml@2.8.4/node_modules/tsup/assets/cjs_shims.js
|
|
47
47
|
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
48
48
|
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
49
49
|
|
|
@@ -761,7 +761,7 @@ var import_node_path7 = __toESM(require("path"), 1);
|
|
|
761
761
|
var import_node_os2 = __toESM(require("os"), 1);
|
|
762
762
|
var import_node_crypto2 = __toESM(require("crypto"), 1);
|
|
763
763
|
var import_portfinder = __toESM(require("portfinder"), 1);
|
|
764
|
-
var
|
|
764
|
+
var import_types3 = require("@inspecto-dev/types");
|
|
765
765
|
|
|
766
766
|
// src/server/snippet.ts
|
|
767
767
|
var fs = __toESM(require("fs"), 1);
|
|
@@ -1123,13 +1123,28 @@ function resolveIntents(serverPrompts) {
|
|
|
1123
1123
|
);
|
|
1124
1124
|
continue;
|
|
1125
1125
|
}
|
|
1126
|
-
if (
|
|
1127
|
-
|
|
1128
|
-
|
|
1126
|
+
if (item.kind === "workflow") {
|
|
1127
|
+
if (!item.prompt) {
|
|
1128
|
+
configLogger.warn(`Workflow "${item.id}" missing required "prompt", skipping`);
|
|
1129
|
+
continue;
|
|
1130
|
+
}
|
|
1131
|
+
result.push({
|
|
1132
|
+
kind: "workflow",
|
|
1133
|
+
id: item.id,
|
|
1134
|
+
label: item.label ?? item.id,
|
|
1135
|
+
prompt: item.prompt,
|
|
1136
|
+
confirm: item.confirm ?? false,
|
|
1137
|
+
enabled: item.enabled ?? true
|
|
1138
|
+
});
|
|
1139
|
+
} else {
|
|
1140
|
+
if (!item.aiIntent) {
|
|
1141
|
+
configLogger.warn(`Intent "${item.id}" is missing required "aiIntent".`);
|
|
1142
|
+
continue;
|
|
1143
|
+
}
|
|
1144
|
+
result.push(
|
|
1145
|
+
baseMap.has(item.id) ? { ...baseMap.get(item.id), ...item } : item
|
|
1146
|
+
);
|
|
1129
1147
|
}
|
|
1130
|
-
result.push(
|
|
1131
|
-
baseMap.has(item.id) ? { ...baseMap.get(item.id), ...item } : item
|
|
1132
|
-
);
|
|
1133
1148
|
}
|
|
1134
1149
|
}
|
|
1135
1150
|
return result;
|
|
@@ -1149,26 +1164,61 @@ function resolveIntents(serverPrompts) {
|
|
|
1149
1164
|
configLogger.warn('Intent object missing required "id" field, skipping.');
|
|
1150
1165
|
continue;
|
|
1151
1166
|
}
|
|
1152
|
-
if (
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1167
|
+
if (item.kind === "workflow") {
|
|
1168
|
+
if (!item.prompt) {
|
|
1169
|
+
configLogger.warn(`Workflow "${item.id}" missing required "prompt", skipping`);
|
|
1170
|
+
continue;
|
|
1171
|
+
}
|
|
1172
|
+
const wfConfig = {
|
|
1173
|
+
kind: "workflow",
|
|
1174
|
+
id: item.id,
|
|
1175
|
+
label: item.label ?? item.id,
|
|
1176
|
+
prompt: item.prompt,
|
|
1177
|
+
confirm: item.confirm ?? false,
|
|
1178
|
+
enabled: item.enabled ?? true
|
|
1179
|
+
};
|
|
1180
|
+
const existingIdx = merged.findIndex((i2) => i2.id === item.id);
|
|
1181
|
+
if (existingIdx !== -1) {
|
|
1182
|
+
if (item.enabled === false) {
|
|
1183
|
+
merged.splice(existingIdx, 1);
|
|
1184
|
+
} else {
|
|
1185
|
+
merged[existingIdx] = wfConfig;
|
|
1186
|
+
}
|
|
1160
1187
|
} else {
|
|
1161
|
-
|
|
1188
|
+
if (item.enabled !== false) {
|
|
1189
|
+
merged.push(wfConfig);
|
|
1190
|
+
}
|
|
1162
1191
|
}
|
|
1163
1192
|
} else {
|
|
1164
|
-
if (item.
|
|
1165
|
-
|
|
1193
|
+
if (!item.aiIntent) {
|
|
1194
|
+
configLogger.warn(`Intent "${item.id}" is missing required "aiIntent".`);
|
|
1195
|
+
continue;
|
|
1196
|
+
}
|
|
1197
|
+
const existingIdx = merged.findIndex((i2) => i2.id === item.id);
|
|
1198
|
+
if (existingIdx !== -1) {
|
|
1199
|
+
if (item.enabled === false) {
|
|
1200
|
+
merged.splice(existingIdx, 1);
|
|
1201
|
+
} else {
|
|
1202
|
+
merged[existingIdx] = { ...merged[existingIdx], ...item };
|
|
1203
|
+
}
|
|
1204
|
+
} else {
|
|
1205
|
+
if (item.enabled !== false) {
|
|
1206
|
+
merged.push(item);
|
|
1207
|
+
}
|
|
1166
1208
|
}
|
|
1167
1209
|
}
|
|
1168
1210
|
}
|
|
1169
1211
|
}
|
|
1170
1212
|
return merged;
|
|
1171
1213
|
}
|
|
1214
|
+
function resolveWorkflowSlots(intents) {
|
|
1215
|
+
return intents.filter(import_types.isWorkflowConfig).filter((w3) => w3.enabled !== false).map((w3) => ({
|
|
1216
|
+
id: w3.id,
|
|
1217
|
+
label: w3.label ?? w3.id,
|
|
1218
|
+
prompt: w3.prompt,
|
|
1219
|
+
confirm: w3.confirm ?? false
|
|
1220
|
+
}));
|
|
1221
|
+
}
|
|
1172
1222
|
var watchers = [];
|
|
1173
1223
|
function watchConfig(onReload, cwd = process.cwd(), gitRoot) {
|
|
1174
1224
|
if (isWatching) return;
|
|
@@ -1398,6 +1448,10 @@ function assertPathWithinIdeOpenScope(file, projectRoot) {
|
|
|
1398
1448
|
}
|
|
1399
1449
|
}
|
|
1400
1450
|
|
|
1451
|
+
// src/server/annotation-dispatch.ts
|
|
1452
|
+
var import_node_child_process2 = require("child_process");
|
|
1453
|
+
var import_node_util = require("util");
|
|
1454
|
+
|
|
1401
1455
|
// src/server/session-store.ts
|
|
1402
1456
|
var DEFAULT_STATUS = "pending";
|
|
1403
1457
|
function createAnnotationSessionStore(options = {}) {
|
|
@@ -1405,8 +1459,12 @@ function createAnnotationSessionStore(options = {}) {
|
|
|
1405
1459
|
const listeners = /* @__PURE__ */ new Set();
|
|
1406
1460
|
const now = options.now ?? (() => Date.now());
|
|
1407
1461
|
const createId = options.createId ?? createRandomId;
|
|
1408
|
-
function findNewestMatchingSession(statuses) {
|
|
1409
|
-
return [...sessions.values()].filter((session) =>
|
|
1462
|
+
function findNewestMatchingSession(statuses, source) {
|
|
1463
|
+
return [...sessions.values()].filter((session) => {
|
|
1464
|
+
if (statuses && !statuses.has(session.status)) return false;
|
|
1465
|
+
if (source && session.source !== source) return false;
|
|
1466
|
+
return true;
|
|
1467
|
+
}).sort((left, right) => right.updatedAt - left.updatedAt)[0] ?? null;
|
|
1410
1468
|
}
|
|
1411
1469
|
function updateSessionStatus(id, status) {
|
|
1412
1470
|
const session = sessions.get(id);
|
|
@@ -1466,7 +1524,7 @@ function createAnnotationSessionStore(options = {}) {
|
|
|
1466
1524
|
},
|
|
1467
1525
|
async claimNextSession(options2 = {}) {
|
|
1468
1526
|
const statuses = normalizeStatuses(DEFAULT_STATUS);
|
|
1469
|
-
const existingSession = findNewestMatchingSession(statuses);
|
|
1527
|
+
const existingSession = findNewestMatchingSession(statuses, options2.source);
|
|
1470
1528
|
if (existingSession) {
|
|
1471
1529
|
return {
|
|
1472
1530
|
session: claimSession(existingSession.id, statuses),
|
|
@@ -1581,6 +1639,7 @@ function cloneValue(value) {
|
|
|
1581
1639
|
}
|
|
1582
1640
|
|
|
1583
1641
|
// src/server/annotation-dispatch.ts
|
|
1642
|
+
var execAsync = (0, import_node_util.promisify)(import_node_child_process2.exec);
|
|
1584
1643
|
var AnnotationDispatchError = class extends Error {
|
|
1585
1644
|
constructor(message, errorCode) {
|
|
1586
1645
|
super(message);
|
|
@@ -1592,9 +1651,14 @@ async function dispatchAnnotationsToAi(req, state, store = annotationSessionStor
|
|
|
1592
1651
|
try {
|
|
1593
1652
|
validateAnnotationDispatchRequest(req, state);
|
|
1594
1653
|
const batch = normalizeAnnotationBatch(req);
|
|
1595
|
-
|
|
1654
|
+
let prompt = buildAnnotationBatchPrompt(batch);
|
|
1655
|
+
if (req.source === "workflow") {
|
|
1656
|
+
prompt = await appendProjectMetadata(prompt, state);
|
|
1657
|
+
}
|
|
1596
1658
|
const deliveryMode = normalizeDeliveryMode(req.deliveryMode);
|
|
1597
1659
|
const session = store.createSession({
|
|
1660
|
+
source: req.source || "annotation",
|
|
1661
|
+
...req.workflowId ? { workflowId: req.workflowId } : {},
|
|
1598
1662
|
instruction: batch.instruction,
|
|
1599
1663
|
annotations: toSessionAnnotations(batch.annotations),
|
|
1600
1664
|
deliveryMode,
|
|
@@ -1620,6 +1684,33 @@ async function dispatchAnnotationsToAi(req, state, store = annotationSessionStor
|
|
|
1620
1684
|
};
|
|
1621
1685
|
}
|
|
1622
1686
|
}
|
|
1687
|
+
async function appendProjectMetadata(prompt, state) {
|
|
1688
|
+
const lines = ["\n## Project"];
|
|
1689
|
+
lines.push(`- Root: ${state.projectRoot}`);
|
|
1690
|
+
try {
|
|
1691
|
+
const options = {
|
|
1692
|
+
cwd: state.projectRoot,
|
|
1693
|
+
encoding: "utf-8",
|
|
1694
|
+
timeout: 2e3
|
|
1695
|
+
};
|
|
1696
|
+
const { stdout: branchStdout } = await execAsync("git branch --show-current", options);
|
|
1697
|
+
const branch = branchStdout.trim();
|
|
1698
|
+
lines.push(`- Branch: ${branch}`);
|
|
1699
|
+
const { stdout: statusStdout } = await execAsync("git status --porcelain", options);
|
|
1700
|
+
const statusRaw = statusStdout.trim();
|
|
1701
|
+
const entries = statusRaw ? statusRaw.split("\n") : [];
|
|
1702
|
+
const staged = entries.filter((l) => l[0] !== " " && l[0] !== "?").length;
|
|
1703
|
+
const unstaged = entries.filter((l) => l[1] !== " " && l[1] !== "?").length;
|
|
1704
|
+
const untracked = entries.filter((l) => l[0] === "?").length;
|
|
1705
|
+
lines.push(`- Status: ${staged} staged, ${unstaged} unstaged, ${untracked} untracked`);
|
|
1706
|
+
} catch (err) {
|
|
1707
|
+
console.warn("[inspecto] Failed to get git status for workflow:", err);
|
|
1708
|
+
lines.push("- Git: unavailable or check timeout");
|
|
1709
|
+
}
|
|
1710
|
+
return `${prompt}
|
|
1711
|
+
|
|
1712
|
+
${lines.join("\n")}`;
|
|
1713
|
+
}
|
|
1623
1714
|
function normalizeDeliveryMode(input) {
|
|
1624
1715
|
return input === "agent" ? "agent" : "ide";
|
|
1625
1716
|
}
|
|
@@ -1656,7 +1747,7 @@ function toSessionSummary(session) {
|
|
|
1656
1747
|
};
|
|
1657
1748
|
}
|
|
1658
1749
|
function validateAnnotationDispatchRequest(req, state) {
|
|
1659
|
-
if (!req.annotations.length) {
|
|
1750
|
+
if (!req.annotations.length && req.source !== "workflow") {
|
|
1660
1751
|
throw new AnnotationDispatchError("At least one annotation is required.", "INVALID_REQUEST");
|
|
1661
1752
|
}
|
|
1662
1753
|
for (const annotation of req.annotations) {
|
|
@@ -1758,6 +1849,7 @@ function getAnnotationDispatchErrorCode(error) {
|
|
|
1758
1849
|
}
|
|
1759
1850
|
|
|
1760
1851
|
// src/server/client-config.ts
|
|
1852
|
+
var import_types2 = require("@inspecto-dev/types");
|
|
1761
1853
|
async function buildClientConfig(serverState2) {
|
|
1762
1854
|
const userConfig = loadUserConfigSync(false, serverState2.cwd, serverState2.configRoot);
|
|
1763
1855
|
const promptsConfig = await loadPromptsConfig(false, serverState2.cwd, serverState2.configRoot);
|
|
@@ -1769,11 +1861,13 @@ async function buildClientConfig(serverState2) {
|
|
|
1769
1861
|
const { scheme: _scheme, ...rest } = serverState2.ideInfo;
|
|
1770
1862
|
info = rest;
|
|
1771
1863
|
}
|
|
1864
|
+
const allIntents = resolveIntents(promptsConfig);
|
|
1772
1865
|
return {
|
|
1773
1866
|
...info,
|
|
1774
|
-
prompts:
|
|
1867
|
+
prompts: allIntents.filter(import_types2.isAiIntentConfig),
|
|
1868
|
+
workflows: resolveWorkflowSlots(allIntents),
|
|
1775
1869
|
hotKeys: userConfig["inspector.hotKey"] ?? "alt",
|
|
1776
|
-
annotateDeliveryMode: userConfig["annotate.deliveryMode"] ?? "
|
|
1870
|
+
annotateDeliveryMode: userConfig["annotate.deliveryMode"] ?? "agent",
|
|
1777
1871
|
includeSnippet: userConfig["prompt.includeSnippet"] ?? false,
|
|
1778
1872
|
runtimeContext: {
|
|
1779
1873
|
enabled: true,
|
|
@@ -1786,7 +1880,7 @@ async function buildClientConfig(serverState2) {
|
|
|
1786
1880
|
}
|
|
1787
1881
|
|
|
1788
1882
|
// src/server/open-file.ts
|
|
1789
|
-
var
|
|
1883
|
+
var import_node_child_process3 = require("child_process");
|
|
1790
1884
|
var import_launch_ide2 = require("launch-ide");
|
|
1791
1885
|
var serverLogger2 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
1792
1886
|
var VSCODE_FAMILY_SCHEMES = [
|
|
@@ -1837,11 +1931,11 @@ function handleOpenFileRequest(body, serverState2) {
|
|
|
1837
1931
|
serverLogger2.debug(`SOURCE_OPEN: Bypassing launchIDE, using URI scheme directly: ${uri}`);
|
|
1838
1932
|
try {
|
|
1839
1933
|
if (process.platform === "darwin") {
|
|
1840
|
-
(0,
|
|
1934
|
+
(0, import_node_child_process3.execFileSync)("open", [uri]);
|
|
1841
1935
|
} else if (process.platform === "win32") {
|
|
1842
|
-
(0,
|
|
1936
|
+
(0, import_node_child_process3.execFileSync)("cmd", ["/c", "start", '""', uri]);
|
|
1843
1937
|
} else {
|
|
1844
|
-
(0,
|
|
1938
|
+
(0, import_node_child_process3.execFileSync)("xdg-open", [uri]);
|
|
1845
1939
|
}
|
|
1846
1940
|
} catch (e) {
|
|
1847
1941
|
serverLogger2.error(`Failed to launch URI for SOURCE_OPEN (${uri}):`, e);
|
|
@@ -1868,35 +1962,72 @@ function handleOpenFileRequest(body, serverState2) {
|
|
|
1868
1962
|
// src/server/project-root.ts
|
|
1869
1963
|
var import_node_fs3 = __toESM(require("fs"), 1);
|
|
1870
1964
|
var import_node_path6 = __toESM(require("path"), 1);
|
|
1871
|
-
var
|
|
1965
|
+
var import_node_child_process4 = require("child_process");
|
|
1872
1966
|
var serverLogger3 = createLogger("inspecto:server", { logLevel: getGlobalLogLevel() });
|
|
1873
|
-
function
|
|
1874
|
-
const cwd = process.cwd();
|
|
1875
|
-
let gitRoot;
|
|
1967
|
+
function resolveGitRoot(_cwd) {
|
|
1876
1968
|
try {
|
|
1877
|
-
|
|
1969
|
+
const output = (0, import_node_child_process4.execSync)("git rev-parse --show-toplevel", { encoding: "utf-8" });
|
|
1970
|
+
return typeof output === "string" ? output.trim() : null;
|
|
1878
1971
|
} catch (e) {
|
|
1879
1972
|
serverLogger3.warn("Failed to resolve git root via git rev-parse:", e);
|
|
1880
|
-
gitRoot = cwd;
|
|
1881
|
-
}
|
|
1882
|
-
const visited = /* @__PURE__ */ new Set();
|
|
1883
|
-
const search = (start, stop) => {
|
|
1884
|
-
let current = start;
|
|
1885
|
-
while (!visited.has(current)) {
|
|
1886
|
-
visited.add(current);
|
|
1887
|
-
if (import_node_fs3.default.existsSync(import_node_path6.default.join(current, ".inspecto"))) return current;
|
|
1888
|
-
if (current === stop) break;
|
|
1889
|
-
const parent = import_node_path6.default.dirname(current);
|
|
1890
|
-
if (parent === current) break;
|
|
1891
|
-
current = parent;
|
|
1892
|
-
}
|
|
1893
1973
|
return null;
|
|
1894
|
-
}
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
function findNearestAncestorWith(start, predicate) {
|
|
1977
|
+
let current = start;
|
|
1978
|
+
while (true) {
|
|
1979
|
+
if (predicate(current)) return current;
|
|
1980
|
+
const parent = import_node_path6.default.dirname(current);
|
|
1981
|
+
if (parent === current) break;
|
|
1982
|
+
current = parent;
|
|
1983
|
+
}
|
|
1984
|
+
return null;
|
|
1985
|
+
}
|
|
1986
|
+
function resolveWorkspaceRoot() {
|
|
1987
|
+
const cwd = process.cwd();
|
|
1988
|
+
const inspectoRoot = findNearestAncestorWith(
|
|
1989
|
+
cwd,
|
|
1990
|
+
(dir) => import_node_fs3.default.existsSync(import_node_path6.default.join(dir, ".inspecto"))
|
|
1991
|
+
);
|
|
1992
|
+
if (inspectoRoot) return inspectoRoot;
|
|
1993
|
+
const packageRoot = findNearestAncestorWith(
|
|
1994
|
+
cwd,
|
|
1995
|
+
(dir) => import_node_fs3.default.existsSync(import_node_path6.default.join(dir, "package.json"))
|
|
1996
|
+
);
|
|
1997
|
+
if (packageRoot) return packageRoot;
|
|
1998
|
+
return resolveGitRoot(cwd) ?? cwd;
|
|
1999
|
+
}
|
|
2000
|
+
function resolveProjectRoot() {
|
|
2001
|
+
const cwd = process.cwd();
|
|
2002
|
+
const packageRoot = findNearestAncestorWith(
|
|
2003
|
+
cwd,
|
|
2004
|
+
(dir) => import_node_fs3.default.existsSync(import_node_path6.default.join(dir, "package.json"))
|
|
2005
|
+
);
|
|
2006
|
+
if (packageRoot) return packageRoot;
|
|
2007
|
+
const inspectoRoot = findNearestAncestorWith(
|
|
2008
|
+
cwd,
|
|
2009
|
+
(dir) => import_node_fs3.default.existsSync(import_node_path6.default.join(dir, ".inspecto"))
|
|
2010
|
+
);
|
|
2011
|
+
if (inspectoRoot) return inspectoRoot;
|
|
2012
|
+
return resolveGitRoot(cwd) ?? cwd;
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
// src/server/server-url.ts
|
|
2016
|
+
function resolveServerHost(cwd, configRoot) {
|
|
2017
|
+
if (process.env["VITEST"]) return "127.0.0.1";
|
|
2018
|
+
const userConfig = loadUserConfigSync(false, cwd, configRoot);
|
|
2019
|
+
const configuredHost = userConfig["server.host"]?.trim();
|
|
2020
|
+
if (configuredHost) return configuredHost;
|
|
2021
|
+
return "127.0.0.1";
|
|
2022
|
+
}
|
|
2023
|
+
function resolvePublicServerUrl(args) {
|
|
2024
|
+
const userConfig = loadUserConfigSync(false, args.cwd, args.configRoot);
|
|
2025
|
+
const configuredPublicUrl = userConfig["server.publicUrl"]?.trim();
|
|
2026
|
+
if (configuredPublicUrl) {
|
|
2027
|
+
return configuredPublicUrl.replace(/\/$/, "");
|
|
2028
|
+
}
|
|
2029
|
+
const host = resolveServerHost(args.cwd, args.configRoot);
|
|
2030
|
+
return `http://${host}:${args.port}`;
|
|
1900
2031
|
}
|
|
1901
2032
|
|
|
1902
2033
|
// src/server/index.ts
|
|
@@ -1951,8 +2082,9 @@ async function startServer() {
|
|
|
1951
2082
|
return serverState.port;
|
|
1952
2083
|
}
|
|
1953
2084
|
serverState.projectRoot = resolveProjectRoot();
|
|
1954
|
-
serverState.configRoot =
|
|
2085
|
+
serverState.configRoot = resolveWorkspaceRoot();
|
|
1955
2086
|
serverState.cwd = process.cwd();
|
|
2087
|
+
const serverHost = resolveServerHost(serverState.cwd, serverState.configRoot);
|
|
1956
2088
|
import_portfinder.default.basePort = 5678;
|
|
1957
2089
|
const port = await import_portfinder.default.getPortPromise();
|
|
1958
2090
|
watchConfig(
|
|
@@ -1979,7 +2111,7 @@ async function startServer() {
|
|
|
1979
2111
|
});
|
|
1980
2112
|
});
|
|
1981
2113
|
await new Promise((resolve2, reject) => {
|
|
1982
|
-
serverInstance.listen(port,
|
|
2114
|
+
serverInstance.listen(port, serverHost, () => {
|
|
1983
2115
|
serverInstance.unref();
|
|
1984
2116
|
resolve2();
|
|
1985
2117
|
});
|
|
@@ -2001,7 +2133,7 @@ async function startServer() {
|
|
|
2001
2133
|
} catch {
|
|
2002
2134
|
}
|
|
2003
2135
|
});
|
|
2004
|
-
serverLogger4.info(`server running at http
|
|
2136
|
+
serverLogger4.info(`server running at http://${serverHost}:${port}`);
|
|
2005
2137
|
return port;
|
|
2006
2138
|
}
|
|
2007
2139
|
async function readBody(req) {
|
|
@@ -2014,19 +2146,19 @@ async function readBody(req) {
|
|
|
2014
2146
|
}
|
|
2015
2147
|
async function handleRequest(url, req, res) {
|
|
2016
2148
|
const pathname = url.pathname;
|
|
2017
|
-
if ((pathname === "/health" || pathname ===
|
|
2149
|
+
if ((pathname === "/health" || pathname === import_types3.INSPECTO_API_PATHS.HEALTH) && req.method === "GET") {
|
|
2018
2150
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2019
2151
|
res.end(JSON.stringify({ ok: true, port: serverState.port }));
|
|
2020
2152
|
return;
|
|
2021
2153
|
}
|
|
2022
|
-
if (pathname ===
|
|
2154
|
+
if (pathname === import_types3.INSPECTO_API_PATHS.CLIENT_CONFIG && req.method === "GET") {
|
|
2023
2155
|
const config = await buildClientConfig(serverState);
|
|
2024
2156
|
delete config.providers;
|
|
2025
2157
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2026
2158
|
res.end(JSON.stringify(config));
|
|
2027
2159
|
return;
|
|
2028
2160
|
}
|
|
2029
|
-
if (pathname ===
|
|
2161
|
+
if (pathname === import_types3.INSPECTO_API_PATHS.IDE_INFO && req.method === "POST") {
|
|
2030
2162
|
try {
|
|
2031
2163
|
const body = JSON.parse(await readBody(req));
|
|
2032
2164
|
const ideWorkspace = body.workspaceRoot || "";
|
|
@@ -2047,13 +2179,13 @@ async function handleRequest(url, req, res) {
|
|
|
2047
2179
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2048
2180
|
res.end(JSON.stringify({ success: true }));
|
|
2049
2181
|
} catch (e) {
|
|
2050
|
-
serverLogger4.error(`Error parsing ${
|
|
2182
|
+
serverLogger4.error(`Error parsing ${import_types3.INSPECTO_API_PATHS.IDE_INFO} POST request:`, e);
|
|
2051
2183
|
res.writeHead(400, { "Content-Type": "application/json" });
|
|
2052
2184
|
res.end(JSON.stringify({ error: "Invalid JSON body" }));
|
|
2053
2185
|
}
|
|
2054
2186
|
return;
|
|
2055
2187
|
}
|
|
2056
|
-
if ((pathname ===
|
|
2188
|
+
if ((pathname === import_types3.INSPECTO_API_PATHS.SOURCE_OPEN || pathname === import_types3.INSPECTO_API_PATHS.IDE_OPEN) && req.method === "POST") {
|
|
2057
2189
|
let body;
|
|
2058
2190
|
try {
|
|
2059
2191
|
body = JSON.parse(await readBody(req));
|
|
@@ -2076,7 +2208,7 @@ async function handleRequest(url, req, res) {
|
|
|
2076
2208
|
res.end(JSON.stringify({ success: true }));
|
|
2077
2209
|
return;
|
|
2078
2210
|
}
|
|
2079
|
-
if (pathname ===
|
|
2211
|
+
if (pathname === import_types3.INSPECTO_API_PATHS.PROJECT_SNIPPET && req.method === "GET") {
|
|
2080
2212
|
const file = url.searchParams.get("file") ?? "";
|
|
2081
2213
|
const line = parseInt(url.searchParams.get("line") ?? "1", 10);
|
|
2082
2214
|
const column = parseInt(url.searchParams.get("column") ?? "1", 10);
|
|
@@ -2110,7 +2242,7 @@ async function handleRequest(url, req, res) {
|
|
|
2110
2242
|
}
|
|
2111
2243
|
return;
|
|
2112
2244
|
}
|
|
2113
|
-
if (pathname ===
|
|
2245
|
+
if (pathname === import_types3.INSPECTO_API_PATHS.AI_DISPATCH && req.method === "POST") {
|
|
2114
2246
|
try {
|
|
2115
2247
|
const rawBody = await readBody(req);
|
|
2116
2248
|
const body = JSON.parse(rawBody);
|
|
@@ -2118,13 +2250,13 @@ async function handleRequest(url, req, res) {
|
|
|
2118
2250
|
res.writeHead(result.success ? 200 : 500, { "Content-Type": "application/json" });
|
|
2119
2251
|
res.end(JSON.stringify(result));
|
|
2120
2252
|
} catch (e) {
|
|
2121
|
-
serverLogger4.error(`Error parsing ${
|
|
2253
|
+
serverLogger4.error(`Error parsing ${import_types3.INSPECTO_API_PATHS.AI_DISPATCH} request:`, e);
|
|
2122
2254
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2123
2255
|
res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
|
|
2124
2256
|
}
|
|
2125
2257
|
return;
|
|
2126
2258
|
}
|
|
2127
|
-
if (pathname ===
|
|
2259
|
+
if (pathname === import_types3.INSPECTO_API_PATHS.AI_BATCH_DISPATCH && req.method === "POST") {
|
|
2128
2260
|
try {
|
|
2129
2261
|
const rawBody = await readBody(req);
|
|
2130
2262
|
const body = JSON.parse(rawBody);
|
|
@@ -2134,13 +2266,13 @@ async function handleRequest(url, req, res) {
|
|
|
2134
2266
|
});
|
|
2135
2267
|
res.end(JSON.stringify(result));
|
|
2136
2268
|
} catch (e) {
|
|
2137
|
-
serverLogger4.error(`Error parsing ${
|
|
2269
|
+
serverLogger4.error(`Error parsing ${import_types3.INSPECTO_API_PATHS.AI_BATCH_DISPATCH} request:`, e);
|
|
2138
2270
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2139
2271
|
res.end(JSON.stringify({ success: false, error: String(e), errorCode: "INTERNAL_ERROR" }));
|
|
2140
2272
|
}
|
|
2141
2273
|
return;
|
|
2142
2274
|
}
|
|
2143
|
-
if (pathname ===
|
|
2275
|
+
if (pathname === import_types3.INSPECTO_API_PATHS.SESSION_CLAIM_NEXT && req.method === "POST") {
|
|
2144
2276
|
try {
|
|
2145
2277
|
const rawBody = await readBody(req);
|
|
2146
2278
|
const body = rawBody ? JSON.parse(rawBody) : {};
|
|
@@ -2167,7 +2299,7 @@ async function handleRequest(url, req, res) {
|
|
|
2167
2299
|
}
|
|
2168
2300
|
return;
|
|
2169
2301
|
}
|
|
2170
|
-
if (pathname ===
|
|
2302
|
+
if (pathname === import_types3.INSPECTO_API_PATHS.SESSION_EVENTS && req.method === "GET") {
|
|
2171
2303
|
const statusParam = url.searchParams.getAll("status");
|
|
2172
2304
|
const statuses = statusParam.length ? new Set(statusParam) : null;
|
|
2173
2305
|
const sessionId = url.searchParams.get("sessionId")?.trim() || null;
|
|
@@ -2195,7 +2327,7 @@ data: ${JSON.stringify({ ok: true })}
|
|
|
2195
2327
|
});
|
|
2196
2328
|
return;
|
|
2197
2329
|
}
|
|
2198
|
-
if (pathname ===
|
|
2330
|
+
if (pathname === import_types3.INSPECTO_API_PATHS.SESSIONS && req.method === "GET") {
|
|
2199
2331
|
const statusParam = url.searchParams.getAll("status");
|
|
2200
2332
|
const sessions = annotationSessionStore.listSessions(
|
|
2201
2333
|
statusParam.length ? {
|
|
@@ -2206,8 +2338,8 @@ data: ${JSON.stringify({ ok: true })}
|
|
|
2206
2338
|
res.end(JSON.stringify({ success: true, sessions }));
|
|
2207
2339
|
return;
|
|
2208
2340
|
}
|
|
2209
|
-
if (pathname.startsWith(`${
|
|
2210
|
-
const sessionId = pathname.substring(
|
|
2341
|
+
if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.SESSIONS}/`) && req.method === "GET") {
|
|
2342
|
+
const sessionId = pathname.substring(import_types3.INSPECTO_API_PATHS.SESSIONS.length + 1);
|
|
2211
2343
|
const session = annotationSessionStore.getSession(sessionId);
|
|
2212
2344
|
if (!session) {
|
|
2213
2345
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
@@ -2218,10 +2350,10 @@ data: ${JSON.stringify({ ok: true })}
|
|
|
2218
2350
|
res.end(JSON.stringify({ success: true, session }));
|
|
2219
2351
|
return;
|
|
2220
2352
|
}
|
|
2221
|
-
if (pathname.startsWith(`${
|
|
2353
|
+
if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types3.INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX) && req.method === "POST") {
|
|
2222
2354
|
const sessionId = pathname.slice(
|
|
2223
|
-
|
|
2224
|
-
-
|
|
2355
|
+
import_types3.INSPECTO_API_PATHS.SESSIONS.length + 1,
|
|
2356
|
+
-import_types3.INSPECTO_API_PATHS.SESSION_REPLY_SUFFIX.length
|
|
2225
2357
|
);
|
|
2226
2358
|
try {
|
|
2227
2359
|
const rawBody = await readBody(req);
|
|
@@ -2254,10 +2386,10 @@ data: ${JSON.stringify({ ok: true })}
|
|
|
2254
2386
|
}
|
|
2255
2387
|
return;
|
|
2256
2388
|
}
|
|
2257
|
-
if (pathname.startsWith(`${
|
|
2389
|
+
if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types3.INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX) && req.method === "POST") {
|
|
2258
2390
|
const sessionId = pathname.slice(
|
|
2259
|
-
|
|
2260
|
-
-
|
|
2391
|
+
import_types3.INSPECTO_API_PATHS.SESSIONS.length + 1,
|
|
2392
|
+
-import_types3.INSPECTO_API_PATHS.SESSION_RESOLVE_SUFFIX.length
|
|
2261
2393
|
);
|
|
2262
2394
|
try {
|
|
2263
2395
|
const rawBody = await readBody(req);
|
|
@@ -2305,10 +2437,10 @@ data: ${JSON.stringify({ ok: true })}
|
|
|
2305
2437
|
}
|
|
2306
2438
|
return;
|
|
2307
2439
|
}
|
|
2308
|
-
if (pathname.startsWith(`${
|
|
2440
|
+
if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.SESSIONS}/`) && pathname.endsWith(import_types3.INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX) && req.method === "POST") {
|
|
2309
2441
|
const sessionId = pathname.slice(
|
|
2310
|
-
|
|
2311
|
-
-
|
|
2442
|
+
import_types3.INSPECTO_API_PATHS.SESSIONS.length + 1,
|
|
2443
|
+
-import_types3.INSPECTO_API_PATHS.SESSION_DISMISS_SUFFIX.length
|
|
2312
2444
|
);
|
|
2313
2445
|
try {
|
|
2314
2446
|
const rawBody = await readBody(req);
|
|
@@ -2346,8 +2478,8 @@ data: ${JSON.stringify({ ok: true })}
|
|
|
2346
2478
|
}
|
|
2347
2479
|
return;
|
|
2348
2480
|
}
|
|
2349
|
-
if (pathname.startsWith(`${
|
|
2350
|
-
const ticketId = pathname.substring(
|
|
2481
|
+
if (pathname.startsWith(`${import_types3.INSPECTO_API_PATHS.AI_TICKET}/`) && req.method === "GET") {
|
|
2482
|
+
const ticketId = pathname.substring(import_types3.INSPECTO_API_PATHS.AI_TICKET.length + 1);
|
|
2351
2483
|
const payloadStr = readTicket(ticketId);
|
|
2352
2484
|
if (!payloadStr) {
|
|
2353
2485
|
res.writeHead(404, { "Content-Type": "application/json" });
|
|
@@ -2363,10 +2495,23 @@ data: ${JSON.stringify({ ok: true })}
|
|
|
2363
2495
|
}
|
|
2364
2496
|
async function dispatchToAi(req) {
|
|
2365
2497
|
const { location, snippet, prompt } = req;
|
|
2366
|
-
|
|
2498
|
+
if (prompt?.trim()) {
|
|
2499
|
+
const runtime2 = resolvePromptDispatchRuntime(serverState);
|
|
2500
|
+
return dispatchPromptThroughIde(runtime2, {
|
|
2501
|
+
prompt: prompt.trim()
|
|
2502
|
+
});
|
|
2503
|
+
}
|
|
2504
|
+
if (!location) {
|
|
2505
|
+
return {
|
|
2506
|
+
success: false,
|
|
2507
|
+
error: "Source location is required when prompt is omitted.",
|
|
2508
|
+
errorCode: "INVALID_REQUEST"
|
|
2509
|
+
};
|
|
2510
|
+
}
|
|
2511
|
+
const formattedPrompt = `Please help me with this code from \`${location.file}\` (line ${location.line}):
|
|
2367
2512
|
|
|
2368
2513
|
\`\`\`
|
|
2369
|
-
${snippet}
|
|
2514
|
+
${snippet ?? ""}
|
|
2370
2515
|
\`\`\`
|
|
2371
2516
|
`;
|
|
2372
2517
|
const runtime = resolvePromptDispatchRuntime(serverState);
|
|
@@ -2375,7 +2520,7 @@ ${snippet}
|
|
|
2375
2520
|
filePath: location.file,
|
|
2376
2521
|
line: location.line,
|
|
2377
2522
|
column: location.column,
|
|
2378
|
-
snippet
|
|
2523
|
+
...snippet !== void 0 ? { snippet } : {}
|
|
2379
2524
|
});
|
|
2380
2525
|
}
|
|
2381
2526
|
function getBatchDispatchStatusCode(errorCode, success) {
|
|
@@ -2418,26 +2563,28 @@ var resolveClientModule = () => {
|
|
|
2418
2563
|
};
|
|
2419
2564
|
|
|
2420
2565
|
// src/injectors/webpack.ts
|
|
2421
|
-
function getWebpackHtmlScript(serverPort) {
|
|
2566
|
+
function getWebpackHtmlScript(serverPort, publicServerUrl) {
|
|
2422
2567
|
return `
|
|
2423
2568
|
window.__AI_INSPECTOR_PORT__ = ${serverPort};
|
|
2569
|
+
window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
|
|
2424
2570
|
window.addEventListener('load', () => {
|
|
2425
2571
|
if (window.InspectoClient) {
|
|
2426
2572
|
window.InspectoClient.mountInspector({
|
|
2427
|
-
serverUrl:
|
|
2573
|
+
serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
|
|
2428
2574
|
});
|
|
2429
2575
|
}
|
|
2430
2576
|
});
|
|
2431
2577
|
`;
|
|
2432
2578
|
}
|
|
2433
|
-
function getWebpackAssetScript(serverPort) {
|
|
2579
|
+
function getWebpackAssetScript(serverPort, publicServerUrl) {
|
|
2434
2580
|
return `
|
|
2435
2581
|
if (typeof window !== 'undefined') {
|
|
2436
2582
|
window.__AI_INSPECTOR_PORT__ = ${serverPort};
|
|
2583
|
+
window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
|
|
2437
2584
|
const _initInspecto = () => {
|
|
2438
2585
|
if (window.InspectoClient) {
|
|
2439
2586
|
window.InspectoClient.mountInspector({
|
|
2440
|
-
serverUrl:
|
|
2587
|
+
serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
|
|
2441
2588
|
});
|
|
2442
2589
|
} else {
|
|
2443
2590
|
setTimeout(_initInspecto, 100);
|
|
@@ -2451,7 +2598,7 @@ if (typeof window !== 'undefined') {
|
|
|
2451
2598
|
}
|
|
2452
2599
|
`;
|
|
2453
2600
|
}
|
|
2454
|
-
function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
|
|
2601
|
+
function injectWebpack(compiler, serverPortFn, publicServerUrlFn, resolveClientModule2) {
|
|
2455
2602
|
const inspectoClientPath = resolveClientModule2();
|
|
2456
2603
|
if (compiler.webpack && compiler.webpack.EntryPlugin) {
|
|
2457
2604
|
new compiler.webpack.EntryPlugin(compiler.context, inspectoClientPath, {
|
|
@@ -2466,11 +2613,12 @@ function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
|
|
|
2466
2613
|
const hooks = HtmlWebpackPlugin.constructor.getHooks(compilation);
|
|
2467
2614
|
hooks.alterAssetTagGroups.tapPromise("inspecto-overlay", async (data) => {
|
|
2468
2615
|
const port = await serverPortFn();
|
|
2616
|
+
const publicServerUrl = publicServerUrlFn(port);
|
|
2469
2617
|
data.headTags.unshift({
|
|
2470
2618
|
tagName: "script",
|
|
2471
2619
|
voidTag: false,
|
|
2472
2620
|
meta: { plugin: "inspecto-overlay" },
|
|
2473
|
-
innerHTML: getWebpackHtmlScript(port)
|
|
2621
|
+
innerHTML: getWebpackHtmlScript(port, publicServerUrl)
|
|
2474
2622
|
});
|
|
2475
2623
|
return data;
|
|
2476
2624
|
});
|
|
@@ -2483,13 +2631,14 @@ function injectWebpack(compiler, serverPortFn, resolveClientModule2) {
|
|
|
2483
2631
|
},
|
|
2484
2632
|
async (assets) => {
|
|
2485
2633
|
const port = await serverPortFn();
|
|
2634
|
+
const publicServerUrl = publicServerUrlFn(port);
|
|
2486
2635
|
const mainAssetKey = Object.keys(assets).find(
|
|
2487
2636
|
(key) => key.endsWith(".js") && (key.includes("main") || key.includes("app") || key.includes("umi"))
|
|
2488
2637
|
);
|
|
2489
2638
|
if (!mainAssetKey) return;
|
|
2490
2639
|
const originalSource = assets[mainAssetKey].source();
|
|
2491
2640
|
assets[mainAssetKey] = new compiler.webpack.sources.RawSource(
|
|
2492
|
-
getWebpackAssetScript(port) + "\n" + originalSource
|
|
2641
|
+
getWebpackAssetScript(port, publicServerUrl) + "\n" + originalSource
|
|
2493
2642
|
);
|
|
2494
2643
|
}
|
|
2495
2644
|
);
|
|
@@ -2523,12 +2672,13 @@ function injectRspack(compiler, serverPortFn, resolveClientModule2) {
|
|
|
2523
2672
|
}
|
|
2524
2673
|
|
|
2525
2674
|
// src/injectors/vite.ts
|
|
2526
|
-
function getViteVirtualModuleScript(serverPort) {
|
|
2675
|
+
function getViteVirtualModuleScript(serverPort, publicServerUrl) {
|
|
2527
2676
|
return `
|
|
2528
2677
|
import { mountInspector } from '@inspecto-dev/core';
|
|
2529
2678
|
window.__AI_INSPECTOR_PORT__ = ${serverPort};
|
|
2679
|
+
window.__AI_INSPECTOR_SERVER_URL__ = '${publicServerUrl ?? `http://127.0.0.1:${serverPort}`}';
|
|
2530
2680
|
mountInspector({
|
|
2531
|
-
serverUrl:
|
|
2681
|
+
serverUrl: window.__AI_INSPECTOR_SERVER_URL__,
|
|
2532
2682
|
});
|
|
2533
2683
|
`;
|
|
2534
2684
|
}
|
|
@@ -2561,6 +2711,11 @@ var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
2561
2711
|
}
|
|
2562
2712
|
return serverPort;
|
|
2563
2713
|
};
|
|
2714
|
+
const getPublicServerUrl = (port) => resolvePublicServerUrl({
|
|
2715
|
+
cwd: serverState.cwd || process.cwd(),
|
|
2716
|
+
configRoot: serverState.configRoot || projectRoot,
|
|
2717
|
+
port
|
|
2718
|
+
});
|
|
2564
2719
|
return {
|
|
2565
2720
|
name: "inspecto-overlay",
|
|
2566
2721
|
enforce: "pre",
|
|
@@ -2573,7 +2728,7 @@ var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
2573
2728
|
},
|
|
2574
2729
|
webpack: (compiler) => {
|
|
2575
2730
|
if (isProduction) return;
|
|
2576
|
-
injectWebpack(compiler, ensureServer, resolveClientModule);
|
|
2731
|
+
injectWebpack(compiler, ensureServer, getPublicServerUrl, resolveClientModule);
|
|
2577
2732
|
},
|
|
2578
2733
|
rspack: (compiler) => {
|
|
2579
2734
|
if (isProduction) return;
|
|
@@ -2599,7 +2754,10 @@ var InspectoPlugin = (0, import_unplugin.createUnplugin)((userOptions = {}) => {
|
|
|
2599
2754
|
},
|
|
2600
2755
|
load(id) {
|
|
2601
2756
|
if (id === VITE_VIRTUAL_MODULE_ID) {
|
|
2602
|
-
return getViteVirtualModuleScript(
|
|
2757
|
+
return getViteVirtualModuleScript(
|
|
2758
|
+
serverPort ?? DEFAULT_PORT,
|
|
2759
|
+
getPublicServerUrl(serverPort ?? DEFAULT_PORT)
|
|
2760
|
+
);
|
|
2603
2761
|
}
|
|
2604
2762
|
return null;
|
|
2605
2763
|
},
|