@enactprotocol/cli 1.2.8 → 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",
@@ -229706,6 +229713,33 @@ class EnactCore {
229706
229713
  };
229707
229714
  }
229708
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
+ }
229709
229743
  async verifyTool(tool, dangerouslySkipVerification = false) {
229710
229744
  if (dangerouslySkipVerification) {
229711
229745
  logger_default.warn(`Skipping signature verification for tool: ${tool.name}`);
@@ -229715,23 +229749,8 @@ class EnactCore {
229715
229749
  if (!tool.signatures || tool.signatures.length === 0) {
229716
229750
  throw new Error(`Tool ${tool.name} does not have any signatures`);
229717
229751
  }
229718
- const documentForVerification = {
229719
- command: tool.command,
229720
- description: tool.description,
229721
- from: tool.from,
229722
- name: tool.name
229723
- };
229724
- const referenceSignature = {
229725
- signature: tool.signatures[0].value,
229726
- publicKey: "",
229727
- algorithm: tool.signatures[0].algorithm,
229728
- timestamp: new Date(tool.signatures[0].created).getTime()
229729
- };
229730
- const canonicalDoc = SigningService.getCanonicalDocument(documentForVerification, { includeFields: ["command", "description", "from", "name"] });
229731
- const docString = JSON.stringify(canonicalDoc);
229732
- const messageHash = CryptoUtils.hash(docString);
229733
- const directVerify = CryptoUtils.verify(referenceSignature.publicKey, messageHash, referenceSignature.signature);
229734
- 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);
229735
229754
  if (!isValid) {
229736
229755
  throw new Error(`Tool ${tool.name} has invalid signatures`);
229737
229756
  }
@@ -230085,9 +230104,11 @@ ${import_picocolors13.default.bold("EXAMPLES:")}
230085
230104
  try {
230086
230105
  const tool = await apiClient.getTool(result.name);
230087
230106
  if (tool) {
230107
+ const isValid = await EnactCore.checkToolVerificationStatus(tool);
230088
230108
  const enactTool = {
230089
230109
  name: tool.name,
230090
230110
  description: tool.description || "",
230111
+ verified: isValid,
230091
230112
  command: tool.command,
230092
230113
  from: tool.from,
230093
230114
  version: tool.version || "1.0.0",
@@ -230269,6 +230290,159 @@ async function collectParametersInteractively(inputSchema) {
230269
230290
  }
230270
230291
  return params;
230271
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
+ }
230272
230446
  async function handleCoreExecCommand(args, options) {
230273
230447
  if (options.help) {
230274
230448
  console.error(`
@@ -230510,6 +230684,7 @@ Environment variables:`));
230510
230684
  const enactTool = {
230511
230685
  name: toolDefinition.name,
230512
230686
  description: toolDefinition.description || "",
230687
+ verified: true,
230513
230688
  command: toolDefinition.command,
230514
230689
  from: toolDefinition.from,
230515
230690
  version: toolDefinition.version || "1.0.0",
@@ -230676,9 +230851,11 @@ ${import_picocolors13.default.bold("EXAMPLES:")}
230676
230851
  Se(import_picocolors13.default.red(`Tool not found: ${toolName}`));
230677
230852
  process.exit(1);
230678
230853
  }
230854
+ const isValid = EnactCore.checkToolVerificationStatus(toolDefinition);
230679
230855
  const tool = {
230680
230856
  name: toolDefinition.name,
230681
230857
  description: toolDefinition.description || "",
230858
+ verified: isValid,
230682
230859
  command: toolDefinition.command,
230683
230860
  from: toolDefinition.from,
230684
230861
  version: toolDefinition.version || "1.0.0",
@@ -230717,6 +230894,11 @@ ${import_picocolors13.default.bold(import_picocolors13.default.cyan(`\uD83D\uDCE
230717
230894
  if (tool.command) {
230718
230895
  console.error(`${import_picocolors13.default.bold("Command:")} ${import_picocolors13.default.gray(tool.command)}`);
230719
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
+ }
230720
230902
  if (tool.from) {
230721
230903
  console.error(`${import_picocolors13.default.bold("Container:")} ${import_picocolors13.default.gray(tool.from)}`);
230722
230904
  }
@@ -230767,20 +230949,25 @@ ${import_picocolors13.default.bold("Examples:")}`);
230767
230949
  function displayResultsTable(results) {
230768
230950
  console.error(`
230769
230951
  ` + import_picocolors13.default.bold("Search Results:"));
230770
- console.error("═".repeat(100));
230771
230952
  const nameWidth = 40;
230953
+ const statusWidth = 15;
230772
230954
  const descWidth = 45;
230773
230955
  const tagsWidth = 20;
230774
- 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))));
230775
- 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)));
230776
230960
  results.forEach((tool) => {
230777
- 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));
230778
230965
  const desc = tool.description.length > descWidth ? tool.description.substring(0, descWidth - 3) + "..." : tool.description.padEnd(descWidth);
230779
230966
  const tags = (tool.tags || []).join(", ");
230780
230967
  const tagsDisplay = tags.length > tagsWidth ? tags.substring(0, tagsWidth - 3) + "..." : tags.padEnd(tagsWidth);
230781
- 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));
230782
230969
  });
