@topline-build/harness-mcp 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -1
- package/dist/index.js +16 -5
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -70,5 +70,5 @@ export declare function openArtifact(opts: HarnessMcpStdioOptions, artifactId: s
|
|
|
70
70
|
liveUrl: string | null;
|
|
71
71
|
versionUrl: string | null;
|
|
72
72
|
}>;
|
|
73
|
-
export declare function packArtifactAppDirectory(appDir: string): Promise<PackedArtifactAppBundle>;
|
|
73
|
+
export declare function packArtifactAppDirectory(appDir: string, archivePrefix?: string): Promise<PackedArtifactAppBundle>;
|
|
74
74
|
export declare function getBearerToken(opts: HarnessMcpStdioOptions): Promise<string>;
|
package/dist/index.js
CHANGED
|
@@ -94,6 +94,7 @@ export async function callHarnessTool(opts, name, args) {
|
|
|
94
94
|
export async function deployArtifactApp(opts, input) {
|
|
95
95
|
const appDir = stringArg(input, "appDir");
|
|
96
96
|
const absoluteAppDir = resolveWorkspacePath(opts.workspaceRoot, appDir);
|
|
97
|
+
const platformAppDir = workspaceRelativeAppDir(opts.workspaceRoot, absoluteAppDir);
|
|
97
98
|
const manifest = await readManifest(absoluteAppDir);
|
|
98
99
|
const created = await fetchJson(opts, artifactAppsPath(opts), {
|
|
99
100
|
method: "POST",
|
|
@@ -111,7 +112,7 @@ export async function deployArtifactApp(opts, input) {
|
|
|
111
112
|
throw new Error(`artifact_app_create_failed:${JSON.stringify(createdRecord)}`);
|
|
112
113
|
const artifactId = stringValue(createdRecord.artifactId, "artifactId");
|
|
113
114
|
const artifactVersionId = stringValue(createdRecord.artifactVersionId, "artifactVersionId");
|
|
114
|
-
const bundle = await packArtifactAppDirectory(absoluteAppDir);
|
|
115
|
+
const bundle = await packArtifactAppDirectory(absoluteAppDir, platformAppDir);
|
|
115
116
|
const bearerToken = await getBearerToken(opts);
|
|
116
117
|
const deployed = await fetchJson(opts, `${artifactAppsPath(opts)}/${encodeURIComponent(artifactId)}/deploy-bundle`, {
|
|
117
118
|
method: "POST",
|
|
@@ -120,7 +121,7 @@ export async function deployArtifactApp(opts, input) {
|
|
|
120
121
|
"content-type": "application/gzip",
|
|
121
122
|
"MCP-Protocol-Version": opts.protocolVersion,
|
|
122
123
|
"x-platform-artifact-version-id": artifactVersionId,
|
|
123
|
-
"x-platform-app-dir":
|
|
124
|
+
"x-platform-app-dir": platformAppDir
|
|
124
125
|
},
|
|
125
126
|
body: bundle.body
|
|
126
127
|
});
|
|
@@ -195,8 +196,9 @@ export async function openArtifact(opts, artifactId) {
|
|
|
195
196
|
versionUrl: typeof draft?.versionUrl === "string" ? draft.versionUrl : typeof live?.versionUrl === "string" ? live.versionUrl : null
|
|
196
197
|
};
|
|
197
198
|
}
|
|
198
|
-
export async function packArtifactAppDirectory(appDir) {
|
|
199
|
+
export async function packArtifactAppDirectory(appDir, archivePrefix = "") {
|
|
199
200
|
const root = path.resolve(appDir);
|
|
201
|
+
const prefix = archivePrefix ? validateArchivePrefix(archivePrefix) : "";
|
|
200
202
|
const files = [];
|
|
201
203
|
const excluded = [];
|
|
202
204
|
await walk(root, root, files, excluded);
|
|
@@ -209,7 +211,7 @@ export async function packArtifactAppDirectory(appDir) {
|
|
|
209
211
|
if (byteCount > MAX_UNPACKED_BYTES)
|
|
210
212
|
throw new Error(`artifact_app_bundle_unpacked_too_large:${MAX_UNPACKED_BYTES}`);
|
|
211
213
|
const content = await readFile(file.absolute);
|
|
212
|
-
chunks.push(tarHeader(file.relative, content.length));
|
|
214
|
+
chunks.push(tarHeader(prefix ? `${prefix}/${file.relative}` : file.relative, content.length));
|
|
213
215
|
chunks.push(content);
|
|
214
216
|
chunks.push(Buffer.alloc(padSize(content.length)));
|
|
215
217
|
}
|
|
@@ -262,11 +264,20 @@ function resolveWorkspacePath(workspaceRoot, inputPath) {
|
|
|
262
264
|
throw new Error("appDir_must_be_inside_workspace_root");
|
|
263
265
|
return resolved;
|
|
264
266
|
}
|
|
267
|
+
function workspaceRelativeAppDir(workspaceRoot, absoluteAppDir) {
|
|
268
|
+
const relative = toPosix(path.relative(path.resolve(workspaceRoot), path.resolve(absoluteAppDir)));
|
|
269
|
+
return validateArchivePrefix(relative);
|
|
270
|
+
}
|
|
271
|
+
function validateArchivePrefix(prefix) {
|
|
272
|
+
const normalized = toPosix(prefix).replace(/^\/+|\/+$/g, "");
|
|
273
|
+
validateRelativePath(normalized);
|
|
274
|
+
return normalized;
|
|
275
|
+
}
|
|
265
276
|
function validateRelativePath(relative) {
|
|
266
277
|
if (!relative || relative.startsWith("/") || /^[A-Za-z]:\//.test(relative))
|
|
267
278
|
throw new Error("artifact_app_bundle_path_invalid");
|
|
268
279
|
const parts = relative.split("/").filter(Boolean);
|
|
269
|
-
if (parts.some((part) => part === ".."))
|
|
280
|
+
if (parts.some((part) => part === "." || part === ".."))
|
|
270
281
|
throw new Error(`artifact_app_bundle_path_escape:${relative}`);
|
|
271
282
|
if (parts.length > MAX_DEPTH)
|
|
272
283
|
throw new Error(`artifact_app_bundle_depth_limit:${MAX_DEPTH}`);
|