@meltstudio/meltctl 5.22.0 → 5.24.0
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.js +150 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -7499,7 +7499,7 @@ var CLI_VERSION;
|
|
|
7499
7499
|
var init_version = __esm({
|
|
7500
7500
|
"src/utils/version.ts"() {
|
|
7501
7501
|
"use strict";
|
|
7502
|
-
CLI_VERSION = "5.
|
|
7502
|
+
CLI_VERSION = "5.24.0";
|
|
7503
7503
|
}
|
|
7504
7504
|
});
|
|
7505
7505
|
|
|
@@ -27010,6 +27010,8 @@ function createProjectsResource(config2) {
|
|
|
27010
27010
|
method: "POST",
|
|
27011
27011
|
body: JSON.stringify(input)
|
|
27012
27012
|
});
|
|
27013
|
+
if (status === 403)
|
|
27014
|
+
throw new Error("Access denied. Only Team Managers can link repos.");
|
|
27013
27015
|
if (status !== 201)
|
|
27014
27016
|
throw new Error(`Failed to add repo (${status})`);
|
|
27015
27017
|
},
|
|
@@ -27018,6 +27020,8 @@ function createProjectsResource(config2) {
|
|
|
27018
27020
|
method: "DELETE",
|
|
27019
27021
|
body: JSON.stringify({ repository })
|
|
27020
27022
|
});
|
|
27023
|
+
if (status === 403)
|
|
27024
|
+
throw new Error("Access denied. Only Team Managers can link repos.");
|
|
27021
27025
|
if (status !== 200)
|
|
27022
27026
|
throw new Error(`Failed to remove repo (${status})`);
|
|
27023
27027
|
},
|
|
@@ -27953,6 +27957,39 @@ function createEndpointChecksResource(config2) {
|
|
|
27953
27957
|
if (status >= 400) {
|
|
27954
27958
|
throw new Error(data.error ?? `Failed to delete endpoint check (${status})`);
|
|
27955
27959
|
}
|
|
27960
|
+
},
|
|
27961
|
+
/** Weekly Slack reminder settings (#651). Manager-gated. */
|
|
27962
|
+
async getReminderSettings() {
|
|
27963
|
+
const { data, status } = await apiFetch(config2, "/endpoint-reminders/settings");
|
|
27964
|
+
if (status === 403) {
|
|
27965
|
+
throw new Error("Access denied. Only Team Managers can view endpoint reminder settings.");
|
|
27966
|
+
}
|
|
27967
|
+
if (status !== 200) {
|
|
27968
|
+
throw new Error(data.error ?? `Failed to fetch endpoint reminder settings (${status})`);
|
|
27969
|
+
}
|
|
27970
|
+
return data.settings;
|
|
27971
|
+
},
|
|
27972
|
+
/** Save the reminder settings (#651). Turning `enabled` on starts the weekly DMs. */
|
|
27973
|
+
async updateReminderSettings(input) {
|
|
27974
|
+
const { data, status } = await apiFetch(config2, "/endpoint-reminders/settings", { method: "PUT", body: JSON.stringify(input) });
|
|
27975
|
+
if (status === 403) {
|
|
27976
|
+
throw new Error("Access denied. Only Team Managers can change endpoint reminder settings.");
|
|
27977
|
+
}
|
|
27978
|
+
if (status !== 200) {
|
|
27979
|
+
throw new Error(data.error ?? `Failed to save endpoint reminder settings (${status})`);
|
|
27980
|
+
}
|
|
27981
|
+
return data.settings;
|
|
27982
|
+
},
|
|
27983
|
+
/** Who would get a DM this week and who would be in the digest. Sends nothing. */
|
|
27984
|
+
async previewReminders() {
|
|
27985
|
+
const { data, status } = await apiFetch(config2, "/endpoint-reminders/preview");
|
|
27986
|
+
if (status === 403) {
|
|
27987
|
+
throw new Error("Access denied. Only Team Managers can preview endpoint reminders.");
|
|
27988
|
+
}
|
|
27989
|
+
if (status !== 200) {
|
|
27990
|
+
throw new Error(data.error ?? `Failed to preview endpoint reminders (${status})`);
|
|
27991
|
+
}
|
|
27992
|
+
return data;
|
|
27956
27993
|
}
|
|
27957
27994
|
};
|
|
27958
27995
|
}
|
|
@@ -54207,6 +54244,8 @@ function createProjectsResource2(config2) {
|
|
|
54207
54244
|
method: "POST",
|
|
54208
54245
|
body: JSON.stringify(input)
|
|
54209
54246
|
});
|
|
54247
|
+
if (status === 403)
|
|
54248
|
+
throw new Error("Access denied. Only Team Managers can link repos.");
|
|
54210
54249
|
if (status !== 201)
|
|
54211
54250
|
throw new Error(`Failed to add repo (${status})`);
|
|
54212
54251
|
},
|
|
@@ -54215,6 +54254,8 @@ function createProjectsResource2(config2) {
|
|
|
54215
54254
|
method: "DELETE",
|
|
54216
54255
|
body: JSON.stringify({ repository })
|
|
54217
54256
|
});
|
|
54257
|
+
if (status === 403)
|
|
54258
|
+
throw new Error("Access denied. Only Team Managers can link repos.");
|
|
54218
54259
|
if (status !== 200)
|
|
54219
54260
|
throw new Error(`Failed to remove repo (${status})`);
|
|
54220
54261
|
},
|
|
@@ -55130,6 +55171,39 @@ function createEndpointChecksResource2(config2) {
|
|
|
55130
55171
|
if (status >= 400) {
|
|
55131
55172
|
throw new Error(data.error ?? `Failed to delete endpoint check (${status})`);
|
|
55132
55173
|
}
|
|
55174
|
+
},
|
|
55175
|
+
/** Weekly Slack reminder settings (#651). Manager-gated. */
|
|
55176
|
+
async getReminderSettings() {
|
|
55177
|
+
const { data, status } = await apiFetch2(config2, "/endpoint-reminders/settings");
|
|
55178
|
+
if (status === 403) {
|
|
55179
|
+
throw new Error("Access denied. Only Team Managers can view endpoint reminder settings.");
|
|
55180
|
+
}
|
|
55181
|
+
if (status !== 200) {
|
|
55182
|
+
throw new Error(data.error ?? `Failed to fetch endpoint reminder settings (${status})`);
|
|
55183
|
+
}
|
|
55184
|
+
return data.settings;
|
|
55185
|
+
},
|
|
55186
|
+
/** Save the reminder settings (#651). Turning `enabled` on starts the weekly DMs. */
|
|
55187
|
+
async updateReminderSettings(input) {
|
|
55188
|
+
const { data, status } = await apiFetch2(config2, "/endpoint-reminders/settings", { method: "PUT", body: JSON.stringify(input) });
|
|
55189
|
+
if (status === 403) {
|
|
55190
|
+
throw new Error("Access denied. Only Team Managers can change endpoint reminder settings.");
|
|
55191
|
+
}
|
|
55192
|
+
if (status !== 200) {
|
|
55193
|
+
throw new Error(data.error ?? `Failed to save endpoint reminder settings (${status})`);
|
|
55194
|
+
}
|
|
55195
|
+
return data.settings;
|
|
55196
|
+
},
|
|
55197
|
+
/** Who would get a DM this week and who would be in the digest. Sends nothing. */
|
|
55198
|
+
async previewReminders() {
|
|
55199
|
+
const { data, status } = await apiFetch2(config2, "/endpoint-reminders/preview");
|
|
55200
|
+
if (status === 403) {
|
|
55201
|
+
throw new Error("Access denied. Only Team Managers can preview endpoint reminders.");
|
|
55202
|
+
}
|
|
55203
|
+
if (status !== 200) {
|
|
55204
|
+
throw new Error(data.error ?? `Failed to preview endpoint reminders (${status})`);
|
|
55205
|
+
}
|
|
55206
|
+
return data;
|
|
55133
55207
|
}
|
|
55134
55208
|
};
|
|
55135
55209
|
}
|
|
@@ -55857,6 +55931,57 @@ async function updateProjectSettings(client, input) {
|
|
|
55857
55931
|
async function getProjectContext(client, input) {
|
|
55858
55932
|
return safe(() => client.pm.getProjectContext(input.projectId));
|
|
55859
55933
|
}
|
|
55934
|
+
function normalizeRepository(repository) {
|
|
55935
|
+
return repository.trim().replace(/^(https?:\/\/)?(www\.)?github\.com\//i, "").replace(/\.git$/i, "").replace(/\/+$/, "");
|
|
55936
|
+
}
|
|
55937
|
+
var REPOSITORY_PATTERN = /^[\w.-]+\/[\w.-]+$/;
|
|
55938
|
+
async function findProject(client, projectId) {
|
|
55939
|
+
const projects = await client.projects.list({ includeInternal: true });
|
|
55940
|
+
const project2 = projects.find((p) => p.id === projectId);
|
|
55941
|
+
if (!project2) throw new Error(`Project ${projectId} not found. Use list_projects to find its id.`);
|
|
55942
|
+
return { project: project2, projects };
|
|
55943
|
+
}
|
|
55944
|
+
async function linkRepoToProject(client, input) {
|
|
55945
|
+
return safe(async () => {
|
|
55946
|
+
const repository = normalizeRepository(input.repository);
|
|
55947
|
+
if (!REPOSITORY_PATTERN.test(repository)) {
|
|
55948
|
+
throw new Error(`"${input.repository}" isn't a repository in owner/name form.`);
|
|
55949
|
+
}
|
|
55950
|
+
const { project: project2, projects } = await findProject(client, input.projectId);
|
|
55951
|
+
const alreadyLinked = project2.repos.includes(repository);
|
|
55952
|
+
const alsoLinkedTo = projects.filter((p) => p.id !== project2.id && p.repos.includes(repository)).map((p) => ({ projectId: p.id, projectName: p.name }));
|
|
55953
|
+
if (!alreadyLinked) {
|
|
55954
|
+
await client.projects.addRepo(project2.id, { repository, projectName: project2.name });
|
|
55955
|
+
}
|
|
55956
|
+
return {
|
|
55957
|
+
projectId: project2.id,
|
|
55958
|
+
projectName: project2.name,
|
|
55959
|
+
repository,
|
|
55960
|
+
alreadyLinked,
|
|
55961
|
+
alsoLinkedTo,
|
|
55962
|
+
repos: alreadyLinked ? project2.repos : [...project2.repos, repository]
|
|
55963
|
+
};
|
|
55964
|
+
});
|
|
55965
|
+
}
|
|
55966
|
+
async function unlinkRepoFromProject(client, input) {
|
|
55967
|
+
return safe(async () => {
|
|
55968
|
+
const repository = normalizeRepository(input.repository);
|
|
55969
|
+
const { project: project2 } = await findProject(client, input.projectId);
|
|
55970
|
+
const linked = [...project2.repos, ...project2.inactiveRepos];
|
|
55971
|
+
if (!linked.includes(repository)) {
|
|
55972
|
+
throw new Error(
|
|
55973
|
+
`${repository} isn't linked to ${project2.name}. Its repos: ${linked.join(", ") || "none"}.`
|
|
55974
|
+
);
|
|
55975
|
+
}
|
|
55976
|
+
await client.projects.removeRepo(project2.id, repository);
|
|
55977
|
+
return {
|
|
55978
|
+
projectId: project2.id,
|
|
55979
|
+
projectName: project2.name,
|
|
55980
|
+
repository,
|
|
55981
|
+
repos: project2.repos.filter((r) => r !== repository)
|
|
55982
|
+
};
|
|
55983
|
+
});
|
|
55984
|
+
}
|
|
55860
55985
|
var PROJECT_STAGE_VALUES = ["prototype", "early_revenue", "growth", "scale"];
|
|
55861
55986
|
var LIFECYCLE_STATUS_VALUES = [
|
|
55862
55987
|
"commercial",
|
|
@@ -55952,6 +56077,30 @@ function registerProjectTools(server, getClient2) {
|
|
|
55952
56077
|
},
|
|
55953
56078
|
withClientArgs(getClient2, getProjectContext)
|
|
55954
56079
|
);
|
|
56080
|
+
server.registerTool(
|
|
56081
|
+
"link_repo_to_project",
|
|
56082
|
+
{
|
|
56083
|
+
title: "Link a repo to a project",
|
|
56084
|
+
description: "Links a GitHub repository to a Melt project, so its audits, plans and CLI activity count toward that project (health, audit list, dashboard). Accepts `owner/name` or a GitHub URL. Linking a repo that's already linked is a no-op. The response lists the project's repos and `alsoLinkedTo`, any other project that already has this repo; mention those to the user, since a repo usually belongs to one project. Manager-only (403 for others). This is a write: confirm the project and repo with the user first. list_projects shows each project's current repos.",
|
|
56085
|
+
inputSchema: {
|
|
56086
|
+
projectId: external_exports.number().int().positive().describe("Strapi project id from list_projects."),
|
|
56087
|
+
repository: external_exports.string().min(1).describe('GitHub repository as owner/name, e.g. "kateharline/content-engine".')
|
|
56088
|
+
}
|
|
56089
|
+
},
|
|
56090
|
+
withClientArgs(getClient2, linkRepoToProject)
|
|
56091
|
+
);
|
|
56092
|
+
server.registerTool(
|
|
56093
|
+
"unlink_repo_from_project",
|
|
56094
|
+
{
|
|
56095
|
+
title: "Unlink a repo from a project",
|
|
56096
|
+
description: "Removes a repository from a Melt project. Its past audits, plans and events stay in the database but stop counting toward the project. Fails with the project's linked repos if the repo isn't linked. Manager-only (403 for others). This is a write: confirm with the user first.",
|
|
56097
|
+
inputSchema: {
|
|
56098
|
+
projectId: external_exports.number().int().positive().describe("Strapi project id from list_projects."),
|
|
56099
|
+
repository: external_exports.string().min(1).describe("GitHub repository as owner/name.")
|
|
56100
|
+
}
|
|
56101
|
+
},
|
|
56102
|
+
withClientArgs(getClient2, unlinkRepoFromProject)
|
|
56103
|
+
);
|
|
55955
56104
|
}
|
|
55956
56105
|
var SHAPE_VALUES = ["crawling", "walking", "running"];
|
|
55957
56106
|
var SHAPE_DESC = "crawling | walking | running. Target shape is intent (PM sets when creating); current shape is computed from feature stages.";
|
package/package.json
CHANGED