@enactprotocol/cli 1.2.7 → 1.2.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -214775,6 +214775,13 @@ class EnactApiClient {
214775
214775
  throw new EnactApiError("Unknown error occurred", 0);
214776
214776
  }
214777
214777
  }
214778
+ async signTool(toolId, payload, token, tokenType = "cli") {
214779
+ const endpoint = `/functions/v1/tools/${encodeURIComponent(toolId)}/signatures`;
214780
+ return this.makeRequest(endpoint, {
214781
+ method: "POST",
214782
+ body: JSON.stringify(payload)
214783
+ }, token, tokenType);
214784
+ }
214778
214785
  generateOAuthUrl(options) {
214779
214786
  const params = new URLSearchParams({
214780
214787
  response_type: "code",
@@ -216406,14 +216413,6 @@ var MCP_CLIENTS = {
216406
216413
  win32: join8(homedir6(), ".gemini/settings.json"),
216407
216414
  linux: join8(homedir6(), ".gemini/settings.json")
216408
216415
  }
216409
- },
216410
- cursor: {
216411
- name: "Cursor",
216412
- configPaths: {
216413
- darwin: join8(homedir6(), ".cursor/mcp.json"),
216414
- win32: join8(homedir6(), ".cursor/mcp.json"),
216415
- linux: join8(homedir6(), ".cursor/mcp.json")
216416
- }
216417
216416
  }
216418
216417
  };
216419
216418
  var MCP_SERVERS = {
@@ -216447,7 +216446,7 @@ Subcommands:
216447
216446
 
216448
216447
  Options:
216449
216448
  --help, -h Show this help message
216450
- --client <name> Target specific client (claude-desktop, claude-code, vscode, goose, gemini, cursor)
216449
+ --client <name> Target specific client (claude-desktop, claude-code, vscode, goose, gemini)
216451
216450
  --server <type> Choose server type (main, dev, both) - default: main
216452
216451
  `);
216453
216452
  return;
@@ -216481,8 +216480,7 @@ Supported clients:
216481
216480
  • Claude Code
216482
216481
  • VS Code MCP
216483
216482
  • Goose AI
216484
- • Gemini
216485
- • Cursor`), "No clients found");
216483
+ • Gemini`), "No clients found");
216486
216484
  Se("Please install a supported MCP client first.");
216487
216485
  return;
216488
216486
  }
@@ -216701,7 +216699,7 @@ async function installMcpServer(client, serverType = "main") {
216701
216699
  args: ["-y", "@enactprotocol/mcp-dev-server"]
216702
216700
  };
216703
216701
  }
216704
- if (client.id === "claude-desktop" || client.id === "claude-code" || client.id === "gemini" || client.id === "cursor") {
216702
+ if (client.id === "claude-desktop" || client.id === "claude-code" || client.id === "gemini") {
216705
216703
  if (!config2.mcpServers) {
216706
216704
  config2.mcpServers = {};
216707
216705
  }
@@ -216741,7 +216739,7 @@ async function checkMcpServerInstalled(client, serverType = "main") {
216741
216739
  try {
216742
216740
  const configContent = await readFile6(client.configPath, "utf-8");
216743
216741
  const config2 = JSON.parse(configContent);
216744
- if (client.id === "claude-desktop" || client.id === "claude-code" || client.id === "gemini" || client.id === "cursor") {
216742
+ if (client.id === "claude-desktop" || client.id === "claude-code" || client.id === "gemini") {
216745
216743
  const servers = config2.mcpServers || {};
216746
216744
  if (serverType === "main") {
216747
216745
  return Boolean(servers.enact);
@@ -229715,6 +229713,33 @@ class EnactCore {
229715
229713
  };
229716
229714
  }
229717
229715
  }
229716
+ static async checkToolVerificationStatus(tool) {
229717
+ const documentForVerification = {
229718
+ command: tool.command,
229719
+ description: tool.description,
229720
+ from: tool.from,
229721
+ name: tool.name,
229722
+ signatures: tool.signatures?.map((sig) => ({
229723
+ signature: sig.value,
229724
+ publicKey: "",
229725
+ algorithm: sig.algorithm,
229726
+ timestamp: new Date(sig.created).getTime()
229727
+ }))
229728
+ };
229729
+ let isValid = false;
229730
+ if (tool.signatures && tool.signatures.length > 0) {
229731
+ isValid = tool.signatures.some((sig) => {
229732
+ const referenceSignature = {
229733
+ signature: sig.value,
229734
+ publicKey: "",
229735
+ algorithm: sig.algorithm,
229736
+ timestamp: new Date(sig.created).getTime()
229737
+ };
229738
+ return SigningService.verifyDocument(documentForVerification, referenceSignature, { includeFields: ["command", "description", "from", "name"] });
229739
+ });
229740
+ }
229741
+ return isValid;
229742
+ }
229718
229743
  async verifyTool(tool, dangerouslySkipVerification = false) {
229719
229744
  if (dangerouslySkipVerification) {
229720
229745
  logger_default.warn(`Skipping signature verification for tool: ${tool.name}`);
@@ -229724,23 +229749,8 @@ class EnactCore {
229724
229749
  if (!tool.signatures || tool.signatures.length === 0) {
229725
229750
  throw new Error(`Tool ${tool.name} does not have any signatures`);
229726
229751
  }
229727
- const documentForVerification = {
229728
- command: tool.command,
229729
- description: tool.description,
229730
- from: tool.from,
229731
- name: tool.name
229732
- };
229733
- const referenceSignature = {
229734
- signature: tool.signatures[0].value,
229735
- publicKey: "",
229736
- algorithm: tool.signatures[0].algorithm,
229737
- timestamp: new Date(tool.signatures[0].created).getTime()
229738
- };
229739
- const canonicalDoc = SigningService.getCanonicalDocument(documentForVerification, { includeFields: ["command", "description", "from", "name"] });
229740
- const docString = JSON.stringify(canonicalDoc);
229741
- const messageHash = CryptoUtils.hash(docString);
229742
- const directVerify = CryptoUtils.verify(referenceSignature.publicKey, messageHash, referenceSignature.signature);
229743
- const isValid = SigningService.verifyDocument(documentForVerification, referenceSignature, { includeFields: ["command", "description", "from", "name"] });
229752
+ const isValid = await EnactCore.checkToolVerificationStatus(tool);
229753
+ console.log("Final verification result:", isValid);
229744
229754
  if (!isValid) {
229745
229755
  throw new Error(`Tool ${tool.name} has invalid signatures`);
229746
229756
  }
@@ -230094,9 +230104,11 @@ ${import_picocolors13.default.bold("EXAMPLES:")}
230094
230104
  try {
230095
230105
  const tool = await apiClient.getTool(result.name);
230096
230106
  if (tool) {
230107
+ const isValid = await EnactCore.checkToolVerificationStatus(tool);
230097
230108
  const enactTool = {
230098
230109
  name: tool.name,
230099
230110
  description: tool.description || "",
230111
+ verified: isValid,
230100
230112
  command: tool.command,
230101
230113
  from: tool.from,
230102
230114
  version: tool.version || "1.0.0",
@@ -230278,6 +230290,159 @@ async function collectParametersInteractively(inputSchema) {
230278
230290
  }
230279
230291
  return params;
230280
230292
  }
230293
+ async function handleSignToolCommand(args, options) {
230294
+ if (options.help) {
230295
+ console.error(`
230296
+ Usage: enact sign [options]
230297
+ Sign a tool definition using your private key
230298
+ Options:
230299
+ --help, -h Show this help message
230300
+ --tool query Search for the tool to sign (name)
230301
+ Examples:
230302
+ enact sign --tool myorg/mytool
230303
+ `);
230304
+ return;
230305
+ }
230306
+ if (!options.tool) {
230307
+ const inputSchema = {
230308
+ type: "object",
230309
+ properties: {
230310
+ toolName: {
230311
+ type: "string",
230312
+ description: "The name of the tool to run"
230313
+ }
230314
+ },
230315
+ required: ["tool"]
230316
+ };
230317
+ const params = await collectParametersInteractively(inputSchema);
230318
+ options.tool = params.toolName;
230319
+ }
230320
+ const spinner = Y2();
230321
+ spinner.start("Searching for tools...");
230322
+ const results = [];
230323
+ try {
230324
+ const searchOptions = {
230325
+ query: options.tool ? options.tool : "",
230326
+ limit: 20,
230327
+ tags: undefined,
230328
+ author: undefined,
230329
+ format: "table"
230330
+ };
230331
+ const apiClient = await EnactApiClient.create();
230332
+ const searchResults = await apiClient.searchTools(searchOptions);
230333
+ for (const result of searchResults) {
230334
+ if (result.name) {
230335
+ try {
230336
+ const tool = await apiClient.getTool(result.name);
230337
+ if (tool) {
230338
+ const documentForVerification2 = {
230339
+ command: tool.command,
230340
+ description: tool.description,
230341
+ from: tool.from,
230342
+ name: tool.name
230343
+ };
230344
+ const isValid = await EnactCore.checkToolVerificationStatus(tool);
230345
+ const enactTool = {
230346
+ name: tool.name,
230347
+ description: tool.description || "",
230348
+ verified: isValid,
230349
+ command: tool.command,
230350
+ from: tool.from,
230351
+ version: tool.version || "1.0.0",
230352
+ timeout: tool.timeout,
230353
+ tags: tool.tags || [],
230354
+ inputSchema: tool.inputSchema,
230355
+ outputSchema: tool.outputSchema,
230356
+ env: tool.env_vars ? Object.fromEntries(Object.entries(tool.env_vars).map(([key, config2]) => [
230357
+ key,
230358
+ { ...config2, source: config2.source || "env" }
230359
+ ])) : undefined,
230360
+ signature: tool.signature,
230361
+ signatures: Array.isArray(tool.signatures) ? tool.signatures : tool.signatures ? Object.values(tool.signatures) : undefined,
230362
+ namespace: tool.namespace,
230363
+ resources: tool.resources,
230364
+ license: tool.license,
230365
+ authors: tool.authors,
230366
+ examples: tool.examples,
230367
+ annotations: tool.annotations
230368
+ };
230369
+ results.push(enactTool);
230370
+ }
230371
+ } catch (error2) {
230372
+ continue;
230373
+ }
230374
+ }
230375
+ }
230376
+ spinner.stop(`Found ${results.length} tool${results.length === 1 ? "" : "s"}`);
230377
+ if (results.length === 0) {
230378
+ Me("No tools found matching your criteria.", "No Results");
230379
+ Me(`Try:
230380
+ • Broader keywords
230381
+ • Removing filters
230382
+ • Different spelling`, "Suggestions");
230383
+ return;
230384
+ }
230385
+ } catch (error2) {
230386
+ spinner.stop("Search failed");
230387
+ if (error2.message?.includes("ENOTFOUND") || error2.message?.includes("ECONNREFUSED")) {
230388
+ Me("Could not connect to the Enact registry. Check your internet connection.", "Connection Error");
230389
+ } else {
230390
+ Me(error2 instanceof Error ? error2.message : String(error2), "Error");
230391
+ }
230392
+ console.error(import_picocolors13.default.red(`Search failed: ${error2 instanceof Error ? error2.message : String(error2)}`));
230393
+ process.exit(1);
230394
+ }
230395
+ const selected_tool = await ve({
230396
+ message: "Select a tool to sign:",
230397
+ options: results.map((tool) => ({
230398
+ value: tool,
230399
+ label: `${tool.name} - ${tool.description.substring(0, 60)}${tool.description.length > 60 ? "..." : ""} - Verified: ${tool.verified ? import_picocolors13.default.green("Yes") : import_picocolors13.default.red("No")}`
230400
+ }))
230401
+ });
230402
+ const documentForVerification = {
230403
+ command: selected_tool.command,
230404
+ description: selected_tool.description,
230405
+ from: selected_tool.from,
230406
+ name: selected_tool.name
230407
+ };
230408
+ const privateKeys = await KeyManager.getAllPrivateKeys();
230409
+ const privateKey = await ve({
230410
+ message: "Select a private key to sign with:",
230411
+ options: privateKeys.map((key) => ({
230412
+ value: key,
230413
+ label: `${key.fileName}`
230414
+ }))
230415
+ });
230416
+ const TrustedKey = CryptoUtils.getPublicKeyFromPrivate(privateKey.key);
230417
+ if (selected_tool.signatures && selected_tool.signatures.length > 0) {
230418
+ const alreadySigned = selected_tool.signatures.some((sig) => {
230419
+ const referenceSignature = {
230420
+ signature: sig.value,
230421
+ publicKey: "",
230422
+ algorithm: sig.algorithm,
230423
+ timestamp: new Date(sig.created).getTime()
230424
+ };
230425
+ return SigningService.verifyDocumentWithPublicKey(documentForVerification, referenceSignature, TrustedKey, { includeFields: ["command", "description", "from", "name"] });
230426
+ });
230427
+ if (alreadySigned) {
230428
+ console.log(import_picocolors13.default.green("✓ Tool has already been signed with the selected key."));
230429
+ return;
230430
+ }
230431
+ }
230432
+ const spinnerSign = Y2();
230433
+ console.error(spinnerSign.start("Signing tool..."));
230434
+ const signature = await SigningService.signDocument(documentForVerification, privateKey.key, { includeFields: ["command", "description", "from", "name"] });
230435
+ spinnerSign.stop(import_picocolors13.default.green("✓ Tool signed successfully"));
230436
+ console.error(import_picocolors13.default.cyan(`
230437
+ Signature Details:`));
230438
+ console.error(import_picocolors13.default.cyan(` Signature: ${signature.signature}`));
230439
+ console.error(import_picocolors13.default.cyan(` Algorithm: ${signature.algorithm}`));
230440
+ console.error(import_picocolors13.default.cyan(` Created: ${new Date(signature.timestamp).toISOString()}`));
230441
+ console.error(import_picocolors13.default.cyan(` Public Key: ${TrustedKey}`));
230442
+ console.error(import_picocolors13.default.red(`
230443
+ Pushing the signature to the registry is not yet implemented.`));
230444
+ return signature;
230445
+ }
230281
230446
  async function handleCoreExecCommand(args, options) {
230282
230447
  if (options.help) {
230283
230448
  console.error(`