230783
- console.error("═".repeat(100));
230970
+ console.error(import_picocolors13.default.gray("═".repeat(totalWidth)));
230784
230971
  console.error(import_picocolors13.default.dim(`Total: ${results.length} tool${results.length === 1 ? "" : "s"}`));
230785
230972
  }
230786
230973
  function displayResultsList(results) {
@@ -230788,10 +230975,12 @@ function displayResultsList(results) {
230788
230975
  ` + import_picocolors13.default.bold("Search Results:"));
230789
230976
  console.error("");
230790
230977
  results.forEach((tool, index) => {
230791
- console.error(`${import_picocolors13.default.cyan(`${index + 1}.`)} ${import_picocolors13.default.bold(import_picocolors13.default.green(tool.name))}`);
230792
- 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)}`);
230793
230982
  if (tool.tags && tool.tags.length > 0) {
230794
- 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(", "))}`);
230795
230984
  }
230796
230985
  console.error("");
230797
230986
  });
@@ -231154,6 +231343,9 @@ var { values, positionals } = parseArgs({
231154
231343
  },
231155
231344
  mount: {
231156
231345
  type: "string"
231346
+ },
231347
+ tool: {
231348
+ type: "string"
231157
231349
  }
231158
231350
  },
231159
231351
  allowPositionals: true,
@@ -231228,6 +231420,12 @@ async function main() {
231228
231420
  mount: values.mount
231229
231421
  });
231230
231422
  break;
231423
+ case "sign":
231424
+ await handleSignToolCommand(commandArgs, {
231425
+ help: values.help,
231426
+ tool: values.tool
231427
+ });
231428
+ break;
231231
231429
  case "get":
231232
231430
  await handleCoreGetCommand(commandArgs, {
231233
231431
  help: values.help,
@@ -231268,6 +231466,7 @@ async function main() {
231268
231466
  { value: "publish", label: "\uD83D\uDCE4 Publish a tool" },
231269
231467
  { value: "init", label: "\uD83D\uDCDD Create a new tool definition" },
231270
231468
  { value: "env", label: "\uD83C\uDF0D Manage environment variables" },
231469
+ { value: "sign", label: "✍️ Sign a tool definition" },
231271
231470
  { value: "config", label: "\uD83D\uDD27 Configure Enact settings" },
231272
231471
  { value: "auth", label: "\uD83D\uDD10 Manage authentication" },
231273
231472
  { value: "remote", label: "\uD83C\uDF10 Manage remote servers" },
@@ -231316,6 +231515,9 @@ async function main() {
231316
231515
  }
231317
231516
  return;
231318
231517
  }
231518
+ if (action === "sign") {
231519
+ await handleSignToolCommand([], {});
231520
+ }
231319
231521
  if (action === "auth") {
231320
231522
  const authAction = await ve({
231321
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",
@@ -229705,6 +229712,33 @@ class EnactCore {
229705
229712
  };
229706
229713
  }
229707
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
+ }
229708
229742
  async verifyTool(tool, dangerouslySkipVerification = false) {
229709
229743
  if (dangerouslySkipVerification) {
229710
229744
  logger_default.warn(`Skipping signature verification for tool: ${tool.name}`);
@@ -229714,23 +229748,8 @@ class EnactCore {
229714
229748
  if (!tool.signatures || tool.signatures.length === 0) {
229715
229749
  throw new Error(`Tool ${tool.name} does not have any signatures`);
229716
229750
  }
229717
- const documentForVerification = {
229718
- command: tool.command,
229719
- description: tool.description,
229720
- from: tool.from,
229721
- name: tool.name
229722
- };
229723
- const referenceSignature = {
229724
- signature: tool.signatures[0].value,
229725
- publicKey: "",
229726
- algorithm: tool.signatures[0].algorithm,
229727
- timestamp: new Date(tool.signatures[0].created).getTime()
229728
- };
229729
- const canonicalDoc = SigningService.getCanonicalDocument(documentForVerification, { includeFields: ["command", "description", "from", "name"] });
229730
- const docString = JSON.stringify(canonicalDoc);
229731
- const messageHash = CryptoUtils.hash(docString);
229732
- const directVerify = CryptoUtils.verify(referenceSignature.publicKey, messageHash, referenceSignature.signature);
229733
- 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);
229734
229753
  if (!isValid) {
229735
229754
  throw new Error(`Tool ${tool.name} has invalid signatures`);
229736
229755
  }
@@ -230084,9 +230103,11 @@ ${import_picocolors13.default.bold("EXAMPLES:")}
230084
230103
  try {
230085
230104
  const tool = await apiClient.getTool(result.name);
230086
230105
  if (tool) {
230106
+ const isValid = await EnactCore.checkToolVerificationStatus(tool);
230087
230107
  const enactTool = {
230088
230108
  name: tool.name,
230089
230109
  description: tool.description || "",
230110
+ verified: isValid,
230090
230111
  command: tool.command,
230091
230112
  from: tool.from,
230092
230113
  version: tool.version || "1.0.0",
@@ -230268,6 +230289,159 @@ async function collectParametersInteractively(inputSchema) {
230268
230289
  }
230269
230290
  return params;
230270
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
+ }
230271
230445
  async function handleCoreExecCommand(args, options) {
230272
230446
  if (options.help) {
230273
230447
  console.error(`
