hngr 0.3.0 → 0.5.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/README.md +13 -3
- package/dist/{auth-CgBUQUQn.mjs → auth-ByGgd_Yn.mjs} +49 -11
- package/dist/{catalog-DbGLqQ8a.mjs → catalog-Bv304SXJ.mjs} +412 -20
- package/dist/{commands-BHXSZ04F.mjs → commands-CLqLwQHY.mjs} +1 -1
- package/dist/{http-2HWxLIOq.mjs → http-DgHX7Fux.mjs} +13 -7
- package/dist/index.mjs +136 -21
- package/dist/{mcp-b6bE3ZRt.mjs → mcp-B0sbQABp.mjs} +27 -50
- package/dist/{pagination-BbKLKSw3.mjs → pagination-BXyFxGYA.mjs} +1 -1
- package/dist/{publish-EUqgdp0G.mjs → scope-DVfDeQi2.mjs} +37 -3
- package/dist/{skills-XDbBCC5f.mjs → skills-ZFmFyZtw.mjs} +80 -70
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as kebabCase, i as normalizeCommandName, n as COMMANDS, o as COMMAND_ALIASES, r as findCommand, t as commandCatalog } from "./catalog-
|
|
2
|
-
import { C as
|
|
3
|
-
import { t as collectPages } from "./pagination-
|
|
1
|
+
import { a as kebabCase, i as normalizeCommandName, n as COMMANDS, o as COMMAND_ALIASES, r as findCommand, t as commandCatalog } from "./catalog-Bv304SXJ.mjs";
|
|
2
|
+
import { C as HngrError, S as CancelledError, c as redactUrlForDisplay, g as resolveConnection, i as buildRequestUrl, o as redactQuery, r as apiRequest, s as redactSensitive, u as DEFAULT_SERVER_URL, w as renderError } from "./http-DgHX7Fux.mjs";
|
|
3
|
+
import { t as collectPages } from "./pagination-BXyFxGYA.mjs";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { notStrictEqual, strictEqual } from "assert";
|
|
6
6
|
import { basename, dirname, extname, join, normalize, relative, resolve } from "path";
|
|
@@ -5279,7 +5279,7 @@ function isYargsInstance(y) {
|
|
|
5279
5279
|
// ../../node_modules/.pnpm/yargs@18.2.0/node_modules/yargs/index.mjs
|
|
5280
5280
|
const Yargs = YargsFactory(esm_default);
|
|
5281
5281
|
// package.json
|
|
5282
|
-
var version = "0.
|
|
5282
|
+
var version = "0.5.0";
|
|
5283
5283
|
// src/generated/completion.ts
|
|
5284
5284
|
function isCompletionShell(value) {
|
|
5285
5285
|
return value === "bash" || value === "zsh" || value === "fish";
|
|
@@ -6499,6 +6499,32 @@ let u$1 = class u extends y {
|
|
|
6499
6499
|
});
|
|
6500
6500
|
}
|
|
6501
6501
|
};
|
|
6502
|
+
let n$1 = class n extends y {
|
|
6503
|
+
options;
|
|
6504
|
+
cursor = 0;
|
|
6505
|
+
get _selectedValue() {
|
|
6506
|
+
return this.options[this.cursor];
|
|
6507
|
+
}
|
|
6508
|
+
changeValue() {
|
|
6509
|
+
const e = this._selectedValue;
|
|
6510
|
+
this.value = e === void 0 ? void 0 : e.value;
|
|
6511
|
+
}
|
|
6512
|
+
constructor(e) {
|
|
6513
|
+
super(e, false), this.options = e.options;
|
|
6514
|
+
const o = this.options.findIndex(({ value: s }) => s === e.initialValue), t = o === -1 ? 0 : o;
|
|
6515
|
+
this.cursor = this.options[t]?.disabled ? findCursor(t, 1, this.options) : t, this.changeValue(), this.on("cursor", (s) => {
|
|
6516
|
+
switch (s) {
|
|
6517
|
+
case "left":
|
|
6518
|
+
case "up":
|
|
6519
|
+
this.cursor = findCursor(this.cursor, -1, this.options);
|
|
6520
|
+
break;
|
|
6521
|
+
case "down":
|
|
6522
|
+
case "right": this.cursor = findCursor(this.cursor, 1, this.options);
|
|
6523
|
+
}
|
|
6524
|
+
this.changeValue();
|
|
6525
|
+
});
|
|
6526
|
+
}
|
|
6527
|
+
};
|
|
6502
6528
|
var n = class extends y {
|
|
6503
6529
|
get userInputWithCursor() {
|
|
6504
6530
|
if (this.state === "submit") return this.userInput;
|
|
@@ -6534,6 +6560,8 @@ const S_STEP_ERROR = unicodeOr("▲", "x");
|
|
|
6534
6560
|
const S_STEP_SUBMIT = unicodeOr("◇", "o");
|
|
6535
6561
|
const S_BAR = unicodeOr("│", "|");
|
|
6536
6562
|
const S_BAR_END = unicodeOr("└", "—");
|
|
6563
|
+
const S_RADIO_ACTIVE = unicodeOr("●", ">");
|
|
6564
|
+
const S_RADIO_INACTIVE = unicodeOr("○", " ");
|
|
6537
6565
|
const S_CHECKBOX_ACTIVE = unicodeOr("◻", "[•]");
|
|
6538
6566
|
const S_CHECKBOX_SELECTED = unicodeOr("◼", "[+]");
|
|
6539
6567
|
const S_CHECKBOX_INACTIVE = unicodeOr("◻", "[ ]");
|
|
@@ -6693,6 +6721,13 @@ ${h}
|
|
|
6693
6721
|
}
|
|
6694
6722
|
}).prompt();
|
|
6695
6723
|
};
|
|
6724
|
+
const outro = (o = "", t) => {
|
|
6725
|
+
const i = t?.output ?? process.stdout, e = t?.withGuide ?? settings.withGuide ? `${styleText("gray", S_BAR)}
|
|
6726
|
+
${styleText("gray", S_BAR_END)} ` : "";
|
|
6727
|
+
i.write(`${e}${o}
|
|
6728
|
+
|
|
6729
|
+
`);
|
|
6730
|
+
};
|
|
6696
6731
|
const password = (e) => new u$1({
|
|
6697
6732
|
validate: e.validate,
|
|
6698
6733
|
mask: e.mask ?? S_PASSWORD_MASK,
|
|
@@ -6720,7 +6755,64 @@ ${r ? styleText("cyan", S_BAR_END) : ""}
|
|
|
6720
6755
|
}
|
|
6721
6756
|
}
|
|
6722
6757
|
}).prompt();
|
|
6723
|
-
`${styleText("dim", "↑/↓")}`, `${styleText("dim", "Enter:")}
|
|
6758
|
+
const SELECT_INSTRUCTIONS = [`${styleText("dim", "↑/↓")} to navigate`, `${styleText("dim", "Enter:")} confirm`];
|
|
6759
|
+
const c = (t, o) => t.includes(`
|
|
6760
|
+
`) ? t.split(`
|
|
6761
|
+
`).map((d) => o(d)).join(`
|
|
6762
|
+
`) : o(t);
|
|
6763
|
+
const select = (t) => {
|
|
6764
|
+
const o = (n, m) => {
|
|
6765
|
+
if (n === void 0) return "";
|
|
6766
|
+
const s = n.label ?? String(n.value);
|
|
6767
|
+
switch (m) {
|
|
6768
|
+
case "disabled": return `${styleText("gray", S_RADIO_INACTIVE)} ${c(s, (i) => styleText("gray", i))}${n.hint ? ` ${styleText("dim", `(${n.hint ?? "disabled"})`)}` : ""}`;
|
|
6769
|
+
case "selected": return `${c(s, (i) => styleText("dim", i))}`;
|
|
6770
|
+
case "active": return `${styleText("green", S_RADIO_ACTIVE)} ${s}${n.hint ? ` ${styleText("dim", `(${n.hint})`)}` : ""}`;
|
|
6771
|
+
case "cancelled": return `${c(s, (i) => styleText(["strikethrough", "dim"], i))}`;
|
|
6772
|
+
default: return `${styleText("dim", S_RADIO_INACTIVE)} ${c(s, (i) => styleText("dim", i))}`;
|
|
6773
|
+
}
|
|
6774
|
+
}, d = t.showInstructions ?? true;
|
|
6775
|
+
return new n$1({
|
|
6776
|
+
options: t.options,
|
|
6777
|
+
signal: t.signal,
|
|
6778
|
+
input: t.input,
|
|
6779
|
+
output: t.output,
|
|
6780
|
+
initialValue: t.initialValue,
|
|
6781
|
+
render() {
|
|
6782
|
+
const n = t.withGuide ?? settings.withGuide, m = `${symbol(this.state)} `, s = `${symbolBar(this.state)} `, i = wrapTextWithPrefix(t.output, t.message, s, m), u = `${n ? `${styleText("gray", S_BAR)}
|
|
6783
|
+
` : ""}${i}
|
|
6784
|
+
`;
|
|
6785
|
+
switch (this.state) {
|
|
6786
|
+
case "submit": {
|
|
6787
|
+
const r = n ? `${styleText("gray", S_BAR)} ` : "";
|
|
6788
|
+
return `${u}${wrapTextWithPrefix(t.output, o(this.options[this.cursor], "selected"), r)}`;
|
|
6789
|
+
}
|
|
6790
|
+
case "cancel": {
|
|
6791
|
+
const r = n ? `${styleText("gray", S_BAR)} ` : "";
|
|
6792
|
+
return `${u}${wrapTextWithPrefix(t.output, o(this.options[this.cursor], "cancelled"), r)}${n ? `
|
|
6793
|
+
${styleText("gray", S_BAR)}` : ""}`;
|
|
6794
|
+
}
|
|
6795
|
+
default: {
|
|
6796
|
+
const r = n ? `${styleText("cyan", S_BAR)} ` : "", a = u.split(`
|
|
6797
|
+
`).length, p = d ? formatInstructionFooter(SELECT_INSTRUCTIONS, n) : n ? [styleText("cyan", S_BAR_END)] : [], f = p.join(`
|
|
6798
|
+
`), b = p.length + 1;
|
|
6799
|
+
return `${u}${r}${limitOptions({
|
|
6800
|
+
output: t.output,
|
|
6801
|
+
cursor: this.cursor,
|
|
6802
|
+
options: this.options,
|
|
6803
|
+
maxItems: t.maxItems,
|
|
6804
|
+
columnPadding: r.length,
|
|
6805
|
+
rowPadding: a + b,
|
|
6806
|
+
style: (g, x) => o(g, g.disabled ? "disabled" : x ? "active" : "inactive")
|
|
6807
|
+
}).join(`
|
|
6808
|
+
${r}`)}
|
|
6809
|
+
${f}
|
|
6810
|
+
`;
|
|
6811
|
+
}
|
|
6812
|
+
}
|
|
6813
|
+
}
|
|
6814
|
+
}).prompt();
|
|
6815
|
+
};
|
|
6724
6816
|
`${styleText("gray", S_BAR)}`;
|
|
6725
6817
|
const text = (t) => new n({
|
|
6726
6818
|
validate: t.validate,
|
|
@@ -6804,15 +6896,33 @@ function clackPrompter(streams = {}) {
|
|
|
6804
6896
|
}
|
|
6805
6897
|
}));
|
|
6806
6898
|
},
|
|
6807
|
-
async
|
|
6899
|
+
async select(message, options, initialValue) {
|
|
6900
|
+
return unwrapPrompt(await select({
|
|
6901
|
+
message,
|
|
6902
|
+
input,
|
|
6903
|
+
output,
|
|
6904
|
+
options,
|
|
6905
|
+
initialValue
|
|
6906
|
+
}));
|
|
6907
|
+
},
|
|
6908
|
+
async multiselect(message, options, initialValues = [], hint) {
|
|
6909
|
+
if (hint) output.write(`${import_picocolors.default.dim(hint)}\n`);
|
|
6808
6910
|
return unwrapPrompt(await multiselect({
|
|
6809
6911
|
message,
|
|
6810
6912
|
input,
|
|
6811
6913
|
output,
|
|
6812
6914
|
options,
|
|
6813
6915
|
initialValues,
|
|
6814
|
-
required:
|
|
6916
|
+
required: false
|
|
6815
6917
|
}));
|
|
6918
|
+
},
|
|
6919
|
+
note(message, title) {
|
|
6920
|
+
output.write(`${import_picocolors.default.green("◇")} ${title}\n`);
|
|
6921
|
+
output.write(`${import_picocolors.default.dim("│")}\n`);
|
|
6922
|
+
for (const line of message.split("\n")) output.write(`${import_picocolors.default.dim("│")} ${line}\n`);
|
|
6923
|
+
},
|
|
6924
|
+
outro(message) {
|
|
6925
|
+
outro(message, { output });
|
|
6816
6926
|
}
|
|
6817
6927
|
};
|
|
6818
6928
|
}
|
|
@@ -6828,7 +6938,7 @@ const GLOBAL_OPTIONS = {
|
|
|
6828
6938
|
json: {
|
|
6829
6939
|
type: "boolean",
|
|
6830
6940
|
default: false,
|
|
6831
|
-
describe: "Machine mode:
|
|
6941
|
+
describe: "Machine mode: print the JSON payload even on a TTY, and errors as JSON",
|
|
6832
6942
|
global: true
|
|
6833
6943
|
},
|
|
6834
6944
|
quiet: {
|
|
@@ -6846,7 +6956,7 @@ const GLOBAL_OPTIONS = {
|
|
|
6846
6956
|
force: {
|
|
6847
6957
|
type: "boolean",
|
|
6848
6958
|
default: false,
|
|
6849
|
-
describe: "
|
|
6959
|
+
describe: "Skip destructive confirmations",
|
|
6850
6960
|
global: true
|
|
6851
6961
|
},
|
|
6852
6962
|
"dry-run": {
|
|
@@ -6911,7 +7021,7 @@ function buildParser(onMatched) {
|
|
|
6911
7021
|
parser.command("commands", "Print the command catalog", () => {}, (argv) => {
|
|
6912
7022
|
onMatched({
|
|
6913
7023
|
argv,
|
|
6914
|
-
run: async (ctx) => (await import("./commands-
|
|
7024
|
+
run: async (ctx) => (await import("./commands-CLqLwQHY.mjs")).run(ctx)
|
|
6915
7025
|
});
|
|
6916
7026
|
});
|
|
6917
7027
|
parser.command("auth", "Manage credentials", (auth) => {
|
|
@@ -6924,35 +7034,40 @@ function buildParser(onMatched) {
|
|
|
6924
7034
|
}).conflicts("password", "token"), (argv) => {
|
|
6925
7035
|
onMatched({
|
|
6926
7036
|
argv,
|
|
6927
|
-
run: async (ctx, matchedArgv) => (await import("./auth-
|
|
7037
|
+
run: async (ctx, matchedArgv) => (await import("./auth-ByGgd_Yn.mjs")).login(ctx, matchedArgv)
|
|
6928
7038
|
});
|
|
6929
7039
|
});
|
|
6930
7040
|
auth.command("logout", "Revoke the stored token and delete the local config", () => {}, (argv) => {
|
|
6931
7041
|
onMatched({
|
|
6932
7042
|
argv,
|
|
6933
|
-
run: async (ctx) => (await import("./auth-
|
|
7043
|
+
run: async (ctx) => (await import("./auth-ByGgd_Yn.mjs")).logout(ctx)
|
|
6934
7044
|
});
|
|
6935
7045
|
});
|
|
6936
|
-
auth.command("status", "Show credential source, server, principal
|
|
7046
|
+
auth.command("status", "Show credential source, server, principal, token prefix and audience", (status) => status.option("offline", {
|
|
6937
7047
|
type: "boolean",
|
|
6938
7048
|
default: false,
|
|
6939
7049
|
describe: "Skip the live GET /me check"
|
|
6940
7050
|
}), (argv) => {
|
|
6941
7051
|
onMatched({
|
|
6942
7052
|
argv,
|
|
6943
|
-
run: async (ctx, matchedArgv) => (await import("./auth-
|
|
7053
|
+
run: async (ctx, matchedArgv) => (await import("./auth-ByGgd_Yn.mjs")).status(ctx, matchedArgv)
|
|
6944
7054
|
});
|
|
6945
7055
|
});
|
|
6946
|
-
auth.command("token", "Print the access token to stdout and nothing else", () =>
|
|
7056
|
+
auth.command("token", "Print the access token to stdout and nothing else", (token) => token.option("audience", {
|
|
7057
|
+
type: "string",
|
|
7058
|
+
choices: ["management", "mcp"],
|
|
7059
|
+
default: "management",
|
|
7060
|
+
describe: "management prints the stored token; mcp mints a new MCP token that can read and write the catalog content you have access to, without changing the stored credential"
|
|
7061
|
+
}), (argv) => {
|
|
6947
7062
|
onMatched({
|
|
6948
7063
|
argv,
|
|
6949
|
-
run: async (ctx) => (await import("./auth-
|
|
7064
|
+
run: async (ctx, matchedArgv) => (await import("./auth-ByGgd_Yn.mjs")).token(ctx, matchedArgv)
|
|
6950
7065
|
});
|
|
6951
7066
|
});
|
|
6952
7067
|
auth.command("whoami", "Print the GET /me payload", () => {}, (argv) => {
|
|
6953
7068
|
onMatched({
|
|
6954
7069
|
argv,
|
|
6955
|
-
run: async (ctx) => (await import("./auth-
|
|
7070
|
+
run: async (ctx) => (await import("./auth-ByGgd_Yn.mjs")).whoami(ctx)
|
|
6956
7071
|
});
|
|
6957
7072
|
});
|
|
6958
7073
|
registerGeneratedAuth(auth, onMatched);
|
|
@@ -6986,7 +7101,7 @@ function buildParser(onMatched) {
|
|
|
6986
7101
|
}), (argv) => {
|
|
6987
7102
|
onMatched({
|
|
6988
7103
|
argv,
|
|
6989
|
-
run: async (ctx, matchedArgv) => (await import("./skills-
|
|
7104
|
+
run: async (ctx, matchedArgv) => (await import("./skills-ZFmFyZtw.mjs")).add(ctx, matchedArgv)
|
|
6990
7105
|
});
|
|
6991
7106
|
});
|
|
6992
7107
|
skills.command("publish <paths..>", "Publish a local skill directory as a capability or a new version", (publish) => publish.option("namespace", {
|
|
@@ -7014,7 +7129,7 @@ function buildParser(onMatched) {
|
|
|
7014
7129
|
}), (argv) => {
|
|
7015
7130
|
onMatched({
|
|
7016
7131
|
argv,
|
|
7017
|
-
run: async (ctx, matchedArgv) => (await import("./skills-
|
|
7132
|
+
run: async (ctx, matchedArgv) => (await import("./skills-ZFmFyZtw.mjs")).publish(ctx, matchedArgv)
|
|
7018
7133
|
});
|
|
7019
7134
|
});
|
|
7020
7135
|
return skills.demandCommand(1);
|
|
@@ -7036,7 +7151,7 @@ function buildParser(onMatched) {
|
|
|
7036
7151
|
}), (argv) => {
|
|
7037
7152
|
onMatched({
|
|
7038
7153
|
argv,
|
|
7039
|
-
run: async (ctx, matchedArgv) => (await import("./mcp-
|
|
7154
|
+
run: async (ctx, matchedArgv) => (await import("./mcp-B0sbQABp.mjs")).add(ctx, matchedArgv)
|
|
7040
7155
|
});
|
|
7041
7156
|
});
|
|
7042
7157
|
mcp.command("publish <paths..>", "Publish an MCP snapshot as a capability or a new version", (publish) => publish.option("namespace", {
|
|
@@ -7064,7 +7179,7 @@ function buildParser(onMatched) {
|
|
|
7064
7179
|
}), (argv) => {
|
|
7065
7180
|
onMatched({
|
|
7066
7181
|
argv,
|
|
7067
|
-
run: async (ctx, matchedArgv) => (await import("./mcp-
|
|
7182
|
+
run: async (ctx, matchedArgv) => (await import("./mcp-B0sbQABp.mjs")).publish(ctx, matchedArgv)
|
|
7068
7183
|
});
|
|
7069
7184
|
});
|
|
7070
7185
|
return mcp.demandCommand(1);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { _ as
|
|
1
|
+
import { C as HngrError, g as resolveConnection, s as redactSensitive, t as apiFetch, x as writeFileAtomically } from "./http-DgHX7Fux.mjs";
|
|
2
|
+
import { _ as resolveCapability, a as errorBody, c as runBatch, d as findAgentDefinition, g as parseCapabilityPath, i as runPublish, l as stringValues, m as MCP_KIND, n as explicitName, o as failedResult, p as downloadContent, r as readPublishFlags, s as positionalPaths, t as resolveInstallScope, u as AGENTS, v as resolveCapabilityVersion } from "./scope-DVfDeQi2.mjs";
|
|
3
3
|
import { constants } from "node:fs";
|
|
4
4
|
import { access, readFile, stat } from "node:fs/promises";
|
|
5
5
|
import { basename, delimiter, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
@@ -98,31 +98,24 @@ async function userServerState(executable, name, env) {
|
|
|
98
98
|
/**
|
|
99
99
|
* Installs one user-scope server through Claude Code itself.
|
|
100
100
|
* `~/.claude.json` is never edited directly: Claude Code owns that file and may
|
|
101
|
-
* hold live session state.
|
|
102
|
-
*
|
|
103
|
-
*
|
|
101
|
+
* hold live session state. Re-installing replaces an existing user-scope
|
|
102
|
+
* server through the CLI before the new entry is added, so every write still
|
|
103
|
+
* goes through Claude Code.
|
|
104
104
|
*/
|
|
105
|
-
async function addJsonWithClaude(env, name, config
|
|
105
|
+
async function addJsonWithClaude(env, name, config) {
|
|
106
106
|
const executable = await findExecutable(EXECUTABLE, env);
|
|
107
107
|
if (!executable) throw new HngrError({
|
|
108
108
|
type: "config",
|
|
109
109
|
title: "Claude Code CLI not found",
|
|
110
110
|
detail: "`claude` must be on PATH to install user-level MCP servers; install Claude Code or use project-level (no --global) installation."
|
|
111
111
|
});
|
|
112
|
-
if (await userServerState(executable, name, env) === "present")
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
"mcp",
|
|
120
|
-
"remove",
|
|
121
|
-
"--scope",
|
|
122
|
-
"user",
|
|
123
|
-
name
|
|
124
|
-
], env, name);
|
|
125
|
-
}
|
|
112
|
+
if (await userServerState(executable, name, env) === "present") await runChecked(executable, [
|
|
113
|
+
"mcp",
|
|
114
|
+
"remove",
|
|
115
|
+
"--scope",
|
|
116
|
+
"user",
|
|
117
|
+
name
|
|
118
|
+
], env, name);
|
|
126
119
|
await runChecked(executable, [
|
|
127
120
|
"mcp",
|
|
128
121
|
"add-json",
|
|
@@ -202,8 +195,8 @@ function readTargetDocument(raw, label) {
|
|
|
202
195
|
}
|
|
203
196
|
/**
|
|
204
197
|
* Merges the incoming servers into the document's `mcpServers`. Existing
|
|
205
|
-
* servers and other top-level keys survive
|
|
206
|
-
*
|
|
198
|
+
* servers and other top-level keys survive; a name collision is replaced, so
|
|
199
|
+
* re-installing a capability is idempotent.
|
|
207
200
|
*/
|
|
208
201
|
function mergeSnapshot(document, incoming, options) {
|
|
209
202
|
const existing = document.mcpServers;
|
|
@@ -211,21 +204,13 @@ function mergeSnapshot(document, incoming, options) {
|
|
|
211
204
|
if (existing === null || typeof existing !== "object" || Array.isArray(existing)) throw ioError(`"mcpServers" in ${options.label} is not an object`, "Fix the target file before installing MCP servers.");
|
|
212
205
|
}
|
|
213
206
|
const servers = { ...existing ?? {} };
|
|
214
|
-
const conflicts = [];
|
|
215
207
|
const added = [];
|
|
216
208
|
const replaced = [];
|
|
217
|
-
for (const [name, entry] of Object.entries(incoming))
|
|
218
|
-
if (
|
|
219
|
-
|
|
220
|
-
continue;
|
|
221
|
-
}
|
|
209
|
+
for (const [name, entry] of Object.entries(incoming)) {
|
|
210
|
+
if (Object.hasOwn(servers, name)) replaced.push(name);
|
|
211
|
+
else added.push(name);
|
|
222
212
|
servers[name] = entry;
|
|
223
|
-
replaced.push(name);
|
|
224
|
-
} else {
|
|
225
|
-
servers[name] = entry;
|
|
226
|
-
added.push(name);
|
|
227
213
|
}
|
|
228
|
-
if (conflicts.length > 0) throw ioError(`MCP ${conflicts.length === 1 ? "server" : "servers"} already configured in ${options.label}: ${conflicts.join(", ")}`, "Pass --force to replace only the conflicting entries.");
|
|
229
214
|
return {
|
|
230
215
|
document: {
|
|
231
216
|
...document,
|
|
@@ -381,11 +366,8 @@ async function readExisting(path, label) {
|
|
|
381
366
|
* redacted. The file is never written by dry-run, so this only affects the
|
|
382
367
|
* preview.
|
|
383
368
|
*/
|
|
384
|
-
function previewJsonTarget(plan, existing, servers
|
|
385
|
-
const merged = mergeSnapshot(readTargetDocument(existing, plan.path), servers, {
|
|
386
|
-
force,
|
|
387
|
-
label: plan.path
|
|
388
|
-
});
|
|
369
|
+
function previewJsonTarget(plan, existing, servers) {
|
|
370
|
+
const merged = mergeSnapshot(readTargetDocument(existing, plan.path), servers, { label: plan.path });
|
|
389
371
|
return serializeTargetDocument(redactSensitive(merged.document));
|
|
390
372
|
}
|
|
391
373
|
/** Reports one target's failure without aborting the remaining targets. */
|
|
@@ -393,16 +375,13 @@ function reportTargetFailure(ctx, plan, err) {
|
|
|
393
375
|
const body = errorBody(err);
|
|
394
376
|
ctx.summary(`error: ${plan.agent} ${plan.path}: ${body.title}`);
|
|
395
377
|
}
|
|
396
|
-
async function installJsonTarget(plan, servers
|
|
378
|
+
async function installJsonTarget(plan, servers) {
|
|
397
379
|
const filePath = plan.filePath;
|
|
398
380
|
if (!filePath) throw new HngrError({
|
|
399
381
|
type: "io",
|
|
400
382
|
title: `No file path configured for ${plan.agent}`
|
|
401
383
|
});
|
|
402
|
-
const merged = mergeSnapshot(readTargetDocument(await readExisting(filePath, plan.path), plan.path), servers, {
|
|
403
|
-
force,
|
|
404
|
-
label: plan.path
|
|
405
|
-
});
|
|
384
|
+
const merged = mergeSnapshot(readTargetDocument(await readExisting(filePath, plan.path), plan.path), servers, { label: plan.path });
|
|
406
385
|
await writeFileAtomically(filePath, serializeTargetDocument(merged.document), { label: plan.path });
|
|
407
386
|
}
|
|
408
387
|
async function addOne(ctx, connection, parsed, targets, state) {
|
|
@@ -412,14 +391,12 @@ async function addOne(ctx, connection, parsed, targets, state) {
|
|
|
412
391
|
const snapshot = await downloadMcpSnapshot(connection, capability.id, version);
|
|
413
392
|
if (snapshot.ignoredKeys.length > 0) ctx.summary(`warning: ignoring unsupported top-level keys in the MCP snapshot: ${snapshot.ignoredKeys.join(", ")}`);
|
|
414
393
|
const serverNames = Object.keys(snapshot.servers);
|
|
415
|
-
const etag = snapshot.etag ? ` (ETag ${snapshot.etag})` : "";
|
|
416
|
-
ctx.summary(`resolved ${parsed.namespace}/${parsed.name} to version ${version}${etag}`);
|
|
417
394
|
if (ctx.flags.dryRun) {
|
|
418
395
|
const dryTargets = [];
|
|
419
396
|
let failure = null;
|
|
420
397
|
for (const plan of targets) try {
|
|
421
398
|
if (plan.kind === "json") {
|
|
422
|
-
const preview = previewJsonTarget(plan, plan.filePath ? await readExisting(plan.filePath, plan.path) : void 0, snapshot.servers
|
|
399
|
+
const preview = previewJsonTarget(plan, plan.filePath ? await readExisting(plan.filePath, plan.path) : void 0, snapshot.servers);
|
|
423
400
|
ctx.detail(`dry-run: would write ${plan.path}\n${preview}`);
|
|
424
401
|
} else for (const [name, entry] of Object.entries(snapshot.servers)) ctx.detail(`dry-run: claude mcp add-json --scope user ${name} ${JSON.stringify(redactSensitive(entry))}`);
|
|
425
402
|
dryTargets.push({
|
|
@@ -449,8 +426,8 @@ async function addOne(ctx, connection, parsed, targets, state) {
|
|
|
449
426
|
const installedTargets = [];
|
|
450
427
|
let failure = null;
|
|
451
428
|
for (const plan of targets) try {
|
|
452
|
-
if (plan.kind === "json") await installJsonTarget(plan, snapshot.servers
|
|
453
|
-
else for (const [name, entry] of Object.entries(snapshot.servers)) await addJsonWithClaude(ctx.env, name, entry
|
|
429
|
+
if (plan.kind === "json") await installJsonTarget(plan, snapshot.servers);
|
|
430
|
+
else for (const [name, entry] of Object.entries(snapshot.servers)) await addJsonWithClaude(ctx.env, name, entry);
|
|
454
431
|
installedTargets.push({
|
|
455
432
|
agent: plan.agent,
|
|
456
433
|
path: plan.path,
|
|
@@ -587,7 +564,7 @@ async function add(ctx, argv) {
|
|
|
587
564
|
const rawPaths = positionalPaths(argv.paths);
|
|
588
565
|
if (rawPaths.length === 0) throw usage("No capability path given", "Pass one or more `<name>` or `<namespace>/<name>` arguments.");
|
|
589
566
|
const parsedPaths = rawPaths.map(parseMcpPath);
|
|
590
|
-
const scope = argv.global === true
|
|
567
|
+
const scope = await resolveInstallScope(ctx, argv.global === true);
|
|
591
568
|
const targets = selectMcpTargets(stringValues(argv.agent), argv.all === true, scope, process.cwd(), ctx.env);
|
|
592
569
|
const connection = await resolveConnection(ctx.flags, ctx.env);
|
|
593
570
|
let approvalHintShown = false;
|
|
@@ -604,7 +581,7 @@ async function add(ctx, argv) {
|
|
|
604
581
|
}
|
|
605
582
|
}
|
|
606
583
|
});
|
|
607
|
-
ctx.writePayload({ results });
|
|
584
|
+
if (ctx.flags.json || !ctx.io.stdout.isTTY) ctx.writePayload({ results });
|
|
608
585
|
return failed ? 1 : 0;
|
|
609
586
|
}
|
|
610
587
|
export { add, publish };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as HngrError } from "./http-DgHX7Fux.mjs";
|
|
2
2
|
// src/pagination.ts
|
|
3
3
|
function asCursorPage(body, path) {
|
|
4
4
|
if (body === null || typeof body !== "object" || !Array.isArray(body.items) || !("next_cursor" in body)) throw new HngrError({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as collectPages } from "./pagination-
|
|
1
|
+
import { C as HngrError, _ as scrubCredentials, a as toHngrError, g as resolveConnection, h as redactUrl, i as buildRequestUrl, l as apiErrorFromResponse, n as apiGet } from "./http-DgHX7Fux.mjs";
|
|
2
|
+
import { t as collectPages } from "./pagination-BXyFxGYA.mjs";
|
|
3
3
|
import { readFile } from "node:fs/promises";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { join, resolve } from "node:path";
|
|
@@ -172,6 +172,10 @@ function claudeConfigDir(env) {
|
|
|
172
172
|
function xdgConfigDir(env) {
|
|
173
173
|
return env.XDG_CONFIG_HOME && env.XDG_CONFIG_HOME !== "" ? env.XDG_CONFIG_HOME : join(homeDir(env), ".config");
|
|
174
174
|
}
|
|
175
|
+
/** Pi's agent directory: `PI_CODING_AGENT_DIR` or `~/.pi/agent`. */
|
|
176
|
+
function piAgentDir(env) {
|
|
177
|
+
return env.PI_CODING_AGENT_DIR && env.PI_CODING_AGENT_DIR !== "" ? env.PI_CODING_AGENT_DIR : join(homeDir(env), ".pi", "agent");
|
|
178
|
+
}
|
|
175
179
|
const universalSkills = {
|
|
176
180
|
projectDir: null,
|
|
177
181
|
globalDir: null,
|
|
@@ -220,6 +224,15 @@ const AGENTS = [
|
|
|
220
224
|
reason: "OpenCode uses a top-level `mcp` object with local/remote entries."
|
|
221
225
|
}
|
|
222
226
|
},
|
|
227
|
+
{
|
|
228
|
+
id: "pi",
|
|
229
|
+
skills: universalSkills,
|
|
230
|
+
mcp: {
|
|
231
|
+
kind: "json",
|
|
232
|
+
project: ".pi/mcp.json",
|
|
233
|
+
global: (env) => join(piAgentDir(env), "mcp.json")
|
|
234
|
+
}
|
|
235
|
+
},
|
|
223
236
|
{
|
|
224
237
|
id: "amp",
|
|
225
238
|
skills: universalSkills,
|
|
@@ -539,4 +552,25 @@ async function runPublish(options) {
|
|
|
539
552
|
ctx.writePayload({ results });
|
|
540
553
|
return results.some((result) => result.status === "failed") ? 1 : 0;
|
|
541
554
|
}
|
|
542
|
-
|
|
555
|
+
// src/commands/scope.ts
|
|
556
|
+
const SCOPE_OPTIONS = [{
|
|
557
|
+
value: "project",
|
|
558
|
+
label: "Project",
|
|
559
|
+
hint: "install into the current directory"
|
|
560
|
+
}, {
|
|
561
|
+
value: "global",
|
|
562
|
+
label: "Global",
|
|
563
|
+
hint: "install for the current user"
|
|
564
|
+
}];
|
|
565
|
+
/**
|
|
566
|
+
* Resolves project vs global install scope. `--global` wins without asking.
|
|
567
|
+
* Without an interactive prompter the current-directory default is kept, so
|
|
568
|
+
* scripts, pipes and `--json` runs never block on a prompt.
|
|
569
|
+
*/
|
|
570
|
+
async function resolveInstallScope(ctx, global) {
|
|
571
|
+
if (global) return "global";
|
|
572
|
+
const select = ctx.io.prompts?.select;
|
|
573
|
+
if (!select || ctx.flags.json || !ctx.io.stdin.isTTY || !ctx.io.stdout.isTTY) return "project";
|
|
574
|
+
return await select("Install scope", SCOPE_OPTIONS, "project") === "global" ? "global" : "project";
|
|
575
|
+
}
|
|
576
|
+
export { resolveCapability as _, errorBody as a, runBatch as c, findAgentDefinition as d, homeDir as f, parseCapabilityPath as g, SKILL_KIND as h, runPublish as i, stringValues as l, MCP_KIND as m, explicitName as n, failedResult as o, downloadContent as p, readPublishFlags as r, positionalPaths as s, resolveInstallScope as t, AGENTS as u, resolveCapabilityVersion as v };
|