@@ -230519,6 +230684,7 @@ Environment variables:`));
230519
230684
  const enactTool = {
230520
230685
  name: toolDefinition.name,
230521
230686
  description: toolDefinition.description || "",
230687
+ verified: true,
230522
230688
  command: toolDefinition.command,
230523
230689
  from: toolDefinition.from,
230524
230690
  version: toolDefinition.version || "1.0.0",
@@ -230685,9 +230851,11 @@ ${import_picocolors13.default.bold("EXAMPLES:")}
230685
230851
  Se(import_picocolors13.default.red(`Tool not found: ${toolName}`));
230686
230852
  process.exit(1);
230687
230853
  }
230854
+ const isValid = EnactCore.checkToolVerificationStatus(toolDefinition);
230688
230855
  const tool = {
230689
230856
  name: toolDefinition.name,
230690
230857
  description: toolDefinition.description || "",
230858
+ verified: isValid,
230691
230859
  command: toolDefinition.command,
230692
230860
  from: toolDefinition.from,
230693
230861
  version: toolDefinition.version || "1.0.0",
@@ -230726,6 +230894,11 @@ ${import_picocolors13.default.bold(import_picocolors13.default.cyan(`\uD83D\uDCE
230726
230894
  if (tool.command) {
230727
230895
  console.error(`${import_picocolors13.default.bold("Command:")} ${import_picocolors13.default.gray(tool.command)}`);
230728
230896
  }
