mirror of
				https://github.com/9technologygroup/patchmon.net.git
				synced 2025-11-03 21:43:33 +00:00 
			
		
		
		
	Compare commits
	
		
			6 Commits
		
	
	
		
			renovate/m
			...
			renovate/m
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					d8741ba083 | ||
| 
						 | 
					1e75f2b1fe | ||
| 
						 | 
					79317b0052 | ||
| 
						 | 
					77a945a5b6 | ||
| 
						 | 
					276d910e83 | ||
| 
						 | 
					dae536e96b | 
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -1430,6 +1430,69 @@ router.patch(
 | 
			
		||||
	},
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// Force agent update for specific host
 | 
			
		||||
router.post(
 | 
			
		||||
	"/:hostId/force-agent-update",
 | 
			
		||||
	authenticateToken,
 | 
			
		||||
	requireManageHosts,
 | 
			
		||||
	async (req, res) => {
 | 
			
		||||
		try {
 | 
			
		||||
			const { hostId } = req.params;
 | 
			
		||||
 | 
			
		||||
			// Get host to verify it exists
 | 
			
		||||
			const host = await prisma.hosts.findUnique({
 | 
			
		||||
				where: { id: hostId },
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			if (!host) {
 | 
			
		||||
				return res.status(404).json({ error: "Host not found" });
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Get queue manager
 | 
			
		||||
			const { QUEUE_NAMES } = require("../services/automation");
 | 
			
		||||
			const queueManager = req.app.locals.queueManager;
 | 
			
		||||
 | 
			
		||||
			if (!queueManager) {
 | 
			
		||||
				return res.status(500).json({
 | 
			
		||||
					error: "Queue manager not available",
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Get the agent-commands queue
 | 
			
		||||
			const queue = queueManager.queues[QUEUE_NAMES.AGENT_COMMANDS];
 | 
			
		||||
 | 
			
		||||
			// Add job to queue
 | 
			
		||||
			await queue.add(
 | 
			
		||||
				"update_agent",
 | 
			
		||||
				{
 | 
			
		||||
					api_id: host.api_id,
 | 
			
		||||
					type: "update_agent",
 | 
			
		||||
				},
 | 
			
		||||
				{
 | 
			
		||||
					attempts: 3,
 | 
			
		||||
					backoff: {
 | 
			
		||||
						type: "exponential",
 | 
			
		||||
						delay: 2000,
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
			);
 | 
			
		||||
 | 
			
		||||
			res.json({
 | 
			
		||||
				success: true,
 | 
			
		||||
				message: "Agent update queued successfully",
 | 
			
		||||
				host: {
 | 
			
		||||
					id: host.id,
 | 
			
		||||
					friendlyName: host.friendly_name,
 | 
			
		||||
					apiId: host.api_id,
 | 
			
		||||
				},
 | 
			
		||||
			});
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			console.error("Force agent update error:", error);
 | 
			
		||||
			res.status(500).json({ error: "Failed to force agent update" });
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// Serve the installation script (requires API authentication)
 | 
			
		||||
router.get("/install", async (req, res) => {
 | 
			
		||||
	try {
 | 
			
		||||
 
 | 
			
		||||
@@ -176,6 +176,15 @@ function pushSettingsUpdate(apiId, newInterval) {
 | 
			
		||||
	);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function pushUpdateAgent(apiId) {
 | 
			
		||||
	const ws = apiIdToSocket.get(apiId);
 | 
			
		||||
	safeSend(ws, JSON.stringify({ type: "update_agent" }));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getConnectionByApiId(apiId) {
 | 
			
		||||
	return apiIdToSocket.get(apiId);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function pushUpdateNotification(apiId, updateInfo) {
 | 
			
		||||
	const ws = apiIdToSocket.get(apiId);
 | 
			
		||||
	if (ws && ws.readyState === WebSocket.OPEN) {
 | 
			
		||||
@@ -330,10 +339,12 @@ module.exports = {
 | 
			
		||||
	broadcastSettingsUpdate,
 | 
			
		||||
	pushReportNow,
 | 
			
		||||
	pushSettingsUpdate,
 | 
			
		||||
	pushUpdateAgent,
 | 
			
		||||
	pushUpdateNotification,
 | 
			
		||||
	pushUpdateNotificationToAll,
 | 
			
		||||
	// Expose read-only view of connected agents
 | 
			
		||||
	getConnectedApiIds: () => Array.from(apiIdToSocket.keys()),
 | 
			
		||||
	getConnectionByApiId,
 | 
			
		||||
	isConnected: (apiId) => {
 | 
			
		||||
		const ws = apiIdToSocket.get(apiId);
 | 
			
		||||
		return !!ws && ws.readyState === WebSocket.OPEN;
 | 
			
		||||
 
 | 
			
		||||
@@ -190,6 +190,19 @@ class QueueManager {
 | 
			
		||||
					// For settings update, we need additional data
 | 
			
		||||
					const { update_interval } = job.data;
 | 
			
		||||
					agentWs.pushSettingsUpdate(api_id, update_interval);
 | 
			
		||||
				} else if (type === "update_agent") {
 | 
			
		||||
					// Force agent to update by sending WebSocket command
 | 
			
		||||
					const ws = agentWs.getConnectionByApiId(api_id);
 | 
			
		||||
					if (ws && ws.readyState === 1) {
 | 
			
		||||
						// WebSocket.OPEN
 | 
			
		||||
						agentWs.pushUpdateAgent(api_id);
 | 
			
		||||
						console.log(`✅ Update command sent to agent ${api_id}`);
 | 
			
		||||
					} else {
 | 
			
		||||
						console.error(`❌ Agent ${api_id} is not connected`);
 | 
			
		||||
						throw new Error(
 | 
			
		||||
							`Agent ${api_id} is not connected. Cannot send update command.`,
 | 
			
		||||
						);
 | 
			
		||||
					}
 | 
			
		||||
				} else {
 | 
			
		||||
					console.error(`Unknown agent command type: ${type}`);
 | 
			
		||||
				}
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
		"react-chartjs-2": "^5.2.0",
 | 
			
		||||
		"react-dom": "^18.3.1",
 | 
			
		||||
		"react-icons": "^5.5.0",
 | 
			
		||||
		"react-router-dom": "^6.30.1"
 | 
			
		||||
		"react-router-dom": "^7.0.0"
 | 
			
		||||
	},
 | 
			
		||||
	"devDependencies": {
 | 
			
		||||
		"@types/react": "^18.3.14",
 | 
			
		||||
 
 | 
			
		||||
@@ -187,6 +187,16 @@ const HostDetail = () => {
 | 
			
		||||
		},
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	// Force agent update mutation
 | 
			
		||||
	const forceAgentUpdateMutation = useMutation({
 | 
			
		||||
		mutationFn: () =>
 | 
			
		||||
			adminHostsAPI.forceAgentUpdate(hostId).then((res) => res.data),
 | 
			
		||||
		onSuccess: () => {
 | 
			
		||||
			queryClient.invalidateQueries(["host", hostId]);
 | 
			
		||||
			queryClient.invalidateQueries(["hosts"]);
 | 
			
		||||
		},
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	const updateFriendlyNameMutation = useMutation({
 | 
			
		||||
		mutationFn: (friendlyName) =>
 | 
			
		||||
			adminHostsAPI
 | 
			
		||||
@@ -703,6 +713,29 @@ const HostDetail = () => {
 | 
			
		||||
											/>
 | 
			
		||||
										</button>
 | 
			
		||||
									</div>
 | 
			
		||||
 | 
			
		||||
									<div>
 | 
			
		||||
										<p className="text-xs text-secondary-500 dark:text-secondary-300 mb-1.5">
 | 
			
		||||
											Force Update
 | 
			
		||||
										</p>
 | 
			
		||||
										<button
 | 
			
		||||
											type="button"
 | 
			
		||||
											onClick={() => forceAgentUpdateMutation.mutate()}
 | 
			
		||||
											disabled={forceAgentUpdateMutation.isPending}
 | 
			
		||||
											className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium text-primary-600 dark:text-primary-400 bg-primary-50 dark:bg-primary-900/20 border border-primary-200 dark:border-primary-800 rounded-md hover:bg-primary-100 dark:hover:bg-primary-900/40 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
 | 
			
		||||
										>
 | 
			
		||||
											<RefreshCw
 | 
			
		||||
												className={`h-3 w-3 ${
 | 
			
		||||
													forceAgentUpdateMutation.isPending
 | 
			
		||||
														? "animate-spin"
 | 
			
		||||
														: ""
 | 
			
		||||
												}`}
 | 
			
		||||
											/>
 | 
			
		||||
											{forceAgentUpdateMutation.isPending
 | 
			
		||||
												? "Updating..."
 | 
			
		||||
												: "Update Now"}
 | 
			
		||||
										</button>
 | 
			
		||||
									</div>
 | 
			
		||||
								</div>
 | 
			
		||||
							</div>
 | 
			
		||||
						)}
 | 
			
		||||
 
 | 
			
		||||
@@ -95,6 +95,7 @@ export const adminHostsAPI = {
 | 
			
		||||
		api.put("/hosts/bulk/groups", { hostIds, groupIds }),
 | 
			
		||||
	toggleAutoUpdate: (hostId, autoUpdate) =>
 | 
			
		||||
		api.patch(`/hosts/${hostId}/auto-update`, { auto_update: autoUpdate }),
 | 
			
		||||
	forceAgentUpdate: (hostId) => api.post(`/hosts/${hostId}/force-agent-update`),
 | 
			
		||||
	updateFriendlyName: (hostId, friendlyName) =>
 | 
			
		||||
		api.patch(`/hosts/${hostId}/friendly-name`, {
 | 
			
		||||
			friendly_name: friendlyName,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										313
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										313
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@@ -78,7 +78,7 @@
 | 
			
		||||
				"react-chartjs-2": "^5.2.0",
 | 
			
		||||
				"react-dom": "^18.3.1",
 | 
			
		||||
				"react-icons": "^5.5.0",
 | 
			
		||||
				"react-router-dom": "^6.30.1"
 | 
			
		||||
				"react-router-dom": "^7.0.0"
 | 
			
		||||
			},
 | 
			
		||||
			"devDependencies": {
 | 
			
		||||
				"@types/react": "^18.3.14",
 | 
			
		||||
@@ -134,6 +134,7 @@
 | 
			
		||||
			"version": "7.28.4",
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"@babel/code-frame": "^7.27.1",
 | 
			
		||||
				"@babel/generator": "^7.28.3",
 | 
			
		||||
@@ -386,6 +387,74 @@
 | 
			
		||||
				"@biomejs/cli-win32-x64": "2.3.0"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@biomejs/cli-darwin-arm64": {
 | 
			
		||||
			"version": "2.3.0",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.0.tgz",
 | 
			
		||||
			"integrity": "sha512-3cJVT0Z5pbTkoBmbjmDZTDFYxIkRcrs9sYVJbIBHU8E6qQxgXAaBfSVjjCreG56rfDuQBr43GzwzmaHPcu4vlw==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"arm64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT OR Apache-2.0",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"darwin"
 | 
			
		||||
			],
 | 
			
		||||
			"engines": {
 | 
			
		||||
				"node": ">=14.21.3"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@biomejs/cli-darwin-x64": {
 | 
			
		||||
			"version": "2.3.0",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.0.tgz",
 | 
			
		||||
			"integrity": "sha512-6LIkhglh3UGjuDqJXsK42qCA0XkD1Ke4K/raFOii7QQPbM8Pia7Qj2Hji4XuF2/R78hRmEx7uKJH3t/Y9UahtQ==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"x64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT OR Apache-2.0",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"darwin"
 | 
			
		||||
			],
 | 
			
		||||
			"engines": {
 | 
			
		||||
				"node": ">=14.21.3"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@biomejs/cli-linux-arm64": {
 | 
			
		||||
			"version": "2.3.0",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.0.tgz",
 | 
			
		||||
			"integrity": "sha512-uhAsbXySX7xsXahegDg5h3CDgfMcRsJvWLFPG0pjkylgBb9lErbK2C0UINW52zhwg0cPISB09lxHPxCau4e2xA==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"arm64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT OR Apache-2.0",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"linux"
 | 
			
		||||
			],
 | 
			
		||||
			"engines": {
 | 
			
		||||
				"node": ">=14.21.3"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@biomejs/cli-linux-arm64-musl": {
 | 
			
		||||
			"version": "2.3.0",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.0.tgz",
 | 
			
		||||
			"integrity": "sha512-nDksoFdwZ2YrE7NiYDhtMhL2UgFn8Kb7Y0bYvnTAakHnqEdb4lKindtBc1f+xg2Snz0JQhJUYO7r9CDBosRU5w==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"arm64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT OR Apache-2.0",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"linux"
 | 
			
		||||
			],
 | 
			
		||||
			"engines": {
 | 
			
		||||
				"node": ">=14.21.3"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@biomejs/cli-linux-x64": {
 | 
			
		||||
			"version": "2.3.0",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
@@ -401,6 +470,57 @@
 | 
			
		||||
				"node": ">=14.21.3"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@biomejs/cli-linux-x64-musl": {
 | 
			
		||||
			"version": "2.3.0",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.0.tgz",
 | 
			
		||||
			"integrity": "sha512-+i9UcJwl99uAhtRQDz9jUAh+Xkb097eekxs/D9j4deWDg5/yB/jPWzISe1nBHvlzTXsdUSj0VvB4Go2DSpKIMw==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"x64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT OR Apache-2.0",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"linux"
 | 
			
		||||
			],
 | 
			
		||||
			"engines": {
 | 
			
		||||
				"node": ">=14.21.3"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@biomejs/cli-win32-arm64": {
 | 
			
		||||
			"version": "2.3.0",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.0.tgz",
 | 
			
		||||
			"integrity": "sha512-ynjmsJLIKrAjC3CCnKMMhzcnNy8dbQWjKfSU5YA0mIruTxBNMbkAJp+Pr2iV7/hFou+66ZSD/WV8hmLEmhUaXA==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"arm64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT OR Apache-2.0",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"win32"
 | 
			
		||||
			],
 | 
			
		||||
			"engines": {
 | 
			
		||||
				"node": ">=14.21.3"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@biomejs/cli-win32-x64": {
 | 
			
		||||
			"version": "2.3.0",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.0.tgz",
 | 
			
		||||
			"integrity": "sha512-zOCYmCRVkWXc9v8P7OLbLlGGMxQTKMvi+5IC4v7O8DkjLCOHRzRVK/Lno2pGZNo0lzKM60pcQOhH8HVkXMQdFg==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"x64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT OR Apache-2.0",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"win32"
 | 
			
		||||
			],
 | 
			
		||||
			"engines": {
 | 
			
		||||
				"node": ">=14.21.3"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@bull-board/api": {
 | 
			
		||||
			"version": "6.13.1",
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
@@ -424,6 +544,7 @@
 | 
			
		||||
		"node_modules/@bull-board/ui": {
 | 
			
		||||
			"version": "6.13.1",
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"@bull-board/api": "6.13.1"
 | 
			
		||||
			}
 | 
			
		||||
@@ -457,6 +578,7 @@
 | 
			
		||||
		"node_modules/@dnd-kit/core": {
 | 
			
		||||
			"version": "6.3.1",
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"@dnd-kit/accessibility": "^3.1.1",
 | 
			
		||||
				"@dnd-kit/utilities": "^3.2.2",
 | 
			
		||||
@@ -764,13 +886,6 @@
 | 
			
		||||
				"@prisma/debug": "6.16.2"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@remix-run/router": {
 | 
			
		||||
			"version": "1.23.0",
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"engines": {
 | 
			
		||||
				"node": ">=14.0.0"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@rolldown/pluginutils": {
 | 
			
		||||
			"version": "1.0.0-beta.27",
 | 
			
		||||
			"dev": true,
 | 
			
		||||
@@ -897,6 +1012,7 @@
 | 
			
		||||
			"version": "18.3.24",
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"@types/prop-types": "*",
 | 
			
		||||
				"csstype": "^3.0.2"
 | 
			
		||||
@@ -1144,6 +1260,7 @@
 | 
			
		||||
				}
 | 
			
		||||
			],
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"baseline-browser-mapping": "^2.8.3",
 | 
			
		||||
				"caniuse-lite": "^1.0.30001741",
 | 
			
		||||
@@ -1333,6 +1450,7 @@
 | 
			
		||||
		"node_modules/chart.js": {
 | 
			
		||||
			"version": "4.5.0",
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"@kurkle/color": "^0.3.0"
 | 
			
		||||
			},
 | 
			
		||||
@@ -1907,6 +2025,7 @@
 | 
			
		||||
		"node_modules/express": {
 | 
			
		||||
			"version": "4.21.2",
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"accepts": "~1.3.8",
 | 
			
		||||
				"array-flatten": "1.1.1",
 | 
			
		||||
@@ -2672,6 +2791,76 @@
 | 
			
		||||
				"lefthook-windows-x64": "1.13.5"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/lefthook-darwin-arm64": {
 | 
			
		||||
			"version": "1.13.5",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/lefthook-darwin-arm64/-/lefthook-darwin-arm64-1.13.5.tgz",
 | 
			
		||||
			"integrity": "sha512-BYt5CnAOXasVCS6i+A4ljUo9xru/B5uMFD6EWHhs3R26jGF7mBSDxM3ErzXTUaJRTP0kQI/XBmgqBryBqoqZOQ==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"arm64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"darwin"
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/lefthook-darwin-x64": {
 | 
			
		||||
			"version": "1.13.5",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/lefthook-darwin-x64/-/lefthook-darwin-x64-1.13.5.tgz",
 | 
			
		||||
			"integrity": "sha512-ZDtLBzvI5e26C/RZ4irOHpELTd22x9lDTgF2+eCYcnrBWOkB7800V8tuAvBybsLGvg6JwKjFxn+NTRNZnCC2hw==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"x64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"darwin"
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/lefthook-freebsd-arm64": {
 | 
			
		||||
			"version": "1.13.5",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/lefthook-freebsd-arm64/-/lefthook-freebsd-arm64-1.13.5.tgz",
 | 
			
		||||
			"integrity": "sha512-uQ/kQZSSedw74aGCpsfOPN4yVt3klg8grOP6gHQOCRUMv5oK/Lj3pe1PylpTuuhxWORWRzkauPMot26J0OZZdA==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"arm64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"freebsd"
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/lefthook-freebsd-x64": {
 | 
			
		||||
			"version": "1.13.5",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/lefthook-freebsd-x64/-/lefthook-freebsd-x64-1.13.5.tgz",
 | 
			
		||||
			"integrity": "sha512-6czek8XagVrI7ExURawkfrfX40Qjc/wktc8bLq/iXfRlmdvKDMrx2FrA82mDfEVCAEz+tTvkteK1TfR3icYF3Q==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"x64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"freebsd"
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/lefthook-linux-arm64": {
 | 
			
		||||
			"version": "1.13.5",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/lefthook-linux-arm64/-/lefthook-linux-arm64-1.13.5.tgz",
 | 
			
		||||
			"integrity": "sha512-MjWtiuW1br+rpTtgG1KGV53mSGtL5MWQwgafYzrFleJ89fKb86F4TD/4mVNzk5thmZ+HVPZw9bRZGUHFBnNJWg==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"arm64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"linux"
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/lefthook-linux-x64": {
 | 
			
		||||
			"version": "1.13.5",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
@@ -2684,6 +2873,62 @@
 | 
			
		||||
				"linux"
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/lefthook-openbsd-arm64": {
 | 
			
		||||
			"version": "1.13.5",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/lefthook-openbsd-arm64/-/lefthook-openbsd-arm64-1.13.5.tgz",
 | 
			
		||||
			"integrity": "sha512-lYXrWf0/hBrwtG8ceaHq886bcqRKh3Lfv+jZJs+ykMLB6L/kaqk8tA4V2NHWydQ5h56o45ugs/580nMz36ZdRg==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"arm64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"openbsd"
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/lefthook-openbsd-x64": {
 | 
			
		||||
			"version": "1.13.5",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/lefthook-openbsd-x64/-/lefthook-openbsd-x64-1.13.5.tgz",
 | 
			
		||||
			"integrity": "sha512-Ba1JrsRbfan4WKd8Q7gUhTxCUuppXzirDObd3JxpLRSLxA47yxhjMv7KByDunRDTvzTgsXoykZI6mPupkc1JiQ==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"x64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"openbsd"
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/lefthook-windows-arm64": {
 | 
			
		||||
			"version": "1.13.5",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/lefthook-windows-arm64/-/lefthook-windows-arm64-1.13.5.tgz",
 | 
			
		||||
			"integrity": "sha512-Y/CpmEIb0hlFe+kTT/efWgX6+/gUTp5NItTF+gmUrY1/G/bTLIxdIRS7WpodVM0MEN24sOrQVTSi9DN9FvGoGg==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"arm64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"win32"
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/lefthook-windows-x64": {
 | 
			
		||||
			"version": "1.13.5",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/lefthook-windows-x64/-/lefthook-windows-x64-1.13.5.tgz",
 | 
			
		||||
			"integrity": "sha512-WJBqGNBlFJnunRwy12QyaDHdGULtostPqpYSZSS4boFJDY0lP5qtz9lAGmJ49aA5GQ19jrnDjGLwVPFiwIqksQ==",
 | 
			
		||||
			"cpu": [
 | 
			
		||||
				"x64"
 | 
			
		||||
			],
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"optional": true,
 | 
			
		||||
			"os": [
 | 
			
		||||
				"win32"
 | 
			
		||||
			]
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/lilconfig": {
 | 
			
		||||
			"version": "3.1.3",
 | 
			
		||||
			"dev": true,
 | 
			
		||||
@@ -3296,6 +3541,7 @@
 | 
			
		||||
				}
 | 
			
		||||
			],
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"nanoid": "^3.3.11",
 | 
			
		||||
				"picocolors": "^1.1.1",
 | 
			
		||||
@@ -3425,6 +3671,7 @@
 | 
			
		||||
			"devOptional": true,
 | 
			
		||||
			"hasInstallScript": true,
 | 
			
		||||
			"license": "Apache-2.0",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"@prisma/config": "6.16.2",
 | 
			
		||||
				"@prisma/engines": "6.16.2"
 | 
			
		||||
@@ -3614,6 +3861,7 @@
 | 
			
		||||
		"node_modules/react": {
 | 
			
		||||
			"version": "18.3.1",
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"loose-envify": "^1.1.0"
 | 
			
		||||
			},
 | 
			
		||||
@@ -3632,6 +3880,7 @@
 | 
			
		||||
		"node_modules/react-dom": {
 | 
			
		||||
			"version": "18.3.1",
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"loose-envify": "^1.1.0",
 | 
			
		||||
				"scheduler": "^0.23.2"
 | 
			
		||||
@@ -3656,31 +3905,50 @@
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/react-router": {
 | 
			
		||||
			"version": "6.30.1",
 | 
			
		||||
			"version": "7.9.5",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.5.tgz",
 | 
			
		||||
			"integrity": "sha512-JmxqrnBZ6E9hWmf02jzNn9Jm3UqyeimyiwzD69NjxGySG6lIz/1LVPsoTCwN7NBX2XjCEa1LIX5EMz1j2b6u6A==",
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"@remix-run/router": "1.23.0"
 | 
			
		||||
				"cookie": "^1.0.1",
 | 
			
		||||
				"set-cookie-parser": "^2.6.0"
 | 
			
		||||
			},
 | 
			
		||||
			"engines": {
 | 
			
		||||
				"node": ">=14.0.0"
 | 
			
		||||
				"node": ">=20.0.0"
 | 
			
		||||
			},
 | 
			
		||||
			"peerDependencies": {
 | 
			
		||||
				"react": ">=16.8"
 | 
			
		||||
				"react": ">=18",
 | 
			
		||||
				"react-dom": ">=18"
 | 
			
		||||
			},
 | 
			
		||||
			"peerDependenciesMeta": {
 | 
			
		||||
				"react-dom": {
 | 
			
		||||
					"optional": true
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/react-router-dom": {
 | 
			
		||||
			"version": "6.30.1",
 | 
			
		||||
			"version": "7.9.5",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.5.tgz",
 | 
			
		||||
			"integrity": "sha512-mkEmq/K8tKN63Ae2M7Xgz3c9l9YNbY+NHH6NNeUmLA3kDkhKXRsNb/ZpxaEunvGo2/3YXdk5EJU3Hxp3ocaBPw==",
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"@remix-run/router": "1.23.0",
 | 
			
		||||
				"react-router": "6.30.1"
 | 
			
		||||
				"react-router": "7.9.5"
 | 
			
		||||
			},
 | 
			
		||||
			"engines": {
 | 
			
		||||
				"node": ">=14.0.0"
 | 
			
		||||
				"node": ">=20.0.0"
 | 
			
		||||
			},
 | 
			
		||||
			"peerDependencies": {
 | 
			
		||||
				"react": ">=16.8",
 | 
			
		||||
				"react-dom": ">=16.8"
 | 
			
		||||
				"react": ">=18",
 | 
			
		||||
				"react-dom": ">=18"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/react-router/node_modules/cookie": {
 | 
			
		||||
			"version": "1.0.2",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
 | 
			
		||||
			"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"engines": {
 | 
			
		||||
				"node": ">=18"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/read-cache": {
 | 
			
		||||
@@ -3952,6 +4220,12 @@
 | 
			
		||||
			"version": "2.0.0",
 | 
			
		||||
			"license": "ISC"
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/set-cookie-parser": {
 | 
			
		||||
			"version": "2.7.2",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz",
 | 
			
		||||
			"integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==",
 | 
			
		||||
			"license": "MIT"
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/setprototypeof": {
 | 
			
		||||
			"version": "1.2.0",
 | 
			
		||||
			"license": "ISC"
 | 
			
		||||
@@ -4349,6 +4623,7 @@
 | 
			
		||||
			"version": "4.0.3",
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"engines": {
 | 
			
		||||
				"node": ">=12"
 | 
			
		||||
			},
 | 
			
		||||
@@ -4501,6 +4776,7 @@
 | 
			
		||||
			"version": "7.1.7",
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"dependencies": {
 | 
			
		||||
				"esbuild": "^0.25.0",
 | 
			
		||||
				"fdir": "^6.5.0",
 | 
			
		||||
@@ -4590,6 +4866,7 @@
 | 
			
		||||
			"version": "4.0.3",
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT",
 | 
			
		||||
			"peer": true,
 | 
			
		||||
			"engines": {
 | 
			
		||||
				"node": ">=12"
 | 
			
		||||
			},
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										88
									
								
								setup.sh
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								setup.sh
									
									
									
									
									
								
							@@ -1797,7 +1797,12 @@ create_agent_version() {
 | 
			
		||||
        cp "$APP_DIR/agents/patchmon-agent.sh" "$APP_DIR/backend/"
 | 
			
		||||
        
 | 
			
		||||
        print_status "Agent version management removed - using file-based approach"
 | 
			
		||||
# Ensure we close the conditional and the function properly
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    # Make agent binaries executable
 | 
			
		||||
    if [ -d "$APP_DIR/agents" ]; then
 | 
			
		||||
        chmod +x "$APP_DIR/agents/patchmon-agent-linux-"* 2>/dev/null || true
 | 
			
		||||
        print_status "Agent binaries made executable"
 | 
			
		||||
    fi
 | 
			
		||||
 | 
			
		||||
    return 0
 | 
			
		||||
@@ -2703,6 +2708,13 @@ update_env_file() {
 | 
			
		||||
    : ${TFA_MAX_REMEMBER_SESSIONS:=5}
 | 
			
		||||
    : ${TFA_SUSPICIOUS_ACTIVITY_THRESHOLD:=3}
 | 
			
		||||
    
 | 
			
		||||
    # Prisma Connection Pool
 | 
			
		||||
    : ${DB_CONNECTION_LIMIT:=30}
 | 
			
		||||
    : ${DB_POOL_TIMEOUT:=20}
 | 
			
		||||
    : ${DB_CONNECT_TIMEOUT:=10}
 | 
			
		||||
    : ${DB_IDLE_TIMEOUT:=300}
 | 
			
		||||
    : ${DB_MAX_LIFETIME:=1800}
 | 
			
		||||
    
 | 
			
		||||
    # Track which variables were added
 | 
			
		||||
    local added_vars=()
 | 
			
		||||
    
 | 
			
		||||
@@ -2764,6 +2776,21 @@ update_env_file() {
 | 
			
		||||
    if ! grep -q "^TFA_SUSPICIOUS_ACTIVITY_THRESHOLD=" "$env_file"; then
 | 
			
		||||
        added_vars+=("TFA_SUSPICIOUS_ACTIVITY_THRESHOLD")
 | 
			
		||||
    fi
 | 
			
		||||
    if ! grep -q "^DB_CONNECTION_LIMIT=" "$env_file"; then
 | 
			
		||||
        added_vars+=("DB_CONNECTION_LIMIT")
 | 
			
		||||
    fi
 | 
			
		||||
    if ! grep -q "^DB_POOL_TIMEOUT=" "$env_file"; then
 | 
			
		||||
        added_vars+=("DB_POOL_TIMEOUT")
 | 
			
		||||
    fi
 | 
			
		||||
    if ! grep -q "^DB_CONNECT_TIMEOUT=" "$env_file"; then
 | 
			
		||||
        added_vars+=("DB_CONNECT_TIMEOUT")
 | 
			
		||||
    fi
 | 
			
		||||
    if ! grep -q "^DB_IDLE_TIMEOUT=" "$env_file"; then
 | 
			
		||||
        added_vars+=("DB_IDLE_TIMEOUT")
 | 
			
		||||
    fi
 | 
			
		||||
    if ! grep -q "^DB_MAX_LIFETIME=" "$env_file"; then
 | 
			
		||||
        added_vars+=("DB_MAX_LIFETIME")
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    # If there are missing variables, add them
 | 
			
		||||
    if [ ${#added_vars[@]} -gt 0 ]; then
 | 
			
		||||
@@ -2849,6 +2876,25 @@ EOF
 | 
			
		||||
            echo "TFA_SUSPICIOUS_ACTIVITY_THRESHOLD=$TFA_SUSPICIOUS_ACTIVITY_THRESHOLD" >> "$env_file"
 | 
			
		||||
        fi
 | 
			
		||||
        
 | 
			
		||||
        # Add Prisma connection pool config if missing
 | 
			
		||||
        if printf '%s\n' "${added_vars[@]}" | grep -q "DB_CONNECTION_LIMIT"; then
 | 
			
		||||
            echo "" >> "$env_file"
 | 
			
		||||
            echo "# Database Connection Pool Configuration (Prisma)" >> "$env_file"
 | 
			
		||||
            echo "DB_CONNECTION_LIMIT=$DB_CONNECTION_LIMIT" >> "$env_file"
 | 
			
		||||
        fi
 | 
			
		||||
        if printf '%s\n' "${added_vars[@]}" | grep -q "DB_POOL_TIMEOUT"; then
 | 
			
		||||
            echo "DB_POOL_TIMEOUT=$DB_POOL_TIMEOUT" >> "$env_file"
 | 
			
		||||
        fi
 | 
			
		||||
        if printf '%s\n' "${added_vars[@]}" | grep -q "DB_CONNECT_TIMEOUT"; then
 | 
			
		||||
            echo "DB_CONNECT_TIMEOUT=$DB_CONNECT_TIMEOUT" >> "$env_file"
 | 
			
		||||
        fi
 | 
			
		||||
        if printf '%s\n' "${added_vars[@]}" | grep -q "DB_IDLE_TIMEOUT"; then
 | 
			
		||||
            echo "DB_IDLE_TIMEOUT=$DB_IDLE_TIMEOUT" >> "$env_file"
 | 
			
		||||
        fi
 | 
			
		||||
        if printf '%s\n' "${added_vars[@]}" | grep -q "DB_MAX_LIFETIME"; then
 | 
			
		||||
            echo "DB_MAX_LIFETIME=$DB_MAX_LIFETIME" >> "$env_file"
 | 
			
		||||
        fi
 | 
			
		||||
        
 | 
			
		||||
        print_status ".env file updated with ${#added_vars[@]} new variable(s)"
 | 
			
		||||
        print_info "Added variables: ${added_vars[*]}"
 | 
			
		||||
    else
 | 
			
		||||
@@ -2918,11 +2964,37 @@ update_installation() {
 | 
			
		||||
    print_info "Installation directory: $instance_dir"
 | 
			
		||||
    print_info "Service name: $service_name"
 | 
			
		||||
    
 | 
			
		||||
    # Verify it's a git repository
 | 
			
		||||
    # Verify it's a git repository, if not, initialize it
 | 
			
		||||
    if [ ! -d "$instance_dir/.git" ]; then
 | 
			
		||||
        print_error "Installation directory is not a git repository"
 | 
			
		||||
        print_error "Cannot perform git-based update"
 | 
			
		||||
        exit 1
 | 
			
		||||
        print_warning "Installation directory is not a git repository"
 | 
			
		||||
        print_info "Attempting to re-initialize as git repository..."
 | 
			
		||||
        
 | 
			
		||||
        cd "$instance_dir" || exit 1
 | 
			
		||||
        
 | 
			
		||||
        # Initialize git repository
 | 
			
		||||
        git init
 | 
			
		||||
        git remote add origin https://github.com/PatchMon/PatchMon.git
 | 
			
		||||
        
 | 
			
		||||
        # Fetch all branches
 | 
			
		||||
        git fetch origin
 | 
			
		||||
        
 | 
			
		||||
        # Try to determine current version from package.json or default to main
 | 
			
		||||
        local current_branch="main"
 | 
			
		||||
        if [ -f "$instance_dir/backend/package.json" ]; then
 | 
			
		||||
            local pkg_version=$(grep '"version"' "$instance_dir/backend/package.json" | head -1 | sed 's/.*"version": "\(.*\)".*/\1/')
 | 
			
		||||
            if [ -n "$pkg_version" ]; then
 | 
			
		||||
                # Check if there's a release branch for this version
 | 
			
		||||
                if git ls-remote --heads origin | grep -q "release/$(echo $pkg_version | sed 's/\./-/g')"; then
 | 
			
		||||
                    current_branch="release/$(echo $pkg_version | sed 's/\./-/g')"
 | 
			
		||||
                fi
 | 
			
		||||
            fi
 | 
			
		||||
        fi
 | 
			
		||||
        
 | 
			
		||||
        # Reset to the determined branch
 | 
			
		||||
        git reset --hard "origin/$current_branch"
 | 
			
		||||
        git checkout -B "$current_branch" "origin/$current_branch"
 | 
			
		||||
        
 | 
			
		||||
        print_success "Repository initialized successfully"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    # Add git safe.directory to avoid ownership issues when running as root
 | 
			
		||||
@@ -3028,6 +3100,12 @@ update_installation() {
 | 
			
		||||
    print_info "Building frontend..."
 | 
			
		||||
    npm run build
 | 
			
		||||
    
 | 
			
		||||
    # Make agent binaries executable
 | 
			
		||||
    if [ -d "$instance_dir/agents" ]; then
 | 
			
		||||
        chmod +x "$instance_dir/agents/patchmon-agent-linux-"* 2>/dev/null || true
 | 
			
		||||
        print_status "Agent binaries made executable"
 | 
			
		||||
    fi
 | 
			
		||||
    
 | 
			
		||||
    # Run database migrations with self-healing
 | 
			
		||||
    print_info "Running database migrations..."
 | 
			
		||||
    cd "$instance_dir/backend"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user