@@ -230509,6 +230683,7 @@ Environment variables:`));
230509
230683
  const enactTool = {
230510
230684
  name: toolDefinition.name,
230511
230685
  description: toolDefinition.description || "",
230686
+ verified: true,
230512
230687
  command: toolDefinition.command,
230513
230688
  from: toolDefinition.from,
230514
230689
  version: toolDefinition.version || "1.0.0",
@@ -230675,9 +230850,11 @@ ${import_picocolors13.default.bold("EXAMPLES:")}
230675
230850
  Se(import_picocolors13.default.red(`Tool not found: ${toolName}`));
230676
230851
  process.exit(1);
230677
230852
  }
230853
+ const isValid = EnactCore.checkToolVerificationStatus(toolDefinition);
230678
230854
  const tool = {
230679
230855
  name: toolDefinition.name,
230680
230856
  description: toolDefinition.description || "",
230857
+ verified: isValid,
230681
230858
  command: toolDefinition.command,
230682
230859
  from: toolDefinition.from,
230683
230860
  version: toolDefinition.version || "1.0.0",
@@ -230716,6 +230893,11 @@ ${import_picocolors13.default.bold(import_picocolors13.default.cyan(`\uD83D\uDCE
230716
230893
  if (tool.command) {
230717
230894
  console.error(`${import_picocolors13.default.bold("Command:")} ${import_picocolors13.default.gray(tool.command)}`);
230718
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
+ }
230719
230901
  if (tool.from) {
230720
230902
  console.error(`${import_picocolors13.default.bold("Container:")} ${import_picocolors13.default.gray(tool.from)}`);
230721
230903
  }