230897
+ if (tool.verified) {
230898
+ console.error(`${import_picocolors13.default.bold("Verification:")} ${import_picocolors13.default.green("Verified ✓")}`);
230899
+ } else {
230900
+ console.error(`${import_picocolors13.default.bold("Verification:")} ${import_picocolors13.default.red("Unverified ✗")}`);
230901
+ }
230729
230902
  if (tool.from) {
230730
230903
  console.error(`${import_picocolors13.default.bold("Container:")} ${import_picocolors13.default.gray(tool.from)}`);
230731
230904
  }
@@ -230776,20 +230949,25 @@ ${import_picocolors13.default.bold("Examples:")}`);
230776
230949
  function displayResultsTable(results) {
230777
230950
  console.error(`
230778
230951
  ` + import_picocolors13.default.bold("Search Results:"));
230779
- console.error("═".repeat(100));
230780
230952
  const nameWidth = 40;
230953
+ const statusWidth = 15;
230781
230954
  const descWidth = 45;
230782
230955
  const tagsWidth = 20;
230783
- console.error(import_picocolors13.default.bold(import_picocolors13.default.cyan("NAME".padEnd(nameWidth))) + " │ " + import_picocolors13.default.bold(import_picocolors13.default.cyan("DESCRIPTION".padEnd(descWidth))) + " │ " + import_picocolors13.default.bold(import_picocolors13.default.cyan("TAGS".padEnd(tagsWidth))));
230784
- console.error("─".repeat(nameWidth) + "─┼─" + "─".repeat(descWidth) + "─┼─" + "─".repeat(tagsWidth));
230956
+ const totalWidth = nameWidth + statusWidth + descWidth + tagsWidth + 9;
230957
+ console.error(import_picocolors13.default.gray("".repeat(totalWidth)));
230958
+ console.error(import_picocolors13.default.bold(import_picocolors13.default.white("NAME".padEnd(nameWidth))) + import_picocolors13.default.gray(" │ ") + import_picocolors13.default.bold(import_picocolors13.default.white("STATUS".padEnd(statusWidth))) + import_picocolors13.default.gray(" │ ") + import_picocolors13.default.bold(import_picocolors13.default.white("DESCRIPTION".padEnd(descWidth))) + import_picocolors13.default.gray(" │ ") + import_picocolors13.default.bold(import_picocolors13.default.white("TAGS".padEnd(tagsWidth))));
230959
+ console.error(import_picocolors13.default.gray("─".repeat(nameWidth) + "─┼─" + "─".repeat(statusWidth) + "─┼─" + "─".repeat(descWidth) + "─┼─" + "─".repeat(tagsWidth)));
230785
230960
  results.forEach((tool) => {
230786
- const name = tool.name.length > nameWidth ? tool.name.substring(0, nameWidth - 3) + "..." : tool.name.padEnd(nameWidth);
230961
+ const nameText = tool.name.length > nameWidth ? tool.name.substring(0, nameWidth - 3) + "..." : tool.name.padEnd(nameWidth);
230962
+ const statusText = tool.verified ? "✓ Verified" : "✗ Unverified";
230963
+ const statusColor = tool.verified ? import_picocolors13.default.green : import_picocolors13.default.yellow;
230964
+ const status = statusColor(statusText.padEnd(statusWidth));
230787
230965
  const desc = tool.description.length > descWidth ? tool.description.substring(0, descWidth - 3) + "..." : tool.description.padEnd(descWidth);
230788
230966
  const tags = (tool.tags || []).join(", ");
230789
230967
  const tagsDisplay = tags.length > tagsWidth ? tags.substring(0, tagsWidth - 3) + "..." : tags.padEnd(tagsWidth);
230790
- console.error(import_picocolors13.default.green(name) + " │ " + import_picocolors13.default.dim(desc) + " │ " + import_picocolors13.default.yellow(tagsDisplay));
230968
+ console.error(import_picocolors13.default.cyan(nameText) + import_picocolors13.default.gray(" │ ") + status + import_picocolors13.default.gray(" │ ") + import_picocolors13.default.white(desc) + import_picocolors13.default.gray(" │ ") + import_picocolors13.default.magenta(tagsDisplay));
230791
230969
  });
230792
- console.error("═".repeat(100));
230970
+ console.error(import_picocolors13.default.gray("═".repeat(totalWidth)));
230793
230971
  console.error(import_picocolors13.default.dim(`Total: ${results.length} tool${results.length === 1 ? "" : "s"}`));
230794
230972
  }
230795
230973
  function displayResultsList(results) {
@@ -230797,10 +230975,12 @@ function displayResultsList(results) {
230797
230975
  ` + import_picocolors13.default.bold("Search Results:"));
