//#region imports
import * as readline from 'readline'; // @backend
import { MagicRenamer } from 'magic-renamer/lib-prod'; // @backend
import { Subject } from 'rxjs';
import { config, fileName, folderName, Helpers__NS__clearConsole, Helpers__NS__createSymLink, Helpers__NS__error, Helpers__NS__exists, Helpers__NS__foldersFrom, Helpers__NS__info, Helpers__NS__isFolder, Helpers__NS__isSymlinkFileExitedOrUnexisted, Helpers__NS__isUnexistedLink, Helpers__NS__logInfo, Helpers__NS__mkdirp, Helpers__NS__openFolderInFileExplorer, Helpers__NS__questionYesNo, Helpers__NS__readFile, Helpers__NS__readJson, Helpers__NS__removeFileIfExists, Helpers__NS__removeSymlinks, Helpers__NS__renderError, Helpers__NS__run, Helpers__NS__sleep, Helpers__NS__taskDone, Helpers__NS__taskStarted, Helpers__NS__warn, Helpers__NS__writeJson, UtilsEtcHosts__NS__simulateDomain, UtilsExecProc__NS__spawnAdminSudo, UtilsExecProc__NS__spawnAsync, UtilsFilesFoldersSync__NS__writeFile } from 'tnp-core/lib-prod';
import { chalk, path, os, fse, isElevated, ___NS__first, ___NS__isArray, ___NS__kebabCase, ___NS__merge, ___NS__times, Utils__NS__uniqArray, UtilsOs__NS__commandExistsAsync, UtilsOs__NS__commandExistsSync, UtilsOs__NS__getEditorSettingsJsonPath, UtilsOs__NS__getRealHomeDir, UtilsOs__NS__isNodeVersionOk, UtilsOs__NS__isPortInUse, UtilsOs__NS__isRunningInBrowser, UtilsOs__NS__isRunningInCliMode, UtilsOs__NS__isRunningInDocker, UtilsOs__NS__isRunningInElectron, UtilsOs__NS__isRunningInLinuxGraphicsCapableEnvironment, UtilsOs__NS__isRunningInMochaTest, UtilsOs__NS__isRunningInNode, UtilsOs__NS__isRunningInVscodeExtension, UtilsOs__NS__isRunningInWebSQL, UtilsOs__NS__isRunningInWindowsCmd, UtilsOs__NS__isRunningInWindowsPowerShell, UtilsOs__NS__isRunningInWsl, UtilsOs__NS__killAllEditor, UtilsOs__NS__pipxPackageExists, UtilsOs__NS__pythonModuleExists, UtilsProcess__NS__getPathOfExecutable, UtilsProcess__NS__killProcessOnPort } from 'tnp-core/lib-prod';
import { crossPlatformPath } from 'tnp-core/lib-prod';
import { UtilsTerminal__NS__confirm, UtilsTerminal__NS__pressAnyKeyToContinueAsync, UtilsTerminal__NS__previewLongListGitLogLike, UtilsTerminal__NS__select, UtilsTerminal__NS__waitForUserAnyKey } from 'tnp-core/lib-prod';
import { UtilsDotFile__NS__getValueFromDotFile, UtilsDotFile__NS__getValuesKeysAsJsonObject, UtilsNetwork__NS__checkIfServerOnline, UtilsNetwork__NS__checkIfServerPings, UtilsNetwork__NS__getCurrentPublicIpAddress, UtilsNetwork__NS__getEtcHostsPath, UtilsNetwork__NS__getFirstIpV4LocalActiveIpAddress, UtilsNetwork__NS__getLocalIpAddresses, UtilsNetwork__NS__simulateDomain } from 'tnp-core/lib-prod';
import { child_process } from 'tnp-core/lib-prod'; //@backend
import { UtilsSudo__NS__getStatus } from 'tnp-core/lib-prod';
import { GlobalTaskManager } from 'tnp-core/lib-prod';
import { BaseCLiWorkerStartMode, HelpersTaon__NS__arrays__NS__fuzzy, HelpersTaon__NS__arrays__NS__uniqArray, HelpersTaon__NS__autocompleteAsk, HelpersTaon__NS__cliTool__NS__resolveItemFromArgsBegin, HelpersTaon__NS__consoleGui__NS__select, HelpersTaon__NS__copy, HelpersTaon__NS__copyFile, HelpersTaon__NS__git__NS__allOrigins, HelpersTaon__NS__git__NS__changeRemoteFromHttpsToSSh, HelpersTaon__NS__git__NS__changeRemoveFromSshToHttps, HelpersTaon__NS__git__NS__checkTagExists, HelpersTaon__NS__git__NS__clone, HelpersTaon__NS__git__NS__countCommits, HelpersTaon__NS__git__NS__currentBranchName, HelpersTaon__NS__git__NS__findGitRoot, HelpersTaon__NS__git__NS__getAllTags, HelpersTaon__NS__git__NS__getOriginURL, HelpersTaon__NS__git__NS__isInsideGitRepo, HelpersTaon__NS__git__NS__lastCommitHash, HelpersTaon__NS__git__NS__lastCommitMessage, HelpersTaon__NS__git__NS__originHttpToSsh, HelpersTaon__NS__git__NS__originSshToHttp, HelpersTaon__NS__git__NS__removeTag, HelpersTaon__NS__git__NS__resetSoftHEAD, HelpersTaon__NS__move, HelpersTaon__NS__pressKeyAndContinue, HelpersTaon__NS__readValueFromJson, HelpersTaon__NS__selectChoicesAsk, HelpersTaon__NS__stripTsTypesIntoJs, HelpersTaon__NS__terminalLine, UtilsJava__NS__selectJdkVersion, UtilsJava__NS__selectTomcatVersion, UtilsJava__NS__updateJavaHomePath, UtilsJava__NS__updateTomcatHomePath, UtilsTypescript__NS__formatFile, UtilsTypescript__NS__normalizeBrokenLines, UtilsTypescript__NS__splitNamespaceForContent, UtilsVSCode__NS__installExtensions, UtilsVSCode__NS__openFile, UtilsVSCode__NS__openFolder, UtilsVSCode__NS__regenerateVsCodeSettingsColors, UtilsZip__NS__unzipArchive, UtilsZip__NS__zipDir } from '../../index';
import { UtilsLineCount__NS__forPorject } from '../../utils';
import { CommitData } from '../commit-data';
import { PULL_ACTION_NAME, PUSH_ACTION_NAME } from '../constants';
import { GhTempCode } from '../gh-temp-code';
import { BaseCommandLineFeature } from './base-command-line-feature';
//#endregion
export class BaseGlobalCommandLine extends BaseCommandLineFeature {
    _() {
        Helpers__NS__error('Please select git command');
    }
    /**
     * @returns true is sudo was used to restart the process
     */
    async _runAsSudoIfNotElevated({ globalCommandName, }) {
        //#region @backendFunc
        if (!(await isElevated())) {
            if (process.platform === 'win32') {
                await UtilsExecProc__NS__spawnAdminSudo(`${config.frameworkName} ${globalCommandName}`);
            }
            else {
                let pathOfExecutableNode = await UtilsProcess__NS__getPathOfExecutable('node');
                let pathOfExecutable = await UtilsProcess__NS__getPathOfExecutable(config.frameworkName);
                await UtilsExecProc__NS__spawnAdminSudo(`${pathOfExecutableNode} ${pathOfExecutable} ${globalCommandName}`);
            }
            return true;
        }
        return false;
        //#endregion
    }
    //#region commands / prevent cwd is not project
    /**
     * TODO return argument not need for now
     */
    async cwdIsProject(options) {
        //#region @backendFunc
        const { requireProjectWithGitRoot } = options || {};
        if (!!this.project && !requireProjectWithGitRoot) {
            return true;
        }
        if (requireProjectWithGitRoot &&
            (!this.project || !this.project.git.isGitRoot)) {
            const proj = this.ins.nearestTo(this.cwd, { findGitRoot: true });
            if (proj) {
                Helpers__NS__info(`
              Current folder (${this.cwd})
              is not a git root folder, but nearest project with
              git root has been found in: ${chalk.bold(proj.genericName)}

              `);
                const useRoot = await Helpers__NS__questionYesNo('Would you like to use this project ?');
                if (useRoot) {
                    this.project = proj;
                    this.cwd = proj.location;
                    return true;
                }
                else {
                    Helpers__NS__error(`[${config.frameworkName}] This is not git root project folder`, true, true);
                }
            }
            else {
                Helpers__NS__error(`[${config.frameworkName}] This folder is not project folder`, false, true);
            }
        }
        return true;
        //#endregion
    }
    //#endregion
    //#region commands / hosts
    async hosts() {
        //#region @backendFunc
        await UtilsVSCode__NS__openFile(UtilsNetwork__NS__getEtcHostsPath());
        process.exit(0);
        //#endregion
    }
    //#endregion
    //#region commands / count commits
    countCommits() {
        //#region @backendFunc
        console.log(HelpersTaon__NS__git__NS__countCommits(this.cwd));
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / remove submodules
    removeSubmodules() {
        //#region @backendFunc
        Helpers__NS__taskStarted('Removing submodules...');
        for (const folderAbsPath of Helpers__NS__foldersFrom(this.cwd, {
            recursive: false,
        })) {
            if (Helpers__NS__exists(crossPlatformPath([folderAbsPath, '.git']))) {
                try {
                    Helpers__NS__run(`git rm --cached ${path.basename(folderAbsPath)}`).sync();
                }
                catch (error) { }
            }
        }
        Helpers__NS__taskDone('Done');
        this._exit();
        //#endregion
    }
    removeSubmodule() {
        //#region @backendFunc
        Helpers__NS__taskStarted(`Removing submodules.. ${this.firstArg}`);
        if (Helpers__NS__exists(crossPlatformPath([this.cwd, this.firstArg || '', '.git']))) {
            try {
                Helpers__NS__run(`git rm --cached ${this.firstArg}`).sync();
            }
            catch (error) { }
        }
        Helpers__NS__taskDone('Done');
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / set editor
    async setEditor() {
        //#region @backendFunc
        await this.ins.configDb.codeEditor.selectCodeEditor();
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / api update
    async upapi() {
        //#region @backendFunc
        await this.apiUpdate();
        //#endregion
    }
    async upapiAll() {
        //#region @backendFunc
        await this.apiUpdateAll();
        //#endregion
    }
    async apiup() {
        //#region @backendFunc
        await this.apiUpdate();
        //#endregion
    }
    async apiupall() {
        //#region @backendFunc
        await this.apiUpdateAll();
        //#endregion
    }
    async apiUpdate() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        Helpers__NS__info('Updating & pushing all projects (first level)...');
        await this.updateProject(this.project, {
            commitType: 'chore',
            updateType: 'only-this',
            commitMessagePart: `api ${!!this.firstArg ? this.firstArg : 'update'}`,
        });
        Helpers__NS__info('Done');
        this._exit();
        //#endregion
    }
    async apiUpdateAll() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        Helpers__NS__info('Updating & pushing all projects (first level)...');
        await this.updateProject(this.project, {
            updateType: 'first-level',
            commitType: 'chore',
            commitMessagePart: `api ${!!this.firstArg ? this.firstArg : 'update'}`,
        });
        Helpers__NS__info('Done');
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / api update force
    async upapiforce() {
        //#region @backendFunc
        await this.apiUpdateForce();
        //#endregion
    }
    async apiupforce() {
        //#region @backendFunc
        await this.apiUpdateForce();
        //#endregion
    }
    async apiUpdateForce() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        Helpers__NS__info('Updating & push project...');
        try {
            this.project.git.addAndCommit(`chore: api ${!!this.firstArg ? this.firstArg : 'update'}`);
        }
        catch (error) { }
        await this.project.git.pushCurrentBranch({
            askToRetry: true,
            force: true,
            forcePushNoQuestion: true,
        });
        Helpers__NS__info('Done');
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / chore update
    async cu() {
        //#region @backendFunc
        await this.update();
        //#endregion
    }
    async choreUpdate() {
        //#region @backendFunc
        await this.update();
        //#endregion
    }
    //#endregion
    //#region commands / color vscode
    colorvscode() {
        //#region @backendFunc
        this.settingsVscode();
        //#endregion
    }
    //#endregion
    //#region commands / settings vscode
    /**
     * Generate or update .vscode/settings.json file color settings
     */
    settingsVscode() {
        //#region @backendFunc
        this.refreshVscodeColors();
        //#endregion
    }
    refreshVscodeColors() {
        //#region @backendFunc
        this._regenerateVscodeSettingsColors();
        this._exit();
        //#endregion
    }
    _regenerateVscodeSettingsColors(overideBottomColor) {
        //#region @backendFunc
        UtilsVSCode__NS__regenerateVsCodeSettingsColors(this.cwd, overideBottomColor);
        //#endregion
    }
    //#endregion
    async updateProject(project, options) {
        //#region @backendFunc
        options = options || {};
        options.force = !!options.force;
        options.updateType = options.updateType || 'only-this';
        options.commitType = options.commitType || 'chore';
        while (project.git.hasActionCommitsToMelt) {
            const choices = {
                openInCode: { name: 'Open in code editor' },
                continue: { name: 'Continue' },
                skipUpdate: { name: 'Skip project update' },
                meltNow: { name: 'Melt action commits now' },
            };
            const resp = await UtilsTerminal__NS__select({
                choices,
                question: `Project ${chalk.bold(project.genericName)} has action commits to melt. What you want to do ?`,
            });
            if (resp === 'continue') {
                continue;
            }
            if (resp === 'openInCode') {
                await project.openInEditor();
                continue;
            }
            if (resp === 'skipUpdate') {
                return;
            }
            if (resp === 'meltNow') {
                project.git.meltActionCommits();
                Helpers__NS__info(`Changes after melting:`);
                console.log(await project.git.changesSummary({
                    prefix: `${project.location}/`,
                }));
                await UtilsTerminal__NS__pressAnyKeyToContinueAsync({
                    message: `Press any key to continue...`,
                });
            }
        }
        try {
            await project.packageJson.bumpPatchVersion();
        }
        catch (error) { }
        try {
            project.git.addAndCommit(`${options.commitType}: ${options.commitMessagePart
                ? options.commitMessagePart
                : !!this.firstArg
                    ? this.args.join(' ')
                    : 'update'}`);
        }
        catch (error) { }
        await project.git.pushCurrentBranch({
            askToRetry: true,
            forcePushNoQuestion: true,
            force: options.force,
        });
        if (!project.isMonorepo && options.updateType !== 'only-this') {
            if (options.updateType === 'first-level') {
                options.updateType = 'only-this';
            }
            for (const child of project.children) {
                if (child.git.isGitRoot) {
                    await this.updateProject(child, options);
                }
            }
        }
        //#endregion
    }
    //#region commands / force update
    async forceUpdate() {
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.updateProject(this.project, {
            force: true,
        });
        this._exit();
    }
    /**
     * alias for forceupdate
     */
    async forceup() {
        await this.forceUpdate();
    }
    //#endregion
    //#region commands / update
    async update() {
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.updateProject(this.project);
        this._exit();
    }
    /**
     * alias for update
     */
    async up() {
        await this.update();
    }
    async upForce() {
        await this.forceUpdate();
    }
    /**
     * alias for update
     */
    async pu() {
        await this.update();
    }
    //#endregion
    //#region commands / docs update
    async docsUpdate() {
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.updateProject(this.project, {
            commitType: 'docs',
        });
        this._exit();
    }
    /**
     * alias for docsUpdate
     */
    async docsUp() {
        await this.docsUpdate();
    }
    async upDocs() {
        await this.docsUpdate();
    }
    //#endregion
    //#region commands / deep update
    async deepUpdate() {
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.updateProject(this.project, {
            updateType: 'deep',
        });
        this._exit();
    }
    /**
     * alias for deepupdate
     */
    async deepUp() {
        await this.deepUpdate();
    }
    //#endregion
    //#region commands / update all
    async updateAll() {
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.updateProject(this.project, {
            updateType: 'first-level',
        });
        this._exit();
    }
    /**
     * alias for updateAll
     */
    async upAll() {
        await this.updateAll();
    }
    //#endregion
    //#region commands / deep update force
    async deepUpdateForce() {
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.updateProject(this.project, {
            updateType: 'deep',
            force: true,
        });
        this._exit();
    }
    /**
     * alias for deepUpdateForce
     */
    async deepUpForce() {
        await this.deepUpdateForce();
    }
    //#endregion
    //#region commands / develop
    async develop() {
        //#region @backendFunc
        // Helpers__NS__clearConsole();
        Helpers__NS__taskStarted(`getting all projects...`);
        const founded = ((await this.ins.projectsDb.getAllProjectsFromDB()) || [])
            .filter(p => Helpers__NS__exists(p.location))
            .map(p => {
            const proj = this.ins.From(p.location);
            // console.log(`Proj for ${p.location} `, !!proj)
            if (proj) {
                return proj;
                // return proj.embeddedProject ? proj.embeddedProject : proj;
            }
            // const nereset = this.ins.nearestTo(p.location);
            // if (nereset) {
            //   const embeded = nereset.linkedProjects.find(l => crossPlatformPath([nereset.location, l.relativeClonePath]) === p.location);
            //   if (embeded) {
            //     return this.ins.From([nereset.location, embeded.relativeClonePath]);
            //   }
            // }
        })
            .filter(p => !!p);
        Helpers__NS__taskDone(`found ${founded.length} projects...`);
        Helpers__NS__taskStarted(`searching for project...`);
        // @ts-ignore
        const results = Utils__NS__uniqArray([
            ...HelpersTaon__NS__arrays__NS__fuzzy(this.args.join(' '), founded, p => p.name)
                .results,
            ...HelpersTaon__NS__arrays__NS__fuzzy(this.args.join(' '), founded, p => p.basename).results,
            ...HelpersTaon__NS__arrays__NS__fuzzy(this.args.join(' '), founded, p => p.location).results,
        ], 'location');
        Helpers__NS__taskDone(`found ${results.length} projects...`);
        const openInEditor = async (proj) => {
            Helpers__NS__taskStarted(`Getting code editor info...`);
            // console.log(`Detected editor: ${detectedEditor}`);
            // Helpers__NS__taskDone(`Got code editor info...`);
            const embededProject = proj.linkedProjects.embeddedProject;
            const porjToOpen = embededProject || proj;
            const locaitonFolderToOpen = porjToOpen.location;
            Helpers__NS__info('Initing and opening project...');
            try {
                await porjToOpen?.struct();
            }
            catch (error) { }
            await UtilsVSCode__NS__openFolder(locaitonFolderToOpen);
        };
        if (results.length === 1) {
            await openInEditor(___NS__first(results));
        }
        else if (results.length === 0) {
            Helpers__NS__error(`No project found by name: "${this.args.join(' ')}"`, false, true);
        }
        else {
            Helpers__NS__info(`Opening console gui to select project...`);
            const res = await HelpersTaon__NS__consoleGui__NS__select('Select project to open', results.map(p => {
                return {
                    name: p.genericName,
                    value: p.location,
                };
            }), true);
            await openInEditor(this.ins.From(res));
        }
        this._exit();
        //#endregion
    }
    async dev() {
        //#region @backendFunc
        return await this.develop();
        //#endregion
    }
    //#endregion
    //#region commands / repulll
    async repul() {
        //#region @backendFunc
        await this.repull();
        //#endregion
    }
    async repull() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.project.git.resetHard({ HEAD: 10 });
        await this.pull();
        //#endregion
    }
    //#endregion
    //#region commands / pull
    async pul() {
        //#region @backendFunc
        await this.pull();
        //#endregion
    }
    async pull() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        GlobalTaskManager.start(PULL_ACTION_NAME);
        await this.project.git.pullProcess({
            setOrigin: this.params['setOrigin'],
        });
        GlobalTaskManager.stop(PULL_ACTION_NAME, () => {
            this._exit();
        });
        //#endregion
    }
    //#endregion
    //#region commands / pull all
    async pullAll() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.project.git.pullProcess({
            setOrigin: this.params['setOrigin'],
        });
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / push and pull
    async pp() {
        //#region @backendFunc
        const currentBranch = this.project.git.currentBranchName;
        this.project
            .run(`git push origin ${currentBranch} && git pull origin ${currentBranch}`)
            .sync();
        console.log('Done push and pull');
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / reset
    async fetch() {
        //#region @backendFunc
        try {
            this.project?.git?.fetch();
        }
        catch (error) { }
        this._exit();
        //#endregion
    }
    async reset() {
        await this.resetProject({ commandActionType: 'only-this' });
    }
    async resetAll() {
        await this.resetProject({ commandActionType: 'first-level' });
    }
    async resetDeep() {
        await this.resetProject({ commandActionType: 'deep' });
    }
    async resetProject(options) {
        //#region @backendFunc
        options = options || {};
        options.commandActionType = options.commandActionType || 'only-this';
        // Helpers__NS__clearConsole();
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        const parent = this.project.parent;
        const branchFromLinkedProjectConfig = parent?.linkedProjects?.linkedProjects.find(l => {
            return (crossPlatformPath([parent.location, l.relativeClonePath]) ===
                this.project.location);
        })?.defaultBranch;
        let overrideBranchToReset = this.firstArg ||
            branchFromLinkedProjectConfig ||
            this.project.core?.branch ||
            this.project.git.getDefaultDevelopmentBranch() ||
            this.project.git.currentBranchName;
        if (this.project.core?.branch) {
            Helpers__NS__info(`

        Core branch for project: ${this.project.core?.branch}

        `);
        }
        const resetOnlyChildren = !!this.project.linkedProjects.getLinkedProjectsConfig().resetOnlyChildren;
        const branches = Utils__NS__uniqArray([
            ...this.__filterBranchesByPattern(overrideBranchToReset),
            ...this.__filterBranchesByPattern(''),
        ]);
        const resetChildren = options.commandActionType !== 'only-this';
        if (resetChildren && resetOnlyChildren) {
            Helpers__NS__info(`Reseting only children...for defualt branches.`);
        }
        else {
            if (branches.length > 0) {
                overrideBranchToReset = await this.__selectBranch(branches, 'reset', options.commandActionType);
            }
            else {
                Helpers__NS__error(`No branch found by name "${overrideBranchToReset || this.firstArg}"`, false, true);
            }
        }
        overrideBranchToReset = overrideBranchToReset || '';
        const withChildren = options.commandActionType !== 'only-this';
        Helpers__NS__info(`

    YOU ARE RESETING ${withChildren ? 'EVERYTHING' : 'PROJECT'} ` +
            `TO BRANCH: ${chalk.bold(overrideBranchToReset)}

- curret project (${this.project.name})
${withChildren &&
                ___NS__isArray(this.project.children) &&
                this.project.children.length > 0
                ? `- modules:\n${this.project.children
                    .map(c => `\t${c.basename} (${chalk.yellow(c.name)})`)
                    .join('\n')}`
                : ''}
      `);
        let resetProject = this.project;
        if (this.project.git.isInsideGitRepo && !this.project.git.isGitRoot) {
            Helpers__NS__warn(`You are not in root of git repo...`, false);
            resetProject = this.ins.nearestTo(crossPlatformPath([this.project.location, '..']), {
                findGitRoot: true,
            });
            if (!(await Helpers__NS__questionYesNo(`Would you like to reset root repo instead (project=${chalk.bold.red(resetProject.genericName)}) ?`))) {
                Helpers__NS__error(`Aborted`, false, true);
            }
        }
        const res = await Helpers__NS__questionYesNo(`(${options.commandActionType}) Reset hard and pull current project ` +
            `${resetChildren && resetProject.linkedProjects.linkedProjects.length > 0
                ? '(and children)'
                : ''} ?`);
        if (res) {
            await resetProject.resetProcess(overrideBranchToReset, {
                commandActionType: options.commandActionType,
            });
        }
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / soft
    async soft() {
        //#region @backendFunc
        // TODO when aciton commit
        const howManyCommits = Number(this.firstArg) || 1;
        ___NS__times(howManyCommits, n => {
            console.log(`Resetting soft ${n + 1} commit "${HelpersTaon__NS__git__NS__lastCommitMessage(this.cwd)}"`);
            HelpersTaon__NS__git__NS__resetSoftHEAD(this.cwd, 1);
        });
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / rebase
    async rebase() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        const currentBranch = this.project.git.currentBranchName;
        let safeReset = 10;
        let rebaseBranch = this.firstArg || this.project.git.getDefaultDevelopmentBranch();
        const branches = this.__filterBranchesByPattern(rebaseBranch);
        if (branches.length > 1) {
            rebaseBranch = await this.__selectBranch(branches, 'rebase', 'only-this');
        }
        else if (branches.length === 1) {
            rebaseBranch = ___NS__first(branches);
        }
        else {
            Helpers__NS__error(`No rebase branch found by name "${rebaseBranch}"`, false, true);
        }
        Helpers__NS__info(`
      You are rebasing current branch (${currentBranch}) to ${rebaseBranch}

      Files from last commit:

      "${chalk.gray(await this.project.git.getCommitMessageByHash(this.project.git.lastCommitHash()))}"
      (hash: ${chalk.gray(this.project.git.lastCommitHash())})

      are going to be applied after rebase.

      `);
        if (!(await UtilsTerminal__NS__confirm({
            message: `Do you want to continue ?`,
            defaultValue: true,
        }))) {
            this._exit();
        }
        try {
            this.project.git.resetHard();
            this.project.git.checkout(rebaseBranch);
            this.project.git.resetHard({ HEAD: safeReset });
            await this.project.git.pullCurrentBranch();
            this.project.git.checkout(currentBranch);
            this.project.git.resetSoftHEAD(1);
            this.project.git.stageAllFiles();
            this.project.git.stash();
            this.project.git.resetHard({ HEAD: safeReset });
            this.project.git.rebase(rebaseBranch);
            this.project.git.stashApply();
            await this.project.struct();
            Helpers__NS__info('REBASE DONE');
        }
        catch (error) {
            Helpers__NS__renderError(error);
            try {
                // dummy init to get back to previous vscode settings
                await this.project.init();
            }
            catch (error) { }
            Helpers__NS__error('Not able to rebase', true, true);
        }
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / stash
    /**
     * stash only staged files
     */
    async stash() {
        //#region @backendFunc
        Helpers__NS__info(`Stashing only staged files...`);
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        this.project.git.stash({ onlyStaged: true });
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / stash all
    /**
     * stash all files
     */
    async stashAll() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        this.project.git.stageAllFiles();
        this.project.git.stash();
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / push all origins
    /**
     * push force to all origins
     */
    async pushAllForce() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.pushAll(true);
        //#endregion
    }
    async pAllForce() {
        //#region @backendFunc
        await this.pushAllForce();
        //#endregion
    }
    async pAllf() {
        //#region @backendFunc
        await this.pushAllForce();
        //#endregion
    }
    async pAll() {
        //#region @backendFunc
        await this.pushAll();
        //#endregion
    }
    /**
     * push to all origins
     */
    async pushAll(force = false) {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        const remotes = this.project.git.allOrigins;
        Helpers__NS__info(`

    Remotes for repo:

${remotes.map((r, i) => `${i + 1}. ${r.origin} ${r.url}`).join('\n')}

`);
        for (let index = 0; index < remotes.length; index++) {
            const { origin, url } = remotes[index];
            Helpers__NS__taskStarted(`Pushing to ${chalk.bold(origin)} (${url})...`);
            await this.push({ force, origin, noExit: true });
            Helpers__NS__taskDone(`Pushed to ${origin}`);
        }
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / push force
    async forcePush() {
        //#region @backendFunc
        await this.push({ force: true, typeofCommit: 'feature' });
        //#endregion
    }
    async pushForce() {
        //#region @backendFunc
        await this.push({ force: true, typeofCommit: 'feature' });
        //#endregion
    }
    //#endregion
    //#region commands / commit
    /**
     * Commit and push this for single repo
     */
    async commit(options = {}) {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.project.git.meltActionCommits();
        await this.project.git.pushProcess({
            ...options,
            forcePushNoQuestion: options.force,
            args: this.args,
            exitCallBack: () => {
                this._exit();
            },
            skipChildren: true,
            overrideCommitMessage: this.args.join(' '),
            setOrigin: this.params['setOrigin'],
            currentOrigin: this.project.git.originURL,
        });
        if (options.noExit) {
            return;
        }
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / push
    async _preventPushPullFromNotCorrectBranch() {
        //#region @backendFunc
        while (true) {
            const devBranch = this.project.git.duringPushWarnIfProjectNotOnSpecyficDevBranch();
            if (!!devBranch && devBranch !== this.project.git.currentBranchName) {
                Helpers__NS__warn(`

        ${this.project.genericName}

        You are not on ${devBranch} branch. Please switch to this branch and try again

        `, false);
                const options = {
                    open: { name: 'Open in vscode' },
                    continue: { name: 'Continue (check again)' },
                    continueForce: { name: 'Continue (without checking)' },
                    exit: { name: 'Exit process' },
                };
                const res = await HelpersTaon__NS__selectChoicesAsk('What you want to do ?', Object.keys(options).map(k => {
                    return { name: options[k].name, value: k };
                }));
                if (res === 'continue') {
                    continue;
                }
                if (res === 'exit') {
                    this._exit();
                }
                if (res === 'open') {
                    await this.project.openInEditor();
                    continue;
                }
                if (res === 'continueForce') {
                    return;
                }
            }
            return;
        }
        //#endregion
    }
    async qPush() {
        //#region @backendFunc
        await this.quickPush();
        //#endregion
    }
    async quickPush() {
        //#region @backendFunc
        await this.push({ skipLint: true });
        //#endregion
    }
    async repushauto() {
        //#region @backendFunc
        await this.rePush(true);
        //#endregion
    }
    async rePush(skipQuesion = false) {
        //#region @backendFunc
        const lastCommitMessage = this.project.git.lastCommitMessage();
        this.project.git.resetSoftHEAD();
        this.project.git.stageAllFiles();
        this.project.git.commit(lastCommitMessage);
        if (!skipQuesion) {
            Helpers__NS__info(`Last fixed commit:
${lastCommitMessage}

      ...`);
            await UtilsTerminal__NS__pressAnyKeyToContinueAsync({
                message: `Press any key to force push`,
            });
        }
        await this.project.git.pushCurrentBranch({
            forcePushNoQuestion: true,
            askToRetry: true,
            force: true,
        });
        this._exit();
        //#endregion
    }
    async push(options = {}) {
        GlobalTaskManager.start(PUSH_ACTION_NAME);
        //#region @backendFunc
        // console.log('args', this.args);
        // console.log(`argsWithParams "${this.argsWithParams}"` );
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this._preventPushPullFromNotCorrectBranch();
        if (!options.overrideCommitMessage &&
            this.project.git.useBranchNameDirectlyAsCommitMessage()) {
            const jiraNumbers = CommitData.extractAndOrderJiraNumbers(this.args.join(' '));
            Helpers__NS__info(`Using branch name directly as commit message.
         Found JIRA numbers: ${jiraNumbers.join(', ')}`);
            for (const jiraNum of jiraNumbers) {
                for (const argIndex in this.args) {
                    const arg = this.args[argIndex];
                    if (arg.endsWith(jiraNum)) {
                        this.args[argIndex] = jiraNum;
                    }
                }
            }
        }
        await this.project.git.pushProcess({
            ...options,
            forcePushNoQuestion: options.force,
            args: options?.overrideCommitMessage
                ? (options?.overrideCommitMessage || '').split(' ')
                : this.args,
            exitCallBack: () => {
                this._exit();
            },
            setOrigin: this.params['setOrigin'],
            currentOrigin: this.project.git.originURL,
        });
        GlobalTaskManager.stop(PUSH_ACTION_NAME, () => {
            if (options.noExit) {
                return;
            }
            this._exit();
        });
        //#endregion
    }
    //#endregion
    //#region commands / melt
    async melt() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.meltUpdateCommits({ hideInfo: true });
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / melt
    async meltUp() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        const alreadyProcessedOrigins = [];
        const processProject = async (proj) => {
            if (alreadyProcessedOrigins.includes(proj.git.originURL)) {
                return;
            }
            alreadyProcessedOrigins.push(proj.git.originURL);
            Helpers__NS__clearConsole();
            await proj.git.resolveLastChanges({
                tryAutomaticActionFirst: false,
                projectNameAsOutputPrefix: this.project.location !== proj.location ? proj.name : void 0,
            });
            for (const child of proj.children) {
                await processProject(child);
            }
        };
        await processProject(this.project);
        Helpers__NS__info('All projects are up to date with remote');
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / melt
    async meltAll() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.meltUpdateCommits({ hideInfo: true });
        for (const child of this.project.children) {
            await this.__meltCommitsFunc(child, { hideInfo: true });
        }
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / melt updat ecommits
    async __meltCommitsFunc(project, options) {
        //#region @backendFunc
        options = options || {};
        const meltedCommits = project.git.meltActionCommits();
        if (meltedCommits > 0) {
            Helpers__NS__logInfo(`${meltedCommits} has been soft reset (melted) in ${project.genericName}`);
        }
        else {
            Helpers__NS__logInfo(`No commits to melt for project ${project.genericName}`);
        }
        //#endregion
    }
    async meltUpdateCommits(options) {
        //#region @backendFunc
        await this.__meltCommitsFunc(this.project, options);
        //#endregion
    }
    //#endregion
    //#region commands / push feature
    async pf() {
        //#region @backendFunc
        await this.pushFeature();
        //#endregion
    }
    async pRel() {
        //#region @backendFunc
        await this.pushRelease();
        //#endregion
    }
    async pRelease() {
        //#region @backendFunc
        await this.pushRelease();
        //#endregion
    }
    async pushRelease() {
        //#region @backendFunc
        await this.meltUpdateCommits();
        await this.push({
            typeofCommit: 'release',
            commitMessageRequired: true,
            overrideCommitMessage: `${___NS__first(this.project.releaseProcess.getReleaseWords())}: ` +
                `version ${this.project.packageJson.version}`,
        });
        //#endregion
    }
    async mPush() {
        //#region @backendFunc
        await this.meltPush();
        //#endregion
    }
    async fmPush() {
        //#region @backendFunc
        await this.forceMeltPush();
        //#endregion
    }
    async mfPush() {
        //#region @backendFunc
        await this.forceMeltPush();
        //#endregion
    }
    async mforcePush() {
        //#region @backendFunc
        await this.forceMeltPush();
        //#endregion
    }
    async meltforcePush() {
        //#region @backendFunc
        await this.forceMeltPush();
        //#endregion
    }
    async forceMeltPush() {
        //#region @backendFunc
        await this.meltPush(true);
        //#endregion
    }
    async meltPush(force = false) {
        //#region @backendFunc
        await this.meltUpdateCommits();
        await this.push({
            mergeUpdateCommits: true,
            force,
        });
        //#endregion
    }
    async pushFeature() {
        //#region @backendFunc
        await this.meltUpdateCommits();
        await this.push({ typeofCommit: 'feature', commitMessageRequired: true });
        //#endregion
    }
    //#endregion
    //#region commands / push fix
    async pushFix() {
        //#region @backendFunc
        await this.meltUpdateCommits();
        await this.push({ typeofCommit: 'bugfix', commitMessageRequired: true });
        //#endregion
    }
    pfix() {
        //#region @backendFunc
        this.pushFix();
        //#endregion
    }
    //#endregion
    //#region commands / push chore
    async pushChore() {
        //#region @backendFunc
        await this.meltUpdateCommits();
        await this.push({ typeofCommit: 'chore', commitMessageRequired: true });
        //#endregion
    }
    async pc() {
        //#region @backendFunc
        await this.pushChore();
        //#endregion
    }
    //#endregion
    //#region commands / push refactor
    async pushRefactor() {
        //#region @backendFunc
        await this.meltUpdateCommits();
        await this.push({ typeofCommit: 'refactor', commitMessageRequired: true });
        //#endregion
    }
    async pushref() {
        //#region @backendFunc
        await this.pushRefactor();
        //#endregion
    }
    async pref() {
        //#region @backendFunc
        await this.pushRefactor();
        //#endregion
    }
    //#endregion
    //#region commands / push style
    async pushStyle() {
        //#region @backendFunc
        await this.meltUpdateCommits();
        await this.push({ typeofCommit: 'style', commitMessageRequired: true });
        //#endregion
    }
    async pstyl() {
        //#region @backendFunc
        await this.pushStyle();
        //#endregion
    }
    async pstyle() {
        //#region @backendFunc
        await this.pushStyle();
        //#endregion
    }
    //#endregion
    //#region commands / push docs
    async pushDocs() {
        //#region @backendFunc
        await this.meltUpdateCommits();
        await this.push({ typeofCommit: 'docs', commitMessageRequired: true });
        //#endregion
    }
    async pd() {
        //#region @backendFunc
        await this.pushDocs();
        //#endregion
    }
    async pdocs() {
        //#region @backendFunc
        await this.pushDocs();
        //#endregion
    }
    //#endregion
    //#region commands / push test
    async pushTest() {
        //#region @backendFunc
        await this.meltUpdateCommits();
        await this.push({ typeofCommit: 'test', commitMessageRequired: true });
        //#endregion
    }
    async pTest() {
        //#region @backendFunc
        await this.pushTest();
        //#endregion
    }
    async pTests() {
        //#region @backendFunc
        await this.pushTest();
        //#endregion
    }
    //#endregion
    //#region commands / push perf
    async pushPerf() {
        //#region @backendFunc
        await this.meltUpdateCommits();
        await this.push({
            typeofCommit: 'performance',
            commitMessageRequired: true,
        });
        //#endregion
    }
    //#endregion
    //#region commands / push ci
    async pushCi() {
        //#region @backendFunc
        await this.meltUpdateCommits();
        await this.push({ typeofCommit: 'ci', commitMessageRequired: true });
        //#endregion
    }
    //#endregion
    //#region commands / select branch
    async branch() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.project.struct();
        try {
            this.project.git.fetch();
        }
        catch (error) { }
        let branchName = this.firstArg;
        const branches = this.__filterBranchesByPattern(branchName);
        if (branches.length > 0) {
            branchName = await this.__selectBranch(branches, 'checkout', 'only-this');
        }
        else {
            Helpers__NS__error(`No branch found by name "${branchName}"`, false, true);
        }
        try {
            this.project.git.stageAllFiles();
            this.project.git.stash();
        }
        catch (error) { }
        this.project.git.checkout(branchName);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / push build
    async pushBuild() {
        //#region @backendFunc
        await this.meltUpdateCommits();
        await this.push({ typeofCommit: 'build', commitMessageRequired: true });
        //#endregion
    }
    //#endregion
    //#region commands / set origin
    async SET_ORIGIN() {
        //#region @backendFunc
        let newOriginNameOrUrl = this.firstArg;
        if (newOriginNameOrUrl === 'ssh') {
            newOriginNameOrUrl = HelpersTaon__NS__git__NS__originHttpToSsh(HelpersTaon__NS__git__NS__getOriginURL(this.cwd));
        }
        if (newOriginNameOrUrl === 'http') {
            newOriginNameOrUrl = HelpersTaon__NS__git__NS__originSshToHttp(HelpersTaon__NS__git__NS__getOriginURL(this.cwd));
        }
        if (HelpersTaon__NS__git__NS__isInsideGitRepo(this.cwd)) {
            Helpers__NS__run(`git remote rm origin`, { cwd: this.cwd }).sync();
            Helpers__NS__run(`git remote add origin ${newOriginNameOrUrl} `, {
                cwd: this.cwd,
            }).sync();
            Helpers__NS__info(`Done`);
        }
        else {
            Helpers__NS__error(`This folder is not a git repo... `, false, true);
        }
        this._exit();
        //#endregion
    }
    //#endregion
    //#region copy and rename (vscode option)
    async $COPY_AND_RENAME() {
        //#region @backendFunc
        // console.log(`>> ${this.argsWithParams} <<`)
        const ins = MagicRenamer.Instance(this.cwd);
        await ins.start(this.argsWithParams);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / rename origin
    async RENAME_ORIGIN() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        const newOriginNameOrUrl = this.firstArg;
        const proj = this.project;
        if (proj && proj.git.isInsideGitRepo) {
            proj.git.renameOrigin(newOriginNameOrUrl);
        }
        else {
            Helpers__NS__error(`This folder is not a git repo... `, false, true);
        }
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / last hash tag
    async LAST_TAG_HASH() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        Helpers__NS__info(this.project.git.lastTagHash());
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / last tag
    async LAST_TAG() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        const proj = this.project;
        Helpers__NS__info(`

    last tag: ${proj.git.lastTagVersionName}
    last tag hash: ${proj.git.lastTagHash()}

`);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / check tag exists
    CHECK_TAG_EXISTS() {
        //#region @backendFunc
        Helpers__NS__info(`tag "${this.firstArg}"  exits = ${HelpersTaon__NS__git__NS__checkTagExists(this.firstArg)} `);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / lint
    /**
     * TODO move somewhere
     */
    async lint() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        await this.project.lint();
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / lint
    /**
     * TODO move somewhere
     */
    async lintStaged() {
        //#region @backendFunc
        await UtilsExecProc__NS__spawnAsync(`npm-run eslint $(git diff --name-only --cached -- '*.ts')`).waitUntilDoneOrThrow();
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / version
    /**
     * TODO move somewhere
     */
    async version() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: false }))) {
            return;
        }
        console.log('Current project verison: ' + this.project.packageJson.version);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / init
    /**
     * TODO move somewhere
     */
    async init() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: false }))) {
            return;
        }
        await this.project.init();
        this._exit();
        //#endregion
    }
    /**
     * init parent and first level children
     */
    async initAll() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: false }))) {
            return;
        }
        await this.project.init();
        for (const child of this.project.children) {
            await child.init();
        }
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / struct all
    /**
     * init parent and first level children
     */
    async structAll() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: false }))) {
            return;
        }
        await this.project.struct();
        for (const child of this.project.children) {
            await child.struct();
        }
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / struct
    /**
     * TODO move somewhere
     */
    async struct() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: false }))) {
            return;
        }
        await this.project.struct();
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / info
    /**
     * TODO move somewhere
     */
    async info() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({
            requireProjectWithGitRoot: false,
        }))) {
            return;
        }
        Helpers__NS__clearConsole();
        Helpers__NS__info(await this.project.info());
        await this.project.linkedProjects.saveAllLinkedProjectsToDB();
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / info
    async modified() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        const proj = this.project;
        const libs = proj.children.filter(child => {
            process.stdout.write('.');
            return child.git.thereAreSomeUncommitedChangeExcept([
                config.file.package_json,
            ]);
        });
        console.log('\n' + HelpersTaon__NS__terminalLine());
        Helpers__NS__info(libs.length
            ? libs
                .map(c => `${chalk.bold(c.name)} (${c.git.uncommitedFiles
                .map(p => chalk.black(path.basename(p)))
                .join(', ')})`)
                .join('\n')
            : 'Nothing modifed');
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / update
    async refresh() {
        //#region @backendFunc
        await this.project.refreshChildrenProjects({
            askUserAboutUpdate: true,
        });
        this._exit(0);
        //#endregion
    }
    //#endregion
    //#region commands / changes
    async changes() {
        //#region @backendFunc
        Helpers__NS__info(await this.project.git.changesSummary());
        HelpersTaon__NS__terminalLine();
        for (const chil of this.project.children) {
            Helpers__NS__info(await chil.git.changesSummary());
        }
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / all tags
    async allTags() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: true }))) {
            return;
        }
        const allTags = await HelpersTaon__NS__git__NS__getAllTags(this.cwd);
        console.log(allTags);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / remove tag
    async removeTag() {
        //#region @backendFunc
        let tagToRemove = this.firstArg;
        if (!tagToRemove) {
            const allTags = await HelpersTaon__NS__git__NS__getAllTags(this.cwd);
            tagToRemove = await UtilsTerminal__NS__select({
                question: `Select tag to remove`,
                autocomplete: true,
                choices: allTags.map(t => {
                    return { name: t, value: t };
                }),
            });
        }
        HelpersTaon__NS__git__NS__removeTag(this.cwd, tagToRemove);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / branch name
    BRANCH_NAME() {
        //#region @backendFunc
        console.log(`current branch name: "${HelpersTaon__NS__git__NS__currentBranchName(process.cwd())}"`);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / remotes
    REMOTES() {
        //#region @backendFunc
        console.log(HelpersTaon__NS__git__NS__allOrigins(this.cwd));
        this._exit();
        //#endregion
    }
    async SET_REMOTE_SSH() {
        //#region @backendFunc
        await HelpersTaon__NS__git__NS__changeRemoteFromHttpsToSSh(this.cwd);
        this._exit();
        //#endregion
    }
    async SET_REMOTE_http() {
        //#region @backendFunc
        await HelpersTaon__NS__git__NS__changeRemoveFromSshToHttps(this.cwd);
        this._exit();
        //#endregion
    }
    async SET_REMOTE_https() {
        //#region @backendFunc
        await this.SET_REMOTE_http();
        //#endregion
    }
    _resolveChildFromArg() {
        //#region @backendFunc
        const { resolved: projFromArg, clearedCommand } = HelpersTaon__NS__cliTool__NS__resolveItemFromArgsBegin(this.args, arg => this.ins.From([this.cwd, arg]));
        if (!!projFromArg) {
            this.args = clearedCommand.split(' ');
            this.cwd = projFromArg.location;
            this.project = projFromArg;
        }
        //#endregion
    }
    origin() {
        //#region @backendFunc
        this._resolveChildFromArg();
        console.log(HelpersTaon__NS__git__NS__getOriginURL(this.cwd));
        this._exit();
        //#endregion
    }
    remote() {
        //#region @backendFunc
        console.log(HelpersTaon__NS__git__NS__getOriginURL(this.cwd));
        this._exit();
        //#endregion
    }
    originHttp() {
        //#region @backendFunc
        console.log(HelpersTaon__NS__git__NS__originSshToHttp(HelpersTaon__NS__git__NS__getOriginURL(this.cwd)));
        this._exit();
        //#endregion
    }
    originHttps() {
        //#region @backendFunc
        console.log(HelpersTaon__NS__git__NS__originSshToHttp(HelpersTaon__NS__git__NS__getOriginURL(this.cwd)));
        this._exit();
        //#endregion
    }
    originssh() {
        //#region @backendFunc
        console.log(HelpersTaon__NS__git__NS__originHttpToSsh(HelpersTaon__NS__git__NS__getOriginURL(this.cwd)));
        this._exit();
        //#endregion
    }
    origins() {
        //#region @backendFunc
        this.REMOTES();
        //#endregion
    }
    //#endregion
    //#region commands / git config
    async gitConfig() {
        //#region @backendFunc
        const root = HelpersTaon__NS__git__NS__findGitRoot(this.cwd);
        await UtilsVSCode__NS__openFile([root, '.git', 'config']);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / lastCommitHash
    LAST_COMMIT_HASH() {
        //#region @backendFunc
        console.log(HelpersTaon__NS__git__NS__lastCommitHash(this.cwd));
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / commit message by hash
    async COMMIT_MESSAGE_BY_HASH() {
        //#region @backendFunc
        const hash = this.firstArg;
        console.log(await this.project.git.getCommitMessageByHash(hash));
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / last 5 commit hashes
    async LAST_5_COMMITS() {
        //#region @backendFunc
        for (let index = 0; index < 5; index++) {
            const hash = await this.project.git.getCommitHashByIndex(index);
            console.log(hash);
        }
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / update deps from
    async updateDepsFrom() {
        //#region @backendFunc
        let locations = this.args.join(' ').trim() === '' ? [] : this.args;
        if (___NS__isArray(locations)) {
            locations = locations.map(l => {
                if (path.isAbsolute(l)) {
                    return path.resolve(l);
                }
                return path.resolve(path.join(this.cwd, l));
            });
        }
        this.project.packageJson.updateDepsFrom(locations);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region is terminal supported
    isSupportedTaonTerminal() {
        //#region @backendFunc
        // console.log(`Terminal is supported: ${HelpersTaon.isSupportedTaonTerminal}`);
        // this._exit();
        //#endregion
    }
    //#endregion
    //#region is terminal running inside cmd
    isRunningInWindowsCmd() {
        //#region @backendFunc
        console.log(`Is terminal running insdie cmd.exe: ${UtilsOs__NS__isRunningInWindowsCmd()}`);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region is running inside powershell
    isRunningInWindowsPowerShell() {
        //#region @backendFunc
        console.log(`Is terminal running insdie powershell: ${UtilsOs__NS__isRunningInWindowsPowerShell()}`);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region prox ext
    async INSTALL_PROJECT_EXTENSIONS() {
        //#region @backendFunc
        await this.INSTALL_PROJ_EXT();
        //#endregion
    }
    async INSTALL_PROJECT_EXT() {
        //#region @backendFunc
        await this.INSTALL_PROJ_EXT();
        //#endregion
    }
    async INS_PROJ_EXT() {
        //#region @backendFunc
        await this.INSTALL_PROJ_EXT();
        //#endregion
    }
    async INSTALL_PROJ_EXT() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: false }))) {
            return;
        }
        this.project.vsCodeHelpers.recreateExtensions();
        const p = this.project.pathFor('.vscode/extensions.json');
        const extensions = Helpers__NS__readJson(p, { recommendations: [] }, true);
        Helpers__NS__clearConsole();
        await UtilsVSCode__NS__installExtensions({
            extensions: extensions.recommendations,
            defaultSelectedAll: true,
            editor: await this.project.ins.editor(),
        });
        this._exit();
        //#endregion
    }
    //#endregion
    //#region proj db
    async projdb() {
        //#region @backendFunc
        if (!(await this.cwdIsProject({ requireProjectWithGitRoot: false }))) {
            return;
        }
        Helpers__NS__info(`Projects db location:
    ${this.project.linkedProjects.projectsDbLocation}

    opening in vscode...

    `);
        await UtilsVSCode__NS__openFile(this.project.linkedProjects.projectsDbLocation);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region filter all project branches by pattern
    __filterBranchesByPattern(branchPatternOrBranchName) {
        //#region @backendFunc
        const branches = HelpersTaon__NS__arrays__NS__uniqArray(this.project.git.getBranchesNamesBy(branchPatternOrBranchName) ||
            this.project.getMainBranches());
        // console.log('branches', branches);
        return branches;
        //#endregion
    }
    //#endregion
    //#region select branch from list of branches
    async __selectBranch(branches, task, commandActionType) {
        //#region @backendFunc
        const actionWithoutChildren = commandActionType === 'only-this';
        const childrenMsg = actionWithoutChildren
            ? '(without children)'
            : this.project.children.length == 0
                ? '(no children in project)'
                : `(with children${commandActionType === 'deep' ? ' (resursive deep)' : ''})`;
        return await HelpersTaon__NS__autocompleteAsk(`Choose branch to ${task} in this project ${childrenMsg}: `, branches.map(b => {
            return { name: b, value: b };
        }));
        //#endregion
    }
    //#endregion
    //#region commands / clone
    async clone() {
        //#region @backendFunc
        let url = this.firstArg;
        const originType = this.params['setOrigin'];
        if (originType) {
            if (originType === 'ssh') {
                url = HelpersTaon__NS__git__NS__originHttpToSsh(url);
            }
            if (originType === 'http') {
                url = HelpersTaon__NS__git__NS__originSshToHttp(url);
            }
        }
        await HelpersTaon__NS__git__NS__clone({
            url,
            cwd: this.cwd,
        });
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / gh temp
    async ghSave() {
        //#region @backendFunc
        await new GhTempCode(this.cwd, this.project).init().save();
        this._exit();
        //#endregion
    }
    async ghRestore() {
        //#region @backendFunc
        await new GhTempCode(this.cwd, this.project).init().restore();
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / start cli service ports worker
    async ports() {
        //#region @backendFunc
        await this.ins.portsWorker.terminalUI.infoScreen();
        //#endregion
    }
    /**
     * tnp startCliServicePortsWorker --restart
     */
    async startCliServicePortsWorker() {
        //#region @backendFunc
        await this.ins.portsWorker.cliStartProcedure({
            methodOptions: {
                calledFrom: 'terminal command',
                cliParams: {
                    ...this.params,
                    mode: BaseCLiWorkerStartMode.IN_CURRENT_PROCESS,
                },
            },
        });
        //#endregion
    }
    //#endregion
    //#region commands / wait for any key
    async waitForUserAnyKey() {
        //#region @backendFunc
        console.log('Press any key to exit...');
        await UtilsTerminal__NS__waitForUserAnyKey(async () => {
            console.log('Exiting...');
            this._exit();
        });
        //#endregion
    }
    //#endregion
    //#region commands / pause terminal
    pauseTerminal() {
        //#region @backendFunc
        HelpersTaon__NS__pressKeyAndContinue();
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / sleep terminal
    sleepTerminal() {
        //#region @backendFunc
        Helpers__NS__info(`Sleeping terminal for 1 second... before exit`);
        Helpers__NS__sleep(1);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / gh pages init
    async ghPagesInit() {
        //#region @backendFunc
        await this.project.init();
        await this.project.staticPages.init(this.params['provider'] || 'github', !!this.params['full']);
        await UtilsVSCode__NS__openFolder(this.project.staticPages.mainFolderAbsPath);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / is port in use
    async isPortInUse() {
        //#region @backendFunc
        const port = parseInt(this.firstArg);
        console.log(`Port ${port} is in use: ${await UtilsOs__NS__isPortInUse(port)}`);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / proc menu
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    /* */
    //#endregion
    //#region commands / proc info
    procInfo() {
        //#region @backendFunc
        this.processInfo();
        //#endregion
    }
    processInfo() {
        //#region @backendFunc
        Helpers__NS__info(`

    Is running in CLI mode: ${UtilsOs__NS__isRunningInCliMode()}
    Is running in Mocha test: ${UtilsOs__NS__isRunningInMochaTest()}
    Is running in VSCode extension: ${UtilsOs__NS__isRunningInVscodeExtension()}
    Is running in Electron: ${UtilsOs__NS__isRunningInElectron()}
    Is running in Docker: ${UtilsOs__NS__isRunningInDocker()}
    Is running in WebSQL: ${UtilsOs__NS__isRunningInWebSQL()}
    Is running in WSL: ${UtilsOs__NS__isRunningInWsl()}
    Is running in Linux graphics capable environment: ${UtilsOs__NS__isRunningInLinuxGraphicsCapableEnvironment()}
    Is running in Node: ${UtilsOs__NS__isRunningInNode()}
    Is running in Browser: ${UtilsOs__NS__isRunningInBrowser()}

      `);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / last git tag
    lastGitTag() {
        //#region @backendFunc
        console.log('Latest tag');
        console.log(this.project?.git.lastTagVersionName);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / check ports
    async checkPort() {
        //#region @backendFunc
        await this.checkPorts();
        //#endregion
    }
    async checkPorts() {
        //#region @backendFunc
        const ports = this.args
            .join(' ')
            .replace(/\,/, '')
            .split(' ')
            .map(p => {
            return parseInt(p);
        });
        console.log(`Checking ports: ${ports.join(', ')}`);
        if (ports.length === 0) {
            Helpers__NS__error(`No ports provided`, false, true);
        }
        for (const port of ports) {
            const isPortInUse = await UtilsOs__NS__isPortInUse(port);
            console.log(`Port ${port} is in use: ${isPortInUse ? chalk.red('YES') : chalk.green('NO')}`);
        }
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / symlink
    symlink() {
        //#region @backendFunc
        let [fromArg, toArg] = this.args;
        if (!path.isAbsolute(fromArg)) {
            fromArg = crossPlatformPath([
                this.cwd,
                fromArg.replace('./', '').replace('.\\', ''),
            ]);
        }
        if (!path.isAbsolute(toArg)) {
            toArg = crossPlatformPath([
                this.cwd,
                toArg.replace('./', '').replace('.\\', ''),
            ]);
        }
        if (Helpers__NS__isUnexistedLink(fromArg)) {
            Helpers__NS__error(`Source path "${fromArg}" is an unexisted link`, false, true);
        }
        if (!Helpers__NS__exists(fromArg)) {
            Helpers__NS__error(`Source path "${fromArg}" does not exist`, false, true);
        }
        fromArg = crossPlatformPath(fse.realpathSync(fromArg));
        if (path.basename(fromArg) !== path.basename(toArg)) {
            toArg = crossPlatformPath([toArg, path.basename(fromArg)]);
        }
        Helpers__NS__createSymLink(fromArg, toArg);
        Helpers__NS__info(`Symlink created from "${fromArg}" to "${toArg}"`);
        this._exit();
        //#endregion
    }
    //#endregion
    isSymlinkFileExitedOrUnexisted() {
        //#region @backendFunc
        const firstArg = crossPlatformPath(this.firstArg);
        const pathToFileOrFolder = path.isAbsolute(firstArg)
            ? firstArg
            : crossPlatformPath([this.cwd, firstArg]);
        console.log(`is Symlink File Exited Or Unexisted ${Helpers__NS__isSymlinkFileExitedOrUnexisted(pathToFileOrFolder)}`);
        this._exit();
        //#endregion
    }
    //#region commands / remove symlinks
    removeSymlinksDryRun() {
        //#region @backendFunc
        Helpers__NS__removeSymlinks(this.project.nodeModules.path, {
            dryRun: true,
        });
        //#endregion
    }
    //#endregion
    //#region commands / select java
    async selectJava() {
        //#region @backendFunc
        const selectedJava = await UtilsJava__NS__selectJdkVersion();
        UtilsJava__NS__updateJavaHomePath(selectedJava);
        //#endregion
    }
    //#endregion
    //#region commands / select tomcat
    async selectTomcat() {
        //#region @backendFunc
        const selectedTomcat = await UtilsJava__NS__selectTomcatVersion();
        UtilsJava__NS__updateTomcatHomePath(selectedTomcat);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / ln
    LN() {
        //#region @backendFunc
        const [source, dest] = this.args;
        Helpers__NS__createSymLink(source, dest);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / copy
    copy() {
        //#region @backendFunc
        let [from, to] = this.args;
        from = path.isAbsolute(from)
            ? crossPlatformPath(from)
            : crossPlatformPath([this.cwd, from]);
        to = path.isAbsolute(to)
            ? crossPlatformPath(to)
            : crossPlatformPath([this.cwd, to]);
        if (path.basename(to) !== path.basename(from)) {
            to = crossPlatformPath([to, path.basename(from)]);
        }
        Helpers__NS__taskStarted(`Copying from ${from} to ${to}`);
        if (!Helpers__NS__exists(from)) {
            Helpers__NS__error(`Source file or folder "${from}" does not exist`, false, true);
        }
        if (Helpers__NS__isFolder(from)) {
            HelpersTaon__NS__copy(from, to);
        }
        else {
            HelpersTaon__NS__copyFile(from, to);
        }
        Helpers__NS__taskDone(`Copied`);
        this._exit();
        //#endregion
    }
    //#endregion
    killAllCode() {
        return UtilsOs__NS__killAllEditor('code');
    }
    killAllCodium() {
        return UtilsOs__NS__killAllEditor('codium');
    }
    killAllCursor() {
        return UtilsOs__NS__killAllEditor('cursor');
    }
    killAllTheia() {
        return UtilsOs__NS__killAllEditor('theia');
    }
    killAllCodeOSS() {
        return UtilsOs__NS__killAllEditor('code-oss');
    }
    async editor() {
        //#region @backendFunc
        console.log(`Your current editor is: ${await this.ins.editor()}`);
        this._exit();
        //#endregion
    }
    async editorSettings() {
        //#region @backendFunc
        const editor = await this.ins.editor();
        console.log(`
      Your current editor is: ${editor}

      Your current editor settings path is:
       ${UtilsOs__NS__getEditorSettingsJsonPath(editor)}`);
        this._exit();
        //#endregion
    }
    //#region commands / simulate domain
    async simulateDomain() {
        //#region @backendFunc
        // UtilsTerminal__NS__clearConsole();
        const commandEvaluatedAsSudo = await this._runAsSudoIfNotElevated({
            globalCommandName: 'simulateDomain',
        });
        if (!commandEvaluatedAsSudo) {
            await UtilsEtcHosts__NS__simulateDomain(this.args);
        }
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / preview
    async preview() {
        //#region @backendFunc
        //#region handle preview of docker compose
        if ([fileName.docker_compose_yml, fileName.compose_yml].includes(path.basename(this.firstArg))) {
            const simulateDomain = this.params['domain'] || this.params['domains'];
            const firstArg = path.isAbsolute(this.firstArg)
                ? this.firstArg
                : crossPlatformPath([this.cwd, this.firstArg]);
            const cwd = crossPlatformPath(path.dirname(firstArg));
            const composeFileName = path.basename(firstArg);
            //   import { spawn } from 'child_process';
            //   import { readFileSync } from 'fs';
            //   import { resolve } from 'path';
            const envPath = crossPlatformPath([cwd, '.env']);
            const COMPOSE_PROJECT_NAME = UtilsDotFile__NS__getValueFromDotFile(envPath, 'COMPOSE_PROJECT_NAME');
            const envContent = UtilsDotFile__NS__getValuesKeysAsJsonObject(envPath) || {};
            const allDomains = Utils__NS__uniqArray(Object.keys(envContent)
                .filter(key => {
                return key.startsWith('FRONTEND_HOST_URL_');
            })
                .map(domainKey => envContent[domainKey]));
            if (simulateDomain && allDomains.length === 0) {
                Helpers__NS__error(`No domains to simulate found in .env file.

          Before release build update your

          env.ts or env.angular-node-app.ENVIRONTMENT_NAME.ts with

          ${chalk.bold(`website.useDomain = true;`)}

          `, false, true);
            }
            const project = this.ins.From(cwd);
            await project.docker.updateDockerComposePorts();
            let closing = false;
            const triggerRevertChangesToEtcHosts = new Subject();
            if (simulateDomain) {
                await UtilsNetwork__NS__simulateDomain(allDomains, {
                    triggerRevertChangesToEtcHosts,
                });
            }
            const child = project.docker.getDockerComposeActionChildProcess('up');
            console.log(`

     ${chalk.bold('PRESS ANY KEY TO STOP')} RUNNING CONTAINER(S) ` +
                `FOR ${chalk.bold.underline(COMPOSE_PROJECT_NAME)}
  ${simulateDomain
                    ? `AND SIMULATING DOMAINS: ${allDomains.join(', ')} IN ETC/HOST`
                    : ''}

  `);
            process.stdin.setRawMode(true);
            process.stdin.resume();
            process.stdin.on('data', () => {
                if (closing) {
                    return;
                }
                // If we are already closing, ignore further input
                closing = true;
                triggerRevertChangesToEtcHosts.next();
                console.log('Stopping container...');
                // TODO probably UtilsProcess__NS__killProcess() better
                child.kill('SIGINT');
                console.log('Exiting...');
                const downProcess = project.docker.getDockerComposeActionChildProcess('down');
                downProcess.on('close', code => {
                    console.log(`docker compose down exited with code ${code}`);
                    process.exit(0);
                });
            });
        }
        else {
            Helpers__NS__error(`You can preview only docker-compose.yml or compose.yml files`, false, true);
        }
        //#endregion
        //#endregion
    }
    //#endregion
    //#region commands / shorten
    /**
     * read huge file and display only lines with specyfic words
     */
    async shorten() {
        //#region @backendFunc
        const rl = readline.createInterface({
            input: fse.createReadStream(path.isAbsolute(this.firstArg)
                ? crossPlatformPath(this.firstArg)
                : crossPlatformPath([this.cwd, this.firstArg]), { encoding: 'utf8' }),
            crlfDelay: Infinity,
        });
        const keywords = this.args.splice(1);
        console.log(`Searching for keywords: ${keywords.join(', ')}`);
        for await (const line of rl) {
            if (keywords.some(word => line.includes(word))) {
                console.log(line);
            }
        }
        Helpers__NS__info(`File processed`);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / dump packages versions
    dumpPackagesVersions() {
        //#region @backendFunc
        const getData = (location) => {
            const version = HelpersTaon__NS__readValueFromJson(crossPlatformPath([location, fileName.package_json]), 'version');
            const name = HelpersTaon__NS__readValueFromJson(crossPlatformPath([location, fileName.package_json]), 'name');
            return { version, name };
        };
        const pkgs = Helpers__NS__foldersFrom([this.cwd, folderName.node_modules], {
            recursive: false,
        })
            .reduce((arr, c) => {
            if (path.basename(c).startsWith('@')) {
                const newData = Helpers__NS__foldersFrom([
                    this.cwd,
                    folderName.node_modules,
                    path.basename(c),
                ]).map(c2 => getData(c2));
                return arr.concat(newData);
            }
            return arr.concat(getData(c));
        }, [])
            .reduce((arr, c) => {
            return ___NS__merge(arr, { [c.name]: c.version });
        }, {});
        Helpers__NS__writeJson([this.cwd, 'packages-versions.json'], pkgs);
        Helpers__NS__info(`packages-versions.json created with ${pkgs.length} packages`);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / zip
    async zip() {
        //#region @backendFunc
        let folderPath = crossPlatformPath(this.firstArg);
        if (!path.isAbsolute(folderPath)) {
            folderPath = crossPlatformPath([this.cwd, this.firstArg]);
        }
        if (!Helpers__NS__exists(folderPath)) {
            Helpers__NS__error(`File or folder to zip does not exist: ${folderPath}`, false, true);
        }
        if (!Helpers__NS__isFolder(folderPath)) {
            Helpers__NS__error(`You can zip only folders. Provided path is not a folder: ${folderPath}`, false, true);
        }
        const zipFilePath = await UtilsZip__NS__zipDir(folderPath, {
            overrideIfZipFileExists: true,
        });
        Helpers__NS__info(`Created zip file: ${zipFilePath}`);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / unzip
    async unzip() {
        //#region @backendFunc
        let folderPath = crossPlatformPath(this.firstArg);
        if (!path.isAbsolute(folderPath)) {
            folderPath = crossPlatformPath([this.cwd, this.firstArg]);
        }
        if (!Helpers__NS__exists(folderPath)) {
            Helpers__NS__error(`File or folder to zip does not exist: ${folderPath}`, false, true);
        }
        await UtilsZip__NS__unzipArchive(folderPath);
        Helpers__NS__info(`Created zip file: ${folderPath.replace('.zip', '')}`);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / start transmission
    async startTransmission() {
        //#region @backendFunc
        await this._removeTransmission();
        const userProfile = process.env.USERPROFILE || os.homedir();
        const downloadsDir = path.join(userProfile, 'Downloads');
        const configDir = path.join(userProfile, 'transmission-config');
        await UtilsProcess__NS__killProcessOnPort(9091);
        const ctrl = await this.ins.portsWorker.getRemoteControllerFor({
            methodOptions: {
                calledFrom: `${config.frameworkName} startTransmission`,
            },
        });
        const data = await ctrl
            .registerAndAssignPort('transmission service for whole system')
            .request();
        const mainPort = data.body.json.port;
        Helpers__NS__info(`Transmission will use port: ${mainPort}`);
        const args = [
            'run',
            '-d',
            '--name',
            'transmission',
            '-p',
            '9091:9091',
            '-p',
            `${mainPort}:${mainPort}`,
            '-p',
            `${mainPort}:${mainPort}/udp`,
            '-e',
            'TZ=Europe/Warsaw',
            '-e',
            `TRANSMISSION_PEER_PORT=${mainPort}`,
            '-v',
            `${downloadsDir}:/downloads`,
            '-v',
            `${configDir}:/config`,
            '--restart',
            'unless-stopped',
            'linuxserver/transmission:latest',
        ];
        console.log('Running:', 'docker', args.join(' '));
        const child = child_process.spawn('docker', args, { stdio: 'inherit' });
        child.on('exit', code => {
            if (code === 0) {
                console.log('✅ Transmission container started');
                console.log('➡ Open http://localhost:9091 in your browser');
            }
            else {
                console.error('❌ Docker exited with code', code);
            }
            this._exit();
        });
        //#endregion
    }
    async _removeTransmission() {
        //#region @backendFunc
        return new Promise(resolve => {
            const args = ['rm', '-f', 'transmission'];
            console.log('Running:', 'docker', args.join(' '));
            const child = child_process.spawn('docker', args, { stdio: 'inherit' });
            child.on('exit', code => {
                if (code === 0) {
                    console.log('🗑️  Transmission container removed');
                }
                else {
                    // In bash `2>$null` would silence errors; here we just log a note
                    console.warn('⚠️ Could not remove container (maybe it doesn’t exist)');
                }
                resolve();
            });
        });
        //#endregion
    }
    //#endregion
    //#region commands  / backup branch
    async backupBranch() {
        //#region @backendFunc
        await this.project.git.backupBranch(this.firstArg);
        this._exit();
        //#endregion
    }
    async bb() {
        //#region @backendFunc
        await this.backupBranch();
        //#endregion
    }
    //#endregion
    //#region commands / count code lines
    async countCodeLines() {
        //#region @backendFunc
        await this.countLines();
        //#endregion
    }
    async countCode() {
        //#region @backendFunc
        await this.countLines();
        //#endregion
    }
    async countLines() {
        //#region @backendFunc
        let extensions = (this.args || []).filter(f => !!f).map(ext => `.${ext}`);
        extensions = extensions.length
            ? extensions
            : ['.ts', '.tsx', '.html', '.scss'];
        UtilsLineCount__NS__forPorject(this.project, {
            extensionsOnly: extensions,
            displayInfoChildren: true,
        });
        this._exit(); // your existing exit hook
        //#endregion
    }
    //#endregion
    //#region commands / is node version ok
    isNodeVersionOk() {
        //#region @backendFunc
        try {
            UtilsOs__NS__isNodeVersionOk({
                throwErrorIfNotOk: true,
            });
            console.info(`Node.js version is OK: ${process.version}`);
            this._exit();
        }
        catch (error) {
            console.error(error);
            this._exit(1);
        }
        //#endregion
    }
    //#endregion
    //#region commands / pwd
    pwd() {
        config.frameworkName = 'taon';
        console.log(crossPlatformPath(this.cwd));
        this._exit();
    }
    //#endregion
    //#region commands / less-more big text files preview
    async more() {
        //#region @backendFunc
        const pathToFile = path.isAbsolute(this.firstArg)
            ? crossPlatformPath(this.firstArg)
            : crossPlatformPath([this.cwd, this.firstArg]);
        console.log(`Displaying file: ${pathToFile}`);
        await UtilsTerminal__NS__previewLongListGitLogLike(Helpers__NS__readFile(pathToFile) || '< empty log file >');
        this._exit();
        //#endregion
    }
    async less() {
        //#region @backendFunc
        await this.more();
        //#endregion
    }
    //#endregion
    //#region commands / mp3
    /**
     *  npm install --global bin-version-check-cli
     *  npm i -g yt-dlp
     *  choco install ffmpeg
     */
    MP3() {
        //#region @backendFunc
        const downloadPath = crossPlatformPath([
            UtilsOs__NS__getRealHomeDir(),
            'Downloads',
            'mp3-from-websites',
        ]);
        if (!Helpers__NS__exists(downloadPath)) {
            Helpers__NS__mkdirp(downloadPath);
        }
        Helpers__NS__run(`cd ${downloadPath} && yt-dlp --verbose --extract-audio --audio-format mp3 ` +
            this.args.join(' '), {
            output: true,
            cwd: downloadPath,
        }).sync();
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / mp4
    MP4(args) {
        //#region @backendFunc
        const downloadPath = crossPlatformPath([
            UtilsOs__NS__getRealHomeDir(),
            'Downloads',
            'mp4-from-websites',
        ]);
        // yt-dlp --print filename -o "%(uploader)s-%(upload_date)s-%(title)s.%(ext)s"
        Helpers__NS__run('yt-dlp --verbose  -S "res:1080,fps" -f "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" ' +
            this.args.join(' '), {
            output: true,
            cwd: downloadPath,
        }).sync();
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / gif from video
    gif() {
        //#region @backendFunc
        const cwdToProcess = path.isAbsolute(this.firstArg)
            ? path.dirname(this.firstArg)
            : this.cwd;
        const basenameToProcess = path.basename(this.firstArg);
        const gifDownloadPath = crossPlatformPath([
            UtilsOs__NS__getRealHomeDir(),
            'Downloads',
            'gif-from-videos',
            basenameToProcess.replace(path.extname(basenameToProcess), '.gif'),
        ]);
        const palleteBasename = `${___NS__kebabCase(path.basename(gifDownloadPath))}-palette.png`;
        Helpers__NS__removeFileIfExists([cwdToProcess, palleteBasename]);
        const quality = `fps=10,scale=960`;
        Helpers__NS__info(`Preparing gif from video (creating palette)...`);
        Helpers__NS__run(`ffmpeg -i ${basenameToProcess} -vf "${quality}:-1:flags=lanczos,palettegen"` +
            ` ${palleteBasename} `, {
            output: true,
            cwd: cwdToProcess,
        }).sync();
        Helpers__NS__info(`Preparing gif from video (creating video)...`);
        Helpers__NS__run(`ffmpeg -i ${basenameToProcess} -i ` +
            ` ${palleteBasename}  -filter_complex ` +
            `"${quality}:-1:flags=lanczos[x];[x][1:v]paletteuse" ${path.basename(gifDownloadPath)}`, {
            output: true,
            cwd: cwdToProcess,
        }).sync();
        Helpers__NS__removeFileIfExists(gifDownloadPath);
        HelpersTaon__NS__move(crossPlatformPath([cwdToProcess, path.basename(gifDownloadPath)]), gifDownloadPath);
        Helpers__NS__taskDone(`Done creating gif from video:

      ${gifDownloadPath}

      `);
        Helpers__NS__openFolderInFileExplorer(path.dirname(gifDownloadPath));
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / kill zscaller
    killZs() {
        //#region @backendFunc
        this.killZscaller();
        //#endregion
    }
    startZs() {
        //#region @backendFunc
        this.startZscaller();
        //#endregion
    }
    zsKill() {
        //#region @backendFunc
        this.killZscaller();
        //#endregion
    }
    zsStart() {
        //#region @backendFunc
        this.startZscaller();
        //#endregion
    }
    startZscaller() {
        //#region @backendFunc
        const commands = [
            // `open -a /Applications/Zscaler/Zscaler.app --hide`,
            `open -a /Applications/Zscaler/Zscaler.app`,
            `sudo find /Library/LaunchDaemons -name '*zscaler*' -exec launchctl load {} \\;`,
        ];
        for (const cmd of commands) {
            try {
                Helpers__NS__run(cmd, {
                    // stdio that will let me pass password in child process
                    stdio: 'inherit',
                }).sync();
            }
            catch (error) { }
        }
        Helpers__NS__info(`Zscaller started`);
        this._exit();
        //#endregion
    }
    killZscaller() {
        //#region @backendFunc
        const commands = [
            `find /Library/LaunchAgents -name '*zscaler*' -exec launchctl unload {} \\;`,
            `sudo find /Library/LaunchDaemons -name '*zscaler*' -exec launchctl unload {} \\;`,
            `sudo killall -9 Zscaler ZscalerTunnel ZscalerAppServices`,
        ];
        for (const cmd of commands) {
            try {
                Helpers__NS__run(cmd, {
                    // stdio that will let me pass password in child process
                    stdio: 'inherit',
                }).sync();
            }
            catch (error) { }
        }
        Helpers__NS__info(`Zscaller killed`);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / has command
    async hasCommand() {
        //#region @backendFunc
        if (!this.firstArg) {
            Helpers__NS__error(`You need to provide command name to check`, false, true);
        }
        const hasSudo = await UtilsOs__NS__commandExistsAsync(this.firstArg);
        console.log(`[ASYNC] Your os has "${this.firstArg}" command: ${hasSudo}`);
        this._exit();
        //#endregion
    }
    hasCommandSync() {
        //#region @backendFunc
        if (!this.firstArg) {
            Helpers__NS__error(`You need to provide command name to check`, false, true);
        }
        const hasSudo = UtilsOs__NS__commandExistsSync(this.firstArg);
        console.log(`[sync version] Your os has "${this.firstArg}" command: ${hasSudo}`);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / public ip address
    async publicIpAddress() {
        const ip = await UtilsNetwork__NS__getCurrentPublicIpAddress();
        console.log(`Your public IP address is: ${ip}`);
        this._exit();
    }
    async publicIp() {
        //#region @backendFunc
        await this.publicIpAddress();
        //#endregion
    }
    //#endregion
    //#region commands / open origins in vscode
    async localIps() {
        const firstActiveLocalIp = await UtilsNetwork__NS__getFirstIpV4LocalActiveIpAddress();
        console.log(`Your first active local IP address is: ${firstActiveLocalIp} `);
        const ips = await UtilsNetwork__NS__getLocalIpAddresses();
        for (let index = 0; index < ips.length; index++) {
            const ip = ips[index];
            // console.log(ip);
            console.log(`${index + 1}. Local IP address is: ` +
                `${ip.address}, type: ${ip.type}`);
        }
        this._exit();
    }
    //#endregion
    //#region commands / is online
    async isOnline() {
        //#region @backendFunc
        const pingIsOK = await UtilsNetwork__NS__checkIfServerPings(this.firstArg);
        const checkIfServerIsOnline = await UtilsNetwork__NS__checkIfServerOnline(this.firstArg);
        console.log(`Server ${this.firstArg}

    is ping ok ?: ${pingIsOK}
    is socket connection ok ? : ${checkIfServerIsOnline}

    `);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / configure bash and shell
    async configureBash() {
        // ! TODO @UNCOMMENT
        // await UtilsTerminal.configureBashOrShell();
    }
    async configureShell() {
        // ! TODO @UNCOMMENT
        // await UtilsTerminal.configureBashOrShell();
    }
    confBash() {
        this.configureBash();
    }
    confShell() {
        this.configureShell();
    }
    //#endregion
    //#region commands / git reset all
    gitResetAll() {
        //#region @backendFunc
        Helpers__NS__taskStarted(`Resetting git repo in project and all children to last commit...`);
        this.project.git.resetHard();
        const children = this.project.children;
        for (const child of children) {
            Helpers__NS__info(`Resetting child project: ${child.name}`);
            child.git.resetHard();
        }
        Helpers__NS__taskDone(`Git reset --hard completed in project and all children`);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / is elevated
    async isElevated() {
        //#region @backendFunc
        console.log(`Is running with elevated privileges (sudo/admin): ${await isElevated()}`);
        this._exit();
        //#endregion
    }
    //#endregion
    //#region commands / sudo check
    async sudoCheck() {
        const sudoStatus = await UtilsSudo__NS__getStatus();
        console.log('is command available', sudoStatus.isAvailable);
        console.log('is inline sudo enable', sudoStatus.isInline);
        console.log('is this command elevated (sudo or admin)', await isElevated());
        this._exit();
    }
    //#endregion
    //#region commands / python modules exists
    async pythonModuleExists() {
        //#region @backendFunc
        const moduleName = this.firstArg;
        if (!moduleName) {
            Helpers__NS__error(`You need to provide python module name to check`, false, true);
        }
        let exists = await UtilsOs__NS__pythonModuleExists(moduleName);
        if (!exists) {
            Helpers__NS__warn(`Module not found in global python packages, checking pipx packages...`);
            exists = await UtilsOs__NS__pipxPackageExists(moduleName);
        }
        console.log(`Python module "${moduleName}" exists: ${exists ? 'YES' : 'NO'}`);
        this._exit();
        //#endregion
    }
    //#endregion
    splitNamespaces() {
        this.splitNamespace();
    }
    splitNamespace() {
        //#region @backendFunc
        let namespacePath = path.isAbsolute(this.firstArg)
            ? crossPlatformPath(this.firstArg)
            : crossPlatformPath([process.cwd(), this.firstArg]);
        const splitData = UtilsTypescript__NS__splitNamespaceForContent(Helpers__NS__readFile(namespacePath));
        UtilsFilesFoldersSync__NS__writeFile(namespacePath.replace('.ts', '.split-namespace.ts'), splitData.content);
        UtilsTypescript__NS__formatFile(namespacePath.replace('.ts', '.split-namespace.ts'));
        Helpers__NS__writeJson(namespacePath.replace('.ts', '.split-namespace.json'), {
            namespacesMapObj: splitData.namespacesMapObj,
            namespacesReplace: splitData.namespacesReplace,
        });
        Helpers__NS__info(`Done`);
        this._exit();
        //#endregion
    }
    normalizeBrokenLines() {
        //#region @backendFunc
        let namespacePath = path.isAbsolute(this.firstArg)
            ? crossPlatformPath(this.firstArg)
            : crossPlatformPath([process.cwd(), this.firstArg]);
        const splitData = UtilsTypescript__NS__normalizeBrokenLines(Helpers__NS__readFile(namespacePath));
        UtilsFilesFoldersSync__NS__writeFile(namespacePath, splitData);
        Helpers__NS__info(`Done`);
        this._exit();
        //#endregion
    }
    //#region split ts into js
    async stripTsTypesIntoJs() {
        Helpers__NS__info('Transforming Ts into JS');
        await HelpersTaon__NS__stripTsTypesIntoJs(crossPlatformPath([this.cwd, this.args[0]]), crossPlatformPath([this.cwd, this.args[1]]));
        this._exit();
    }
}
//# sourceMappingURL=c:/Users/darek/projects/npm/taon-dev/tnp-helpers/dist-nocutsrc-prod/lib/base/classes/base-global-command-line.js.map