agent-skills-standard 2.7.2 → 2.7.3
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/README.md +5 -1
- package/dist/index.js +429 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -40,20 +40,20 @@ js_yaml = __toESM(js_yaml);
|
|
|
40
40
|
let zod = require("zod");
|
|
41
41
|
let node_path = require("node:path");
|
|
42
42
|
node_path = __toESM(node_path);
|
|
43
|
+
let child_process = require("child_process");
|
|
43
44
|
let os = require("os");
|
|
44
45
|
os = __toESM(os);
|
|
45
46
|
let node_stream = require("node:stream");
|
|
46
47
|
let node_child_process = require("node:child_process");
|
|
47
48
|
let node_os = require("node:os");
|
|
48
49
|
node_os = __toESM(node_os);
|
|
49
|
-
let child_process = require("child_process");
|
|
50
50
|
let fs = require("fs");
|
|
51
51
|
fs = __toESM(fs);
|
|
52
52
|
let crypto = require("crypto");
|
|
53
53
|
crypto = __toESM(crypto);
|
|
54
54
|
var package_default = {
|
|
55
55
|
name: "agent-skills-standard",
|
|
56
|
-
version: "2.7.
|
|
56
|
+
version: "2.7.3",
|
|
57
57
|
description: "A CLI to manage and sync AI agent skills standard for Cursor, Claude, Copilot, Windsurf, and more.",
|
|
58
58
|
main: "dist/index.js",
|
|
59
59
|
bin: {
|
|
@@ -1436,6 +1436,11 @@ var McpConfigSchema = zod.z.object({
|
|
|
1436
1436
|
scope: McpScopeSchema,
|
|
1437
1437
|
prompted: zod.z.boolean(),
|
|
1438
1438
|
version: zod.z.string().optional(),
|
|
1439
|
+
via: zod.z.enum([
|
|
1440
|
+
"auto",
|
|
1441
|
+
"npx",
|
|
1442
|
+
"global"
|
|
1443
|
+
]).optional(),
|
|
1439
1444
|
snippets: zod.z.boolean().optional()
|
|
1440
1445
|
});
|
|
1441
1446
|
var SkillConfigSchema = zod.z.object({
|
|
@@ -1479,6 +1484,7 @@ var MCP_FIELD_KEYS = [
|
|
|
1479
1484
|
"scope",
|
|
1480
1485
|
"prompted",
|
|
1481
1486
|
"version",
|
|
1487
|
+
"via",
|
|
1482
1488
|
"snippets"
|
|
1483
1489
|
];
|
|
1484
1490
|
var DEFAULT_SDLC_SUPPORT_CATEGORIES = ["quality-engineering"];
|
|
@@ -3629,11 +3635,10 @@ var LockfileService = class {
|
|
|
3629
3635
|
* agent-skills-standard-mcp`, which would silently pull whatever is latest
|
|
3630
3636
|
* on npm at the moment the agent starts.
|
|
3631
3637
|
*
|
|
3632
|
-
*
|
|
3633
|
-
*
|
|
3634
|
-
* category versions are maintained today).
|
|
3638
|
+
* Bumped automatically by `scripts/release-mcp.ts` when the MCP package is
|
|
3639
|
+
* released and gated in CI, so this pin always matches `mcp/package.json`.
|
|
3635
3640
|
*/
|
|
3636
|
-
var MCP_COMPATIBLE_VERSION = "0.
|
|
3641
|
+
var MCP_COMPATIBLE_VERSION = "0.8.0";
|
|
3637
3642
|
/**
|
|
3638
3643
|
* Minimum `agent-skills-standard-mcp` version required for session retrospectives.
|
|
3639
3644
|
*/
|
|
@@ -3655,6 +3660,10 @@ function escapeTomlString(value) {
|
|
|
3655
3660
|
}
|
|
3656
3661
|
//#endregion
|
|
3657
3662
|
//#region src/services/utils/codexTomlMcp.ts
|
|
3663
|
+
/** Structural equality for the server entry we generate and re-read. */
|
|
3664
|
+
function sameMcpEntry(a, b) {
|
|
3665
|
+
return a.command === b.command && a.args.length === b.args.length && a.args.every((arg, index) => arg === b.args[index]);
|
|
3666
|
+
}
|
|
3658
3667
|
var HEADER_RE = /^\s*\[\[?\s*([^\]]+?)\s*\]\]?\s*(#.*)?$/;
|
|
3659
3668
|
function normalizeKey(raw) {
|
|
3660
3669
|
return raw.split(".").map((s) => s.trim().replace(/^"(.*)"$/, "$1").replace(/^'(.*)'$/, "$1")).join(".");
|
|
@@ -3692,6 +3701,61 @@ function renderTomlMcpServer(name, entry) {
|
|
|
3692
3701
|
function hasTomlMcpServer(content, name) {
|
|
3693
3702
|
return findOurRanges(content.split("\n"), name).length > 0;
|
|
3694
3703
|
}
|
|
3704
|
+
function parseTomlStringLiteral(raw) {
|
|
3705
|
+
const value = raw.trim();
|
|
3706
|
+
if (value.length < 2) return null;
|
|
3707
|
+
if (value.startsWith("\"") && value.endsWith("\"")) return value.slice(1, -1).replace(/\\(["\\])/g, "$1");
|
|
3708
|
+
if (value.startsWith("'") && value.endsWith("'")) return value.slice(1, -1);
|
|
3709
|
+
return null;
|
|
3710
|
+
}
|
|
3711
|
+
var STRING_TOKEN_RE = /("(?:\\.|[^"\\])*"|'[^']*')/g;
|
|
3712
|
+
/**
|
|
3713
|
+
* Reads the `[mcp_servers.<name>]` table emitted by `renderTomlMcpServer`.
|
|
3714
|
+
* Returns null when the table is absent or either `command` / `args` is
|
|
3715
|
+
* missing or malformed. Only the exact table block is inspected, so
|
|
3716
|
+
* unrelated tables (and subtables) are ignored.
|
|
3717
|
+
*/
|
|
3718
|
+
function readTomlMcpServer(content, name) {
|
|
3719
|
+
const lines = content.split("\n");
|
|
3720
|
+
const base = `mcp_servers.${name}`;
|
|
3721
|
+
let start = -1;
|
|
3722
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
3723
|
+
const m = HEADER_RE.exec(lines[i]);
|
|
3724
|
+
if (m && normalizeKey(m[1]) === base) {
|
|
3725
|
+
start = i;
|
|
3726
|
+
break;
|
|
3727
|
+
}
|
|
3728
|
+
}
|
|
3729
|
+
if (start === -1) return null;
|
|
3730
|
+
let command = null;
|
|
3731
|
+
let args = null;
|
|
3732
|
+
for (let i = start + 1; i < lines.length; i += 1) {
|
|
3733
|
+
const line = lines[i];
|
|
3734
|
+
if (HEADER_RE.test(line)) break;
|
|
3735
|
+
const commandMatch = /^\s*command\s*=\s*((?:"(?:\\.|[^"\\])*")|(?:'[^']*'))\s*(?:#.*)?$/.exec(line);
|
|
3736
|
+
if (commandMatch) {
|
|
3737
|
+
command = parseTomlStringLiteral(commandMatch[1]);
|
|
3738
|
+
continue;
|
|
3739
|
+
}
|
|
3740
|
+
const argsMatch = /^\s*args\s*=\s*\[(.*)\]\s*(?:#.*)?$/.exec(line);
|
|
3741
|
+
if (argsMatch) {
|
|
3742
|
+
const tokens = argsMatch[1].match(STRING_TOKEN_RE) ?? [];
|
|
3743
|
+
if (argsMatch[1].replace(STRING_TOKEN_RE, "").replace(/[\s,]/g, "").length > 0) return null;
|
|
3744
|
+
const parsed = [];
|
|
3745
|
+
for (const token of tokens) {
|
|
3746
|
+
const value = parseTomlStringLiteral(token);
|
|
3747
|
+
if (value === null) return null;
|
|
3748
|
+
parsed.push(value);
|
|
3749
|
+
}
|
|
3750
|
+
args = parsed;
|
|
3751
|
+
}
|
|
3752
|
+
}
|
|
3753
|
+
if (command === null || args === null) return null;
|
|
3754
|
+
return {
|
|
3755
|
+
command,
|
|
3756
|
+
args
|
|
3757
|
+
};
|
|
3758
|
+
}
|
|
3695
3759
|
function removeTomlMcpServer(content, name) {
|
|
3696
3760
|
const lines = content.split("\n");
|
|
3697
3761
|
const ranges = findOurRanges(lines, name);
|
|
@@ -3727,6 +3791,10 @@ function upsertTomlMcpServer(content, name, entry) {
|
|
|
3727
3791
|
//#region src/services/McpConfigService.ts
|
|
3728
3792
|
var SERVER_NAME = "agent-skills-standard";
|
|
3729
3793
|
var PACKAGE = "agent-skills-standard-mcp";
|
|
3794
|
+
/** Sentinel: the `ags-mcp` command is not on PATH (no manifest fallback allowed). */
|
|
3795
|
+
var GLOBAL_BINARY_MISSING = Symbol("ags-mcp-missing");
|
|
3796
|
+
var SEMVER_PREFIX = /^\d+\.\d+\.\d+/;
|
|
3797
|
+
var SEMVER_EXACT = /^\d+\.\d+\.\d+$/;
|
|
3730
3798
|
var getTargets = (home = os.default.homedir(), platform = process.platform) => {
|
|
3731
3799
|
const out = {};
|
|
3732
3800
|
for (const agent of Object.values(Agent)) {
|
|
@@ -3761,18 +3829,111 @@ var McpConfigService = class {
|
|
|
3761
3829
|
* <package>`, which would otherwise pull whatever is latest on npm the
|
|
3762
3830
|
* moment the agent starts — an unpinned update-drift surface (AST07).
|
|
3763
3831
|
* Pass an explicit `version` (from `mcp.version` in .skillsrc) to override.
|
|
3832
|
+
*
|
|
3833
|
+
* `via` selects the launch strategy (default `auto`). A global install
|
|
3834
|
+
* avoids the ~0.6s npx resolution overhead on every client spawn, but a
|
|
3835
|
+
* stale global must never be silently preferred over the pin.
|
|
3764
3836
|
*/
|
|
3765
|
-
buildEntry(
|
|
3837
|
+
buildEntry(opts = {}) {
|
|
3838
|
+
const version = opts.version || "0.8.0";
|
|
3839
|
+
const via = opts.via ?? "auto";
|
|
3840
|
+
const platform = this.testPlatform ?? process.platform;
|
|
3841
|
+
if (via === "global" || via === "auto" && platform !== "win32" && this.detectGlobalVersion() === version) return platform === "win32" ? {
|
|
3842
|
+
command: "cmd",
|
|
3843
|
+
args: ["/c", "ags-mcp"]
|
|
3844
|
+
} : {
|
|
3845
|
+
command: "ags-mcp",
|
|
3846
|
+
args: []
|
|
3847
|
+
};
|
|
3766
3848
|
return {
|
|
3767
3849
|
command: "npx",
|
|
3768
|
-
args: [
|
|
3850
|
+
args: [
|
|
3851
|
+
"-y",
|
|
3852
|
+
"--prefer-offline",
|
|
3853
|
+
`${PACKAGE}@${version}`
|
|
3854
|
+
]
|
|
3769
3855
|
};
|
|
3770
3856
|
}
|
|
3857
|
+
/**
|
|
3858
|
+
* Version reported by a globally installed `ags-mcp`, or `null` when the
|
|
3859
|
+
* binary is missing/unusable.
|
|
3860
|
+
*
|
|
3861
|
+
* Two probes, in order:
|
|
3862
|
+
* 1. `ags-mcp --version` — authoritative and install-manager agnostic.
|
|
3863
|
+
* 2. the manifest under `npm root -g` — required for servers published
|
|
3864
|
+
* before `--version` existed, where probe 1 either prints nothing or
|
|
3865
|
+
* times out because the stdio server starts normally instead.
|
|
3866
|
+
* A missing binary (ENOENT) never falls through: an installed manifest
|
|
3867
|
+
* alone does not prove the command is on the client's PATH.
|
|
3868
|
+
*/
|
|
3869
|
+
detectGlobalVersion() {
|
|
3870
|
+
const binaryVersion = this.probeGlobalBinaryVersion();
|
|
3871
|
+
if (binaryVersion === GLOBAL_BINARY_MISSING) return null;
|
|
3872
|
+
return binaryVersion ?? this.probeGlobalManifestVersion();
|
|
3873
|
+
}
|
|
3874
|
+
/** `ags-mcp --version`, or the sentinel when the command is not on PATH. */
|
|
3875
|
+
probeGlobalBinaryVersion() {
|
|
3876
|
+
try {
|
|
3877
|
+
if (this.testGlobalVersionProbe) return this.testGlobalVersionProbe();
|
|
3878
|
+
const output = (0, child_process.execFileSync)("ags-mcp", ["--version"], {
|
|
3879
|
+
encoding: "utf8",
|
|
3880
|
+
timeout: 2e3,
|
|
3881
|
+
stdio: [
|
|
3882
|
+
"ignore",
|
|
3883
|
+
"pipe",
|
|
3884
|
+
"ignore"
|
|
3885
|
+
]
|
|
3886
|
+
});
|
|
3887
|
+
const firstLine = String(output).split("\n")[0].trim();
|
|
3888
|
+
return SEMVER_PREFIX.test(firstLine) ? firstLine : null;
|
|
3889
|
+
} catch (err) {
|
|
3890
|
+
return err.code === "ENOENT" ? GLOBAL_BINARY_MISSING : null;
|
|
3891
|
+
}
|
|
3892
|
+
}
|
|
3893
|
+
/** Version field of the globally installed manifest, purely from disk. */
|
|
3894
|
+
probeGlobalManifestVersion() {
|
|
3895
|
+
if (this.testGlobalManifestProbe) return this.testGlobalManifestProbe();
|
|
3896
|
+
const isWindows = (this.testPlatform ?? process.platform) === "win32";
|
|
3897
|
+
try {
|
|
3898
|
+
const globalRoot = String((0, child_process.execFileSync)(isWindows ? "npm.cmd" : "npm", ["root", "-g"], {
|
|
3899
|
+
encoding: "utf8",
|
|
3900
|
+
timeout: 5e3,
|
|
3901
|
+
stdio: [
|
|
3902
|
+
"ignore",
|
|
3903
|
+
"pipe",
|
|
3904
|
+
"ignore"
|
|
3905
|
+
],
|
|
3906
|
+
...isWindows ? { shell: true } : {}
|
|
3907
|
+
})).trim();
|
|
3908
|
+
if (!globalRoot) return null;
|
|
3909
|
+
const manifestPath = path.default.join(globalRoot, PACKAGE, "package.json");
|
|
3910
|
+
if (!fs_extra.default.pathExistsSync(manifestPath)) return null;
|
|
3911
|
+
const manifest = fs_extra.default.readJsonSync(manifestPath);
|
|
3912
|
+
return typeof manifest.version === "string" && SEMVER_EXACT.test(manifest.version) ? manifest.version : null;
|
|
3913
|
+
} catch {
|
|
3914
|
+
return null;
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3771
3917
|
/** For testing: allows overriding the home directory. */
|
|
3772
3918
|
testHome = null;
|
|
3773
3919
|
setHomeForTesting(home) {
|
|
3774
3920
|
this.testHome = home;
|
|
3775
3921
|
}
|
|
3922
|
+
/** For testing: allows overriding the detected platform. */
|
|
3923
|
+
testPlatform = null;
|
|
3924
|
+
setPlatformForTesting(platform) {
|
|
3925
|
+
this.testPlatform = platform;
|
|
3926
|
+
}
|
|
3927
|
+
/** For testing: allows overriding the global-version probe. */
|
|
3928
|
+
testGlobalVersionProbe = null;
|
|
3929
|
+
setGlobalVersionProbeForTesting(fn) {
|
|
3930
|
+
this.testGlobalVersionProbe = fn;
|
|
3931
|
+
}
|
|
3932
|
+
/** For testing: allows overriding the `npm root -g` manifest probe. */
|
|
3933
|
+
testGlobalManifestProbe = null;
|
|
3934
|
+
setGlobalManifestProbeForTesting(fn) {
|
|
3935
|
+
this.testGlobalManifestProbe = fn;
|
|
3936
|
+
}
|
|
3776
3937
|
getTargets() {
|
|
3777
3938
|
return getTargets(this.testHome ?? void 0);
|
|
3778
3939
|
}
|
|
@@ -3791,7 +3952,10 @@ var McpConfigService = class {
|
|
|
3791
3952
|
const { rootDir, agents, mcp } = opts;
|
|
3792
3953
|
if (mcp.scope === "disabled" || !mcp.enabled) return report;
|
|
3793
3954
|
const TARGETS = this.getTargets();
|
|
3794
|
-
const entry = this.buildEntry(
|
|
3955
|
+
const entry = this.buildEntry({
|
|
3956
|
+
version: mcp.version,
|
|
3957
|
+
via: mcp.via
|
|
3958
|
+
});
|
|
3795
3959
|
if (mcp.scope === "snippets-only" || mcp.snippets) await this.generateSnippets(rootDir, agents, entry, report);
|
|
3796
3960
|
if (mcp.scope === "snippets-only") return report;
|
|
3797
3961
|
for (const agent of agents) {
|
|
@@ -3868,12 +4032,45 @@ var McpConfigService = class {
|
|
|
3868
4032
|
const target = TARGETS[agent];
|
|
3869
4033
|
if (!target) continue;
|
|
3870
4034
|
const row = { agent };
|
|
3871
|
-
if (target.projectFile)
|
|
3872
|
-
|
|
4035
|
+
if (target.projectFile) {
|
|
4036
|
+
const abs = path.default.join(opts.rootDir, target.projectFile);
|
|
4037
|
+
row.project = await this.hasOurEntry(abs, target);
|
|
4038
|
+
row.projectEntry = await this.readEntry(abs, target);
|
|
4039
|
+
}
|
|
4040
|
+
if (target.userFile) {
|
|
4041
|
+
row.user = await this.hasOurEntry(target.userFile, target);
|
|
4042
|
+
row.userEntry = await this.readEntry(target.userFile, target);
|
|
4043
|
+
}
|
|
3873
4044
|
out.push(row);
|
|
3874
4045
|
}
|
|
3875
4046
|
return out;
|
|
3876
4047
|
}
|
|
4048
|
+
/** Parse the entry this service wrote for `SERVER_NAME`, if present. */
|
|
4049
|
+
async readEntry(abs, target) {
|
|
4050
|
+
if (!await fs_extra.default.pathExists(abs)) return null;
|
|
4051
|
+
if (target.format === "toml") return readTomlMcpServer(await fs_extra.default.readFile(abs, "utf8"), SERVER_NAME);
|
|
4052
|
+
const data = await fs_extra.default.readJson(abs).catch(() => null);
|
|
4053
|
+
if (!data) return null;
|
|
4054
|
+
const container = this.getNestedValue(data, target.key);
|
|
4055
|
+
if (!container) return null;
|
|
4056
|
+
if (target.shape === "map") {
|
|
4057
|
+
if (typeof container !== "object" || Array.isArray(container)) return null;
|
|
4058
|
+
return this.normalizeEntry(container[SERVER_NAME]);
|
|
4059
|
+
}
|
|
4060
|
+
if (!Array.isArray(container)) return null;
|
|
4061
|
+
const item = container.find((entry) => entry.name === SERVER_NAME);
|
|
4062
|
+
return this.normalizeEntry(item?.transport);
|
|
4063
|
+
}
|
|
4064
|
+
normalizeEntry(value) {
|
|
4065
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
4066
|
+
const record = value;
|
|
4067
|
+
if (typeof record.command !== "string") return null;
|
|
4068
|
+
const args = Array.isArray(record.args) ? record.args.map((arg) => String(arg)) : [];
|
|
4069
|
+
return {
|
|
4070
|
+
command: record.command,
|
|
4071
|
+
args
|
|
4072
|
+
};
|
|
4073
|
+
}
|
|
3877
4074
|
async generateSnippets(rootDir, agents, entry, report) {
|
|
3878
4075
|
const dir = path.default.join(rootDir, "mcp-config-snippets");
|
|
3879
4076
|
await fs_extra.default.ensureDir(dir);
|
|
@@ -3973,7 +4170,11 @@ var McpConfigService = class {
|
|
|
3973
4170
|
if (!data) return false;
|
|
3974
4171
|
const container = this.getNestedValue(data, target.key);
|
|
3975
4172
|
if (!container) return false;
|
|
3976
|
-
if (target.shape === "map")
|
|
4173
|
+
if (target.shape === "map") {
|
|
4174
|
+
if (typeof container !== "object" || Array.isArray(container)) return false;
|
|
4175
|
+
return Boolean(container[SERVER_NAME]);
|
|
4176
|
+
}
|
|
4177
|
+
if (!Array.isArray(container)) return false;
|
|
3977
4178
|
return container.some((item) => item.name === SERVER_NAME);
|
|
3978
4179
|
}
|
|
3979
4180
|
buildFreshDoc(target, entry) {
|
|
@@ -4076,6 +4277,10 @@ function defaultDoctorDeps() {
|
|
|
4076
4277
|
rootDir,
|
|
4077
4278
|
agents
|
|
4078
4279
|
}),
|
|
4280
|
+
buildMcpEntry: (cfg) => mcp.buildEntry({
|
|
4281
|
+
version: cfg.mcp?.version,
|
|
4282
|
+
via: cfg.mcp?.via
|
|
4283
|
+
}),
|
|
4079
4284
|
hookStatus: (rootDir, agents) => hooks.status({
|
|
4080
4285
|
rootDir,
|
|
4081
4286
|
agents
|
|
@@ -4209,13 +4414,48 @@ var DoctorService = class {
|
|
|
4209
4414
|
if (!config.mcp?.enabled || scope !== "project" && scope !== "user") return check("mcp", "skip", "MCP disabled in .skillsrc");
|
|
4210
4415
|
const rows = await this.deps.mcpStatus(rootDir, agents);
|
|
4211
4416
|
const missing = rows.filter((r) => scope === "project" ? !r.project : !(r.project || r.user)).map((r) => r.agent);
|
|
4212
|
-
if (missing.length
|
|
4213
|
-
return check("mcp", "fail", `MCP server not registered for: ${missing.join(", ")}`, {
|
|
4417
|
+
if (missing.length > 0) return check("mcp", "fail", `MCP server not registered for: ${missing.join(", ")}`, {
|
|
4214
4418
|
description: `register MCP for ${missing.join(", ")}`,
|
|
4215
4419
|
apply: async () => {
|
|
4216
4420
|
for (const agent of missing) await this.deps.installMcp(rootDir, agent, config);
|
|
4217
4421
|
}
|
|
4218
4422
|
});
|
|
4423
|
+
const expected = this.deps.buildMcpEntry ? this.deps.buildMcpEntry(config) : new McpConfigService().buildEntry({
|
|
4424
|
+
version: config.mcp.version,
|
|
4425
|
+
via: config.mcp.via
|
|
4426
|
+
});
|
|
4427
|
+
const pin = config.mcp.version ?? "0.8.0";
|
|
4428
|
+
const drifted = [];
|
|
4429
|
+
for (const row of rows) {
|
|
4430
|
+
if (scope === "project") {
|
|
4431
|
+
if (row.project && row.projectEntry && !sameMcpEntry(row.projectEntry, expected)) drifted.push({
|
|
4432
|
+
agent: row.agent,
|
|
4433
|
+
scope: "project",
|
|
4434
|
+
entry: row.projectEntry
|
|
4435
|
+
});
|
|
4436
|
+
continue;
|
|
4437
|
+
}
|
|
4438
|
+
if (row.project && row.projectEntry && !sameMcpEntry(row.projectEntry, expected)) drifted.push({
|
|
4439
|
+
agent: row.agent,
|
|
4440
|
+
scope: "project",
|
|
4441
|
+
entry: row.projectEntry
|
|
4442
|
+
});
|
|
4443
|
+
if (row.user && row.userEntry && !sameMcpEntry(row.userEntry, expected)) drifted.push({
|
|
4444
|
+
agent: row.agent,
|
|
4445
|
+
scope: "user",
|
|
4446
|
+
entry: row.userEntry
|
|
4447
|
+
});
|
|
4448
|
+
}
|
|
4449
|
+
if (drifted.length > 0) {
|
|
4450
|
+
const driftedAgents = [...new Set(drifted.map((item) => item.agent))];
|
|
4451
|
+
return check("mcp", "warn", `MCP pin drift: ${drifted.map((item) => `${item.agent} ${item.scope} pins ${item.entry.command}${item.entry.args.length ? ` ${item.entry.args.join(" ")}` : ""} but this CLI expects agent-skills-standard-mcp@${pin}`).join("; ")}`, {
|
|
4452
|
+
description: `refresh MCP entry for ${driftedAgents.join(", ")}`,
|
|
4453
|
+
apply: async () => {
|
|
4454
|
+
for (const agent of driftedAgents) await this.deps.installMcp(rootDir, agent, config);
|
|
4455
|
+
}
|
|
4456
|
+
});
|
|
4457
|
+
}
|
|
4458
|
+
return check("mcp", "ok", `registered for ${rows.map((r) => r.agent).join(", ") || "no MCP-capable agents"}`);
|
|
4219
4459
|
}
|
|
4220
4460
|
async hooksCheck(rootDir, agents) {
|
|
4221
4461
|
const rows = await this.deps.hookStatus(rootDir, agents);
|
|
@@ -10330,26 +10570,66 @@ var VALID_SCOPES = [
|
|
|
10330
10570
|
"snippets-only",
|
|
10331
10571
|
"disabled"
|
|
10332
10572
|
];
|
|
10573
|
+
var VALID_VIAS = [
|
|
10574
|
+
"auto",
|
|
10575
|
+
"npx",
|
|
10576
|
+
"global"
|
|
10577
|
+
];
|
|
10578
|
+
function parseVia(value) {
|
|
10579
|
+
return typeof value === "string" && VALID_VIAS.includes(value) ? value : null;
|
|
10580
|
+
}
|
|
10581
|
+
function defaultGlobalInstaller(spec) {
|
|
10582
|
+
if (process.platform === "win32") {
|
|
10583
|
+
(0, child_process.execFileSync)("npm.cmd", [
|
|
10584
|
+
"i",
|
|
10585
|
+
"-g",
|
|
10586
|
+
spec
|
|
10587
|
+
], {
|
|
10588
|
+
stdio: "inherit",
|
|
10589
|
+
shell: true
|
|
10590
|
+
});
|
|
10591
|
+
return;
|
|
10592
|
+
}
|
|
10593
|
+
(0, child_process.execFileSync)("npm", [
|
|
10594
|
+
"i",
|
|
10595
|
+
"-g",
|
|
10596
|
+
spec
|
|
10597
|
+
], { stdio: "inherit" });
|
|
10598
|
+
}
|
|
10599
|
+
function formatEntry(entry) {
|
|
10600
|
+
if (!entry) return "(none)";
|
|
10601
|
+
return entry.args.length ? `${entry.command} ${entry.args.join(" ")}` : entry.command;
|
|
10602
|
+
}
|
|
10333
10603
|
/**
|
|
10334
10604
|
* `ags mcp <action>` — manage the optional MCP server integration without
|
|
10335
10605
|
* editing `.skillsrc` by hand.
|
|
10336
10606
|
*
|
|
10337
10607
|
* Sub-actions:
|
|
10338
|
-
* status Show
|
|
10339
|
-
* enable
|
|
10608
|
+
* status Show scope, launch mode, resolved command, and installed configs
|
|
10609
|
+
* enable [--via=...] Set mcp.enabled=true; optionally install configs at the configured scope
|
|
10340
10610
|
* disable Set mcp.enabled=false; existing configs are NOT removed
|
|
10341
10611
|
* scope <scope> Change scope: project | user | snippets-only | disabled
|
|
10342
|
-
*
|
|
10612
|
+
* via <auto|npx|global> Change launch mode (default: auto)
|
|
10613
|
+
* install [--scope=...] [--via=...]
|
|
10614
|
+
* One-shot install at the given (or configured) scope/mode
|
|
10343
10615
|
* uninstall [--from=...] Remove our entry from configs (project | user | all)
|
|
10344
|
-
* snippets
|
|
10616
|
+
* snippets [--via=...] Generate fresh snippet files in ./mcp-config-snippets/
|
|
10617
|
+
*
|
|
10618
|
+
* `--install-global` (on enable) installs `agent-skills-standard-mcp@<pin>`
|
|
10619
|
+
* globally, then verifies the installed binary reports the pin.
|
|
10345
10620
|
*/
|
|
10346
10621
|
var McpCommand = class {
|
|
10347
10622
|
configService;
|
|
10348
10623
|
mcpService;
|
|
10624
|
+
globalInstaller = defaultGlobalInstaller;
|
|
10349
10625
|
constructor(configService, mcpService) {
|
|
10350
10626
|
this.configService = configService ?? new ConfigService();
|
|
10351
10627
|
this.mcpService = mcpService ?? new McpConfigService();
|
|
10352
10628
|
}
|
|
10629
|
+
/** For testing: replace the global npm installer (never run real npm in unit tests). */
|
|
10630
|
+
setGlobalInstallerForTesting(fn) {
|
|
10631
|
+
this.globalInstaller = fn ?? defaultGlobalInstaller;
|
|
10632
|
+
}
|
|
10353
10633
|
async run(action, options = {}) {
|
|
10354
10634
|
const config = await this.configService.loadConfig();
|
|
10355
10635
|
if (!config) {
|
|
@@ -10360,13 +10640,14 @@ var McpCommand = class {
|
|
|
10360
10640
|
const agents = config.agents ?? [];
|
|
10361
10641
|
switch (action) {
|
|
10362
10642
|
case "status": return this.actionStatus(config, cwd);
|
|
10363
|
-
case "enable": return this.actionEnable(config);
|
|
10643
|
+
case "enable": return this.actionEnable(config, agents, cwd, options);
|
|
10364
10644
|
case "disable": return this.actionDisable(config);
|
|
10365
10645
|
case "scope": return this.actionScope(config, options);
|
|
10646
|
+
case "via": return this.actionVia(config, options);
|
|
10366
10647
|
case "install": return this.actionInstall(config, agents, cwd, options);
|
|
10367
10648
|
case "uninstall": return this.actionUninstall(config, agents, cwd, options);
|
|
10368
|
-
case "snippets": return this.actionSnippets(config, agents, cwd);
|
|
10369
|
-
default: console.log(picocolors.default.red(`Unknown action: ${action}`), "\nValid actions: status, enable, disable, scope, install, uninstall, snippets");
|
|
10649
|
+
case "snippets": return this.actionSnippets(config, agents, cwd, options);
|
|
10650
|
+
default: console.log(picocolors.default.red(`Unknown action: ${action}`), "\nValid actions: status, enable, disable, scope, via, install, uninstall, snippets");
|
|
10370
10651
|
}
|
|
10371
10652
|
}
|
|
10372
10653
|
async actionStatus(config, cwd) {
|
|
@@ -10379,20 +10660,50 @@ var McpCommand = class {
|
|
|
10379
10660
|
console.log(picocolors.default.bold("\n🔌 MCP integration status\n"));
|
|
10380
10661
|
console.log(` enabled : ${mcp.enabled ? picocolors.default.green("yes") : picocolors.default.gray("no")}`);
|
|
10381
10662
|
console.log(` scope : ${picocolors.default.cyan(mcp.scope)}`);
|
|
10663
|
+
console.log(` via : ${picocolors.default.cyan(mcp.via ?? "auto")}`);
|
|
10382
10664
|
console.log(` prompted: ${mcp.prompted ? "yes" : "no"}`);
|
|
10383
10665
|
if (mcp.version) console.log(` version : ${mcp.version}`);
|
|
10666
|
+
const pin = mcp.version ?? "0.8.0";
|
|
10667
|
+
const entry = this.mcpService.buildEntry({
|
|
10668
|
+
version: mcp.version,
|
|
10669
|
+
via: mcp.via
|
|
10670
|
+
});
|
|
10671
|
+
const launch = entry.args.length ? `${entry.command} ${entry.args.join(" ")}` : entry.command;
|
|
10672
|
+
console.log(` launch : ${picocolors.default.gray(launch)}`);
|
|
10673
|
+
console.log(` pin : ${pin}`);
|
|
10674
|
+
const detected = this.mcpService.detectGlobalVersion();
|
|
10675
|
+
console.log(` global : ${detected ? picocolors.default.green(detected) : picocolors.default.gray("not found")}`);
|
|
10676
|
+
if (detected && detected !== pin) {
|
|
10677
|
+
console.log(picocolors.default.yellow(`\n⚠️ Global ags-mcp is ${detected} but the CLI pin is ${pin}; "auto" will use npx until they match.`));
|
|
10678
|
+
console.log(picocolors.default.gray(` Update with: npm i -g ${PACKAGE}@${pin}`));
|
|
10679
|
+
}
|
|
10384
10680
|
if (rows.length === 0) {
|
|
10385
10681
|
console.log(picocolors.default.gray("\n (no agents configured)"));
|
|
10386
10682
|
return;
|
|
10387
10683
|
}
|
|
10388
10684
|
console.log("\n Per-agent installation state:");
|
|
10389
10685
|
let installedAnywhere = false;
|
|
10686
|
+
const drift = [];
|
|
10390
10687
|
for (const row of rows) {
|
|
10391
|
-
const project = row.project === void 0 ? "—" : row.project ? picocolors.default.green("✓") : picocolors.default.gray("✗")
|
|
10392
|
-
const user = row.user === void 0 ? "—" : row.user ? picocolors.default.green("✓") : picocolors.default.gray("✗")
|
|
10688
|
+
const project = row.project === void 0 ? "—" : `${row.project ? picocolors.default.green("✓") : picocolors.default.gray("✗")} ${formatEntry(row.projectEntry)}`;
|
|
10689
|
+
const user = row.user === void 0 ? "—" : `${row.user ? picocolors.default.green("✓") : picocolors.default.gray("✗")} ${formatEntry(row.userEntry)}`;
|
|
10393
10690
|
if (row.project === true || row.user === true) installedAnywhere = true;
|
|
10691
|
+
if (row.project === true && row.projectEntry && !sameMcpEntry(row.projectEntry, entry)) drift.push({
|
|
10692
|
+
agent: row.agent,
|
|
10693
|
+
scope: "project",
|
|
10694
|
+
configured: row.projectEntry
|
|
10695
|
+
});
|
|
10696
|
+
if (row.user === true && row.userEntry && !sameMcpEntry(row.userEntry, entry)) drift.push({
|
|
10697
|
+
agent: row.agent,
|
|
10698
|
+
scope: "user",
|
|
10699
|
+
configured: row.userEntry
|
|
10700
|
+
});
|
|
10394
10701
|
console.log(` ${row.agent.padEnd(12)} project: ${project} user: ${user}`);
|
|
10395
10702
|
}
|
|
10703
|
+
if (drift.length > 0) {
|
|
10704
|
+
for (const item of drift) console.log(picocolors.default.yellow(`\n⚠️ MCP pin drift: ${item.agent} ${item.scope} pins ${formatEntry(item.configured)} but this CLI expects ${launch}.`));
|
|
10705
|
+
console.log(picocolors.default.gray(" Run `ags sync` (or `ags mcp install`) to refresh; existing agents pick it up on their next MCP start."));
|
|
10706
|
+
}
|
|
10396
10707
|
if (!mcp.enabled && installedAnywhere) {
|
|
10397
10708
|
console.log(picocolors.default.yellow("\n⚠️ Mismatch detected: .skillsrc says mcp.enabled=false, but the MCP entry IS present in at least one runtime config."));
|
|
10398
10709
|
console.log(picocolors.default.gray(" The MCP will work, but `sync` will not keep its config in step. Consider one of:"));
|
|
@@ -10403,12 +10714,38 @@ var McpCommand = class {
|
|
|
10403
10714
|
console.log(picocolors.default.gray(" Run `ags mcp install` to write the entries, or `ags mcp disable` to clear the consent flag."));
|
|
10404
10715
|
}
|
|
10405
10716
|
}
|
|
10406
|
-
async actionEnable(config) {
|
|
10717
|
+
async actionEnable(config, agents, cwd, options) {
|
|
10407
10718
|
const mcp = config.mcp ?? defaultMcpConfig();
|
|
10719
|
+
const viaOverrideRaw = options.via;
|
|
10720
|
+
const viaOverride = viaOverrideRaw ? parseVia(viaOverrideRaw) : void 0;
|
|
10721
|
+
if (viaOverrideRaw && !viaOverride) {
|
|
10722
|
+
console.log(picocolors.default.red(`Invalid --via value. Valid: ${VALID_VIAS.join(" | ")}`));
|
|
10723
|
+
return;
|
|
10724
|
+
}
|
|
10408
10725
|
if (mcp.scope === "disabled") {
|
|
10409
10726
|
console.log(picocolors.default.yellow("⚠️ scope is currently \"disabled\". Set a real scope first: `ags mcp scope project`"));
|
|
10410
10727
|
return;
|
|
10411
10728
|
}
|
|
10729
|
+
if (options.installGlobal) {
|
|
10730
|
+
const pin = mcp.version ?? "0.8.0";
|
|
10731
|
+
const spec = `${PACKAGE}@${pin}`;
|
|
10732
|
+
try {
|
|
10733
|
+
this.globalInstaller(spec);
|
|
10734
|
+
} catch {
|
|
10735
|
+
console.log(picocolors.default.red(`❌ Global install failed. Run manually:`));
|
|
10736
|
+
console.log(picocolors.default.gray(` npm i -g ${spec}`));
|
|
10737
|
+
process.exitCode = 1;
|
|
10738
|
+
return;
|
|
10739
|
+
}
|
|
10740
|
+
const detected = this.mcpService.detectGlobalVersion();
|
|
10741
|
+
if (detected !== pin) {
|
|
10742
|
+
console.log(picocolors.default.red(`❌ Global ags-mcp reports ${detected ?? "no version"} but the CLI pin is ${pin}.`));
|
|
10743
|
+
console.log(picocolors.default.gray(` Run manually: npm i -g ${spec}`));
|
|
10744
|
+
process.exitCode = 1;
|
|
10745
|
+
return;
|
|
10746
|
+
}
|
|
10747
|
+
console.log(picocolors.default.green(`✅ Global ags-mcp ${pin} installed and verified.`));
|
|
10748
|
+
}
|
|
10412
10749
|
config.mcp = {
|
|
10413
10750
|
...mcp,
|
|
10414
10751
|
enabled: true,
|
|
@@ -10416,8 +10753,37 @@ var McpCommand = class {
|
|
|
10416
10753
|
};
|
|
10417
10754
|
await this.configService.saveConfig(config);
|
|
10418
10755
|
console.log(picocolors.default.green("✅ MCP enabled."));
|
|
10756
|
+
if (viaOverride) {
|
|
10757
|
+
const report = await this.mcpService.install({
|
|
10758
|
+
rootDir: cwd,
|
|
10759
|
+
agents,
|
|
10760
|
+
mcp: {
|
|
10761
|
+
...config.mcp,
|
|
10762
|
+
via: viaOverride
|
|
10763
|
+
}
|
|
10764
|
+
});
|
|
10765
|
+
console.log(picocolors.default.gray(` Installed configs using launch mode "${viaOverride}".`));
|
|
10766
|
+
this.printReport(report, cwd);
|
|
10767
|
+
return;
|
|
10768
|
+
}
|
|
10419
10769
|
console.log(picocolors.default.gray(" Run `ags mcp install` to write configs now, or it happens on next `sync`."));
|
|
10420
10770
|
}
|
|
10771
|
+
async actionVia(config, options) {
|
|
10772
|
+
const via = options.via ?? options._?.[0];
|
|
10773
|
+
if (!parseVia(via)) {
|
|
10774
|
+
console.log(picocolors.default.red(`Invalid via. Valid: ${VALID_VIAS.join(" | ")}`));
|
|
10775
|
+
return;
|
|
10776
|
+
}
|
|
10777
|
+
config.mcp = {
|
|
10778
|
+
...config.mcp ?? defaultMcpConfig(),
|
|
10779
|
+
via,
|
|
10780
|
+
prompted: true
|
|
10781
|
+
};
|
|
10782
|
+
await this.configService.saveConfig(config);
|
|
10783
|
+
console.log(picocolors.default.green(`✅ MCP launch mode set to "${via}".`));
|
|
10784
|
+
if (via === "global") console.log(picocolors.default.yellow("⚠️ \"global\" requires a matching global install: `ags mcp enable --install-global`."));
|
|
10785
|
+
else if (via === "auto") console.log(picocolors.default.gray(" \"auto\" uses a version-matched global ags-mcp when present, otherwise npx."));
|
|
10786
|
+
}
|
|
10421
10787
|
async actionDisable(config) {
|
|
10422
10788
|
config.mcp = {
|
|
10423
10789
|
...config.mcp ?? defaultMcpConfig(),
|
|
@@ -10451,6 +10817,12 @@ var McpCommand = class {
|
|
|
10451
10817
|
console.log(picocolors.default.red(`Invalid --scope value. Valid: ${VALID_SCOPES.join(" | ")}`));
|
|
10452
10818
|
return;
|
|
10453
10819
|
}
|
|
10820
|
+
const viaOverrideRaw = options.via;
|
|
10821
|
+
const viaOverride = viaOverrideRaw ? parseVia(viaOverrideRaw) : void 0;
|
|
10822
|
+
if (viaOverrideRaw && !viaOverride) {
|
|
10823
|
+
console.log(picocolors.default.red(`Invalid --via value. Valid: ${VALID_VIAS.join(" | ")}`));
|
|
10824
|
+
return;
|
|
10825
|
+
}
|
|
10454
10826
|
if (effectiveScope === "disabled") {
|
|
10455
10827
|
console.log(picocolors.default.yellow("Scope is \"disabled\" — nothing to install."));
|
|
10456
10828
|
return;
|
|
@@ -10470,7 +10842,8 @@ var McpCommand = class {
|
|
|
10470
10842
|
mcp: {
|
|
10471
10843
|
...mcp,
|
|
10472
10844
|
enabled: true,
|
|
10473
|
-
scope: effectiveScope
|
|
10845
|
+
scope: effectiveScope,
|
|
10846
|
+
...viaOverride ? { via: viaOverride } : {}
|
|
10474
10847
|
},
|
|
10475
10848
|
userScopePrompt: userPrompt
|
|
10476
10849
|
});
|
|
@@ -10498,15 +10871,22 @@ var McpCommand = class {
|
|
|
10498
10871
|
console.log(picocolors.default.green(`✅ Removed agent-skills MCP entry from:`));
|
|
10499
10872
|
for (const r of removed) console.log(` - ${picocolors.default.cyan(r.agent)} → ${picocolors.default.gray(r.file)}`);
|
|
10500
10873
|
}
|
|
10501
|
-
async actionSnippets(config, agents, cwd) {
|
|
10874
|
+
async actionSnippets(config, agents, cwd, options) {
|
|
10502
10875
|
const mcp = config.mcp ?? defaultMcpConfig();
|
|
10876
|
+
const viaOverrideRaw = options.via;
|
|
10877
|
+
const viaOverride = viaOverrideRaw ? parseVia(viaOverrideRaw) : void 0;
|
|
10878
|
+
if (viaOverrideRaw && !viaOverride) {
|
|
10879
|
+
console.log(picocolors.default.red(`Invalid --via value. Valid: ${VALID_VIAS.join(" | ")}`));
|
|
10880
|
+
return;
|
|
10881
|
+
}
|
|
10503
10882
|
const report = await this.mcpService.install({
|
|
10504
10883
|
rootDir: cwd,
|
|
10505
10884
|
agents,
|
|
10506
10885
|
mcp: {
|
|
10507
10886
|
...mcp,
|
|
10508
10887
|
enabled: true,
|
|
10509
|
-
scope: "snippets-only"
|
|
10888
|
+
scope: "snippets-only",
|
|
10889
|
+
...viaOverride ? { via: viaOverride } : {}
|
|
10510
10890
|
}
|
|
10511
10891
|
});
|
|
10512
10892
|
if (report.snippets.length === 0) {
|
|
@@ -10605,12 +10985,14 @@ var RetrospectiveCommand = class {
|
|
|
10605
10985
|
env;
|
|
10606
10986
|
customExit;
|
|
10607
10987
|
log;
|
|
10988
|
+
mcpVersion;
|
|
10608
10989
|
constructor(deps = {}) {
|
|
10609
10990
|
this.spawnFn = deps.spawnFn ?? defaultSpawn;
|
|
10610
10991
|
this.platform = deps.platform ?? process.platform;
|
|
10611
10992
|
this.env = deps.env ?? process.env;
|
|
10612
10993
|
this.customExit = deps.exit;
|
|
10613
10994
|
this.log = deps.log ?? console.log;
|
|
10995
|
+
this.mcpVersion = deps.mcpVersion ?? "0.8.0";
|
|
10614
10996
|
}
|
|
10615
10997
|
exit(code) {
|
|
10616
10998
|
process.exitCode = code;
|
|
@@ -10639,8 +11021,8 @@ var RetrospectiveCommand = class {
|
|
|
10639
11021
|
}
|
|
10640
11022
|
}
|
|
10641
11023
|
const envSpec = this.env.AGS_MCP_PACKAGE_SPEC;
|
|
10642
|
-
if (!(typeof envSpec === "string" && envSpec.trim() !== "") && !isVersionAtLeast(
|
|
10643
|
-
this.log(`Session retrospectives need agent-skills-standard-mcp ${RETROSPECTIVE_MIN_MCP_VERSION} or newer, but this ags is pinned to ${
|
|
11024
|
+
if (!(typeof envSpec === "string" && envSpec.trim() !== "") && !isVersionAtLeast(this.mcpVersion, "0.8.0")) {
|
|
11025
|
+
this.log(`Session retrospectives need agent-skills-standard-mcp ${RETROSPECTIVE_MIN_MCP_VERSION} or newer, but this ags is pinned to ${this.mcpVersion}. Upgrade ags (ags upgrade), or set AGS_MCP_PACKAGE_SPEC to a newer package for testing.`);
|
|
10644
11026
|
this.exit(1);
|
|
10645
11027
|
return;
|
|
10646
11028
|
}
|
|
@@ -10659,7 +11041,8 @@ var RetrospectiveCommand = class {
|
|
|
10659
11041
|
}
|
|
10660
11042
|
const argsToSpawn = [
|
|
10661
11043
|
"-y",
|
|
10662
|
-
|
|
11044
|
+
"--prefer-offline",
|
|
11045
|
+
typeof envSpec === "string" && envSpec.trim() !== "" ? envSpec : `${PACKAGE}@${this.mcpVersion}`,
|
|
10663
11046
|
"retrospective",
|
|
10664
11047
|
mappedAction,
|
|
10665
11048
|
...forwarded
|
|
@@ -11338,7 +11721,11 @@ var AuditCommand = class {
|
|
|
11338
11721
|
* It checks the latest version on npm and performs the upgrade using the detected package manager.
|
|
11339
11722
|
*/
|
|
11340
11723
|
var UpgradeCommand = class {
|
|
11724
|
+
deps;
|
|
11341
11725
|
currentVersion = package_default.version;
|
|
11726
|
+
constructor(deps = {}) {
|
|
11727
|
+
this.deps = deps;
|
|
11728
|
+
}
|
|
11342
11729
|
/**
|
|
11343
11730
|
* Executes the upgrade flow.
|
|
11344
11731
|
* @param options Command options, including `dryRun` to check for updates without installing.
|
|
@@ -11383,6 +11770,7 @@ var UpgradeCommand = class {
|
|
|
11383
11770
|
const fallbackCmd = this.getUpgradeCommand(pm, "latest");
|
|
11384
11771
|
(0, child_process.execSync)(fallbackCmd, { stdio: "inherit" });
|
|
11385
11772
|
}
|
|
11773
|
+
await this.printMcpRefreshHint();
|
|
11386
11774
|
if (pm === "pnpm") {
|
|
11387
11775
|
const installedVersion = this.getInstalledVersionFromPnpm(latestVersion);
|
|
11388
11776
|
if (installedVersion !== latestVersion) {
|
|
@@ -11434,6 +11822,12 @@ var UpgradeCommand = class {
|
|
|
11434
11822
|
this.printManualInstructions(pm, latestVersion);
|
|
11435
11823
|
}
|
|
11436
11824
|
}
|
|
11825
|
+
async printMcpRefreshHint() {
|
|
11826
|
+
try {
|
|
11827
|
+
if (!(this.deps.loadMcpEnabled ? await this.deps.loadMcpEnabled() : (await new ConfigService().loadConfig())?.mcp?.enabled ?? false)) return;
|
|
11828
|
+
console.log(picocolors.default.gray(`MCP configs are not rewritten by upgrade — run \`ags sync\` (or \`ags mcp install\`) to move them to ${MCP_COMPATIBLE_VERSION}.`));
|
|
11829
|
+
} catch {}
|
|
11830
|
+
}
|
|
11437
11831
|
detectPackageManager() {
|
|
11438
11832
|
const execPath = process.argv[1] || "";
|
|
11439
11833
|
if (execPath.includes("pnpm") || (process.env.npm_config_user_agent || "").includes("pnpm")) return "pnpm";
|
|
@@ -13410,9 +13804,12 @@ program.command("feedback").description("Report skill improvement opportunities
|
|
|
13410
13804
|
program.command("upgrade").description("Upgrade the CLI to the latest version").option("--dry-run", "Check for updates without installing").action(async (options) => {
|
|
13411
13805
|
await new UpgradeCommand().run(options);
|
|
13412
13806
|
});
|
|
13413
|
-
program.command("mcp <action> [scope]").description("Manage the optional MCP server integration. Actions: status | enable | disable | scope <project|user|snippets-only|disabled> | install | uninstall | snippets").option("--scope <scope>", "Override scope for install (project|user|snippets-only|disabled)").option("--from <from>", "For uninstall: project | user | all (default: project)").action(async (action, positional, opts) => {
|
|
13807
|
+
program.command("mcp <action> [scope]").description("Manage the optional MCP server integration. Actions: status | enable | disable | scope <project|user|snippets-only|disabled> | via <auto|npx|global> | install | uninstall | snippets").option("--scope <scope>", "Override scope for install (project|user|snippets-only|disabled)").option("--via <via>", "Override launch mode for this run (auto|npx|global)").option("--install-global", "On enable: install agent-skills-standard-mcp@<pin> globally, then verify its version").option("--from <from>", "For uninstall: project | user | all (default: project)").action(async (action, positional, opts) => {
|
|
13414
13808
|
const merged = { ...opts };
|
|
13415
|
-
if (positional)
|
|
13809
|
+
if (positional) {
|
|
13810
|
+
if (action === "via") merged.via = opts.via ?? positional;
|
|
13811
|
+
else merged.scope = opts.scope ?? positional;
|
|
13812
|
+
}
|
|
13416
13813
|
await new McpCommand().run(action, merged);
|
|
13417
13814
|
});
|
|
13418
13815
|
program.command("retrospective <action> [args...]").description("Enable, disable or inspect local session retrospectives (consent and the cross-session index). Runs the pinned agent-skills-standard-mcp package. Actions: enable | disable | status | index").allowUnknownOption(true).option("--store-root <path>", "Store root directory").option("--source-root <path>", "Additional source root for transcripts (repeatable)", (val, prev) => prev ? [...prev, val] : [val]).option("--since <YYYY-MM-DD>", "Index sessions since date").option("--until <YYYY-MM-DD>", "Index sessions until date").option("--folder <name>", "Index sessions from folder").action(async (action, args = [], options = {}) => {
|