230798
230976
  console.error("");
230799
230977
  results.forEach((tool, index) => {
230800
- console.error(`${import_picocolors13.default.cyan(`${index + 1}.`)} ${import_picocolors13.default.bold(import_picocolors13.default.green(tool.name))}`);
230801
- console.error(` ${import_picocolors13.default.dim(tool.description)}`);
230978
+ const statusIndicator = tool.verified ? import_picocolors13.default.green("✓") : import_picocolors13.default.yellow("✗");
230979
+ const statusText = tool.verified ? import_picocolors13.default.green("verified") : import_picocolors13.default.red("unverified");
230980
+ console.error(`${import_picocolors13.default.cyan(`${index + 1}.`)} ${import_picocolors13.default.cyan(tool.name)} ${statusIndicator} ${import_picocolors13.default.dim(`(${statusText})`)}`);
230981
+ console.error(` ${import_picocolors13.default.white(tool.description)}`);
230802
230982
  if (tool.tags && tool.tags.length > 0) {
230803
- console.error(` ${import_picocolors13.default.yellow("Tags:")} ${tool.tags.join(", ")}`);
230983
+ console.error(` ${import_picocolors13.default.dim("Tags:")} ${import_picocolors13.default.magenta(tool.tags.join(", "))}`);
230804
230984
  }
230805
230985
  console.error("");
230806
230986
  });
@@ -231163,6 +231343,9 @@ var { values, positionals } = parseArgs({
231163
231343
  },
231164
231344
  mount: {
231165
231345
  type: "string"
231346
+ },
231347
+ tool: {
231348
+ type: "string"
231166
231349
  }
231167
231350
  },
231168
231351
  allowPositionals: true,
@@ -231237,6 +231420,12 @@ async function main() {
231237
231420
  mount: values.mount
231238
231421
  });
231239
231422
  break;
231423
+ case "sign":
231424
+ await handleSignToolCommand(commandArgs, {
231425
+ help: values.help,
231426
+ tool: values.tool
231427
+ });
231428
+ break;
231240
231429
  case "get":
