HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: //opt/agentcloud/webapp/src/controllers/app.ts
'use strict';

import { dynamicResponse } from '@dr';
import { getAgentsByTeam } from 'db/agent';
import { addApp, deleteAppById, getAppById, getAppsByTeam, updateApp } from 'db/app';
import { getAssetById } from 'db/asset';
import { addCrew, updateCrew } from 'db/crew';
import { getModelsByTeam } from 'db/model';
import { getTasksByTeam } from 'db/task';
import { getToolsByTeam } from 'db/tool';
import toObjectId from 'misc/toobjectid';
import { AppType } from 'struct/app';
import { ProcessImpl } from 'struct/crew';

export async function appsData(req, res, _next) {
	const [apps, tasks, tools, agents, models] = await Promise.all([
		 getAppsByTeam(req.params.resourceSlug),
		 getTasksByTeam(req.params.resourceSlug),
		 getToolsByTeam(req.params.resourceSlug),
		 getAgentsByTeam(req.params.resourceSlug),
		 getModelsByTeam(req.params.resourceSlug),
	]);
	return {
		csrf: req.csrfToken(),
		apps,
		tasks,
		tools,
		agents,
		models,
	};
}

export async function appData(req, res, _next) {
	const [app, tasks, tools, agents, models] = await Promise.all([
		 getAppById(req.params.resourceSlug, req.params.appId),
		 getTasksByTeam(req.params.resourceSlug),
		 getToolsByTeam(req.params.resourceSlug),
		 getAgentsByTeam(req.params.resourceSlug),
		 getModelsByTeam(req.params.resourceSlug),
	 ]);
	 return {
		csrf: req.csrfToken(),
		app,
		tasks,
		tools,
		agents,
		models
	};
}

/**
 * GET /[resourceSlug]/apps
 * App page html
 */
export async function appsPage(app, req, res, next) {
	const data = await appsData(req, res, next);
	res.locals.data = { ...data, account: res.locals.account };
	return app.render(req, res, `/${req.params.resourceSlug}/apps`);
}

/**
 * GET /[resourceSlug]/app/[appId].json
 * App json data
 */
export async function appJson(req, res, next) {
	const data = await appData(req, res, next);
	return res.json({ ...data, account: res.locals.account });
}

/**
 * GET /[resourceSlug]/apps.json
 * Apps page json data
 */
export async function appsJson(req, res, next) {
	const data = await appsData(req, res, next);
	return res.json({ ...data, account: res.locals.account });
}

/**
 * GET /[resourceSlug]/app/add
 * App add page html
 */
export async function appAddPage(app, req, res, next) {
	const data = await appsData(req, res, next);
	res.locals.data = { ...data, account: res.locals.account };
	return app.render(req, res, `/${req.params.resourceSlug}/app/add`);
}

/**
 * GET /[resourceSlug]/app/[appId]/edit
 * App edit page html
 */
export async function appEditPage(app, req, res, next) {
	const data = await appData(req, res, next);
	res.locals.data = { ...data, account: res.locals.account };
	return app.render(req, res, `/${req.params.resourceSlug}/app/${req.params.appId}/edit`); 
}

/**
 * @api {post} /forms/app/add Add an app
 * @apiName add
 * @apiGroup App
 *
 * @apiParam {String} name App name
 * @apiParam {String[]} tags Tags for the app
 */
export async function addAppApi(req, res, next) {

	const { memory, cache, name, description, tags, capabilities, agents, appType, process, tasks, managerModelId, iconId }  = req.body;

	if (!name || typeof name !== 'string' || name.length === 0) {
		return dynamicResponse(req, res, 400, { error: 'Invalid inputs' });
	}

	const foundIcon = await getAssetById(iconId);

	const addedCrew = await addCrew({
		orgId: res.locals.matchingOrg.id,
		teamId: toObjectId(req.params.resourceSlug),
		name,
		tasks: tasks.map(toObjectId),
		agents: agents.map(toObjectId),
		process,
		managerModelId: toObjectId(managerModelId),
	});
	const addedApp = await addApp({
		orgId: res.locals.matchingOrg.id,
		teamId: toObjectId(req.params.resourceSlug),
		name,
		description,
		memory: memory === true,
		cache: cache === true,
		tags: (tags||[])
			.map(tag => tag.trim()) // Assuming tags is an array of strings
			.filter(x => x),
		capabilities,
		crewId: addedCrew.insertedId,
		appType,
		author: res.locals.matchingTeam.name,
		icon: foundIcon ? {
			id: foundIcon._id,
			filename: foundIcon.filename,
		} : null,
	});

	return dynamicResponse(req, res, 302, { _id: addedApp.insertedId, redirect: `/${req.params.resourceSlug}/apps` });

}

/**
 * @api {post} /forms/app/[appId]/edit Edit an app
 * @apiName edit
 * @apiGroup App
 *
 * @apiParam {String} appId App id
 */
export async function editAppApi(req, res, next) {

	const { memory, cache, name, description, tags, capabilities, agents, appType, process, tasks, managerModelId, iconId }  = req.body;

	if (!name || typeof name !== 'string' || name.length === 0) {
		return dynamicResponse(req, res, 400, { error: 'Invalid inputs' });
	}

	const app = await getAppById(req.params.resourceSlug, req.params.appId);
	if (!app) {
		return dynamicResponse(req, res, 400, { error: 'Invalid inputs' });
	}

	const foundIcon = await getAssetById(iconId);

	//const [updatedCrew, _] = 
	await Promise.all([
		updateCrew(req.params.resourceSlug, app.crewId, {
			orgId: res.locals.matchingOrg.id,
			teamId: toObjectId(req.params.resourceSlug),
			name,
			tasks: tasks.map(toObjectId),
			agents: agents.map(toObjectId),
			process,
			managerModelId: toObjectId(managerModelId)
		}),
		updateApp(req.params.resourceSlug, req.params.appId, {
		    name,
			description,
			memory: memory === true,
			cache: cache === true,
			tags: (tags||[]) //TODO
				.map(t => t.trim())
				.filter(t => t),
			capabilities,
			appType,
			icon: foundIcon ? {
				id: foundIcon._id,
				filename: foundIcon.filename,
			} : null,
		})
	]);

	return dynamicResponse(req, res, 302, { /*redirect: `/${req.params.resourceSlug}/app/${req.params.appId}/edit`*/ });

}

/**
 * @api {delete} /forms/app/[appId] Delete an app
 * @apiName delete
 * @apiGroup App
 *
 * @apiParam {String} appId App id
 */
export async function deleteAppApi(req, res, next) {

	const { appId }  = req.body;

	if (!appId || typeof appId !== 'string' || appId.length !== 24) {
		return dynamicResponse(req, res, 400, { error: 'Invalid inputs' });
	}

	await deleteAppById(req.params.resourceSlug, appId);

	return dynamicResponse(req, res, 302, {});
}