enact-cli 1.0.9 → 1.0.10

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
@@ -11104,7 +11104,7 @@ async function installMcpServer(client) {
11104
11104
  config2.extensions.enact = {
11105
11105
  name: "Enact Tools",
11106
11106
  cmd: "npx",
11107
- args: ["-y", "enact-cli", "mcp"],
11107
+ args: ["-y", "enact-cli", "enact-mcp"],
11108
11108
  enabled: true,
11109
11109
  type: "stdio",
11110
11110
  timeout: 300
@@ -11131,12 +11131,7 @@ async function installMcpServer(client) {
11131
11131
  }
11132
11132
  }
11133
11133
  const mcpServerConfig = {
11134
- command: "npx",
11135
- args: [
11136
- "-y",
11137
- "enact-cli",
11138
- "mcp"
11139
- ]
11134
+ command: "enact-mcp"
11140
11135
  };
11141
11136
  if (client.id === "claude-desktop" || client.id === "claude-code") {
11142
11137
  if (!config.mcpServers) {
@@ -11567,8 +11562,29 @@ class DirectExecutionProvider extends ExecutionProvider {
11567
11562
  try {
11568
11563
  const proc = spawn(cmd, args, {
11569
11564
  env,
11570
- stdio: ["pipe", "pipe", "pipe"]
11565
+ stdio: ["pipe", "pipe", "pipe"],
11566
+ detached: process.platform !== "win32"
11571
11567
  });
11568
+ const cleanup = () => {
11569
+ if (proc && !proc.killed) {
11570
+ try {
11571
+ console.log(`[DEBUG] Cleaning up process PID: ${proc.pid}`);
11572
+ if (process.platform === "win32") {
11573
+ proc.kill("SIGKILL");
11574
+ } else {
11575
+ process.kill(-proc.pid, "SIGTERM");
11576
+ setTimeout(() => {
11577
+ if (!proc.killed) {
11578
+ console.log(`[DEBUG] Force killing process PID: ${proc.pid}`);
11579
+ process.kill(-proc.pid, "SIGKILL");
11580
+ }
11581
+ }, 2000);
11582
+ }
11583
+ } catch (killError) {
11584
+ logger_default.debug(`Process cleanup error (likely harmless): ${killError}`);
11585
+ }
11586
+ }
11587
+ };
11572
11588
  proc.stdout.on("data", (data) => {
11573
11589
  const chunk = data.toString();
11574
11590
  stdout += chunk;
@@ -11580,6 +11596,8 @@ class DirectExecutionProvider extends ExecutionProvider {
11580
11596
  process.stderr.write(chunk);
11581
11597
  });
11582
11598
  proc.on("close", (code) => {
11599
+ console.log(`[DEBUG] Process closed with code: ${code}, PID: ${proc.pid}`);
11600
+ cleanup();
11583
11601
  resolve({
11584
11602
  stdout: stdout.trim(),
11585
11603
  stderr: stderr.trim(),
@@ -11587,12 +11605,13 @@ class DirectExecutionProvider extends ExecutionProvider {
11587
11605
  });
11588
11606
  });
11589
11607
  proc.on("error", (error) => {
11608
+ cleanup();
11590
11609
  reject(new Error(`Command execution error: ${error.message}`));
11591
11610
  });
11592
11611
  if (timeout) {
11593
11612
  const timeoutMs = this.parseTimeout(timeout);
11594
11613
  setTimeout(() => {
11595
- proc.kill("SIGTERM");
11614
+ cleanup();
11596
11615
  reject(new Error(`Command timed out after ${timeout}`));
11597
11616
  }, timeoutMs);
11598
11617
  }
package/dist/index.js.bak CHANGED
@@ -11103,7 +11103,7 @@ async function installMcpServer(client) {
11103
11103
  config2.extensions.enact = {
11104
11104
  name: "Enact Tools",
11105
11105
  cmd: "npx",
11106
- args: ["-y", "enact-cli", "mcp"],
11106
+ args: ["-y", "enact-cli", "enact-mcp"],
11107
11107
  enabled: true,
11108
11108
  type: "stdio",
11109
11109
  timeout: 300
@@ -11130,12 +11130,7 @@ async function installMcpServer(client) {
11130
11130
  }
11131
11131
  }
11132
11132
  const mcpServerConfig = {
11133
- command: "npx",
11134
- args: [
11135
- "-y",
11136
- "enact-cli",
11137
- "mcp"
11138
- ]
11133
+ command: "enact-mcp"
11139
11134
  };
11140
11135
  if (client.id === "claude-desktop" || client.id === "claude-code") {
11141
11136
  if (!config.mcpServers) {
@@ -11566,8 +11561,29 @@ class DirectExecutionProvider extends ExecutionProvider {
11566
11561
  try {
11567
11562
  const proc = spawn(cmd, args, {
11568
11563
  env,
11569
- stdio: ["pipe", "pipe", "pipe"]
11564
+ stdio: ["pipe", "pipe", "pipe"],
11565
+ detached: process.platform !== "win32"
11570
11566
  });
11567
+ const cleanup = () => {
11568
+ if (proc && !proc.killed) {
11569
+ try {
11570
+ console.log(`[DEBUG] Cleaning up process PID: ${proc.pid}`);
11571
+ if (process.platform === "win32") {
11572
+ proc.kill("SIGKILL");
11573
+ } else {
11574
+ process.kill(-proc.pid, "SIGTERM");
11575
+ setTimeout(() => {
11576
+ if (!proc.killed) {
11577
+ console.log(`[DEBUG] Force killing process PID: ${proc.pid}`);
11578
+ process.kill(-proc.pid, "SIGKILL");
11579
+ }
11580
+ }, 2000);
11581
+ }
11582
+ } catch (killError) {
11583
+ logger_default.debug(`Process cleanup error (likely harmless): ${killError}`);
11584
+ }
11585
+ }
11586
+ };
11571
11587
  proc.stdout.on("data", (data) => {
11572
11588
  const chunk = data.toString();
11573
11589
  stdout += chunk;
@@ -11579,6 +11595,8 @@ class DirectExecutionProvider extends ExecutionProvider {
11579
11595
  process.stderr.write(chunk);
11580
11596
  });
11581
11597
  proc.on("close", (code) => {
11598
+ console.log(`[DEBUG] Process closed with code: ${code}, PID: ${proc.pid}`);
11599
+ cleanup();
11582
11600
  resolve({
11583
11601
  stdout: stdout.trim(),
11584
11602
  stderr: stderr.trim(),
@@ -11586,12 +11604,13 @@ class DirectExecutionProvider extends ExecutionProvider {
11586
11604
  });
11587
11605
  });
11588
11606
  proc.on("error", (error) => {
11607
+ cleanup();
11589
11608
  reject(new Error(`Command execution error: ${error.message}`));
11590
11609
  });
11591
11610
  if (timeout) {
11592
11611
  const timeoutMs = this.parseTimeout(timeout);
11593
11612
  setTimeout(() => {
11594
- proc.kill("SIGTERM");
11613
+ cleanup();
11595
11614
  reject(new Error(`Command timed out after ${timeout}`));
11596
11615
  }, timeoutMs);
11597
11616
  }
@@ -21044,8 +21044,29 @@ class DirectExecutionProvider extends ExecutionProvider {
21044
21044
  try {
21045
21045
  const proc = spawn(cmd, args, {
21046
21046
  env,
21047
- stdio: ["pipe", "pipe", "pipe"]
21047
+ stdio: ["pipe", "pipe", "pipe"],
21048
+ detached: process.platform !== "win32"
21048
21049
  });
21050
+ const cleanup = () => {
21051
+ if (proc && !proc.killed) {
21052
+ try {
21053
+ console.log(`[DEBUG] Cleaning up process PID: ${proc.pid}`);
21054
+ if (process.platform === "win32") {
21055
+ proc.kill("SIGKILL");
21056
+ } else {
21057
+ process.kill(-proc.pid, "SIGTERM");
21058
+ setTimeout(() => {
21059
+ if (!proc.killed) {
21060
+ console.log(`[DEBUG] Force killing process PID: ${proc.pid}`);
21061
+ process.kill(-proc.pid, "SIGKILL");
21062
+ }
21063
+ }, 2000);
21064
+ }
21065
+ } catch (killError) {
21066
+ logger_default.debug(`Process cleanup error (likely harmless): ${killError}`);
21067
+ }
21068
+ }
21069
+ };
21049
21070
  proc.stdout.on("data", (data) => {
21050
21071
  const chunk = data.toString();
21051
21072
  stdout += chunk;
@@ -21057,6 +21078,8 @@ class DirectExecutionProvider extends ExecutionProvider {
21057
21078
  process.stderr.write(chunk);
21058
21079
  });
21059
21080
  proc.on("close", (code) => {
21081
+ console.log(`[DEBUG] Process closed with code: ${code}, PID: ${proc.pid}`);
21082
+ cleanup();
21060
21083
  resolve({
21061
21084
  stdout: stdout.trim(),
21062
21085
  stderr: stderr.trim(),
@@ -21064,12 +21087,13 @@ class DirectExecutionProvider extends ExecutionProvider {
21064
21087
  });
21065
21088
  });
21066
21089
  proc.on("error", (error) => {
21090
+ cleanup();
21067
21091
  reject(new Error(`Command execution error: ${error.message}`));
21068
21092
  });
21069
21093
  if (timeout) {
21070
21094
  const timeoutMs = this.parseTimeout(timeout);
21071
21095
  setTimeout(() => {
21072
- proc.kill("SIGTERM");
21096
+ cleanup();
21073
21097
  reject(new Error(`Command timed out after ${timeout}`));
21074
21098
  }, timeoutMs);
21075
21099
  }
@@ -21875,7 +21899,8 @@ var enactCore2 = new EnactCore({
21875
21899
  supabaseUrl: process.env.ENACT_SUPABASE_URL || "https://xjnhhxwxovjifdxdwzih.supabase.co",
21876
21900
  executionProvider: "direct",
21877
21901
  verificationPolicy: process.env.ENACT_VERIFY_POLICY || "permissive",
21878
- authToken: process.env.ENACT_AUTH_TOKEN
21902
+ authToken: process.env.ENACT_AUTH_TOKEN,
21903
+ defaultTimeout: "120s"
21879
21904
  });
21880
21905
  var server = new McpServer({
21881
21906
  name: "enact-mcp-server",
@@ -21887,6 +21912,7 @@ var server = new McpServer({
21887
21912
  }
21888
21913
  }
21889
21914
  });
21915
+ var runningOperations = new Map;
21890
21916
  function safeJsonStringify(obj, fallback = "Unable to stringify object") {
21891
21917
  try {
21892
21918
  return JSON.stringify(obj, null, 2);
@@ -21895,6 +21921,266 @@ function safeJsonStringify(obj, fallback = "Unable to stringify object") {
21895
21921
  return fallback;
21896
21922
  }
21897
21923
  }
21924
+ server.registerTool("execute-tool-by-name-async", {
21925
+ title: "Execute Enact Tool (Async)",
21926
+ description: "Execute an Enact tool by its name using direct core integration with background execution for long-running operations",
21927
+ inputSchema: {
21928
+ name: exports_external.string().describe("Name of the tool to execute"),
21929
+ inputs: exports_external.record(exports_external.any()).optional().describe("Input parameters for the tool"),
21930
+ timeout: exports_external.string().optional().describe("Execution timeout"),
21931
+ verifyPolicy: exports_external.enum(["permissive", "enterprise", "paranoid"]).optional().describe("Verification policy"),
21932
+ skipVerification: exports_external.boolean().optional().describe("Skip signature verification"),
21933
+ force: exports_external.boolean().optional().describe("Force execution"),
21934
+ dryRun: exports_external.boolean().optional().describe("Dry run mode"),
21935
+ verbose: exports_external.boolean().optional().describe("Verbose output"),
21936
+ async: exports_external.boolean().optional().describe("Run in background for long operations")
21937
+ }
21938
+ }, async (params) => {
21939
+ const { name, inputs = {}, timeout, verifyPolicy, skipVerification, force, dryRun, verbose, async = false } = params;
21940
+ try {
21941
+ logger_default.info(`Executing tool ${name} via direct core library`);
21942
+ const isLongRunningTool = name.includes("dagger") || name.includes("docker") || name.includes("build") || async;
21943
+ if (isLongRunningTool) {
21944
+ const operationId = `${name}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
21945
+ const executionPromise = enactCore2.executeToolByName(name, inputs, {
21946
+ timeout: timeout || "300s",
21947
+ verifyPolicy,
21948
+ skipVerification,
21949
+ force,
21950
+ dryRun,
21951
+ verbose
21952
+ });
21953
+ const operation = {
21954
+ id: operationId,
21955
+ name,
21956
+ startTime: new Date,
21957
+ promise: executionPromise,
21958
+ status: "running",
21959
+ result: undefined,
21960
+ error: undefined
21961
+ };
21962
+ runningOperations.set(operationId, operation);
21963
+ executionPromise.then((result2) => {
21964
+ operation.status = "completed";
21965
+ operation.result = result2;
21966
+ logger_default.info(`Background operation completed: ${operationId}`);
21967
+ }).catch((error) => {
21968
+ operation.status = "failed";
21969
+ operation.error = error;
21970
+ logger_default.error(`Background operation failed: ${operationId}`, error);
21971
+ });
21972
+ return {
21973
+ content: [{
21974
+ type: "text",
21975
+ text: `\uD83D\uDE80 Started background execution of tool: ${name}
21976
+
21977
+ Operation ID: ${operationId}
21978
+ Started: ${operation.startTime.toISOString()}
21979
+
21980
+ ⏳ This operation is running in the background. Use the "check-operation-status" tool with operation ID "${operationId}" to check progress.
21981
+
21982
+ Estimated completion time: 1-3 minutes for Dagger operations.`
21983
+ }]
21984
+ };
21985
+ }
21986
+ const result = await enactCore2.executeToolByName(name, inputs, {
21987
+ timeout: timeout || "30s",
21988
+ verifyPolicy,
21989
+ skipVerification,
21990
+ force,
21991
+ dryRun,
21992
+ verbose
21993
+ });
21994
+ if (!result.success) {
21995
+ return {
21996
+ content: [{
21997
+ type: "text",
21998
+ text: `❌ Error executing tool ${name}: ${result.error?.message}`
21999
+ }],
22000
+ isError: true
22001
+ };
22002
+ }
22003
+ return {
22004
+ content: [{
22005
+ type: "text",
22006
+ text: `✅ Successfully executed tool ${name}
22007
+ Output: ${safeJsonStringify(result)}`
22008
+ }]
22009
+ };
22010
+ } catch (error) {
22011
+ logger_default.error(`Error executing tool:`, error);
22012
+ if (error instanceof Error && error.message.includes("timed out")) {
22013
+ return {
22014
+ content: [{
22015
+ type: "text",
22016
+ text: `⏰ Tool execution timed out: ${name}
22017
+
22018
+ For long-running operations like Dagger builds, try using the async mode by setting "async": true in your request.
22019
+
22020
+ Original error: ${error.message}`
22021
+ }],
22022
+ isError: true
22023
+ };
22024
+ }
22025
+ return {
22026
+ content: [{
22027
+ type: "text",
22028
+ text: `Internal error executing tool: ${error instanceof Error ? error.message : String(error)}`
22029
+ }],
22030
+ isError: true
22031
+ };
22032
+ }
22033
+ });
22034
+ server.registerTool("check-operation-status", {
22035
+ title: "Check Operation Status",
22036
+ description: "Check the status of a background operation",
22037
+ inputSchema: {
22038
+ operationId: exports_external.string().describe("The operation ID to check")
22039
+ }
22040
+ }, async ({ operationId }) => {
22041
+ try {
22042
+ const operation = runningOperations.get(operationId);
22043
+ if (!operation) {
22044
+ return {
22045
+ content: [{
22046
+ type: "text",
22047
+ text: `❌ Operation not found: ${operationId}
22048
+
22049
+ The operation may have been completed and cleaned up, or the ID is incorrect.`
22050
+ }],
22051
+ isError: true
22052
+ };
22053
+ }
22054
+ const duration = Math.round((Date.now() - operation.startTime.getTime()) / 1000);
22055
+ switch (operation.status) {
22056
+ case "running":
22057
+ return {
22058
+ content: [{
22059
+ type: "text",
22060
+ text: `⏳ Operation Status: RUNNING
22061
+
22062
+ Operation ID: ${operationId}
22063
+ Tool: ${operation.name}
22064
+ Started: ${operation.startTime.toISOString()}
22065
+ Duration: ${duration} seconds
22066
+
22067
+ The operation is still running. Please check again in a moment.`
22068
+ }]
22069
+ };
22070
+ case "completed":
22071
+ if (!operation.resultFetched) {
22072
+ operation.resultFetched = true;
22073
+ setTimeout(() => {
22074
+ console.log(`[INFO] Cleaning up completed operation: ${operationId}`);
22075
+ runningOperations.delete(operationId);
22076
+ }, 60000);
22077
+ }
22078
+ return {
22079
+ content: [{
22080
+ type: "text",
22081
+ text: `✅ Operation Status: COMPLETED
22082
+
22083
+ Operation ID: ${operationId}
22084
+ Tool: ${operation.name}
22085
+ Started: ${operation.startTime.toISOString()}
22086
+ Duration: ${duration} seconds
22087
+
22088
+ Result:
22089
+ ${safeJsonStringify(operation.result)}`
22090
+ }]
22091
+ };
22092
+ case "failed":
22093
+ if (!operation.errorFetched) {
22094
+ operation.errorFetched = true;
22095
+ setTimeout(() => {
22096
+ console.log(`[INFO] Cleaning up failed operation: ${operationId}`);
22097
+ runningOperations.delete(operationId);
22098
+ }, 60000);
22099
+ }
22100
+ return {
22101
+ content: [{
22102
+ type: "text",
22103
+ text: `❌ Operation Status: FAILED
22104
+
22105
+ Operation ID: ${operationId}
22106
+ Tool: ${operation.name}
22107
+ Started: ${operation.startTime.toISOString()}
22108
+ Duration: ${duration} seconds
22109
+
22110
+ Error: ${operation.error instanceof Error ? operation.error.message : String(operation.error)}`
22111
+ }],
22112
+ isError: true
22113
+ };
22114
+ default:
22115
+ return {
22116
+ content: [{
22117
+ type: "text",
22118
+ text: `❓ Unknown operation status: ${operation.status}`
22119
+ }],
22120
+ isError: true
22121
+ };
22122
+ }
22123
+ } catch (error) {
22124
+ logger_default.error(`Error checking operation status:`, error);
22125
+ return {
22126
+ content: [{
22127
+ type: "text",
22128
+ text: `Error checking operation status: ${error instanceof Error ? error.message : String(error)}`
22129
+ }],
22130
+ isError: true
22131
+ };
22132
+ }
22133
+ });
22134
+ server.registerTool("list-operations", {
22135
+ title: "List Operations",
22136
+ description: "List all background operations",
22137
+ inputSchema: {}
22138
+ }, async () => {
22139
+ try {
22140
+ const operations = Array.from(runningOperations.values());
22141
+ if (operations.length === 0) {
22142
+ return {
22143
+ content: [{
22144
+ type: "text",
22145
+ text: `\uD83D\uDCCB No background operations currently running or recently completed.`
22146
+ }]
22147
+ };
22148
+ }
22149
+ let summary = `\uD83D\uDCCB Background Operations (${operations.length} total)
22150
+
22151
+ `;
22152
+ operations.forEach((op) => {
22153
+ const duration = Math.round((Date.now() - op.startTime.getTime()) / 1000);
22154
+ const statusEmoji = op.status === "running" ? "⏳" : op.status === "completed" ? "✅" : "❌";
22155
+ summary += `${statusEmoji} ${op.id}
22156
+ `;
22157
+ summary += ` Tool: ${op.name}
22158
+ `;
22159
+ summary += ` Status: ${op.status.toUpperCase()}
22160
+ `;
22161
+ summary += ` Duration: ${duration}s
22162
+ `;
22163
+ summary += ` Started: ${op.startTime.toISOString()}
22164
+
22165
+ `;
22166
+ });
22167
+ return {
22168
+ content: [{
22169
+ type: "text",
22170
+ text: summary
22171
+ }]
22172
+ };
22173
+ } catch (error) {
22174
+ logger_default.error(`Error listing operations:`, error);
22175
+ return {
22176
+ content: [{
22177
+ type: "text",
22178
+ text: `Error listing operations: ${error instanceof Error ? error.message : String(error)}`
22179
+ }],
22180
+ isError: true
22181
+ };
22182
+ }
22183
+ });
21898
22184
  server.registerTool("execute-tool-by-name", {
21899
22185
  title: "Execute Enact Tool",
21900
22186
  description: "Execute an Enact tool by its name using direct core integration",
@@ -21912,8 +22198,12 @@ server.registerTool("execute-tool-by-name", {
21912
22198
  const { name, inputs = {}, timeout, verifyPolicy, skipVerification, force, dryRun, verbose } = params;
21913
22199
  try {
21914
22200
  logger_default.info(`Executing tool ${name} via direct core library`);
22201
+ const isLongRunningTool = name.includes("dagger") || name.includes("docker") || name.includes("build");
22202
+ if (isLongRunningTool) {
22203
+ logger_default.info(`⏳ Starting long-running operation: ${name} (this may take 1-2 minutes)`);
22204
+ }
21915
22205
  const result = await enactCore2.executeToolByName(name, inputs, {
21916
- timeout,
22206
+ timeout: timeout || "120s",
21917
22207
  verifyPolicy,
21918
22208
  skipVerification,
21919
22209
  force,
@@ -21938,6 +22228,23 @@ Output: ${safeJsonStringify(result)}`
21938
22228
  };
21939
22229
  } catch (error) {
21940
22230
  logger_default.error(`Error executing tool:`, error);
22231
+ if (error instanceof Error && error.message.includes("timed out")) {
22232
+ return {
22233
+ content: [{
22234
+ type: "text",
22235
+ text: `⏰ Tool execution timed out: ${name}
22236
+
22237
+ This may happen with long-running operations like Dagger builds. The operation may still be running in the background. Consider:
22238
+
22239
+ 1. Running the tool directly from CLI for long operations
22240
+ 2. Using smaller, more focused operations
22241
+ 3. Checking if the operation completed successfully outside of MCP
22242
+
22243
+ Original error: ${error.message}`
22244
+ }],
22245
+ isError: true
22246
+ };
22247
+ }
21941
22248
  return {
21942
22249
  content: [{
21943
22250
  type: "text",
@@ -22355,25 +22662,6 @@ ${safeJsonStringify(result)}`
22355
22662
  });
22356
22663
  server.server.sendToolListChanged();
22357
22664
  }
22358
- async function main() {
22359
- try {
22360
- const transport = new StdioServerTransport;
22361
- await server.connect(transport);
22362
- logger_default.info("\uD83D\uDE80 Enact MCP Server with Direct Core Integration started successfully");
22363
- } catch (error) {
22364
- console.error("❌ Server connection error:", error);
22365
- if (error instanceof Error) {
22366
- console.error("Stack trace:", error.stack);
22367
- }
22368
- process.exit(1);
22369
- }
22370
- }
22371
- if (__require.main == __require.module) {
22372
- main().catch((error) => {
22373
- console.error("❌ Failed to start server:", error);
22374
- process.exit(1);
22375
- });
22376
- }
22377
22665
  server.registerTool("enact-get-tools-by-author", {
22378
22666
  title: "Get Tools by Author",
22379
22667
  description: "Get tools by a specific author using direct core integration",
@@ -22514,6 +22802,25 @@ ${safeJsonStringify(allResults)}`
22514
22802
  };
22515
22803
  }
22516
22804
  });
22805
+ async function main() {
22806
+ try {
22807
+ const transport = new StdioServerTransport;
22808
+ await server.connect(transport);
22809
+ logger_default.info("\uD83D\uDE80 Enact MCP Server with Direct Core Integration started successfully");
22810
+ } catch (error) {
22811
+ console.error("❌ Server connection error:", error);
22812
+ if (error instanceof Error) {
22813
+ console.error("Stack trace:", error.stack);
22814
+ }
22815
+ process.exit(1);
22816
+ }
22817
+ }
22818
+ if (__require.main == __require.module) {
22819
+ main().catch((error) => {
22820
+ console.error("❌ Failed to start server:", error);
22821
+ process.exit(1);
22822
+ });
22823
+ }
22517
22824
  export {
22518
22825
  server,
22519
22826
  enactCore2 as enactCore
@@ -21043,8 +21043,29 @@ class DirectExecutionProvider extends ExecutionProvider {
21043
21043
  try {
21044
21044
  const proc = spawn(cmd, args, {
21045
21045
  env,
21046
- stdio: ["pipe", "pipe", "pipe"]
21046
+ stdio: ["pipe", "pipe", "pipe"],
21047
+ detached: process.platform !== "win32"
21047
21048
  });
21049
+ const cleanup = () => {
21050
+ if (proc && !proc.killed) {
21051
+ try {
21052
+ console.log(`[DEBUG] Cleaning up process PID: ${proc.pid}`);
21053
+ if (process.platform === "win32") {
21054
+ proc.kill("SIGKILL");
21055
+ } else {
21056
+ process.kill(-proc.pid, "SIGTERM");
21057
+ setTimeout(() => {
21058
+ if (!proc.killed) {
21059
+ console.log(`[DEBUG] Force killing process PID: ${proc.pid}`);
21060
+ process.kill(-proc.pid, "SIGKILL");
21061
+ }
21062
+ }, 2000);
21063
+ }
21064
+ } catch (killError) {
21065
+ logger_default.debug(`Process cleanup error (likely harmless): ${killError}`);
21066
+ }
21067
+ }
21068
+ };
21048
21069
  proc.stdout.on("data", (data) => {
21049
21070
  const chunk = data.toString();
21050
21071
  stdout += chunk;
@@ -21056,6 +21077,8 @@ class DirectExecutionProvider extends ExecutionProvider {
21056
21077
  process.stderr.write(chunk);
21057
21078
  });
21058
21079
  proc.on("close", (code) => {
21080
+ console.log(`[DEBUG] Process closed with code: ${code}, PID: ${proc.pid}`);
21081
+ cleanup();
21059
21082
  resolve({
21060
21083
  stdout: stdout.trim(),
21061
21084
  stderr: stderr.trim(),
@@ -21063,12 +21086,13 @@ class DirectExecutionProvider extends ExecutionProvider {
21063
21086
  });
21064
21087
  });
21065
21088
  proc.on("error", (error) => {
21089
+ cleanup();
21066
21090
  reject(new Error(`Command execution error: ${error.message}`));
21067
21091
  });
21068
21092
  if (timeout) {
21069
21093
  const timeoutMs = this.parseTimeout(timeout);
21070
21094
  setTimeout(() => {
21071
- proc.kill("SIGTERM");
21095
+ cleanup();
21072
21096
  reject(new Error(`Command timed out after ${timeout}`));
21073
21097
  }, timeoutMs);
21074
21098
  }
@@ -21874,7 +21898,8 @@ var enactCore2 = new EnactCore({
21874
21898
  supabaseUrl: process.env.ENACT_SUPABASE_URL || "https://xjnhhxwxovjifdxdwzih.supabase.co",
21875
21899
  executionProvider: "direct",
21876
21900
  verificationPolicy: process.env.ENACT_VERIFY_POLICY || "permissive",
21877
- authToken: process.env.ENACT_AUTH_TOKEN
21901
+ authToken: process.env.ENACT_AUTH_TOKEN,
21902
+ defaultTimeout: "120s"
21878
21903
  });
21879
21904
  var server = new McpServer({
21880
21905
  name: "enact-mcp-server",
@@ -21886,6 +21911,7 @@ var server = new McpServer({
21886
21911
  }
21887
21912
  }
21888
21913
  });
21914
+ var runningOperations = new Map;
21889
21915
  function safeJsonStringify(obj, fallback = "Unable to stringify object") {
21890
21916
  try {
21891
21917
  return JSON.stringify(obj, null, 2);
@@ -21894,6 +21920,266 @@ function safeJsonStringify(obj, fallback = "Unable to stringify object") {
21894
21920
  return fallback;
21895
21921
  }
21896
21922
  }
21923
+ server.registerTool("execute-tool-by-name-async", {
21924
+ title: "Execute Enact Tool (Async)",
21925
+ description: "Execute an Enact tool by its name using direct core integration with background execution for long-running operations",
21926
+ inputSchema: {
21927
+ name: exports_external.string().describe("Name of the tool to execute"),
21928
+ inputs: exports_external.record(exports_external.any()).optional().describe("Input parameters for the tool"),
21929
+ timeout: exports_external.string().optional().describe("Execution timeout"),
21930
+ verifyPolicy: exports_external.enum(["permissive", "enterprise", "paranoid"]).optional().describe("Verification policy"),
21931
+ skipVerification: exports_external.boolean().optional().describe("Skip signature verification"),
21932
+ force: exports_external.boolean().optional().describe("Force execution"),
21933
+ dryRun: exports_external.boolean().optional().describe("Dry run mode"),
21934
+ verbose: exports_external.boolean().optional().describe("Verbose output"),
21935
+ async: exports_external.boolean().optional().describe("Run in background for long operations")
21936
+ }
21937
+ }, async (params) => {
21938
+ const { name, inputs = {}, timeout, verifyPolicy, skipVerification, force, dryRun, verbose, async = false } = params;
21939
+ try {
21940
+ logger_default.info(`Executing tool ${name} via direct core library`);
21941
+ const isLongRunningTool = name.includes("dagger") || name.includes("docker") || name.includes("build") || async;
21942
+ if (isLongRunningTool) {
21943
+ const operationId = `${name}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
21944
+ const executionPromise = enactCore2.executeToolByName(name, inputs, {
21945
+ timeout: timeout || "300s",
21946
+ verifyPolicy,
21947
+ skipVerification,
21948
+ force,
21949
+ dryRun,
21950
+ verbose
21951
+ });
21952
+ const operation = {
21953
+ id: operationId,
21954
+ name,
21955
+ startTime: new Date,
21956
+ promise: executionPromise,
21957
+ status: "running",
21958
+ result: undefined,
21959
+ error: undefined
21960
+ };
21961
+ runningOperations.set(operationId, operation);
21962
+ executionPromise.then((result2) => {
21963
+ operation.status = "completed";
21964
+ operation.result = result2;
21965
+ logger_default.info(`Background operation completed: ${operationId}`);
21966
+ }).catch((error) => {
21967
+ operation.status = "failed";
21968
+ operation.error = error;
21969
+ logger_default.error(`Background operation failed: ${operationId}`, error);
21970
+ });
21971
+ return {
21972
+ content: [{
21973
+ type: "text",
21974
+ text: `\uD83D\uDE80 Started background execution of tool: ${name}
21975
+
21976
+ Operation ID: ${operationId}
21977
+ Started: ${operation.startTime.toISOString()}
21978
+
21979
+ ⏳ This operation is running in the background. Use the "check-operation-status" tool with operation ID "${operationId}" to check progress.
21980
+
21981
+ Estimated completion time: 1-3 minutes for Dagger operations.`
21982
+ }]
21983
+ };
21984
+ }
21985
+ const result = await enactCore2.executeToolByName(name, inputs, {
21986
+ timeout: timeout || "30s",
21987
+ verifyPolicy,
21988
+ skipVerification,
21989
+ force,
21990
+ dryRun,
21991
+ verbose
21992
+ });
21993
+ if (!result.success) {
21994
+ return {
21995
+ content: [{
21996
+ type: "text",
21997
+ text: `❌ Error executing tool ${name}: ${result.error?.message}`
21998
+ }],
21999
+ isError: true
22000
+ };
22001
+ }
22002
+ return {
22003
+ content: [{
22004
+ type: "text",
22005
+ text: `✅ Successfully executed tool ${name}
22006
+ Output: ${safeJsonStringify(result)}`
22007
+ }]
22008
+ };
22009
+ } catch (error) {
22010
+ logger_default.error(`Error executing tool:`, error);
22011
+ if (error instanceof Error && error.message.includes("timed out")) {
22012
+ return {
22013
+ content: [{
22014
+ type: "text",
22015
+ text: `⏰ Tool execution timed out: ${name}
22016
+
22017
+ For long-running operations like Dagger builds, try using the async mode by setting "async": true in your request.
22018
+
22019
+ Original error: ${error.message}`
22020
+ }],
22021
+ isError: true
22022
+ };
22023
+ }
22024
+ return {
22025
+ content: [{
22026
+ type: "text",
22027
+ text: `Internal error executing tool: ${error instanceof Error ? error.message : String(error)}`
22028
+ }],
22029
+ isError: true
22030
+ };
22031
+ }
22032
+ });
22033
+ server.registerTool("check-operation-status", {
22034
+ title: "Check Operation Status",
22035
+ description: "Check the status of a background operation",
22036
+ inputSchema: {
22037
+ operationId: exports_external.string().describe("The operation ID to check")
22038
+ }
22039
+ }, async ({ operationId }) => {
22040
+ try {
22041
+ const operation = runningOperations.get(operationId);
22042
+ if (!operation) {
22043
+ return {
22044
+ content: [{
22045
+ type: "text",
22046
+ text: `❌ Operation not found: ${operationId}
22047
+
22048
+ The operation may have been completed and cleaned up, or the ID is incorrect.`
22049
+ }],
22050
+ isError: true
22051
+ };
22052
+ }
22053
+ const duration = Math.round((Date.now() - operation.startTime.getTime()) / 1000);
22054
+ switch (operation.status) {
22055
+ case "running":
22056
+ return {
22057
+ content: [{
22058
+ type: "text",
22059
+ text: `⏳ Operation Status: RUNNING
22060
+
22061
+ Operation ID: ${operationId}
22062
+ Tool: ${operation.name}
22063
+ Started: ${operation.startTime.toISOString()}
22064
+ Duration: ${duration} seconds
22065
+
22066
+ The operation is still running. Please check again in a moment.`
22067
+ }]
22068
+ };
22069
+ case "completed":
22070
+ if (!operation.resultFetched) {
22071
+ operation.resultFetched = true;
22072
+ setTimeout(() => {
22073
+ console.log(`[INFO] Cleaning up completed operation: ${operationId}`);
22074
+ runningOperations.delete(operationId);
22075
+ }, 60000);
22076
+ }
22077
+ return {
22078
+ content: [{
22079
+ type: "text",
22080
+ text: `✅ Operation Status: COMPLETED
22081
+
22082
+ Operation ID: ${operationId}
22083
+ Tool: ${operation.name}
22084
+ Started: ${operation.startTime.toISOString()}
22085
+ Duration: ${duration} seconds
22086
+
22087
+ Result:
22088
+ ${safeJsonStringify(operation.result)}`
22089
+ }]
22090
+ };
22091
+ case "failed":
22092
+ if (!operation.errorFetched) {
22093
+ operation.errorFetched = true;
22094
+ setTimeout(() => {
22095
+ console.log(`[INFO] Cleaning up failed operation: ${operationId}`);
22096
+ runningOperations.delete(operationId);
22097
+ }, 60000);
22098
+ }
22099
+ return {
22100
+ content: [{
22101
+ type: "text",
22102
+ text: `❌ Operation Status: FAILED
22103
+
22104
+ Operation ID: ${operationId}
22105
+ Tool: ${operation.name}
22106
+ Started: ${operation.startTime.toISOString()}
22107
+ Duration: ${duration} seconds
22108
+
22109
+ Error: ${operation.error instanceof Error ? operation.error.message : String(operation.error)}`
22110
+ }],
22111
+ isError: true
22112
+ };
22113
+ default:
22114
+ return {
22115
+ content: [{
22116
+ type: "text",
22117
+ text: `❓ Unknown operation status: ${operation.status}`
22118
+ }],
22119
+ isError: true
22120
+ };
22121
+ }
22122
+ } catch (error) {
22123
+ logger_default.error(`Error checking operation status:`, error);
22124
+ return {
22125
+ content: [{
22126
+ type: "text",
22127
+ text: `Error checking operation status: ${error instanceof Error ? error.message : String(error)}`
22128
+ }],
22129
+ isError: true
22130
+ };
22131
+ }
22132
+ });
22133
+ server.registerTool("list-operations", {
22134
+ title: "List Operations",
22135
+ description: "List all background operations",
22136
+ inputSchema: {}
22137
+ }, async () => {
22138
+ try {
22139
+ const operations = Array.from(runningOperations.values());
22140
+ if (operations.length === 0) {
22141
+ return {
22142
+ content: [{
22143
+ type: "text",
22144
+ text: `\uD83D\uDCCB No background operations currently running or recently completed.`
22145
+ }]
22146
+ };
22147
+ }
22148
+ let summary = `\uD83D\uDCCB Background Operations (${operations.length} total)
22149
+
22150
+ `;
22151
+ operations.forEach((op) => {
22152
+ const duration = Math.round((Date.now() - op.startTime.getTime()) / 1000);
22153
+ const statusEmoji = op.status === "running" ? "⏳" : op.status === "completed" ? "✅" : "❌";
22154
+ summary += `${statusEmoji} ${op.id}
22155
+ `;
22156
+ summary += ` Tool: ${op.name}
22157
+ `;
22158
+ summary += ` Status: ${op.status.toUpperCase()}
22159
+ `;
22160
+ summary += ` Duration: ${duration}s
22161
+ `;
22162
+ summary += ` Started: ${op.startTime.toISOString()}
22163
+
22164
+ `;
22165
+ });
22166
+ return {
22167
+ content: [{
22168
+ type: "text",
22169
+ text: summary
22170
+ }]
22171
+ };
22172
+ } catch (error) {
22173
+ logger_default.error(`Error listing operations:`, error);
22174
+ return {
22175
+ content: [{
22176
+ type: "text",
22177
+ text: `Error listing operations: ${error instanceof Error ? error.message : String(error)}`
22178
+ }],
22179
+ isError: true
22180
+ };
22181
+ }
22182
+ });
21897
22183
  server.registerTool("execute-tool-by-name", {
21898
22184
  title: "Execute Enact Tool",
21899
22185
  description: "Execute an Enact tool by its name using direct core integration",
@@ -21911,8 +22197,12 @@ server.registerTool("execute-tool-by-name", {
21911
22197
  const { name, inputs = {}, timeout, verifyPolicy, skipVerification, force, dryRun, verbose } = params;
21912
22198
  try {
21913
22199
  logger_default.info(`Executing tool ${name} via direct core library`);
22200
+ const isLongRunningTool = name.includes("dagger") || name.includes("docker") || name.includes("build");
22201
+ if (isLongRunningTool) {
22202
+ logger_default.info(`⏳ Starting long-running operation: ${name} (this may take 1-2 minutes)`);
22203
+ }
21914
22204
  const result = await enactCore2.executeToolByName(name, inputs, {
21915
- timeout,
22205
+ timeout: timeout || "120s",
21916
22206
  verifyPolicy,
21917
22207
  skipVerification,
21918
22208
  force,
@@ -21937,6 +22227,23 @@ Output: ${safeJsonStringify(result)}`
21937
22227
  };
21938
22228
  } catch (error) {
21939
22229
  logger_default.error(`Error executing tool:`, error);
22230
+ if (error instanceof Error && error.message.includes("timed out")) {
22231
+ return {
22232
+ content: [{
22233
+ type: "text",
22234
+ text: `⏰ Tool execution timed out: ${name}
22235
+
22236
+ This may happen with long-running operations like Dagger builds. The operation may still be running in the background. Consider:
22237
+
22238
+ 1. Running the tool directly from CLI for long operations
22239
+ 2. Using smaller, more focused operations
22240
+ 3. Checking if the operation completed successfully outside of MCP
22241
+
22242
+ Original error: ${error.message}`
22243
+ }],
22244
+ isError: true
22245
+ };
22246
+ }
21940
22247
  return {
21941
22248
  content: [{
21942
22249
  type: "text",
@@ -22354,25 +22661,6 @@ ${safeJsonStringify(result)}`
22354
22661
  });
22355
22662
  server.server.sendToolListChanged();
22356
22663
  }
22357
- async function main() {
22358
- try {
22359
- const transport = new StdioServerTransport;
22360
- await server.connect(transport);
22361
- logger_default.info("\uD83D\uDE80 Enact MCP Server with Direct Core Integration started successfully");
22362
- } catch (error) {
22363
- console.error("❌ Server connection error:", error);
22364
- if (error instanceof Error) {
22365
- console.error("Stack trace:", error.stack);
22366
- }
22367
- process.exit(1);
22368
- }
22369
- }
22370
- if (__require.main == __require.module) {
22371
- main().catch((error) => {
22372
- console.error("❌ Failed to start server:", error);
22373
- process.exit(1);
22374
- });
22375
- }
22376
22664
  server.registerTool("enact-get-tools-by-author", {
22377
22665
  title: "Get Tools by Author",
22378
22666
  description: "Get tools by a specific author using direct core integration",
@@ -22513,6 +22801,25 @@ ${safeJsonStringify(allResults)}`
22513
22801
  };
22514
22802
  }
22515
22803
  });
22804
+ async function main() {
22805
+ try {
22806
+ const transport = new StdioServerTransport;
22807
+ await server.connect(transport);
22808
+ logger_default.info("\uD83D\uDE80 Enact MCP Server with Direct Core Integration started successfully");
22809
+ } catch (error) {
22810
+ console.error("❌ Server connection error:", error);
22811
+ if (error instanceof Error) {
22812
+ console.error("Stack trace:", error.stack);
22813
+ }
22814
+ process.exit(1);
22815
+ }
22816
+ }
22817
+ if (__require.main == __require.module) {
22818
+ main().catch((error) => {
22819
+ console.error("❌ Failed to start server:", error);
22820
+ process.exit(1);
22821
+ });
22822
+ }
22516
22823
  export {
22517
22824
  server,
22518
22825
  enactCore2 as enactCore
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "enact-cli",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
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",
@@ -76,4 +76,4 @@
76
76
  "yaml": "^2.8.0",
77
77
  "zod": "^3.25.67"
78
78
  }
79
- }
79
+ }