231241
231430
  await handleCoreGetCommand(commandArgs, {
231242
231431
  help: values.help,
@@ -231277,6 +231466,7 @@ async function main() {
231277
231466
  { value: "publish", label: "\uD83D\uDCE4 Publish a tool" },
231278
231467
  { value: "init", label: "\uD83D\uDCDD Create a new tool definition" },
231279
231468
  { value: "env", label: "\uD83C\uDF0D Manage environment variables" },
231469
+ { value: "sign", label: "✍️ Sign a tool definition" },
231280
231470
  { value: "config", label: "\uD83D\uDD27 Configure Enact settings" },
231281
231471
  { value: "auth", label: "\uD83D\uDD10 Manage authentication" },
231282
231472
  { value: "remote", label: "\uD83C\uDF10 Manage remote servers" },
@@ -231325,6 +231515,9 @@ async function main() {
231325
231515
  }
231326
231516
  return;
231327
231517
  }
231518
+ if (action === "sign") {
231519
+ await handleSignToolCommand([], {});
231520
+ }
231328
231521
  if (action === "auth") {
231329
231522
  const authAction = await ve({
231330
231523
  message: "Authentication:",
package/dist/index.js.bak CHANGED
@@ -214774,6 +214774,13 @@ class EnactApiClient {
214774
214774
  throw new EnactApiError("Unknown error occurred", 0);
214775
214775
  }
214776
214776
  }
214777
+ async signTool(toolId, payload, token, tokenType = "cli") {
214778
+ const endpoint = `/functions/v1/tools/${encodeURIComponent(toolId)}/signatures`;
214779
+ return this.makeRequest(endpoint, {
214780
+ method: "POST",
214781
+ body: JSON.stringify(payload)
214782
+ }, token, tokenType);
214783
+ }
214777
214784
  generateOAuthUrl(options) {
214778
214785
  const params = new URLSearchParams({
214779
214786
  response_type: "code",
@@ -216405,14 +216412,6 @@ var MCP_CLIENTS = {
216405
216412
  win32: join8(homedir6(), ".gemini/settings.json"),
216406
216413
  linux: join8(homedir6(), ".gemini/settings.json")
216407
216414
  }
216408
- },
216409
- cursor: {
216410
- name: "Cursor",
216411
- configPaths: {
216412
- darwin: join8(homedir6(), ".cursor/mcp.json"),
216413
- win32: join8(homedir6(), ".cursor/mcp.json"),
216414
- linux: join8(homedir6(), ".cursor/mcp.json")
216415
- }
216416
216415
  }
216417
216416
  };
216418
216417
  var MCP_SERVERS = {
@@ -216446,7 +216445,7 @@ Subcommands:
216446
216445
 
216447
216446
  Options:
216448
216447
  --help, -h Show this help message
216449
- --client <name> Target specific client (claude-desktop, claude-code, vscode, goose, gemini, cursor)
216448
+ --client <name> Target specific client (claude-desktop, claude-code, vscode, goose, gemini)
216450
216449
  --server <type> Choose server type (main, dev, both) - default: main
216451
216450
  `);
216452
216451
  return;
@@ -216480,8 +216479,7 @@ Supported clients:
216480
216479
  • Claude Code
216481
216480
  • VS Code MCP
216482
216481
  • Goose AI
216483
- • Gemini
216484
- • Cursor`), "No clients found");
216482
+ • Gemini`), "No clients found");
216485
216483
  Se("Please install a supported MCP client first.");
216486
216484
  return;
216487
216485
  }
@@ -216700,7 +216698,7 @@ async function installMcpServer(client, serverType = "main") {
216700
216698
  args: ["-y", "@enactprotocol/mcp-dev-server"]
216701
216699
  };
216702
216700
  }
216703
- if (client.id === "claude-desktop" || client.id === "claude-code" || client.id === "gemini" || client.id === "cursor") {
216701
+ if (client.id === "claude-desktop" || client.id === "claude-code" || client.id === "gemini") {
216704
216702
  if (!config2.mcpServers) {
216705
216703
  config2.mcpServers = {};
216706
216704
  }
@@ -216740,7 +216738,7 @@ async function checkMcpServerInstalled(client, serverType = "main") {
216740
216738
  try {
216741
216739
  const configContent = await readFile6(client.configPath, "utf-8");
216742
216740
  const config2 = JSON.parse(configContent);
216743
- if (client.id === "claude-desktop" || client.id === "claude-code" || client.id === "gemini" || client.id === "cursor") {
216741
+ if (client.id === "claude-desktop" || client.id === "claude-code" || client.id === "gemini") {
216744
216742
  const servers = config2.mcpServers || {};
216745
216743
  if (serverType === "main") {
216746
216744
  return Boolean(servers.enact);
@@ -229714,6 +229712,33 @@ class EnactCore {
229714
229712
  };
229715
229713
  }
229716
229714
  }
229715
+ static async checkToolVerificationStatus(tool) {
229716
+ const documentForVerification = {
229717
+ command: tool.command,
229718
+ description: tool.description,
229719
+ from: tool.from,
229720
+ name: tool.name,
229721
+ signatures: tool.signatures?.map((sig) => ({
229722
+ signature: sig.value,
229723
+ publicKey: "",
229724
+ algorithm: sig.algorithm,
229725
+ timestamp: new Date(sig.created).getTime()
229726
+ }))
229727
+ };
229728
+ let isValid = false;
229729
+ if (tool.signatures && tool.signatures.length > 0) {
229730
+ isValid = tool.signatures.some((sig) => {
229731
+ const referenceSignature = {
229732
+ signature: sig.value,
229733
+ publicKey: "",
229734
+ algorithm: sig.algorithm,
229735
+ timestamp: new Date(sig.created).getTime()
229736
+ };
229737
+ return SigningService.verifyDocument(documentForVerification, referenceSignature, { includeFields: ["command", "description", "from", "name"] });
229738
+ });
229739
+ }
229740
+ return isValid;
229741
+ }
229717
229742
  async verifyTool(tool, dangerouslySkipVerification = false) {
229718
229743
  if (dangerouslySkipVerification) {
229719
229744
  logger_default.warn(`Skipping signature verification for tool: ${tool.name}`);
@@ -229723,23 +229748,8 @@ class EnactCore {
229723
229748
  if (!tool.signatures || tool.signatures.length === 0) {
229724
229749
  throw new Error(`Tool ${tool.name} does not have any signatures`);
229725
229750
  }
229726
- const documentForVerification = {
229727
- command: tool.command,
229728
- description: tool.description,
229729
- from: tool.from,
229730
- name: tool.name
229731
- };
229732
- const referenceSignature = {
229733
- signature: tool.signatures[0].value,
229734
- publicKey: "",
229735
- algorithm: tool.signatures[0].algorithm,
229736
- timestamp: new Date(tool.signatures[0].created).getTime()
229737
- };
229738
- const canonicalDoc = SigningService.getCanonicalDocument(documentForVerification, { includeFields: ["command", "description", "from", "name"] });
229739
- const docString = JSON.stringify(canonicalDoc);
229740
- const messageHash = CryptoUtils.hash(docString);
229741
- const directVerify = CryptoUtils.verify(referenceSignature.publicKey, messageHash, referenceSignature.signature);
229742
- const isValid = SigningService.verifyDocument(documentForVerification, referenceSignature, { includeFields: ["command", "description", "from", "name"] });
229751
+ const isValid = await EnactCore.checkToolVerificationStatus(tool);
229752
+ console.log("Final verification result:", isValid);
229743
229753
  if (!isValid) {
229744
229754
  throw new Error(`Tool ${tool.name} has invalid signatures`);
229745
229755
  }
@@ -230093,9 +230103,11 @@ ${import_picocolors13.default.bold("EXAMPLES:")}
230093
230103
  try {
230094
230104
  const tool = await apiClient.getTool(result.name);
230095
230105
  if (tool) {
230106
+ const isValid = await EnactCore.checkToolVerificationStatus(tool);
230096
230107
  const enactTool = {
230097
230108
  name: tool.name,
230098
230109
  description: tool.description || "",
230110
+ verified: isValid,
230099
230111
  command: tool.command,
230100
230112
  from: tool.from,
230101
230113
  version: tool.version || "1.0.0",
@@ -230277,6 +230289,159 @@ async function collectParametersInteractively(inputSchema) {
230277
230289
  }
230278
230290
  return params;
230279
230291
  }
230292
+ async function handleSignToolCommand(args, options) {
230293
+ if (options.help) {
230294
+ console.error(`
230295
+ Usage: enact sign [options]
230296
+ Sign a tool definition using your private key
230297
+ Options:
230298
+ --help, -h Show this help message
230299
+ --tool query Search for the tool to sign (name)
230300
+ Examples:
230301
+ enact sign --tool myorg/mytool
230302
+ `);
230303
+ return;
230304
+ }
230305
+ if (!options.tool) {
230306
+ const inputSchema = {
230307
+ type: "object",
230308
+ properties: {
230309
+ toolName: {
230310
+ type: "string",
230311
+ description: "The name of the tool to run"
230312
+ }
230313
+ },
230314
+ required: ["tool"]
230315
+ };
230316
+ const params = await collectParametersInteractively(inputSchema);
230317
+ options.tool = params.toolName;
230318
+ }
230319
+ const spinner = Y2();
230320
+ spinner.start("Searching for tools...");
230321
+ const results = [];
230322
+ try {
230323
+ const searchOptions = {
230324
+ query: options.tool ? options.tool : "",
230325
+ limit: 20,
230326
+ tags: undefined,
230327
+ author: undefined,
230328
+ format: "table"
230329
+ };
230330
+ const apiClient = await EnactApiClient.create();
230331
+ const searchResults = await apiClient.searchTools(searchOptions);
230332
+ for (const result of searchResults) {
230333
+ if (result.name) {
230334
+ try {
230335
+ const tool = await apiClient.getTool(result.name);
230336
+ if (tool) {
230337
+ const documentForVerification2 = {
230338
+ command: tool.command,
230339
+ description: tool.description,
230340
+ from: tool.from,
230341
+ name: tool.name
230342
+ };
230343
+ const isValid = await EnactCore.checkToolVerificationStatus(tool);
230344
+ const enactTool = {
230345
+ name: tool.name,
230346
+ description: tool.description || "",
230347
+ verified: isValid,
230348
+ command: tool.command,
230349
+ from: tool.from,
230350
+ version: tool.version || "1.0.0",
230351
+ timeout: tool.timeout,
230352
+ tags: tool.tags || [],
230353
+ inputSchema: tool.inputSchema,
230354
+ outputSchema: tool.outputSchema,
230355
+ env: tool.env_vars ? Object.fromEntries(Object.entries(tool.env_vars).map(([key, config2]) => [
230356
+ key,
230357
+ { ...config2, source: config2.source || "env" }
230358
+ ])) : undefined,
230359
+ signature: tool.signature,
230360
+ signatures: Array.isArray(tool.signatures) ? tool.signatures : tool.signatures ? Object.values(tool.signatures) : undefined,
230361
+ namespace: tool.namespace,
230362
+ resources: tool.resources,
230363
+ license: tool.license,
230364
+ authors: tool.authors,
230365
+ examples: tool.examples,
230366
+ annotations: tool.annotations
230367
+ };
230368
+ results.push(enactTool);
230369
+ }
230370
+ } catch (error2) {
230371
+ continue;
230372
+ }
230373
+ }
230374
+ }
230375
+ spinner.stop(`Found ${results.length} tool${results.length === 1 ? "" : "s"}`);
230376
+ if (results.length === 0) {
230377
+ Me("No tools found matching your criteria.", "No Results");
230378
+ Me(`Try:
230379
+ • Broader keywords
230380
+ • Removing filters
230381
+ • Different spelling`, "Suggestions");
230382
+ return;
230383
+ }
230384
+ } catch (error2) {
230385
+ spinner.stop("Search failed");
230386
+ if (error2.message?.includes("ENOTFOUND") || error2.message?.includes("ECONNREFUSED")) {
230387
+ Me("Could not connect to the Enact registry. Check your internet connection.", "Connection Error");
230388
+ } else {
230389
+ Me(error2 instanceof Error ? error2.message : String(error2), "Error");
230390
+ }
230391
+ console.error(import_picocolors13.default.red(`Search failed: ${error2 instanceof Error ? error2.message : String(error2)}`));
230392
+ process.exit(1);
230393
+ }
230394
+ const selected_tool = await ve({
230395
+ message: "Select a tool to sign:",
230396
+ options: results.map((tool) => ({
230397
+ value: tool,
230398
+ label: `${tool.name} - ${tool.description.substring(0, 60)}${tool.description.length > 60 ? "..." : ""} - Verified: ${tool.verified ? import_picocolors13.default.green("Yes") : import_picocolors13.default.red("No")}`
230399
+ }))
230400
+ });
230401
+ const documentForVerification = {
230402
+ command: selected_tool.command,
230403
+ description: selected_tool.description,
230404
+ from: selected_tool.from,
230405
+ name: selected_tool.name
230406
+ };
230407
+ const privateKeys = await KeyManager.getAllPrivateKeys();
230408
+ const privateKey = await ve({
230409
+ message: "Select a private key to sign with:",
230410
+ options: privateKeys.map((key) => ({
230411
+ value: key,
230412
+ label: `${key.fileName}`
230413
+ }))
230414
+ });
230415
+ const TrustedKey = CryptoUtils.getPublicKeyFromPrivate(privateKey.key);
230416
+ if (selected_tool.signatures && selected_tool.signatures.length > 0) {
230417
+ const alreadySigned = selected_tool.signatures.some((sig) => {
230418
+ const referenceSignature = {
230419
+ signature: sig.value,
230420
+ publicKey: "",
230421
+ algorithm: sig.algorithm,
230422
+ timestamp: new Date(sig.created).getTime()
230423
+ };
230424
+ return SigningService.verifyDocumentWithPublicKey(documentForVerification, referenceSignature, TrustedKey, { includeFields: ["command", "description", "from", "name"] });
230425
+ });
230426
+ if (alreadySigned) {
230427
+ console.log(import_picocolors13.default.green("✓ Tool has already been signed with the selected key."));
230428
+ return;
230429
+ }
230430
+ }
230431
+ const spinnerSign = Y2();
230432
+ console.error(spinnerSign.start("Signing tool..."));
230433
+ const signature = await SigningService.signDocument(documentForVerification, privateKey.key, { includeFields: ["command", "description", "from", "name"] });
230434
+ spinnerSign.stop(import_picocolors13.default.green("✓ Tool signed successfully"));
230435
+ console.error(import_picocolors13.default.cyan(`
230436
+ Signature Details:`));
230437
+ console.error(import_picocolors13.default.cyan(` Signature: ${signature.signature}`));
230438
+ console.error(import_picocolors13.default.cyan(` Algorithm: ${signature.algorithm}`));
230439
+ console.error(import_picocolors13.default.cyan(` Created: ${new Date(signature.timestamp).toISOString()}`));
230440
+ console.error(import_picocolors13.default.cyan(` Public Key: ${TrustedKey}`));
230441
+ console.error(import_picocolors13.default.red(`
230442
+ Pushing the signature to the registry is not yet implemented.`));
230443
+ return signature;
230444
+ }
230280
230445
  async function handleCoreExecCommand(args, options) {
230281
230446
  if (options.help) {
230282
230447
  console.error(`
@@ -230518,6 +230683,7 @@ Environment variables:`));
230518
230683
  const enactTool = {
230519
230684
  name: toolDefinition.name,
230520
230685
  description: toolDefinition.description || "",
230686
+ verified: true,
230521
230687
  command: toolDefinition.command,
230522
230688
  from: toolDefinition.from,
230523
230689
  version: toolDefinition.version || "1.0.0",
@@ -230684,9 +230850,11 @@ ${import_picocolors13.default.bold("EXAMPLES:")}
230684
230850
  Se(import_picocolors13.default.red(`Tool not found: ${toolName}`));
230685
230851
  process.exit(1);
230686
230852
  }
230853
+ const isValid = EnactCore.checkToolVerificationStatus(toolDefinition);
230687
230854
  const tool = {
230688
230855
  name: toolDefinition.name,
230689
230856
  description: toolDefinition.description || "",
230857
+ verified: isValid,
230690
230858
  command: toolDefinition.command,
230691
230859
  from: toolDefinition.from,
230692
230860
  version: toolDefinition.version || "1.0.0",
@@ -230725,6 +230893,11 @@ ${import_picocolors13.default.bold(import_picocolors13.default.cyan(`\uD83D\uDCE
230725
230893
  if (tool.command) {
230726
230894
  console.error(`${import_picocolors13.default.bold("Command:")} ${import_picocolors13.default.gray(tool.command)}`);
230727
230895
  }
230896
+ if (tool.verified) {
230897
+ console.error(`${import_picocolors13.default.bold("Verification:")} ${import_picocolors13.default.green("Verified ✓")}`);
230898
+ } else {
230899
+ console.error(`${import_picocolors13.default.bold("Verification:")} ${import_picocolors13.default.red("Unverified ✗")}`);
230900
+ }
230728
230901
  if (tool.from) {
230729
230902
  console.error(`${import_picocolors13.default.bold("Container:")} ${import_picocolors13.default.gray(tool.from)}`);
230730
230903
  }
@@ -230775,20 +230948,25 @@ ${import_picocolors13.default.bold("Examples:")}`);
230775
230948
  function displayResultsTable(results) {
230776
230949
  console.error(`
230777
230950
  ` + import_picocolors13.default.bold("Search Results:"));
230778
- console.error("═".repeat(100));
230779
230951
  const nameWidth = 40;
230952
+ const statusWidth = 15;
230780
230953
  const descWidth = 45;
230781
230954
  const tagsWidth = 20;
230782
- console.error(import_picocolors13.default.bold(import_picocolors13.default.cyan("NAME".padEnd(nameWidth))) + " │ " + import_picocolors13.default.bold(import_picocolors13.default.cyan("DESCRIPTION".padEnd(descWidth))) + " │ " + import_picocolors13.default.bold(import_picocolors13.default.cyan("TAGS".padEnd(tagsWidth))));
230783
- console.error("─".repeat(nameWidth) + "─┼─" + "─".repeat(descWidth) + "─┼─" + "─".repeat(tagsWidth));
230955
+ const totalWidth = nameWidth + statusWidth + descWidth + tagsWidth + 9;
230956
+ console.error(import_picocolors13.default.gray("".repeat(totalWidth)));
230957
+ console.error(import_picocolors13.default.bold(import_picocolors13.default.white("NAME".padEnd(nameWidth))) + import_picocolors13.default.gray(" │ ") + import_picocolors13.default.bold(import_picocolors13.default.white("STATUS".padEnd(statusWidth))) + import_picocolors13.default.gray(" │ ") + import_picocolors13.default.bold(import_picocolors13.default.white("DESCRIPTION".padEnd(descWidth))) + import_picocolors13.default.gray(" │ ") + import_picocolors13.default.bold(import_picocolors13.default.white("TAGS".padEnd(tagsWidth))));
230958
+ console.error(import_picocolors13.default.gray("─".repeat(nameWidth) + "─┼─" + "─".repeat(statusWidth) + "─┼─" + "─".repeat(descWidth) + "─┼─" + "─".repeat(tagsWidth)));
230784
230959
  results.forEach((tool) => {
230785
- const name = tool.name.length > nameWidth ? tool.name.substring(0, nameWidth - 3) + "..." : tool.name.padEnd(nameWidth);
230960
+ const nameText = tool.name.length > nameWidth ? tool.name.substring(0, nameWidth - 3) + "..." : tool.name.padEnd(nameWidth);
230961
+ const statusText = tool.verified ? "✓ Verified" : "✗ Unverified";
230962
+ const statusColor = tool.verified ? import_picocolors13.default.green : import_picocolors13.default.yellow;
230963
+ const status = statusColor(statusText.padEnd(statusWidth));
230786
230964
  const desc = tool.description.length > descWidth ? tool.description.substring(0, descWidth - 3) + "..." : tool.description.padEnd(descWidth);
230787
230965
  const tags = (tool.tags || []).join(", ");
230788
230966
  const tagsDisplay = tags.length > tagsWidth ? tags.substring(0, tagsWidth - 3) + "..." : tags.padEnd(tagsWidth);
230789
- console.error(import_picocolors13.default.green(name) + " │ " + import_picocolors13.default.dim(desc) + " │ " + import_picocolors13.default.yellow(tagsDisplay));
230967
+ console.error(import_picocolors13.default.cyan(nameText) + import_picocolors13.default.gray(" │ ") + status + import_picocolors13.default.gray(" │ ") + import_picocolors13.default.white(desc) + import_picocolors13.default.gray(" │ ") + import_picocolors13.default.magenta(tagsDisplay));
230790
230968
  });
230791
- console.error("═".repeat(100));
230969
+ console.error(import_picocolors13.default.gray("═".repeat(totalWidth)));
230792
230970
  console.error(import_picocolors13.default.dim(`Total: ${results.length} tool${results.length === 1 ? "" : "s"}`));
230793
230971
  }
230794
230972
  function displayResultsList(results) {
@@ -230796,10 +230974,12 @@ function displayResultsList(results) {
230796
230974
  ` + import_picocolors13.default.bold("Search Results:"));
230797
230975
  console.error("");
230798
230976
  results.forEach((tool, index) => {
230799
- console.error(`${import_picocolors13.default.cyan(`${index + 1}.`)} ${import_picocolors13.default.bold(import_picocolors13.default.green(tool.name))}`);
230800
- console.error(` ${import_picocolors13.default.dim(tool.description)}`);
230977
+ const statusIndicator = tool.verified ? import_picocolors13.default.green("✓") : import_picocolors13.default.yellow("✗");
230978
+ const statusText = tool.verified ? import_picocolors13.default.green("verified") : import_picocolors13.default.red("unverified");
230979
+ console.error(`${import_picocolors13.default.cyan(`${index + 1}.`)} ${import_picocolors13.default.cyan(tool.name)} ${statusIndicator} ${import_picocolors13.default.dim(`(${statusText})`)}`);
230980
+ console.error(` ${import_picocolors13.default.white(tool.description)}`);
230801
230981
  if (tool.tags && tool.tags.length > 0) {
230802
- console.error(` ${import_picocolors13.default.yellow("Tags:")} ${tool.tags.join(", ")}`);
230982
+ console.error(` ${import_picocolors13.default.dim("Tags:")} ${import_picocolors13.default.magenta(tool.tags.join(", "))}`);
230803
230983
  }
230804
230984
  console.error("");
230805
230985
  });
@@ -231162,6 +231342,9 @@ var { values, positionals } = parseArgs({
231162
231342
  },
231163
231343
  mount: {
231164
231344
  type: "string"
231345
+ },
231346
+ tool: {
231347
+ type: "string"
231165
231348
  }
231166
231349
  },
231167
231350
  allowPositionals: true,
@@ -231236,6 +231419,12 @@ async function main() {
231236
231419
  mount: values.mount
231237
231420
  });
231238
231421
  break;
231422
+ case "sign":
231423
+ await handleSignToolCommand(commandArgs, {
231424
+ help: values.help,
231425
+ tool: values.tool
231426
+ });
231427
+ break;
231239
231428
  case "get":
231240
231429
  await handleCoreGetCommand(commandArgs, {
231241
231430
  help: values.help,
@@ -231276,6 +231465,7 @@ async function main() {
231276
231465
  { value: "publish", label: "\uD83D\uDCE4 Publish a tool" },
231277
231466
  { value: "init", label: "\uD83D\uDCDD Create a new tool definition" },
231278
231467
  { value: "env", label: "\uD83C\uDF0D Manage environment variables" },
231468
+ { value: "sign", label: "✍️ Sign a tool definition" },
231279
231469
  { value: "config", label: "\uD83D\uDD27 Configure Enact settings" },
231280
231470
  { value: "auth", label: "\uD83D\uDD10 Manage authentication" },
231281
231471
  { value: "remote", label: "\uD83C\uDF10 Manage remote servers" },
@@ -231324,6 +231514,9 @@ async function main() {
231324
231514
  }
231325
231515
  return;
231326
231516
  }
231517
+ if (action === "sign") {
231518
+ await handleSignToolCommand([], {});
231519
+ }
231327
231520
  if (action === "auth") {
231328
231521
  const authAction = await ve({
231329
231522
  message: "Authentication:",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enactprotocol/cli",
3
- "version": "1.2.7",
3
+ "version": "1.2.13",
4
4
  "description": "Official CLI for the Enact Protocol - package, secure, and discover AI tools",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -42,7 +42,7 @@
42
42
  "node": ">=18.0.0"
43
43
  },
44
44
  "dependencies": {
45
- "@enactprotocol/shared": "1.2.7",
45
+ "@enactprotocol/shared": "1.2.13",
46
46
  "@clack/core": "^0.4.2",
47
47
  "@clack/prompts": "^0.10.1",
48
48
  "picocolors": "^1.1.1"