@hasna/mcps 0.0.13 → 0.0.15
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/bin/index.js +897 -94
- package/bin/mcp.js +618 -53
- package/dist/index.d.ts +5 -1
- package/dist/index.js +620 -13
- package/dist/lib/doctor.d.ts +4 -1
- package/dist/lib/install.d.ts +5 -1
- package/dist/lib/local-command-consent.d.ts +38 -0
- package/dist/lib/provider-profile-seeds.d.ts +2 -0
- package/dist/lib/provider-profiles.d.ts +14 -0
- package/dist/lib/proxy.d.ts +6 -2
- package/dist/lib/remote.d.ts +4 -1
- package/dist/mcp/index.js +618 -53
- package/dist/types.d.ts +87 -2
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -9451,6 +9451,85 @@ var init_config2 = __esm(() => {
|
|
|
9451
9451
|
DB_PATH = process.env.HASNA_MCPS_DB_PATH ?? process.env.MCPS_DB_PATH ?? join5(MCPS_DIR, "registry.db");
|
|
9452
9452
|
});
|
|
9453
9453
|
|
|
9454
|
+
// src/lib/provider-profile-seeds.ts
|
|
9455
|
+
var DEFAULT_PROVIDER_PROFILE_SEEDS;
|
|
9456
|
+
var init_provider_profile_seeds = __esm(() => {
|
|
9457
|
+
DEFAULT_PROVIDER_PROFILE_SEEDS = [
|
|
9458
|
+
{
|
|
9459
|
+
id: "notion",
|
|
9460
|
+
displayName: "Notion",
|
|
9461
|
+
description: "Connect a Notion workspace so agents can search, read, create, and update workspace content.",
|
|
9462
|
+
endpoint: "https://mcp.notion.com/mcp",
|
|
9463
|
+
transport: "streamable-http",
|
|
9464
|
+
fallbackEndpoints: [
|
|
9465
|
+
{
|
|
9466
|
+
transport: "sse",
|
|
9467
|
+
url: "https://mcp.notion.com/sse",
|
|
9468
|
+
notes: "Fallback for clients that do not support Streamable HTTP."
|
|
9469
|
+
}
|
|
9470
|
+
],
|
|
9471
|
+
authType: "oauth2",
|
|
9472
|
+
authMetadata: {
|
|
9473
|
+
oauthVersion: "2.0",
|
|
9474
|
+
pkce: true,
|
|
9475
|
+
dynamicClientRegistration: true,
|
|
9476
|
+
bearerToken: "none",
|
|
9477
|
+
notes: "Remote Notion MCP uses OAuth with PKCE. Bearer-token authentication is only appropriate for self-hosted/local fallback deployments."
|
|
9478
|
+
},
|
|
9479
|
+
tokenMode: "workspace",
|
|
9480
|
+
installFallback: {
|
|
9481
|
+
command: "npx",
|
|
9482
|
+
args: ["-y", "mcp-remote", "https://mcp.notion.com/sse", "--transport", "sse-only"],
|
|
9483
|
+
packageName: "mcp-remote",
|
|
9484
|
+
url: "https://mcp.notion.com/sse"
|
|
9485
|
+
},
|
|
9486
|
+
docsUrl: "https://developers.notion.com/guides/mcp/build-mcp-client",
|
|
9487
|
+
safety: {
|
|
9488
|
+
requiresApproval: true,
|
|
9489
|
+
dataClasses: ["workspace_content", "pages", "databases", "comments"],
|
|
9490
|
+
notes: "Connected agents operate with the authorizing user's workspace access. Human confirmation is recommended for write-capable workflows."
|
|
9491
|
+
},
|
|
9492
|
+
provenance: {
|
|
9493
|
+
source: "curated",
|
|
9494
|
+
sourceUrl: "https://developers.notion.com/guides/mcp/build-mcp-client",
|
|
9495
|
+
verifiedAt: "2026-05-10"
|
|
9496
|
+
}
|
|
9497
|
+
},
|
|
9498
|
+
{
|
|
9499
|
+
id: "linear",
|
|
9500
|
+
displayName: "Linear",
|
|
9501
|
+
description: "Connect Linear so agents can find, create, and update issues, projects, comments, and related workspace objects.",
|
|
9502
|
+
endpoint: "https://mcp.linear.app/mcp",
|
|
9503
|
+
transport: "streamable-http",
|
|
9504
|
+
authType: "oauth2",
|
|
9505
|
+
authMetadata: {
|
|
9506
|
+
oauthVersion: "2.1",
|
|
9507
|
+
dynamicClientRegistration: true,
|
|
9508
|
+
bearerToken: "optional",
|
|
9509
|
+
notes: "Linear supports interactive OAuth 2.1 with dynamic client registration and optional Authorization: Bearer tokens for OAuth tokens or API keys."
|
|
9510
|
+
},
|
|
9511
|
+
tokenMode: "workspace",
|
|
9512
|
+
installFallback: {
|
|
9513
|
+
command: "npx",
|
|
9514
|
+
args: ["-y", "mcp-remote", "https://mcp.linear.app/mcp"],
|
|
9515
|
+
packageName: "mcp-remote",
|
|
9516
|
+
url: "https://mcp.linear.app/mcp"
|
|
9517
|
+
},
|
|
9518
|
+
docsUrl: "https://linear.app/docs/mcp",
|
|
9519
|
+
safety: {
|
|
9520
|
+
requiresApproval: true,
|
|
9521
|
+
dataClasses: ["issues", "projects", "comments", "teams", "users"],
|
|
9522
|
+
notes: "Linear tools can create and update workspace objects, so write actions should be policy-gated by the platform."
|
|
9523
|
+
},
|
|
9524
|
+
provenance: {
|
|
9525
|
+
source: "curated",
|
|
9526
|
+
sourceUrl: "https://linear.app/docs/mcp",
|
|
9527
|
+
verifiedAt: "2026-05-10"
|
|
9528
|
+
}
|
|
9529
|
+
}
|
|
9530
|
+
];
|
|
9531
|
+
});
|
|
9532
|
+
|
|
9454
9533
|
// src/lib/db.ts
|
|
9455
9534
|
import { mkdirSync as mkdirSync5 } from "fs";
|
|
9456
9535
|
function getDb() {
|
|
@@ -9536,6 +9615,50 @@ function getDb() {
|
|
|
9536
9615
|
('github-mcp-topic', 'GitHub MCP Topic', 'github-topic', 'https://api.github.com/search/repositories', 'GitHub repositories tagged with mcp-server topic')
|
|
9537
9616
|
`);
|
|
9538
9617
|
}
|
|
9618
|
+
db.exec(`
|
|
9619
|
+
CREATE TABLE IF NOT EXISTS provider_profiles (
|
|
9620
|
+
id TEXT PRIMARY KEY,
|
|
9621
|
+
display_name TEXT NOT NULL,
|
|
9622
|
+
description TEXT,
|
|
9623
|
+
endpoint TEXT,
|
|
9624
|
+
transport TEXT NOT NULL,
|
|
9625
|
+
fallback_endpoints TEXT NOT NULL DEFAULT '[]',
|
|
9626
|
+
auth_type TEXT NOT NULL,
|
|
9627
|
+
auth_metadata TEXT NOT NULL DEFAULT '{}',
|
|
9628
|
+
scopes TEXT NOT NULL DEFAULT '[]',
|
|
9629
|
+
token_mode TEXT NOT NULL DEFAULT 'none',
|
|
9630
|
+
install_fallback TEXT NOT NULL DEFAULT '{}',
|
|
9631
|
+
docs_url TEXT,
|
|
9632
|
+
safety TEXT NOT NULL DEFAULT '{}',
|
|
9633
|
+
provenance TEXT NOT NULL DEFAULT '{"source":"manual"}',
|
|
9634
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
9635
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
9636
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
9637
|
+
)
|
|
9638
|
+
`);
|
|
9639
|
+
try {
|
|
9640
|
+
db.exec("ALTER TABLE provider_profiles ADD COLUMN fallback_endpoints TEXT NOT NULL DEFAULT '[]'");
|
|
9641
|
+
} catch {}
|
|
9642
|
+
try {
|
|
9643
|
+
db.exec("ALTER TABLE provider_profiles ADD COLUMN auth_metadata TEXT NOT NULL DEFAULT '{}'");
|
|
9644
|
+
} catch {}
|
|
9645
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_provider_profiles_enabled ON provider_profiles(enabled)");
|
|
9646
|
+
const providerProfileCount = db.query("SELECT COUNT(*) as c FROM provider_profiles").get().c;
|
|
9647
|
+
if (providerProfileCount === 0) {
|
|
9648
|
+
const insertProviderProfile = db.prepare(`
|
|
9649
|
+
INSERT OR IGNORE INTO provider_profiles (
|
|
9650
|
+
id, display_name, description, endpoint, transport, fallback_endpoints,
|
|
9651
|
+
auth_type, auth_metadata, scopes, token_mode, install_fallback,
|
|
9652
|
+
docs_url, safety, provenance, enabled
|
|
9653
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
9654
|
+
`);
|
|
9655
|
+
const run = db.transaction(() => {
|
|
9656
|
+
for (const profile of DEFAULT_PROVIDER_PROFILE_SEEDS) {
|
|
9657
|
+
insertProviderProfile.run(profile.id, profile.displayName, profile.description ?? null, profile.endpoint ?? null, profile.transport, JSON.stringify(profile.fallbackEndpoints ?? []), profile.authType, JSON.stringify(profile.authMetadata ?? {}), JSON.stringify(profile.scopes ?? []), profile.tokenMode ?? "none", JSON.stringify(profile.installFallback ?? null), profile.docsUrl ?? null, JSON.stringify(profile.safety ?? {}), JSON.stringify(profile.provenance), profile.enabled === false ? 0 : 1);
|
|
9658
|
+
}
|
|
9659
|
+
});
|
|
9660
|
+
run();
|
|
9661
|
+
}
|
|
9539
9662
|
db.exec(`
|
|
9540
9663
|
CREATE TABLE IF NOT EXISTS feedback (
|
|
9541
9664
|
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
|
|
@@ -9560,6 +9683,7 @@ var db = null, _adapter = null;
|
|
|
9560
9683
|
var init_db = __esm(() => {
|
|
9561
9684
|
init_dist();
|
|
9562
9685
|
init_config2();
|
|
9686
|
+
init_provider_profile_seeds();
|
|
9563
9687
|
});
|
|
9564
9688
|
|
|
9565
9689
|
// node_modules/ajv/dist/compile/codegen/code.js
|
|
@@ -25118,6 +25242,185 @@ class StreamableHTTPClientTransport {
|
|
|
25118
25242
|
// src/lib/proxy.ts
|
|
25119
25243
|
init_config2();
|
|
25120
25244
|
init_db();
|
|
25245
|
+
|
|
25246
|
+
// src/lib/local-command-consent.ts
|
|
25247
|
+
class LocalCommandConsentError extends Error {
|
|
25248
|
+
review;
|
|
25249
|
+
constructor(message, review) {
|
|
25250
|
+
super(message);
|
|
25251
|
+
this.name = "LocalCommandConsentError";
|
|
25252
|
+
this.review = review;
|
|
25253
|
+
}
|
|
25254
|
+
}
|
|
25255
|
+
var SHELL_COMMANDS = new Set(["bash", "sh", "zsh", "fish", "cmd", "cmd.exe", "powershell", "powershell.exe", "pwsh"]);
|
|
25256
|
+
var DESTRUCTIVE_COMMANDS = new Set([
|
|
25257
|
+
"rm",
|
|
25258
|
+
"dd",
|
|
25259
|
+
"mkfs",
|
|
25260
|
+
"shutdown",
|
|
25261
|
+
"reboot",
|
|
25262
|
+
"poweroff",
|
|
25263
|
+
"halt",
|
|
25264
|
+
"killall",
|
|
25265
|
+
"pkill"
|
|
25266
|
+
]);
|
|
25267
|
+
var SHELL_EVAL_FLAGS = new Set(["-c", "/c", "-Command", "-command", "-EncodedCommand", "-encodedcommand"]);
|
|
25268
|
+
var SECRET_FLAG_PATTERN = /(?:^|[-_])(api[-_]?key|token|secret|password|passwd|credential|auth|private[-_]?key)(?:$|[-_])/i;
|
|
25269
|
+
var SECRET_KEY_PATTERN = /(?:^|[_-])(api[_-]?key|token|secret|password|passwd|credential|auth|private[_-]?key)(?:$|[_-])/i;
|
|
25270
|
+
var SECRET_VALUE_PATTERN = /^(sk_(?:live|test)_[A-Za-z0-9_]+|ghp_[A-Za-z0-9_]+|github_pat_[A-Za-z0-9_]+|xox[baprs]-[A-Za-z0-9-]+|AIza[A-Za-z0-9_-]{20,}|eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)$/;
|
|
25271
|
+
var SHELL_META_PATTERN = /[;&|`<>]|\$\(/;
|
|
25272
|
+
function commandBase(command) {
|
|
25273
|
+
return command.trim().split(/[\\/]/).pop()?.toLowerCase() || command.trim().toLowerCase();
|
|
25274
|
+
}
|
|
25275
|
+
function normalizeArgs(args) {
|
|
25276
|
+
return (args ?? []).map((arg) => String(arg));
|
|
25277
|
+
}
|
|
25278
|
+
function isSecretKey(key) {
|
|
25279
|
+
return SECRET_KEY_PATTERN.test(key) || SECRET_FLAG_PATTERN.test(key);
|
|
25280
|
+
}
|
|
25281
|
+
function isSecretValue(value) {
|
|
25282
|
+
return SECRET_VALUE_PATTERN.test(value.trim());
|
|
25283
|
+
}
|
|
25284
|
+
function isSecretAssignment(arg) {
|
|
25285
|
+
const eqIdx = arg.indexOf("=");
|
|
25286
|
+
if (eqIdx <= 0)
|
|
25287
|
+
return false;
|
|
25288
|
+
const key = arg.slice(0, eqIdx);
|
|
25289
|
+
const value = arg.slice(eqIdx + 1);
|
|
25290
|
+
return isSecretKey(key) || isSecretValue(value);
|
|
25291
|
+
}
|
|
25292
|
+
function isSecretArg(args, index) {
|
|
25293
|
+
const arg = args[index] ?? "";
|
|
25294
|
+
const previous = args[index - 1] ?? "";
|
|
25295
|
+
return isSecretAssignment(arg) || isSecretValue(arg) || SECRET_FLAG_PATTERN.test(previous);
|
|
25296
|
+
}
|
|
25297
|
+
function quoteArg(value) {
|
|
25298
|
+
return JSON.stringify(value);
|
|
25299
|
+
}
|
|
25300
|
+
function displayCommand(command, args) {
|
|
25301
|
+
return [quoteArg(command), ...args.map((arg, index) => quoteArg(isSecretArg(args, index) ? "<redacted>" : arg))].join(" ");
|
|
25302
|
+
}
|
|
25303
|
+
function pushRisk(risks, risk) {
|
|
25304
|
+
if (risks.some((existing) => existing.code === risk.code && existing.evidence === risk.evidence))
|
|
25305
|
+
return;
|
|
25306
|
+
risks.push(risk);
|
|
25307
|
+
}
|
|
25308
|
+
function inspectRisks(command, args, env) {
|
|
25309
|
+
const risks = [];
|
|
25310
|
+
const base = commandBase(command);
|
|
25311
|
+
const joined = [command, ...args].join(" ");
|
|
25312
|
+
if (SHELL_COMMANDS.has(base)) {
|
|
25313
|
+
pushRisk(risks, {
|
|
25314
|
+
code: "shell_interpreter",
|
|
25315
|
+
severity: "warning",
|
|
25316
|
+
message: "Command launches a shell interpreter.",
|
|
25317
|
+
evidence: base
|
|
25318
|
+
});
|
|
25319
|
+
if (args.some((arg) => SHELL_EVAL_FLAGS.has(arg))) {
|
|
25320
|
+
pushRisk(risks, {
|
|
25321
|
+
code: "shell_eval",
|
|
25322
|
+
severity: "danger",
|
|
25323
|
+
message: "Shell command evaluates an inline script.",
|
|
25324
|
+
evidence: base
|
|
25325
|
+
});
|
|
25326
|
+
}
|
|
25327
|
+
}
|
|
25328
|
+
if (base === "sudo") {
|
|
25329
|
+
pushRisk(risks, {
|
|
25330
|
+
code: "privilege_escalation",
|
|
25331
|
+
severity: "danger",
|
|
25332
|
+
message: "Command requests elevated privileges.",
|
|
25333
|
+
evidence: base
|
|
25334
|
+
});
|
|
25335
|
+
}
|
|
25336
|
+
if (DESTRUCTIVE_COMMANDS.has(base) || /\brm\s+-[^\s]*[rf][^\s]*\b/.test(joined) || /--no-preserve-root\b/.test(joined)) {
|
|
25337
|
+
pushRisk(risks, {
|
|
25338
|
+
code: "destructive_command",
|
|
25339
|
+
severity: "danger",
|
|
25340
|
+
message: "Command includes a destructive system operation.",
|
|
25341
|
+
evidence: base
|
|
25342
|
+
});
|
|
25343
|
+
}
|
|
25344
|
+
if (/\b(curl|wget)\b[\s\S]*\|[\s\S]*\b(sh|bash|zsh|fish)\b/.test(joined)) {
|
|
25345
|
+
pushRisk(risks, {
|
|
25346
|
+
code: "download_pipe_shell",
|
|
25347
|
+
severity: "danger",
|
|
25348
|
+
message: "Command downloads remote content and pipes it to a shell."
|
|
25349
|
+
});
|
|
25350
|
+
}
|
|
25351
|
+
if ([command, ...args].some((part) => SHELL_META_PATTERN.test(part))) {
|
|
25352
|
+
pushRisk(risks, {
|
|
25353
|
+
code: "shell_metacharacters",
|
|
25354
|
+
severity: "warning",
|
|
25355
|
+
message: "Command or arguments contain shell metacharacters."
|
|
25356
|
+
});
|
|
25357
|
+
}
|
|
25358
|
+
if (args.some((arg, index) => isSecretArg(args, index))) {
|
|
25359
|
+
pushRisk(risks, {
|
|
25360
|
+
code: "inline_secret",
|
|
25361
|
+
severity: "danger",
|
|
25362
|
+
message: "Command arguments appear to contain inline secret material."
|
|
25363
|
+
});
|
|
25364
|
+
}
|
|
25365
|
+
const secretEnvKeys = Object.keys(env).filter(isSecretKey).sort();
|
|
25366
|
+
if (secretEnvKeys.length > 0) {
|
|
25367
|
+
pushRisk(risks, {
|
|
25368
|
+
code: "secret_env",
|
|
25369
|
+
severity: "warning",
|
|
25370
|
+
message: "Environment contains secret-like keys; values are redacted from consent output.",
|
|
25371
|
+
evidence: secretEnvKeys.join(", ")
|
|
25372
|
+
});
|
|
25373
|
+
}
|
|
25374
|
+
return risks;
|
|
25375
|
+
}
|
|
25376
|
+
function inspectLocalCommand(input) {
|
|
25377
|
+
const args = normalizeArgs(input.args);
|
|
25378
|
+
const env = input.env ?? {};
|
|
25379
|
+
const transport = input.transport ?? "stdio";
|
|
25380
|
+
const risks = inspectRisks(input.command, args, env);
|
|
25381
|
+
return {
|
|
25382
|
+
requiresConsent: transport === "stdio",
|
|
25383
|
+
operation: input.operation ?? "launch",
|
|
25384
|
+
command: input.command,
|
|
25385
|
+
args,
|
|
25386
|
+
displayCommand: displayCommand(input.command, args),
|
|
25387
|
+
envKeys: Object.keys(env).sort(),
|
|
25388
|
+
risks,
|
|
25389
|
+
hasDangerousRisk: risks.some((risk) => risk.severity === "danger")
|
|
25390
|
+
};
|
|
25391
|
+
}
|
|
25392
|
+
function formatLocalCommandReview(review) {
|
|
25393
|
+
const lines = [
|
|
25394
|
+
`Command: ${review.displayCommand}`,
|
|
25395
|
+
review.envKeys.length > 0 ? `Env keys: ${review.envKeys.join(", ")}` : "Env keys: <none>"
|
|
25396
|
+
];
|
|
25397
|
+
if (review.risks.length > 0) {
|
|
25398
|
+
lines.push("Risks:");
|
|
25399
|
+
for (const risk of review.risks) {
|
|
25400
|
+
lines.push(`- ${risk.severity}: ${risk.code} - ${risk.message}${risk.evidence ? ` (${risk.evidence})` : ""}`);
|
|
25401
|
+
}
|
|
25402
|
+
} else {
|
|
25403
|
+
lines.push("Risks: none detected");
|
|
25404
|
+
}
|
|
25405
|
+
return lines.join(`
|
|
25406
|
+
`);
|
|
25407
|
+
}
|
|
25408
|
+
function assertLocalCommandConsent(input, consent = {}) {
|
|
25409
|
+
const review = inspectLocalCommand(input);
|
|
25410
|
+
if (!review.requiresConsent)
|
|
25411
|
+
return review;
|
|
25412
|
+
if (consent.approved !== true) {
|
|
25413
|
+
throw new LocalCommandConsentError(`local stdio command approval is required before ${review.operation}.
|
|
25414
|
+
${formatLocalCommandReview(review)}`, review);
|
|
25415
|
+
}
|
|
25416
|
+
if (review.hasDangerousRisk && consent.allowRisky !== true) {
|
|
25417
|
+
throw new LocalCommandConsentError(`risky command approval is required before ${review.operation}.
|
|
25418
|
+
${formatLocalCommandReview(review)}`, review);
|
|
25419
|
+
}
|
|
25420
|
+
return review;
|
|
25421
|
+
}
|
|
25422
|
+
|
|
25423
|
+
// src/lib/proxy.ts
|
|
25121
25424
|
var connections = new Map;
|
|
25122
25425
|
var inflightConnections = new Map;
|
|
25123
25426
|
function buildEnv(extra) {
|
|
@@ -25143,7 +25446,7 @@ function requireUrl(entry) {
|
|
|
25143
25446
|
throw new Error(`Server "${entry.id}" has an invalid URL: ${entry.url}`);
|
|
25144
25447
|
}
|
|
25145
25448
|
}
|
|
25146
|
-
async function connectToServer(entry) {
|
|
25449
|
+
async function connectToServer(entry, options = {}) {
|
|
25147
25450
|
if (connections.has(entry.id)) {
|
|
25148
25451
|
return connections.get(entry.id);
|
|
25149
25452
|
}
|
|
@@ -25159,6 +25462,13 @@ async function connectToServer(entry) {
|
|
|
25159
25462
|
if (!entry.command?.trim()) {
|
|
25160
25463
|
throw new Error(`Server "${entry.id}" is missing a command`);
|
|
25161
25464
|
}
|
|
25465
|
+
assertLocalCommandConsent({
|
|
25466
|
+
command: entry.command,
|
|
25467
|
+
args: entry.args,
|
|
25468
|
+
env: entry.env,
|
|
25469
|
+
transport: entry.transport,
|
|
25470
|
+
operation: "launch"
|
|
25471
|
+
}, options.localCommandConsent);
|
|
25162
25472
|
transport = new StdioClientTransport({
|
|
25163
25473
|
command: entry.command,
|
|
25164
25474
|
args: entry.args,
|
|
@@ -25294,13 +25604,28 @@ async function refreshTools(id) {
|
|
|
25294
25604
|
}
|
|
25295
25605
|
|
|
25296
25606
|
// src/lib/doctor.ts
|
|
25297
|
-
async function diagnoseServer(server) {
|
|
25607
|
+
async function diagnoseServer(server, options = {}) {
|
|
25298
25608
|
const checks3 = [];
|
|
25609
|
+
let hasLocalConsent = true;
|
|
25299
25610
|
if (server.transport === "stdio") {
|
|
25611
|
+
try {
|
|
25612
|
+
assertLocalCommandConsent({
|
|
25613
|
+
command: server.command,
|
|
25614
|
+
args: server.args,
|
|
25615
|
+
env: server.env,
|
|
25616
|
+
transport: server.transport,
|
|
25617
|
+
operation: "diagnose"
|
|
25618
|
+
}, options.localCommandConsent);
|
|
25619
|
+
} catch (err) {
|
|
25620
|
+
hasLocalConsent = false;
|
|
25621
|
+
checks3.push({ name: "local command consent", pass: false, message: err.message });
|
|
25622
|
+
}
|
|
25300
25623
|
try {
|
|
25301
25624
|
const path = execFileSync("which", [server.command], { stdio: "pipe" }).toString().trim();
|
|
25302
25625
|
let version2 = "";
|
|
25303
25626
|
try {
|
|
25627
|
+
if (!hasLocalConsent)
|
|
25628
|
+
throw new Error("local stdio command approval is required before version probing");
|
|
25304
25629
|
version2 = execFileSync(server.command, ["--version"], { stdio: "pipe" }).toString().trim().split(`
|
|
25305
25630
|
`)[0];
|
|
25306
25631
|
} catch {}
|
|
@@ -25331,10 +25656,10 @@ async function diagnoseServer(server) {
|
|
|
25331
25656
|
checks3.push({ name: "URL reachable", pass: false, message: `unreachable: ${err.message}` });
|
|
25332
25657
|
}
|
|
25333
25658
|
}
|
|
25334
|
-
if (server.enabled) {
|
|
25659
|
+
if (server.enabled && hasLocalConsent) {
|
|
25335
25660
|
try {
|
|
25336
25661
|
await Promise.race([
|
|
25337
|
-
connectToServer(server),
|
|
25662
|
+
connectToServer(server, { localCommandConsent: options.localCommandConsent }),
|
|
25338
25663
|
new Promise((_, reject) => setTimeout(() => reject(new Error("timeout after 10s")), 1e4))
|
|
25339
25664
|
]);
|
|
25340
25665
|
await disconnectServer(server.id);
|
|
@@ -25342,8 +25667,10 @@ async function diagnoseServer(server) {
|
|
|
25342
25667
|
} catch (err) {
|
|
25343
25668
|
checks3.push({ name: "connect & list tools", pass: false, message: err.message });
|
|
25344
25669
|
}
|
|
25345
|
-
} else {
|
|
25670
|
+
} else if (!server.enabled) {
|
|
25346
25671
|
checks3.push({ name: "connect & list tools", pass: true, message: "skipped (server disabled)" });
|
|
25672
|
+
} else {
|
|
25673
|
+
checks3.push({ name: "connect & list tools", pass: false, message: "skipped until local stdio command is approved" });
|
|
25347
25674
|
}
|
|
25348
25675
|
return {
|
|
25349
25676
|
server,
|
|
@@ -25383,7 +25710,7 @@ async function getRegistryServer(id) {
|
|
|
25383
25710
|
const all = entries.map(parseRegistryEntry);
|
|
25384
25711
|
return all.find((s) => s.id === id) || null;
|
|
25385
25712
|
}
|
|
25386
|
-
async function installFromRegistry(id) {
|
|
25713
|
+
async function installFromRegistry(id, options = {}) {
|
|
25387
25714
|
const server = await getRegistryServer(id);
|
|
25388
25715
|
if (!server) {
|
|
25389
25716
|
throw new Error(`Server "${id}" not found in registry`);
|
|
@@ -25403,6 +25730,13 @@ async function installFromRegistry(id) {
|
|
|
25403
25730
|
transport = pkg.transport.type;
|
|
25404
25731
|
}
|
|
25405
25732
|
}
|
|
25733
|
+
assertLocalCommandConsent({
|
|
25734
|
+
command,
|
|
25735
|
+
args,
|
|
25736
|
+
transport,
|
|
25737
|
+
env: {},
|
|
25738
|
+
operation: "register"
|
|
25739
|
+
}, options.localCommandConsent);
|
|
25406
25740
|
return addServer({
|
|
25407
25741
|
name: server.name,
|
|
25408
25742
|
description: server.description,
|
|
@@ -25425,6 +25759,250 @@ async function listAwesomeServers() {
|
|
|
25425
25759
|
// src/index.ts
|
|
25426
25760
|
init_sources();
|
|
25427
25761
|
|
|
25762
|
+
// src/lib/provider-profiles.ts
|
|
25763
|
+
init_db();
|
|
25764
|
+
init_provider_profile_seeds();
|
|
25765
|
+
var TRANSPORTS = new Set(["stdio", "sse", "streamable-http"]);
|
|
25766
|
+
var AUTH_TYPES = new Set(["none", "oauth2", "api_key", "bearer_token", "custom"]);
|
|
25767
|
+
var TOKEN_MODES = new Set(["none", "user", "workspace", "service"]);
|
|
25768
|
+
var BEARER_TOKEN_MODES = new Set(["none", "optional", "required"]);
|
|
25769
|
+
var PROVENANCE_SOURCES = new Set(["curated", "official-registry", "npm", "github", "manual"]);
|
|
25770
|
+
function safeJsonParse2(value, fallback) {
|
|
25771
|
+
if (typeof value !== "string")
|
|
25772
|
+
return fallback;
|
|
25773
|
+
try {
|
|
25774
|
+
return JSON.parse(value);
|
|
25775
|
+
} catch {
|
|
25776
|
+
return fallback;
|
|
25777
|
+
}
|
|
25778
|
+
}
|
|
25779
|
+
function normalizeString(value) {
|
|
25780
|
+
const trimmed = value?.trim();
|
|
25781
|
+
return trimmed ? trimmed : null;
|
|
25782
|
+
}
|
|
25783
|
+
function normalizeId(id) {
|
|
25784
|
+
const normalized = id.trim().toLowerCase();
|
|
25785
|
+
if (!/^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/.test(normalized)) {
|
|
25786
|
+
throw new Error("Provider profile id must be lowercase kebab-case");
|
|
25787
|
+
}
|
|
25788
|
+
return normalized;
|
|
25789
|
+
}
|
|
25790
|
+
function normalizeScopes(scopes) {
|
|
25791
|
+
const seen = new Set;
|
|
25792
|
+
const normalized = [];
|
|
25793
|
+
for (const scope of scopes ?? []) {
|
|
25794
|
+
const trimmed = scope.trim();
|
|
25795
|
+
if (!trimmed || seen.has(trimmed))
|
|
25796
|
+
continue;
|
|
25797
|
+
seen.add(trimmed);
|
|
25798
|
+
normalized.push(trimmed);
|
|
25799
|
+
}
|
|
25800
|
+
return normalized;
|
|
25801
|
+
}
|
|
25802
|
+
function assertKnown(value, allowed, label) {
|
|
25803
|
+
if (!allowed.has(value))
|
|
25804
|
+
throw new Error(`Unknown provider profile ${label}: ${value}`);
|
|
25805
|
+
return value;
|
|
25806
|
+
}
|
|
25807
|
+
function normalizeProvenance(provenance) {
|
|
25808
|
+
const source = assertKnown(provenance.source, PROVENANCE_SOURCES, "provenance source");
|
|
25809
|
+
return {
|
|
25810
|
+
source,
|
|
25811
|
+
sourceUrl: normalizeString(provenance.sourceUrl) ?? undefined,
|
|
25812
|
+
repositoryUrl: normalizeString(provenance.repositoryUrl) ?? undefined,
|
|
25813
|
+
packageName: normalizeString(provenance.packageName) ?? undefined,
|
|
25814
|
+
verifiedAt: normalizeString(provenance.verifiedAt) ?? undefined
|
|
25815
|
+
};
|
|
25816
|
+
}
|
|
25817
|
+
function normalizeInstallFallback(fallback) {
|
|
25818
|
+
if (!fallback)
|
|
25819
|
+
return null;
|
|
25820
|
+
const normalized = {
|
|
25821
|
+
command: normalizeString(fallback.command) ?? undefined,
|
|
25822
|
+
args: Array.isArray(fallback.args) ? fallback.args.map((arg) => arg.trim()).filter(Boolean) : undefined,
|
|
25823
|
+
env: fallback.env && Object.keys(fallback.env).length > 0 ? fallback.env : undefined,
|
|
25824
|
+
packageName: normalizeString(fallback.packageName) ?? undefined,
|
|
25825
|
+
registryId: normalizeString(fallback.registryId) ?? undefined,
|
|
25826
|
+
url: normalizeString(fallback.url) ?? undefined
|
|
25827
|
+
};
|
|
25828
|
+
return Object.values(normalized).some((value) => value !== undefined) ? normalized : null;
|
|
25829
|
+
}
|
|
25830
|
+
function normalizeFallbackEndpoints(fallbacks) {
|
|
25831
|
+
const seen = new Set;
|
|
25832
|
+
const normalized = [];
|
|
25833
|
+
for (const fallback of fallbacks ?? []) {
|
|
25834
|
+
const transport = assertKnown(fallback.transport, TRANSPORTS, "fallback transport");
|
|
25835
|
+
const url2 = normalizeString(fallback.url);
|
|
25836
|
+
if (!url2)
|
|
25837
|
+
continue;
|
|
25838
|
+
const key = `${transport}:${url2}`;
|
|
25839
|
+
if (seen.has(key))
|
|
25840
|
+
continue;
|
|
25841
|
+
seen.add(key);
|
|
25842
|
+
normalized.push({
|
|
25843
|
+
transport,
|
|
25844
|
+
url: url2,
|
|
25845
|
+
notes: normalizeString(fallback.notes) ?? undefined
|
|
25846
|
+
});
|
|
25847
|
+
}
|
|
25848
|
+
return normalized;
|
|
25849
|
+
}
|
|
25850
|
+
function normalizeAuthMetadata(authMetadata) {
|
|
25851
|
+
const bearerToken = authMetadata?.bearerToken ? assertKnown(authMetadata.bearerToken, BEARER_TOKEN_MODES, "bearer token mode") : undefined;
|
|
25852
|
+
return {
|
|
25853
|
+
oauthVersion: authMetadata?.oauthVersion,
|
|
25854
|
+
pkce: authMetadata?.pkce,
|
|
25855
|
+
dynamicClientRegistration: authMetadata?.dynamicClientRegistration,
|
|
25856
|
+
bearerToken,
|
|
25857
|
+
notes: normalizeString(authMetadata?.notes) ?? undefined
|
|
25858
|
+
};
|
|
25859
|
+
}
|
|
25860
|
+
function parseRow2(row) {
|
|
25861
|
+
const installFallback = safeJsonParse2(row.install_fallback, null);
|
|
25862
|
+
return {
|
|
25863
|
+
id: row.id,
|
|
25864
|
+
displayName: row.display_name,
|
|
25865
|
+
description: row.description || null,
|
|
25866
|
+
endpoint: row.endpoint || null,
|
|
25867
|
+
transport: row.transport,
|
|
25868
|
+
fallbackEndpoints: safeJsonParse2(row.fallback_endpoints, []),
|
|
25869
|
+
authType: row.auth_type,
|
|
25870
|
+
authMetadata: safeJsonParse2(row.auth_metadata, {}),
|
|
25871
|
+
scopes: safeJsonParse2(row.scopes, []),
|
|
25872
|
+
tokenMode: row.token_mode,
|
|
25873
|
+
installFallback,
|
|
25874
|
+
docsUrl: row.docs_url || null,
|
|
25875
|
+
safety: safeJsonParse2(row.safety, {}),
|
|
25876
|
+
provenance: safeJsonParse2(row.provenance, { source: "manual" }),
|
|
25877
|
+
enabled: row.enabled === 1 || row.enabled === true,
|
|
25878
|
+
created_at: row.created_at,
|
|
25879
|
+
updated_at: row.updated_at
|
|
25880
|
+
};
|
|
25881
|
+
}
|
|
25882
|
+
function upsertProviderProfile(opts) {
|
|
25883
|
+
const db2 = getDb();
|
|
25884
|
+
const id = normalizeId(opts.id);
|
|
25885
|
+
const displayName = normalizeString(opts.displayName);
|
|
25886
|
+
if (!displayName)
|
|
25887
|
+
throw new Error("Provider profile displayName is required");
|
|
25888
|
+
const transport = assertKnown(opts.transport, TRANSPORTS, "transport");
|
|
25889
|
+
const fallbackEndpoints = normalizeFallbackEndpoints(opts.fallbackEndpoints);
|
|
25890
|
+
const authType = assertKnown(opts.authType, AUTH_TYPES, "auth type");
|
|
25891
|
+
const authMetadata = normalizeAuthMetadata(opts.authMetadata);
|
|
25892
|
+
const tokenMode = assertKnown(opts.tokenMode ?? "none", TOKEN_MODES, "token mode");
|
|
25893
|
+
const scopes = normalizeScopes(opts.scopes);
|
|
25894
|
+
const installFallback = normalizeInstallFallback(opts.installFallback);
|
|
25895
|
+
const provenance = normalizeProvenance(opts.provenance);
|
|
25896
|
+
const safety = opts.safety ?? {};
|
|
25897
|
+
const enabled = opts.enabled === false ? 0 : 1;
|
|
25898
|
+
const row = db2.prepare(`INSERT INTO provider_profiles (
|
|
25899
|
+
id, display_name, description, endpoint, transport, fallback_endpoints, auth_type, auth_metadata, scopes,
|
|
25900
|
+
token_mode, install_fallback, docs_url, safety, provenance, enabled
|
|
25901
|
+
)
|
|
25902
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
25903
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
25904
|
+
display_name = excluded.display_name,
|
|
25905
|
+
description = excluded.description,
|
|
25906
|
+
endpoint = excluded.endpoint,
|
|
25907
|
+
transport = excluded.transport,
|
|
25908
|
+
fallback_endpoints = excluded.fallback_endpoints,
|
|
25909
|
+
auth_type = excluded.auth_type,
|
|
25910
|
+
auth_metadata = excluded.auth_metadata,
|
|
25911
|
+
scopes = excluded.scopes,
|
|
25912
|
+
token_mode = excluded.token_mode,
|
|
25913
|
+
install_fallback = excluded.install_fallback,
|
|
25914
|
+
docs_url = excluded.docs_url,
|
|
25915
|
+
safety = excluded.safety,
|
|
25916
|
+
provenance = excluded.provenance,
|
|
25917
|
+
enabled = excluded.enabled,
|
|
25918
|
+
updated_at = datetime('now')
|
|
25919
|
+
RETURNING *`).get(id, displayName, normalizeString(opts.description), normalizeString(opts.endpoint), transport, JSON.stringify(fallbackEndpoints), authType, JSON.stringify(authMetadata), JSON.stringify(scopes), tokenMode, JSON.stringify(installFallback), normalizeString(opts.docsUrl), JSON.stringify(safety), JSON.stringify(provenance), enabled);
|
|
25920
|
+
return parseRow2(row);
|
|
25921
|
+
}
|
|
25922
|
+
function listProviderProfiles(options = {}) {
|
|
25923
|
+
const db2 = getDb();
|
|
25924
|
+
const sql = options.enabledOnly ? "SELECT * FROM provider_profiles WHERE enabled = 1 ORDER BY display_name" : "SELECT * FROM provider_profiles ORDER BY display_name";
|
|
25925
|
+
return db2.prepare(sql).all().map(parseRow2);
|
|
25926
|
+
}
|
|
25927
|
+
function searchProviderProfiles(query, options = {}) {
|
|
25928
|
+
const normalizedQuery = query.trim().toLowerCase();
|
|
25929
|
+
if (!normalizedQuery)
|
|
25930
|
+
return listProviderProfiles(options);
|
|
25931
|
+
return listProviderProfiles(options).filter((profile) => {
|
|
25932
|
+
const searchable = [
|
|
25933
|
+
profile.id,
|
|
25934
|
+
profile.displayName,
|
|
25935
|
+
profile.description ?? "",
|
|
25936
|
+
profile.endpoint ?? "",
|
|
25937
|
+
profile.docsUrl ?? "",
|
|
25938
|
+
profile.provenance.sourceUrl ?? "",
|
|
25939
|
+
profile.provenance.packageName ?? ""
|
|
25940
|
+
].join(`
|
|
25941
|
+
`).toLowerCase();
|
|
25942
|
+
return searchable.includes(normalizedQuery);
|
|
25943
|
+
});
|
|
25944
|
+
}
|
|
25945
|
+
function getProviderProfile(id) {
|
|
25946
|
+
const db2 = getDb();
|
|
25947
|
+
const row = db2.prepare("SELECT * FROM provider_profiles WHERE id = ?").get(normalizeId(id));
|
|
25948
|
+
return row ? parseRow2(row) : null;
|
|
25949
|
+
}
|
|
25950
|
+
function removeProviderProfile(id) {
|
|
25951
|
+
const db2 = getDb();
|
|
25952
|
+
db2.prepare("DELETE FROM provider_profiles WHERE id = ?").run(normalizeId(id));
|
|
25953
|
+
}
|
|
25954
|
+
function enableProviderProfile(id) {
|
|
25955
|
+
return setProviderProfileEnabled(id, true);
|
|
25956
|
+
}
|
|
25957
|
+
function disableProviderProfile(id) {
|
|
25958
|
+
return setProviderProfileEnabled(id, false);
|
|
25959
|
+
}
|
|
25960
|
+
function seedDefaultProviderProfiles() {
|
|
25961
|
+
return DEFAULT_PROVIDER_PROFILE_SEEDS.map((profile) => upsertProviderProfile(profile));
|
|
25962
|
+
}
|
|
25963
|
+
function installProviderProfile(id, options = {}) {
|
|
25964
|
+
const profile = getProviderProfile(id);
|
|
25965
|
+
if (!profile)
|
|
25966
|
+
throw new Error(`Provider profile "${id}" not found`);
|
|
25967
|
+
if (!profile.enabled)
|
|
25968
|
+
throw new Error(`Provider profile "${id}" is disabled`);
|
|
25969
|
+
const fallback = profile.installFallback;
|
|
25970
|
+
const useFallback = options.useFallback || !profile.endpoint;
|
|
25971
|
+
const command = useFallback ? fallback?.command : fallback?.command ?? "npx";
|
|
25972
|
+
const args = useFallback ? fallback?.args ?? [] : fallback?.args ?? [];
|
|
25973
|
+
if (!command) {
|
|
25974
|
+
throw new Error(`Provider profile "${id}" does not define an install fallback command`);
|
|
25975
|
+
}
|
|
25976
|
+
assertLocalCommandConsent({
|
|
25977
|
+
command,
|
|
25978
|
+
args,
|
|
25979
|
+
env: fallback?.env ?? {},
|
|
25980
|
+
transport: useFallback ? "stdio" : profile.transport,
|
|
25981
|
+
operation: "register"
|
|
25982
|
+
}, options.localCommandConsent);
|
|
25983
|
+
return addServer({
|
|
25984
|
+
name: options.name ?? profile.displayName,
|
|
25985
|
+
description: profile.description ?? undefined,
|
|
25986
|
+
command,
|
|
25987
|
+
args,
|
|
25988
|
+
env: fallback?.env,
|
|
25989
|
+
transport: useFallback ? "stdio" : profile.transport,
|
|
25990
|
+
url: useFallback ? fallback?.url : profile.endpoint ?? undefined,
|
|
25991
|
+
source: "provider-profile"
|
|
25992
|
+
});
|
|
25993
|
+
}
|
|
25994
|
+
function setProviderProfileEnabled(id, enabled) {
|
|
25995
|
+
const db2 = getDb();
|
|
25996
|
+
const row = db2.prepare("UPDATE provider_profiles SET enabled = ?, updated_at = datetime('now') WHERE id = ? RETURNING *").get(enabled ? 1 : 0, normalizeId(id));
|
|
25997
|
+
if (!row) {
|
|
25998
|
+
throw new Error(`Provider profile "${id}" not found`);
|
|
25999
|
+
}
|
|
26000
|
+
return parseRow2(row);
|
|
26001
|
+
}
|
|
26002
|
+
|
|
26003
|
+
// src/index.ts
|
|
26004
|
+
init_provider_profile_seeds();
|
|
26005
|
+
|
|
25428
26006
|
// src/lib/install.ts
|
|
25429
26007
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
25430
26008
|
import { existsSync as existsSync7, readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync7 } from "fs";
|
|
@@ -25496,7 +26074,22 @@ function installToGemini(entry) {
|
|
|
25496
26074
|
return { agent: "gemini", success: false, error: err.message };
|
|
25497
26075
|
}
|
|
25498
26076
|
}
|
|
25499
|
-
function installToAgents(entry, targets = ["claude", "codex", "gemini"]) {
|
|
26077
|
+
function installToAgents(entry, targets = ["claude", "codex", "gemini"], options = {}) {
|
|
26078
|
+
try {
|
|
26079
|
+
assertLocalCommandConsent({
|
|
26080
|
+
command: entry.command,
|
|
26081
|
+
args: entry.args,
|
|
26082
|
+
env: entry.env,
|
|
26083
|
+
transport: entry.transport,
|
|
26084
|
+
operation: "install"
|
|
26085
|
+
}, options.localCommandConsent);
|
|
26086
|
+
} catch (err) {
|
|
26087
|
+
return targets.map((target) => ({
|
|
26088
|
+
agent: target,
|
|
26089
|
+
success: false,
|
|
26090
|
+
error: err.message
|
|
26091
|
+
}));
|
|
26092
|
+
}
|
|
25500
26093
|
return targets.map((target) => {
|
|
25501
26094
|
if (target === "claude")
|
|
25502
26095
|
return installToClaude(entry);
|
|
@@ -25510,7 +26103,7 @@ function installToAgents(entry, targets = ["claude", "codex", "gemini"]) {
|
|
|
25510
26103
|
// src/lib/machines.ts
|
|
25511
26104
|
init_db();
|
|
25512
26105
|
import { userInfo } from "os";
|
|
25513
|
-
function
|
|
26106
|
+
function parseRow3(row) {
|
|
25514
26107
|
return {
|
|
25515
26108
|
id: row.id,
|
|
25516
26109
|
name: row.name,
|
|
@@ -25553,12 +26146,12 @@ function toSqlBool(value, fallback = true) {
|
|
|
25553
26146
|
function listMachines() {
|
|
25554
26147
|
const db2 = getDb();
|
|
25555
26148
|
const rows = db2.prepare("SELECT * FROM machines ORDER BY name ASC").all();
|
|
25556
|
-
return rows.map(
|
|
26149
|
+
return rows.map(parseRow3);
|
|
25557
26150
|
}
|
|
25558
26151
|
function getMachine(id) {
|
|
25559
26152
|
const db2 = getDb();
|
|
25560
26153
|
const row = db2.prepare("SELECT * FROM machines WHERE id = ?").get(id);
|
|
25561
|
-
return row ?
|
|
26154
|
+
return row ? parseRow3(row) : null;
|
|
25562
26155
|
}
|
|
25563
26156
|
function addMachine(opts) {
|
|
25564
26157
|
const db2 = getDb();
|
|
@@ -25573,7 +26166,7 @@ function addMachine(opts) {
|
|
|
25573
26166
|
id, name, host, username, port, platform, arch, bun_path, npm_path, installer, ssh_key_path, enabled
|
|
25574
26167
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
25575
26168
|
RETURNING *`).get(id, name, host, normalizeText(opts.username) ?? resolveDefaultUser(), opts.port ?? 22, opts.platform ?? "unknown", opts.arch ?? "unknown", normalizeText(opts.bun_path) ?? null, normalizeText(opts.npm_path) ?? null, opts.installer ?? "auto", normalizeText(opts.ssh_key_path) ?? null, toSqlBool(opts.enabled, true));
|
|
25576
|
-
return
|
|
26169
|
+
return parseRow3(row);
|
|
25577
26170
|
}
|
|
25578
26171
|
function upsertMachine(opts) {
|
|
25579
26172
|
const db2 = getDb();
|
|
@@ -25601,7 +26194,7 @@ function upsertMachine(opts) {
|
|
|
25601
26194
|
enabled = excluded.enabled,
|
|
25602
26195
|
updated_at = datetime('now')
|
|
25603
26196
|
RETURNING *`).get(id, name, host, normalizeText(opts.username) ?? resolveDefaultUser(), opts.port ?? 22, opts.platform ?? "unknown", opts.arch ?? "unknown", normalizeText(opts.bun_path) ?? null, normalizeText(opts.npm_path) ?? null, opts.installer ?? "auto", normalizeText(opts.ssh_key_path) ?? null, toSqlBool(opts.enabled, true));
|
|
25604
|
-
return
|
|
26197
|
+
return parseRow3(row);
|
|
25605
26198
|
}
|
|
25606
26199
|
function updateMachine(id, updates) {
|
|
25607
26200
|
const db2 = getDb();
|
|
@@ -25664,7 +26257,7 @@ function updateMachine(id, updates) {
|
|
|
25664
26257
|
const row = db2.prepare(`UPDATE machines SET ${sets.join(", ")} WHERE id = ? RETURNING *`).get(...values);
|
|
25665
26258
|
if (!row)
|
|
25666
26259
|
throw new Error(`Machine "${id}" not found`);
|
|
25667
|
-
return
|
|
26260
|
+
return parseRow3(row);
|
|
25668
26261
|
}
|
|
25669
26262
|
function removeMachine(id) {
|
|
25670
26263
|
const db2 = getDb();
|
|
@@ -26431,49 +27024,63 @@ function readPackageVersion(moduleUrl, fallback = FALLBACK_VERSION) {
|
|
|
26431
27024
|
// src/index.ts
|
|
26432
27025
|
init_db();
|
|
26433
27026
|
export {
|
|
27027
|
+
upsertProviderProfile,
|
|
26434
27028
|
upsertMachine,
|
|
26435
27029
|
updateServer,
|
|
26436
27030
|
updateMachine,
|
|
26437
27031
|
unsetServerEnv,
|
|
26438
27032
|
setServerEnv,
|
|
27033
|
+
seedDefaultProviderProfiles,
|
|
26439
27034
|
seedDefaultMachines,
|
|
26440
27035
|
searchRegistry,
|
|
27036
|
+
searchProviderProfiles,
|
|
26441
27037
|
runFleetInstall,
|
|
26442
27038
|
runFleetHealthCheck,
|
|
26443
27039
|
removeSource,
|
|
26444
27040
|
removeServer,
|
|
27041
|
+
removeProviderProfile,
|
|
26445
27042
|
removeMachine,
|
|
26446
27043
|
refreshTools,
|
|
26447
27044
|
readPackageVersion,
|
|
26448
27045
|
listSources,
|
|
26449
27046
|
listServers,
|
|
27047
|
+
listProviderProfiles,
|
|
26450
27048
|
listMachines,
|
|
26451
27049
|
listHasnaMcpCatalog,
|
|
26452
27050
|
listAwesomeServers,
|
|
26453
27051
|
listAllTools,
|
|
26454
27052
|
installToAgents,
|
|
27053
|
+
installProviderProfile,
|
|
26455
27054
|
installFromRegistry,
|
|
27055
|
+
inspectLocalCommand,
|
|
26456
27056
|
getToolCounts,
|
|
26457
27057
|
getSource,
|
|
26458
27058
|
getServer,
|
|
26459
27059
|
getRegistryServer,
|
|
27060
|
+
getProviderProfile,
|
|
26460
27061
|
getMachine,
|
|
26461
27062
|
getDb,
|
|
26462
27063
|
getCachedTools,
|
|
27064
|
+
formatLocalCommandReview,
|
|
26463
27065
|
findServers,
|
|
26464
27066
|
enableSource,
|
|
26465
27067
|
enableServer,
|
|
27068
|
+
enableProviderProfile,
|
|
26466
27069
|
disconnectServer,
|
|
26467
27070
|
disconnectAll,
|
|
26468
27071
|
disableSource,
|
|
26469
27072
|
disableServer,
|
|
27073
|
+
disableProviderProfile,
|
|
26470
27074
|
diagnoseServer,
|
|
26471
27075
|
connectToServer,
|
|
26472
27076
|
closeDb,
|
|
26473
27077
|
cloneServer,
|
|
26474
27078
|
callTool,
|
|
27079
|
+
assertLocalCommandConsent,
|
|
26475
27080
|
addSource,
|
|
26476
27081
|
addServer,
|
|
26477
27082
|
addMachine,
|
|
27083
|
+
LocalCommandConsentError,
|
|
27084
|
+
DEFAULT_PROVIDER_PROFILE_SEEDS,
|
|
26478
27085
|
DEFAULT_MACHINE_SEEDS
|
|
26479
27086
|
};
|