@meltstudio/meltctl 5.26.0 → 5.28.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 +345 -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.28.0";
|
|
7503
7503
|
}
|
|
7504
7504
|
});
|
|
7505
7505
|
|
|
@@ -26933,6 +26933,43 @@ function createTemplatesResource(config2) {
|
|
|
26933
26933
|
};
|
|
26934
26934
|
}
|
|
26935
26935
|
|
|
26936
|
+
// ../sdk/dist/resources/skills.js
|
|
26937
|
+
function skillPath(plugin, skill) {
|
|
26938
|
+
return `/skills/${encodeURIComponent(plugin)}/${encodeURIComponent(skill)}`;
|
|
26939
|
+
}
|
|
26940
|
+
function createSkillsResource(config2) {
|
|
26941
|
+
return {
|
|
26942
|
+
/** Every Melt skill (`melt-dev:plan`, …) with its frontmatter description. Auth-only. */
|
|
26943
|
+
async list() {
|
|
26944
|
+
const { data, status } = await apiFetch(config2, "/skills");
|
|
26945
|
+
if (status !== 200)
|
|
26946
|
+
throw new Error(data.error ?? `Failed to list skills (${status})`);
|
|
26947
|
+
return data.skills;
|
|
26948
|
+
},
|
|
26949
|
+
/** One skill's instructions plus the list of its reference files. */
|
|
26950
|
+
async get(plugin, skill, opts = {}) {
|
|
26951
|
+
const query = opts.client ? `?client=${encodeURIComponent(opts.client)}` : "";
|
|
26952
|
+
const { data, status } = await apiFetch(config2, `${skillPath(plugin, skill)}${query}`);
|
|
26953
|
+
if (status === 404)
|
|
26954
|
+
throw new Error(`Skill not found: ${plugin}:${skill}`);
|
|
26955
|
+
if (status !== 200)
|
|
26956
|
+
throw new Error(data.error ?? `Failed to fetch skill (${status})`);
|
|
26957
|
+
return data;
|
|
26958
|
+
},
|
|
26959
|
+
/** One file from the skill's folder, by the path `get` lists (`references/x.md`). */
|
|
26960
|
+
async getFile(plugin, skill, path10, opts = {}) {
|
|
26961
|
+
const params = new URLSearchParams({ path: path10 });
|
|
26962
|
+
if (opts.client)
|
|
26963
|
+
params.set("client", opts.client);
|
|
26964
|
+
const { data, status } = await apiFetch(config2, `${skillPath(plugin, skill)}/file?${params.toString()}`);
|
|
26965
|
+
if (status !== 200) {
|
|
26966
|
+
throw new Error(data.error ?? `Failed to fetch skill file (${status})`);
|
|
26967
|
+
}
|
|
26968
|
+
return data;
|
|
26969
|
+
}
|
|
26970
|
+
};
|
|
26971
|
+
}
|
|
26972
|
+
|
|
26936
26973
|
// ../sdk/dist/resources/auth.js
|
|
26937
26974
|
function createAuthResource(config2) {
|
|
26938
26975
|
return {
|
|
@@ -27958,6 +27995,58 @@ function createEndpointChecksResource(config2) {
|
|
|
27958
27995
|
throw new Error(data.error ?? `Failed to delete endpoint check (${status})`);
|
|
27959
27996
|
}
|
|
27960
27997
|
},
|
|
27998
|
+
/**
|
|
27999
|
+
* The caller's own devices, derived from their checks, with the latest
|
|
28000
|
+
* check and status of each. Self-scoped by the JWT.
|
|
28001
|
+
*/
|
|
28002
|
+
async listMyDevices() {
|
|
28003
|
+
const { data, status } = await apiFetch(config2, "/endpoint-checks/devices/me");
|
|
28004
|
+
if (status !== 200) {
|
|
28005
|
+
throw new Error(data.error ?? `Failed to list your devices (${status})`);
|
|
28006
|
+
}
|
|
28007
|
+
return data;
|
|
28008
|
+
},
|
|
28009
|
+
/**
|
|
28010
|
+
* Ask to retire one of the caller's own devices (status
|
|
28011
|
+
* `retire_requested`). It still counts as active until a manager confirms.
|
|
28012
|
+
*/
|
|
28013
|
+
async requestRetireDevice(input) {
|
|
28014
|
+
const { data, status } = await apiFetch(config2, "/endpoint-checks/devices/me/retire-request", { method: "POST", body: JSON.stringify(input) });
|
|
28015
|
+
if (status !== 200) {
|
|
28016
|
+
throw new Error(data.error ?? `Failed to request device retirement (${status})`);
|
|
28017
|
+
}
|
|
28018
|
+
return data.device;
|
|
28019
|
+
},
|
|
28020
|
+
/**
|
|
28021
|
+
* Every device a person ever checked (or everyone's, without `email`),
|
|
28022
|
+
* with status, last check and any pending retire request. Manager-gated:
|
|
28023
|
+
* the offboarding read.
|
|
28024
|
+
*/
|
|
28025
|
+
async listDevices(email3) {
|
|
28026
|
+
const query = email3 ? `?email=${encodeURIComponent(email3)}` : "";
|
|
28027
|
+
const { data, status } = await apiFetch(config2, `/endpoint-checks/devices${query}`);
|
|
28028
|
+
if (status === 403) {
|
|
28029
|
+
throw new Error("Access denied. Only Team Managers can list endpoint devices.");
|
|
28030
|
+
}
|
|
28031
|
+
if (status !== 200) {
|
|
28032
|
+
throw new Error(data.error ?? `Failed to list endpoint devices (${status})`);
|
|
28033
|
+
}
|
|
28034
|
+
return data;
|
|
28035
|
+
},
|
|
28036
|
+
/**
|
|
28037
|
+
* Set a device's status (active / retired / wiped). Manager-gated.
|
|
28038
|
+
* Confirming a person's retire request means setting `retired`.
|
|
28039
|
+
*/
|
|
28040
|
+
async setDeviceStatus(input) {
|
|
28041
|
+
const { data, status } = await apiFetch(config2, "/endpoint-checks/devices/status", { method: "PUT", body: JSON.stringify(input) });
|
|
28042
|
+
if (status === 403) {
|
|
28043
|
+
throw new Error("Access denied. Only Team Managers can change a device status.");
|
|
28044
|
+
}
|
|
28045
|
+
if (status !== 200) {
|
|
28046
|
+
throw new Error(data.error ?? `Failed to set device status (${status})`);
|
|
28047
|
+
}
|
|
28048
|
+
return data.device;
|
|
28049
|
+
},
|
|
27961
28050
|
/** Weekly Slack reminder settings (#651). Manager-gated. */
|
|
27962
28051
|
async getReminderSettings() {
|
|
27963
28052
|
const { data, status } = await apiFetch(config2, "/endpoint-reminders/settings");
|
|
@@ -28138,6 +28227,7 @@ function createMeltClient(config2) {
|
|
|
28138
28227
|
feedback: createFeedbackResource(config2),
|
|
28139
28228
|
coins: createCoinsResource(config2),
|
|
28140
28229
|
templates: createTemplatesResource(config2),
|
|
28230
|
+
skills: createSkillsResource(config2),
|
|
28141
28231
|
auth: createAuthResource(config2),
|
|
28142
28232
|
people: createPeopleResource(config2),
|
|
28143
28233
|
projects: createProjectsResource(config2),
|
|
@@ -54172,6 +54262,41 @@ function createTemplatesResource2(config2) {
|
|
|
54172
54262
|
}
|
|
54173
54263
|
};
|
|
54174
54264
|
}
|
|
54265
|
+
function skillPath2(plugin, skill) {
|
|
54266
|
+
return `/skills/${encodeURIComponent(plugin)}/${encodeURIComponent(skill)}`;
|
|
54267
|
+
}
|
|
54268
|
+
function createSkillsResource2(config2) {
|
|
54269
|
+
return {
|
|
54270
|
+
/** Every Melt skill (`melt-dev:plan`, …) with its frontmatter description. Auth-only. */
|
|
54271
|
+
async list() {
|
|
54272
|
+
const { data, status } = await apiFetch2(config2, "/skills");
|
|
54273
|
+
if (status !== 200)
|
|
54274
|
+
throw new Error(data.error ?? `Failed to list skills (${status})`);
|
|
54275
|
+
return data.skills;
|
|
54276
|
+
},
|
|
54277
|
+
/** One skill's instructions plus the list of its reference files. */
|
|
54278
|
+
async get(plugin, skill, opts = {}) {
|
|
54279
|
+
const query = opts.client ? `?client=${encodeURIComponent(opts.client)}` : "";
|
|
54280
|
+
const { data, status } = await apiFetch2(config2, `${skillPath2(plugin, skill)}${query}`);
|
|
54281
|
+
if (status === 404)
|
|
54282
|
+
throw new Error(`Skill not found: ${plugin}:${skill}`);
|
|
54283
|
+
if (status !== 200)
|
|
54284
|
+
throw new Error(data.error ?? `Failed to fetch skill (${status})`);
|
|
54285
|
+
return data;
|
|
54286
|
+
},
|
|
54287
|
+
/** One file from the skill's folder, by the path `get` lists (`references/x.md`). */
|
|
54288
|
+
async getFile(plugin, skill, path22, opts = {}) {
|
|
54289
|
+
const params = new URLSearchParams({ path: path22 });
|
|
54290
|
+
if (opts.client)
|
|
54291
|
+
params.set("client", opts.client);
|
|
54292
|
+
const { data, status } = await apiFetch2(config2, `${skillPath2(plugin, skill)}/file?${params.toString()}`);
|
|
54293
|
+
if (status !== 200) {
|
|
54294
|
+
throw new Error(data.error ?? `Failed to fetch skill file (${status})`);
|
|
54295
|
+
}
|
|
54296
|
+
return data;
|
|
54297
|
+
}
|
|
54298
|
+
};
|
|
54299
|
+
}
|
|
54175
54300
|
function createAuthResource2(config2) {
|
|
54176
54301
|
return {
|
|
54177
54302
|
async exchangeToken(code, redirectUri) {
|
|
@@ -55172,6 +55297,58 @@ function createEndpointChecksResource2(config2) {
|
|
|
55172
55297
|
throw new Error(data.error ?? `Failed to delete endpoint check (${status})`);
|
|
55173
55298
|
}
|
|
55174
55299
|
},
|
|
55300
|
+
/**
|
|
55301
|
+
* The caller's own devices, derived from their checks, with the latest
|
|
55302
|
+
* check and status of each. Self-scoped by the JWT.
|
|
55303
|
+
*/
|
|
55304
|
+
async listMyDevices() {
|
|
55305
|
+
const { data, status } = await apiFetch2(config2, "/endpoint-checks/devices/me");
|
|
55306
|
+
if (status !== 200) {
|
|
55307
|
+
throw new Error(data.error ?? `Failed to list your devices (${status})`);
|
|
55308
|
+
}
|
|
55309
|
+
return data;
|
|
55310
|
+
},
|
|
55311
|
+
/**
|
|
55312
|
+
* Ask to retire one of the caller's own devices (status
|
|
55313
|
+
* `retire_requested`). It still counts as active until a manager confirms.
|
|
55314
|
+
*/
|
|
55315
|
+
async requestRetireDevice(input) {
|
|
55316
|
+
const { data, status } = await apiFetch2(config2, "/endpoint-checks/devices/me/retire-request", { method: "POST", body: JSON.stringify(input) });
|
|
55317
|
+
if (status !== 200) {
|
|
55318
|
+
throw new Error(data.error ?? `Failed to request device retirement (${status})`);
|
|
55319
|
+
}
|
|
55320
|
+
return data.device;
|
|
55321
|
+
},
|
|
55322
|
+
/**
|
|
55323
|
+
* Every device a person ever checked (or everyone's, without `email`),
|
|
55324
|
+
* with status, last check and any pending retire request. Manager-gated:
|
|
55325
|
+
* the offboarding read.
|
|
55326
|
+
*/
|
|
55327
|
+
async listDevices(email3) {
|
|
55328
|
+
const query = email3 ? `?email=${encodeURIComponent(email3)}` : "";
|
|
55329
|
+
const { data, status } = await apiFetch2(config2, `/endpoint-checks/devices${query}`);
|
|
55330
|
+
if (status === 403) {
|
|
55331
|
+
throw new Error("Access denied. Only Team Managers can list endpoint devices.");
|
|
55332
|
+
}
|
|
55333
|
+
if (status !== 200) {
|
|
55334
|
+
throw new Error(data.error ?? `Failed to list endpoint devices (${status})`);
|
|
55335
|
+
}
|
|
55336
|
+
return data;
|
|
55337
|
+
},
|
|
55338
|
+
/**
|
|
55339
|
+
* Set a device's status (active / retired / wiped). Manager-gated.
|
|
55340
|
+
* Confirming a person's retire request means setting `retired`.
|
|
55341
|
+
*/
|
|
55342
|
+
async setDeviceStatus(input) {
|
|
55343
|
+
const { data, status } = await apiFetch2(config2, "/endpoint-checks/devices/status", { method: "PUT", body: JSON.stringify(input) });
|
|
55344
|
+
if (status === 403) {
|
|
55345
|
+
throw new Error("Access denied. Only Team Managers can change a device status.");
|
|
55346
|
+
}
|
|
55347
|
+
if (status !== 200) {
|
|
55348
|
+
throw new Error(data.error ?? `Failed to set device status (${status})`);
|
|
55349
|
+
}
|
|
55350
|
+
return data.device;
|
|
55351
|
+
},
|
|
55175
55352
|
/** Weekly Slack reminder settings (#651). Manager-gated. */
|
|
55176
55353
|
async getReminderSettings() {
|
|
55177
55354
|
const { data, status } = await apiFetch2(config2, "/endpoint-reminders/settings");
|
|
@@ -55346,6 +55523,7 @@ function createMeltClient2(config2) {
|
|
|
55346
55523
|
feedback: createFeedbackResource2(config2),
|
|
55347
55524
|
coins: createCoinsResource2(config2),
|
|
55348
55525
|
templates: createTemplatesResource2(config2),
|
|
55526
|
+
skills: createSkillsResource2(config2),
|
|
55349
55527
|
auth: createAuthResource2(config2),
|
|
55350
55528
|
people: createPeopleResource2(config2),
|
|
55351
55529
|
projects: createProjectsResource2(config2),
|
|
@@ -56732,6 +56910,38 @@ var submitEndpointCheckSchema = external_exports.object(submitEndpointCheckShape
|
|
|
56732
56910
|
async function submitEndpointCheck(client, input) {
|
|
56733
56911
|
return safe(() => client.endpointChecks.submit(input));
|
|
56734
56912
|
}
|
|
56913
|
+
async function listMyEndpointDevices(client) {
|
|
56914
|
+
return safe(() => client.endpointChecks.listMyDevices());
|
|
56915
|
+
}
|
|
56916
|
+
var requestRetireShape = {
|
|
56917
|
+
deviceKey: external_exports.string().min(1).describe(
|
|
56918
|
+
"The device key from list_my_endpoint_devices (serial, else device name, else model)."
|
|
56919
|
+
),
|
|
56920
|
+
note: external_exports.string().max(500).optional().describe(`Why, in the person's words, e.g. "kept at home, not used for work anymore".`)
|
|
56921
|
+
};
|
|
56922
|
+
var requestRetireEndpointDeviceInputSchema = external_exports.object(requestRetireShape);
|
|
56923
|
+
async function requestRetireEndpointDevice(client, input) {
|
|
56924
|
+
return safe(() => client.endpointChecks.requestRetireDevice(input));
|
|
56925
|
+
}
|
|
56926
|
+
var listDevicesShape = {
|
|
56927
|
+
email: external_exports.string().optional().describe("The person's @meltstudio.co email. Omit to list every person's devices.")
|
|
56928
|
+
};
|
|
56929
|
+
var listEndpointDevicesInputSchema = external_exports.object(listDevicesShape);
|
|
56930
|
+
async function listEndpointDevices(client, input) {
|
|
56931
|
+
return safe(() => client.endpointChecks.listDevices(input.email));
|
|
56932
|
+
}
|
|
56933
|
+
var setStatusShape = {
|
|
56934
|
+
email: external_exports.string().min(1).describe("The device owner's @meltstudio.co email."),
|
|
56935
|
+
deviceKey: external_exports.string().min(1).describe("The device key from list_endpoint_devices."),
|
|
56936
|
+
status: external_exports.enum(["active", "retired", "wiped"]).describe(
|
|
56937
|
+
"active = in use for work; retired = still owned, not used for work (confirms a retire request); wiped = cleaned."
|
|
56938
|
+
),
|
|
56939
|
+
note: external_exports.string().max(500).optional().describe('Optional note, e.g. "wiped on hand-back". Omit to keep the current note.')
|
|
56940
|
+
};
|
|
56941
|
+
var setEndpointDeviceStatusInputSchema = external_exports.object(setStatusShape);
|
|
56942
|
+
async function setEndpointDeviceStatus(client, input) {
|
|
56943
|
+
return safe(() => client.endpointChecks.setDeviceStatus(input));
|
|
56944
|
+
}
|
|
56735
56945
|
function registerEndpointCheckTools(server, getClient2) {
|
|
56736
56946
|
server.registerTool(
|
|
56737
56947
|
"submit_endpoint_check",
|
|
@@ -56742,6 +56952,42 @@ function registerEndpointCheckTools(server, getClient2) {
|
|
|
56742
56952
|
},
|
|
56743
56953
|
withClientArgs(getClient2, submitEndpointCheck)
|
|
56744
56954
|
);
|
|
56955
|
+
server.registerTool(
|
|
56956
|
+
"list_my_endpoint_devices",
|
|
56957
|
+
{
|
|
56958
|
+
title: "List my endpoint devices",
|
|
56959
|
+
description: "Lists the calling person's own devices, derived from their endpoint checks: label, deviceKey, model, serial, last check date, number of checks and status (active / retire_requested / retired / wiped). Self-scoped from the JWT. melt-company:verify-endpoint calls it after submitting to spot other devices that haven't been checked in a while.",
|
|
56960
|
+
inputSchema: {}
|
|
56961
|
+
},
|
|
56962
|
+
withClient(getClient2, listMyEndpointDevices)
|
|
56963
|
+
);
|
|
56964
|
+
server.registerTool(
|
|
56965
|
+
"request_retire_endpoint_device",
|
|
56966
|
+
{
|
|
56967
|
+
title: "Ask to retire one of my endpoint devices",
|
|
56968
|
+
description: "Asks to retire one of the calling person's OWN devices: one they still have but no longer use for work. Sets status retire_requested; the device still counts for the weekly reminders until a manager confirms it (set_endpoint_device_status with retired). Self-scoped: only the caller's own device keys (from list_my_endpoint_devices) are accepted. Fails for a device already retired or wiped.",
|
|
56969
|
+
inputSchema: requestRetireShape
|
|
56970
|
+
},
|
|
56971
|
+
withClientArgs(getClient2, requestRetireEndpointDevice)
|
|
56972
|
+
);
|
|
56973
|
+
server.registerTool(
|
|
56974
|
+
"list_endpoint_devices",
|
|
56975
|
+
{
|
|
56976
|
+
title: "List endpoint devices (manager)",
|
|
56977
|
+
description: "Every device a person ever checked (or everyone's, without email), with status, last check, the pending retire request (requestedBy / requestedAt / note) and who last set the status. Nothing is ever deleted, so retired and wiped devices are listed too. Use it when offboarding someone to make sure each of their machines is handled, or to find pending retire requests (status retire_requested). Manager-gated.",
|
|
56978
|
+
inputSchema: listDevicesShape
|
|
56979
|
+
},
|
|
56980
|
+
withClientArgs(getClient2, listEndpointDevices)
|
|
56981
|
+
);
|
|
56982
|
+
server.registerTool(
|
|
56983
|
+
"set_endpoint_device_status",
|
|
56984
|
+
{
|
|
56985
|
+
title: "Set an endpoint device status (manager)",
|
|
56986
|
+
description: "Sets a person's device to active, retired or wiped. retired = still owned but not used for work: left out of the endpoint-check reminders and the overdue math, still listed. Setting retired confirms the person's retire request. wiped = the device was cleaned; who and when are recorded. Get the email and deviceKey from list_endpoint_devices. Manager-gated.",
|
|
56987
|
+
inputSchema: setStatusShape
|
|
56988
|
+
},
|
|
56989
|
+
withClientArgs(getClient2, setEndpointDeviceStatus)
|
|
56990
|
+
);
|
|
56745
56991
|
}
|
|
56746
56992
|
async function getSupportEffort(client, input) {
|
|
56747
56993
|
return safe(async () => {
|
|
@@ -56772,6 +57018,103 @@ function registerSupportEffortTools(server, getClient2) {
|
|
|
56772
57018
|
withClientArgs(getClient2, getSupportEffort)
|
|
56773
57019
|
);
|
|
56774
57020
|
}
|
|
57021
|
+
var clientSchema = external_exports.enum(["claude", "cursor", "other"]).optional().describe(
|
|
57022
|
+
'Which agent you are. Use "cursor" in Cursor; "other" (the default) for any agent without the Melt Claude plugins; "claude" only to get the file exactly as Claude Code would.'
|
|
57023
|
+
);
|
|
57024
|
+
var skillNameSchema = external_exports.string().min(1).describe(
|
|
57025
|
+
'The skill, as "<plugin>:<skill>" (melt-company:verify-endpoint) or "<plugin>-<skill>" (melt-company-verify-endpoint). A leading "/" is ignored.'
|
|
57026
|
+
);
|
|
57027
|
+
var getSkillShape = { name: skillNameSchema, client: clientSchema };
|
|
57028
|
+
var getSkillInputSchema = external_exports.object(getSkillShape);
|
|
57029
|
+
var getSkillReferenceShape = {
|
|
57030
|
+
name: skillNameSchema,
|
|
57031
|
+
path: external_exports.string().min(1).describe(
|
|
57032
|
+
'The file as the skill names it, relative to the skill folder, e.g. "references/standards.md" (as listed by get_skill).'
|
|
57033
|
+
),
|
|
57034
|
+
client: clientSchema
|
|
57035
|
+
};
|
|
57036
|
+
var getSkillReferenceInputSchema = external_exports.object(getSkillReferenceShape);
|
|
57037
|
+
async function safeText(fn) {
|
|
57038
|
+
try {
|
|
57039
|
+
return { content: [{ type: "text", text: await fn() }] };
|
|
57040
|
+
} catch (err) {
|
|
57041
|
+
return fail(err instanceof Error ? err.message : String(err));
|
|
57042
|
+
}
|
|
57043
|
+
}
|
|
57044
|
+
async function resolveSkillName(client, rawName) {
|
|
57045
|
+
const name = rawName.trim().replace(/^\//, "");
|
|
57046
|
+
const colon = name.indexOf(":");
|
|
57047
|
+
if (colon > 0) return { plugin: name.slice(0, colon), skill: name.slice(colon + 1) };
|
|
57048
|
+
const match = (await client.skills.list()).find((s) => `${s.plugin}-${s.skill}` === name);
|
|
57049
|
+
if (!match) throw new Error(`Skill not found: ${rawName}. Call list_skills to see the names.`);
|
|
57050
|
+
return { plugin: match.plugin, skill: match.skill };
|
|
57051
|
+
}
|
|
57052
|
+
async function listSkills(client) {
|
|
57053
|
+
return safe(() => client.skills.list());
|
|
57054
|
+
}
|
|
57055
|
+
async function getSkill(client, input) {
|
|
57056
|
+
return safeText(async () => {
|
|
57057
|
+
const { plugin, skill } = await resolveSkillName(client, input.name);
|
|
57058
|
+
const detail = await client.skills.get(plugin, skill, { client: input.client ?? "other" });
|
|
57059
|
+
const references = detail.references.length ? detail.references.map((path22) => `- ${path22}`).join("\n") : "(none)";
|
|
57060
|
+
return [
|
|
57061
|
+
`# Melt skill: ${detail.name}`,
|
|
57062
|
+
"",
|
|
57063
|
+
`Follow the instructions below as if you were running the ${detail.name} skill. When they say to read a file (for example references/standards.md), fetch it with get_skill_reference (name: "${detail.name}", path: the file).`,
|
|
57064
|
+
"",
|
|
57065
|
+
`Files in this skill:
|
|
57066
|
+
${references}`,
|
|
57067
|
+
"",
|
|
57068
|
+
"---",
|
|
57069
|
+
"",
|
|
57070
|
+
detail.body
|
|
57071
|
+
].join("\n");
|
|
57072
|
+
});
|
|
57073
|
+
}
|
|
57074
|
+
async function getSkillReference(client, input) {
|
|
57075
|
+
return safeText(async () => {
|
|
57076
|
+
const { plugin, skill } = await resolveSkillName(client, input.name);
|
|
57077
|
+
const file2 = await client.skills.getFile(plugin, skill, input.path, {
|
|
57078
|
+
client: input.client ?? "other"
|
|
57079
|
+
});
|
|
57080
|
+
return file2.content;
|
|
57081
|
+
});
|
|
57082
|
+
}
|
|
57083
|
+
function registerSkillTools(server, getClient2) {
|
|
57084
|
+
server.registerTool(
|
|
57085
|
+
"list_skills",
|
|
57086
|
+
{
|
|
57087
|
+
title: "List Melt skills",
|
|
57088
|
+
description: "Lists Melt Studio's skills (the dev pipeline and audits, the PM suite, company checks like the endpoint check) with what each does. Use it when the user asks for a Melt skill you don't have installed, then load the one that fits with get_skill.",
|
|
57089
|
+
inputSchema: {}
|
|
57090
|
+
},
|
|
57091
|
+
withClient(getClient2, listSkills)
|
|
57092
|
+
);
|
|
57093
|
+
server.registerTool(
|
|
57094
|
+
"get_skill",
|
|
57095
|
+
{
|
|
57096
|
+
title: "Load a Melt skill",
|
|
57097
|
+
description: `Loads a Melt skill's full instructions. Treat what it returns as the skill itself: follow the instructions exactly, step by step, as if the skill were installed. When they say to read a file ("read references/x.md"), fetch it with get_skill_reference instead of looking on disk. Pass client: "cursor" when running in Cursor.`,
|
|
57098
|
+
inputSchema: getSkillShape
|
|
57099
|
+
},
|
|
57100
|
+
withClientArgs(
|
|
57101
|
+
getClient2,
|
|
57102
|
+
(client, args) => getSkill(client, args)
|
|
57103
|
+
)
|
|
57104
|
+
);
|
|
57105
|
+
server.registerTool(
|
|
57106
|
+
"get_skill_reference",
|
|
57107
|
+
{
|
|
57108
|
+
title: "Read a file from a Melt skill",
|
|
57109
|
+
description: `Returns one of a Melt skill's reference files (a checklist, template or standards doc) as markdown. Use it whenever a skill loaded with get_skill says to read a file like "references/standards.md"; the files are not on disk. Follow its contents as part of the skill.`,
|
|
57110
|
+
inputSchema: getSkillReferenceShape
|
|
57111
|
+
},
|
|
57112
|
+
withClientArgs(
|
|
57113
|
+
getClient2,
|
|
57114
|
+
(client, args) => getSkillReference(client, args)
|
|
57115
|
+
)
|
|
57116
|
+
);
|
|
57117
|
+
}
|
|
56775
57118
|
var VERSION = "0.0.0";
|
|
56776
57119
|
function createMcpServer(clientOrProvider) {
|
|
56777
57120
|
const getClient2 = typeof clientOrProvider === "function" ? clientOrProvider : () => Promise.resolve(clientOrProvider);
|
|
@@ -56791,6 +57134,7 @@ function createMcpServer(clientOrProvider) {
|
|
|
56791
57134
|
registerDailyPlanTools(server, getClient2);
|
|
56792
57135
|
registerEndpointCheckTools(server, getClient2);
|
|
56793
57136
|
registerSupportEffortTools(server, getClient2);
|
|
57137
|
+
registerSkillTools(server, getClient2);
|
|
56794
57138
|
return server;
|
|
56795
57139
|
}
|
|
56796
57140
|
async function startServer() {
|
package/package.json
CHANGED