@mastra/platform-workspace 1.5.0-alpha.0 → 1.5.0-alpha.2
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/index.cjs +82 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +82 -27
- package/dist/index.js.map +1 -1
- package/dist/repo-template.d.ts +25 -5
- package/dist/repo-template.d.ts.map +1 -1
- package/dist/sandbox.d.ts.map +1 -1
- package/package.json +4 -5
- package/CHANGELOG.md +0 -826
package/dist/index.cjs
CHANGED
|
@@ -1812,9 +1812,10 @@ var PlatformSandbox = class PlatformSandbox extends _mastra_core_workspace.Mastr
|
|
|
1812
1812
|
}
|
|
1813
1813
|
lastLease = lease;
|
|
1814
1814
|
attemptsMade = attempt + 1;
|
|
1815
|
+
const leaseCwd = options?.cwd ?? this.workingDirectory;
|
|
1815
1816
|
const execOptions = {
|
|
1816
1817
|
command: fullCommand,
|
|
1817
|
-
...
|
|
1818
|
+
...leaseCwd !== void 0 && { cwd: leaseCwd },
|
|
1818
1819
|
...filteredEnv !== void 0 && { env: filteredEnv },
|
|
1819
1820
|
...effectiveTimeout != null && effectiveTimeout > 0 && { timeoutMs: effectiveTimeout },
|
|
1820
1821
|
...this._webSocketFactory && { webSocketFactory: this._webSocketFactory }
|
|
@@ -1851,9 +1852,10 @@ var PlatformSandbox = class PlatformSandbox extends _mastra_core_workspace.Mastr
|
|
|
1851
1852
|
*/
|
|
1852
1853
|
async _tryExecViaPrivateNetwork(instanceUrl, fullCommand, effectiveTimeout, options) {
|
|
1853
1854
|
const filteredEnv = this._execEnv(options);
|
|
1855
|
+
const privateNetCwd = options?.cwd ?? this.workingDirectory;
|
|
1854
1856
|
const execOptions = {
|
|
1855
1857
|
command: fullCommand,
|
|
1856
|
-
...
|
|
1858
|
+
...privateNetCwd !== void 0 && { cwd: privateNetCwd },
|
|
1857
1859
|
...filteredEnv !== void 0 && { env: filteredEnv },
|
|
1858
1860
|
...effectiveTimeout != null && effectiveTimeout > 0 && { timeoutMs: effectiveTimeout },
|
|
1859
1861
|
...this._privateNetFetch && { fetch: this._privateNetFetch }
|
|
@@ -1987,38 +1989,71 @@ const CLONE_URL_SEGMENT_PATTERN = /^[\w.-]+$/;
|
|
|
1987
1989
|
* pins repositories to their current default-branch commit. Private repository
|
|
1988
1990
|
* credentials are used for head resolution and sent to the provider as
|
|
1989
1991
|
* transient build envs; they never enter the serialized definition. If the
|
|
1990
|
-
* head cannot be resolved, the resolver
|
|
1991
|
-
*
|
|
1992
|
-
* the checkout
|
|
1992
|
+
* repository or its head cannot be resolved, the resolver keeps `cpuCount` and
|
|
1993
|
+
* `memoryMB` in a resources-only template so the sandbox still boots at the
|
|
1994
|
+
* requested size, and the caller's runtime setup materializes the checkout.
|
|
1993
1995
|
*/
|
|
1994
1996
|
function createRepoTemplate(options) {
|
|
1995
1997
|
const getRepositoryAccess = options.getRepositoryAccess;
|
|
1996
|
-
|
|
1998
|
+
const resourcesOnly = () => {
|
|
1999
|
+
if (options.cpuCount === void 0 && options.memoryMB === void 0) return void 0;
|
|
2000
|
+
return withResources(Template(), options);
|
|
2001
|
+
};
|
|
2002
|
+
if (!getRepositoryAccess) {
|
|
2003
|
+
const template = resourcesOnly();
|
|
2004
|
+
return template ? async () => template : void 0;
|
|
2005
|
+
}
|
|
1997
2006
|
const resolveHead = options.resolveHead ?? resolveDefaultBranchHead;
|
|
1998
2007
|
return async () => {
|
|
1999
|
-
|
|
2000
|
-
|
|
2008
|
+
let accessError;
|
|
2009
|
+
const access = await getRepositoryAccess().catch((error) => {
|
|
2010
|
+
accessError = error;
|
|
2011
|
+
});
|
|
2012
|
+
if (!access?.cloneUrl) {
|
|
2013
|
+
console.warn("[platform-workspace] repo template skipped: repository access unavailable", { error: redactSecrets(accessError) });
|
|
2014
|
+
return resourcesOnly();
|
|
2015
|
+
}
|
|
2001
2016
|
const cloneUrl = normalizeCloneUrl(access.cloneUrl);
|
|
2002
|
-
if (!isValidCloneUrl(cloneUrl))
|
|
2017
|
+
if (!isValidCloneUrl(cloneUrl)) {
|
|
2018
|
+
console.warn("[platform-workspace] repo template skipped: clone URL failed validation", { cloneUrl: redactSecrets(cloneUrl) });
|
|
2019
|
+
return resourcesOnly();
|
|
2020
|
+
}
|
|
2003
2021
|
const token = access.authorization?.token;
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2022
|
+
let headError;
|
|
2023
|
+
const sha = await (token ? resolveHead(cloneUrl, token) : resolveHead(cloneUrl)).catch((error) => {
|
|
2024
|
+
headError = error;
|
|
2025
|
+
});
|
|
2026
|
+
if (!sha || !SHA_PATTERN.test(sha)) {
|
|
2027
|
+
console.warn("[platform-workspace] repo template skipped: could not resolve default-branch head", {
|
|
2028
|
+
cloneUrl,
|
|
2029
|
+
sha,
|
|
2030
|
+
error: redactSecrets(headError)
|
|
2031
|
+
});
|
|
2032
|
+
return resourcesOnly();
|
|
2033
|
+
}
|
|
2034
|
+
const workingDirectory = options.workingDirectory === void 0 ? void 0 : trimTrailingSlashes(assertWorkingDirectory(options.workingDirectory));
|
|
2035
|
+
const repoDir = repoDirName(cloneUrl);
|
|
2007
2036
|
const auth = token ? `${gitAuthFlag()} ` : "";
|
|
2008
|
-
const
|
|
2009
|
-
|
|
2010
|
-
`git -C "${workdir}" ${auth}fetch origin ${sha}`,
|
|
2011
|
-
`git -C "${workdir}" checkout ${sha}`,
|
|
2012
|
-
...options.setupCommand ? [`cd "${workdir}" && ${options.setupCommand}`] : []
|
|
2013
|
-
];
|
|
2014
|
-
const family = `repo:${cloneUrl}:${workdir}`;
|
|
2037
|
+
const setupCommands = (options.setupCommand === void 0 ? [] : Array.isArray(options.setupCommand) ? options.setupCommand : [options.setupCommand]).filter((command) => command.trim() !== "");
|
|
2038
|
+
const family = `repo:${cloneUrl}:${workingDirectory ?? ""}/${repoDir}`;
|
|
2015
2039
|
let template = Template();
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2040
|
+
const buildEnv = {
|
|
2041
|
+
...options.buildEnv,
|
|
2042
|
+
...token ? { [BUILD_TOKEN_ENV]: token } : {}
|
|
2043
|
+
};
|
|
2044
|
+
if (Object.keys(buildEnv).length > 0) template = template.setEnvs(buildEnv, { ephemeral: true });
|
|
2045
|
+
template = withResources(template, options);
|
|
2046
|
+
if (workingDirectory) template = template.runCmd(`mkdir -p "${workingDirectory}"`).setWorkdir(workingDirectory);
|
|
2047
|
+
template = template.runCmd(`git ${auth}clone ${cloneUrl} "${repoDir}"`).runCmd(`git -C "${repoDir}" ${auth}fetch origin ${sha}`).runCmd(`git -C "${repoDir}" checkout ${sha}`);
|
|
2048
|
+
for (const command of setupCommands) template = template.runCmd(`cd "${repoDir}" && ${command}`);
|
|
2049
|
+
return template.withFamily(family);
|
|
2020
2050
|
};
|
|
2021
2051
|
}
|
|
2052
|
+
function withResources(template, options) {
|
|
2053
|
+
if (options.cpuCount !== void 0) template = template.cpuCount(options.cpuCount);
|
|
2054
|
+
if (options.memoryMB !== void 0) template = template.memoryMB(options.memoryMB);
|
|
2055
|
+
return template;
|
|
2056
|
+
}
|
|
2022
2057
|
function isValidCloneUrl(cloneUrl) {
|
|
2023
2058
|
if (cloneUrl.length > 2048 || !CLONE_URL_ALLOWED_CHARS.test(cloneUrl)) return false;
|
|
2024
2059
|
let url;
|
|
@@ -2044,8 +2079,26 @@ function normalizeCloneUrl(cloneUrl) {
|
|
|
2044
2079
|
return `${scheme.toLowerCase()}${host.toLowerCase()}`;
|
|
2045
2080
|
});
|
|
2046
2081
|
}
|
|
2047
|
-
function
|
|
2048
|
-
return
|
|
2082
|
+
function repoDirName(cloneUrl) {
|
|
2083
|
+
return (normalizeCloneUrl(cloneUrl).split("/").at(-1) ?? "").replace(/[^\w.-]/g, "-").replace(/^\.+/, "") || "repo";
|
|
2084
|
+
}
|
|
2085
|
+
function trimTrailingSlashes(path) {
|
|
2086
|
+
let end = path.length;
|
|
2087
|
+
while (end > 1 && path[end - 1] === "/") end--;
|
|
2088
|
+
return path.slice(0, end);
|
|
2089
|
+
}
|
|
2090
|
+
/** Validate a literal absolute path before embedding it in shell build steps. */
|
|
2091
|
+
function assertWorkingDirectory(dir) {
|
|
2092
|
+
if (!(/^\/[A-Za-z0-9._/-]*$/.test(dir) && !dir.split("/").includes(".."))) throw new Error(`Repo template workingDirectory must be an absolute path of plain path characters (got ${JSON.stringify(dir)}); ~ and $HOME are not expanded.`);
|
|
2093
|
+
return dir;
|
|
2094
|
+
}
|
|
2095
|
+
/**
|
|
2096
|
+
* Render a caught value for a warning without leaking credentials: URL
|
|
2097
|
+
* userinfo, HTTP authorization values, and GitHub token shapes are masked.
|
|
2098
|
+
*/
|
|
2099
|
+
function redactSecrets(value) {
|
|
2100
|
+
if (value === void 0 || value === null) return void 0;
|
|
2101
|
+
return (value instanceof Error ? value.message : typeof value === "string" ? value : String(value)).replace(/\/\/[^/@\s]+@/g, "//***@").replace(/\b(bearer|basic)\s+[^\s"']+/gi, "$1 ***").replace(/\b(gh[pousr]_|github_pat_)[A-Za-z0-9_]+/g, "$1***");
|
|
2049
2102
|
}
|
|
2050
2103
|
function gitAuthFlag() {
|
|
2051
2104
|
return `-c http.extraheader="AUTHORIZATION: basic $(printf 'x-access-token:%s' "$${BUILD_TOKEN_ENV}" | base64 -w0)"`;
|
|
@@ -2073,8 +2126,10 @@ async function resolveDefaultBranchHead(cloneUrl, token, execute = execFileAsync
|
|
|
2073
2126
|
});
|
|
2074
2127
|
const sha = stdout.trim().split(/\s+/, 1)[0];
|
|
2075
2128
|
return sha && SHA_PATTERN.test(sha) ? sha : void 0;
|
|
2076
|
-
} catch {
|
|
2077
|
-
|
|
2129
|
+
} catch (error) {
|
|
2130
|
+
const stderr = error.stderr;
|
|
2131
|
+
const detail = typeof stderr === "string" && stderr.trim() ? stderr.trim() : String(error);
|
|
2132
|
+
throw new Error(`git ls-remote failed: ${detail}`);
|
|
2078
2133
|
}
|
|
2079
2134
|
}
|
|
2080
2135
|
//#endregion
|