@@ -230766,20 +230948,25 @@ ${import_picocolors13.default.bold("Examples:")}`);
230766
230948
  function displayResultsTable(results) {
230767
230949
  console.error(`
230768
230950
  ` + import_picocolors13.default.bold("Search Results:"));
230769
- console.error("═".repeat(100));
230770
230951
  const nameWidth = 40;
230952
+ const statusWidth = 15;
230771
230953
  const descWidth = 45;
230772
230954
  const tagsWidth = 20;
230773
- 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))));
230774
- 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)));
230775
230959
  results.forEach((tool) => {
230776
- 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));
230777
230964
  const desc = tool.description.length > descWidth ? tool.description.substring(0, descWidth - 3) + "..." : tool.description.padEnd(descWidth);
230778
230965
  const tags = (tool.tags || []).join(", ");
230779
230966
  const tagsDisplay = tags.length > tagsWidth ? tags.substring(0, tagsWidth - 3) + "..." : tags.padEnd(tagsWidth);
230780
- 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));
230781
230968
  });
230782
- console.error("═".repeat(100));
230969
+ console.error(import_picocolors13.default.gray("═".repeat(totalWidth)));
230783
230970
  console.error(import_picocolors13.default.dim(`Total: ${results.length} tool${results.length === 1 ? "" : "s"}`));
230784
230971
  }
230785
230972
  function displayResultsList(results) {
@@ -230787,10 +230974,12 @@ function displayResultsList(results) {
230787
230974
  ` + import_picocolors13.default.bold("Search Results:"));
230788
230975
  console.error("");
230789
230976
  results.forEach((tool, index) => {
230790
- console.error(`${import_picocolors13.default.cyan(`${index + 1}.`)} ${import_picocolors13.default.bold(import_picocolors13.default.green(tool.name))}`);
230791
- 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)}`);
230792
230981
  if (tool.tags && tool.tags.length > 0) {
230793
- 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(", "))}`);
230794
230983
  }
230795
230984
  console.error("");
230796
230985
  });
@@ -231153,6 +231342,9 @@ var { values, positionals } = parseArgs({
231153
231342
  },
231154
231343
  mount: {
231155
231344
  type: "string"
231345
+ },
231346
+ tool: {
231347
+ type: "string"
231156
231348
  }
231157
231349
  },
231158
231350
  allowPositionals: true,
@@ -231227,6 +231419,12 @@ async function main() {
231227
231419
  mount: values.mount
231228
231420
  });
231229
231421
  break;
231422
+ case "sign":
231423
+ await handleSignToolCommand(commandArgs, {
231424
+ help: values.help,
231425
+ tool: values.tool
231426
+ });
231427
+ break;
231230
231428
  case "get":
231231
231429
  await handleCoreGetCommand(commandArgs, {
231232
231430
  help: values.help,
@@ -231267,6 +231465,7 @@ async function main() {
231267
231465
  { value: "publish", label: "\uD83D\uDCE4 Publish a tool" },
231268
231466
  { value: "init", label: "\uD83D\uDCDD Create a new tool definition" },
231269
231467
  { value: "env", label: "\uD83C\uDF0D Manage environment variables" },
231468
+ { value: "sign", label: "✍️ Sign a tool definition" },
231270
231469
  { value: "config", label: "\uD83D\uDD27 Configure Enact settings" },
231271
231470
  { value: "auth", label: "\uD83D\uDD10 Manage authentication" },
231272
231471
  { value: "remote", label: "\uD83C\uDF10 Manage remote servers" },
@@ -231315,6 +231514,9 @@ async function main() {
231315
231514
  }
231316
231515
  return;
231317
231516
  }
231517
+ if (action === "sign") {
231518
+ await handleSignToolCommand([], {});
231519
+ }
231318
231520
  if (action === "auth") {
231319
231521
  const authAction = await ve({
231320
231522
  message: "Authentication:",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@enactprotocol/cli",
3
- "version": "1.2.8",
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.8",
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"