monorepotime 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.httpServer = exports.io = exports.app = void 0;
41
+ const express_1 = __importDefault(require("express"));
42
+ const cors_1 = __importDefault(require("cors"));
43
+ const path_1 = __importDefault(require("path"));
44
+ const apiroute_1 = __importDefault(require("apiroute"));
45
+ const config_1 = __importDefault(require("config"));
46
+ const open_1 = __importDefault(require("open"));
47
+ const http_1 = require("http");
48
+ const socket_io_1 = require("socket.io");
49
+ //routers
50
+ const scanworkspace_1 = __importDefault(require("./routes/scanworkspace"));
51
+ const runcmddev_1 = __importDefault(require("./routes/runcmddev"));
52
+ const stopcmd_1 = __importDefault(require("./routes/stopcmd"));
53
+ const listworkspacedirs_1 = __importDefault(require("./routes/listworkspacedirs"));
54
+ const newworkspace_1 = __importDefault(require("./routes/newworkspace"));
55
+ const interactiveTerminal_1 = __importStar(require("./routes/interactiveTerminal"));
56
+ const updateworkspace_1 = __importDefault(require("./routes/updateworkspace"));
57
+ const vscodeHideShow_1 = __importDefault(require("./routes/vscodeHideShow"));
58
+ const rootPath_1 = __importDefault(require("./routes/rootPath"));
59
+ const scafoldrepo_1 = __importDefault(require("./routes/scafoldrepo"));
60
+ const turborepoexist_1 = __importDefault(require("./routes/turborepoexist"));
61
+ const app = (0, express_1.default)();
62
+ exports.app = app;
63
+ const port = config_1.default.apiPort;
64
+ app.use((0, cors_1.default)({
65
+ origin: true,
66
+ credentials: true,
67
+ }));
68
+ app.use(express_1.default.static('public'));
69
+ app.use(express_1.default.json());
70
+ // Serve frontend static files
71
+ //routes=======================================================================
72
+ app.use("/" + apiroute_1.default.scanWorkspace, scanworkspace_1.default);
73
+ app.use("/" + apiroute_1.default.stopProcess, stopcmd_1.default);
74
+ app.use("/" + apiroute_1.default.listWorkspacesDir, listworkspacedirs_1.default);
75
+ app.use("/" + apiroute_1.default.newWorkspace, newworkspace_1.default);
76
+ app.use("/" + apiroute_1.default.interactvTerminal, interactiveTerminal_1.default);
77
+ app.use("/" + apiroute_1.default.updateWorkspace, updateworkspace_1.default);
78
+ app.use("/" + apiroute_1.default.hideShowFileFolder, vscodeHideShow_1.default);
79
+ app.use("/" + apiroute_1.default.getRootPath, rootPath_1.default);
80
+ app.use("/" + apiroute_1.default.scaffoldRepo, scafoldrepo_1.default);
81
+ app.use("/" + apiroute_1.default.turborepoExist, turborepoexist_1.default);
82
+ // Serve frontend static files==================================================
83
+ const frontendPath = path_1.default.join(__dirname, '../public');
84
+ app.use(express_1.default.static(frontendPath));
85
+ app.get('*', (req, res) => {
86
+ res.sendFile(path_1.default.join(frontendPath, 'index.html'));
87
+ });
88
+ // Socket.IO Setup ============================================================
89
+ const httpServer = (0, http_1.createServer)(app);
90
+ exports.httpServer = httpServer;
91
+ const io = new socket_io_1.Server(httpServer, {
92
+ cors: {
93
+ origin: "*",
94
+ methods: ["GET", "POST"],
95
+ },
96
+ transports: ['websocket', 'polling']
97
+ });
98
+ exports.io = io;
99
+ (0, runcmddev_1.default)(io);
100
+ (0, interactiveTerminal_1.interactiveTerminalSocket)(io);
101
+ //=============================================================================
102
+ httpServer.listen(port, () => {
103
+ console.log(`Server running at http://localhost:${port}`);
104
+ (0, open_1.default)(`http://localhost:${port}`);
105
+ });
106
+ exports.default = app;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const express_1 = require("express");
4
+ const router = (0, express_1.Router)();
5
+ router.get("/", async (req, res) => {
6
+ console.log('called');
7
+ res.send("Hello World!");
8
+ });
9
+ exports.default = router;
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.interactiveTerminalSocket = interactiveTerminalSocket;
4
+ const express_1 = require("express");
5
+ const child_process_1 = require("child_process");
6
+ const router = (0, express_1.Router)();
7
+ // Keep the router for potential future HTTP endpoints, though we primarily use sockets now
8
+ router.get("/", async (req, res) => {
9
+ res.send("Interactive Terminal Route");
10
+ });
11
+ exports.default = router;
12
+ // Map to store active terminal processes for each socket
13
+ const activeTerminals = new Map();
14
+ function interactiveTerminalSocket(io) {
15
+ io.on('connection', (socket) => {
16
+ socket.on('terminal:start', (data) => {
17
+ const { path, command } = data;
18
+ if (activeTerminals.has(socket.id)) {
19
+ const oldChild = activeTerminals.get(socket.id);
20
+ if (oldChild) {
21
+ // Remove all listeners to prevent 'exit' or 'data' events from the old process
22
+ // interfering with the new one or sending confusing logs.
23
+ oldChild.removeAllListeners();
24
+ oldChild.stdout?.removeAllListeners();
25
+ oldChild.stderr?.removeAllListeners();
26
+ oldChild.kill();
27
+ activeTerminals.delete(socket.id);
28
+ socket.emit('terminal:log', '\r\n\x1b[33m[System] Previous command terminated.\x1b[0m\r\n');
29
+ }
30
+ }
31
+ try {
32
+ const env = { ...process.env };
33
+ delete env.CI;
34
+ env.TERM = 'xterm-256color';
35
+ env.FORCE_COLOR = '1';
36
+ // Use PROMPT_COMMAND to force the PS1 prompt.
37
+ // This overrides any PS1 set by .bashrc which is sourced by the interactive shell.
38
+ // Format: [PATH] /current/path (newline) $
39
+ // \033[34m = Blue, \033[32m = Green, \033[0m = Reset
40
+ // We use \033 (octal) which is standard for bash PS1.
41
+ env.PROMPT_COMMAND = 'export PS1="\\[\\033[34m\\][PATH] \\[\\033[32m\\]\\w\\[\\033[0m\\]\\n$ ";';
42
+ let child;
43
+ if (process.platform === 'win32') {
44
+ // Windows does not support the python pty module.
45
+ // We fall back to standard spawn with shell: true.
46
+ // Interactivity might be limited (arrow keys might not work in some apps),
47
+ // but standard input/output should function.
48
+ socket.emit('terminal:log', '\x1b[33m[System] Windows detected. Running in compatible mode (limited interactivity).\x1b[0m\r\n');
49
+ const baseCMD = command.split(" ")[0];
50
+ const args = command.split(" ").slice(1);
51
+ child = (0, child_process_1.spawn)(baseCMD, args, {
52
+ cwd: path,
53
+ env: env,
54
+ shell: true,
55
+ stdio: ['pipe', 'pipe', 'pipe']
56
+ });
57
+ }
58
+ else {
59
+ // Linux/Mac: Use Python PTY bridge for full interactivity
60
+ env.CMD = command;
61
+ const pythonScript = `
62
+ import pty, sys, os
63
+
64
+ try:
65
+ cmd = os.environ.get('CMD')
66
+ if not cmd:
67
+ sys.exit(1)
68
+
69
+ # pty.spawn(argv) executes argv and connects stdin/stdout to pty
70
+ status = pty.spawn(['/bin/bash', '-c', 'stty cols 80 rows 24; ' + cmd])
71
+
72
+ if os.WIFEXITED(status):
73
+ sys.exit(os.WEXITSTATUS(status))
74
+ else:
75
+ sys.exit(1)
76
+ except ImportError:
77
+ sys.exit(127) # Return special code if pty module missing (unlikely on unix)
78
+ except Exception as e:
79
+ sys.exit(1)
80
+ `;
81
+ child = (0, child_process_1.spawn)('python3', ['-u', '-c', pythonScript], {
82
+ cwd: path,
83
+ env: env,
84
+ stdio: ['pipe', 'pipe', 'pipe']
85
+ });
86
+ }
87
+ activeTerminals.set(socket.id, child);
88
+ child.stdout?.on('data', (chunk) => {
89
+ socket.emit('terminal:log', chunk.toString());
90
+ });
91
+ child.stderr?.on('data', (chunk) => {
92
+ socket.emit('terminal:log', chunk.toString());
93
+ });
94
+ child.on('error', (err) => {
95
+ if (err.code === 'ENOENT' && process.platform !== 'win32') {
96
+ socket.emit('terminal:error', '\r\n\x1b[31mError: Python3 is required for interactive mode on Linux/Mac but was not found.\x1b[0m');
97
+ }
98
+ else {
99
+ socket.emit('terminal:error', `Failed to start command: ${err.message}`);
100
+ }
101
+ cleanup(socket.id);
102
+ });
103
+ child.on('exit', (code) => {
104
+ // Check for our custom "Python missing pty" code or general failure logic
105
+ if (code === 127 && process.platform !== 'win32') {
106
+ socket.emit('terminal:error', '\r\n\x1b[31mError: Python PTY module issue.\x1b[0m');
107
+ }
108
+ else if (code !== 0) {
109
+ socket.emit('terminal:error', `\r\nProcess exited with code ${code}`);
110
+ }
111
+ else {
112
+ //socket.emit('terminal:log', `\r\nProcess finished successfully.`);
113
+ }
114
+ socket.emit('terminal:exit', code);
115
+ cleanup(socket.id);
116
+ });
117
+ }
118
+ catch (error) {
119
+ socket.emit('terminal:error', `Error handling command: ${error.message}`);
120
+ cleanup(socket.id);
121
+ }
122
+ });
123
+ socket.on('terminal:input', (input) => {
124
+ const child = activeTerminals.get(socket.id);
125
+ if (child && child.stdin) {
126
+ // With PTY bridge, we send raw input. PTY handles newlines/signals.
127
+ child.stdin.write(input);
128
+ }
129
+ });
130
+ socket.on('disconnect', () => {
131
+ const child = activeTerminals.get(socket.id);
132
+ if (child) {
133
+ // Remove listeners so we don't try to emit 'exit' or 'error' to a disconnected socket
134
+ child.removeAllListeners();
135
+ child.stdout?.removeAllListeners();
136
+ child.stderr?.removeAllListeners();
137
+ child.kill(); // Kill the process if client disconnects
138
+ activeTerminals.delete(socket.id);
139
+ }
140
+ });
141
+ function cleanup(socketId) {
142
+ activeTerminals.delete(socketId);
143
+ }
144
+ });
145
+ }
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = require("express");
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const router = (0, express_1.Router)();
10
+ const START_DIR = process.cwd();
11
+ // Find the monorepo root (where package.json with "workspaces" is defined)
12
+ // If not found, default to START_DIR
13
+ const findRoot = async (dir) => {
14
+ const pkgPath = path_1.default.join(dir, 'package.json');
15
+ if (await fs_extra_1.default.pathExists(pkgPath)) {
16
+ try {
17
+ const pkg = await fs_extra_1.default.readJSON(pkgPath);
18
+ // If "workspaces" is defined, we assume this is the root
19
+ if (pkg.workspaces) {
20
+ return dir;
21
+ }
22
+ }
23
+ catch {
24
+ // ignore
25
+ }
26
+ }
27
+ const parent = path_1.default.dirname(dir);
28
+ if (parent === dir)
29
+ return START_DIR;
30
+ return findRoot(parent);
31
+ };
32
+ router.get("/", async (req, res) => {
33
+ res.header("Access-Control-Allow-Origin", "*");
34
+ try {
35
+ const rootPath = await findRoot(START_DIR);
36
+ const pkgPath = path_1.default.join(rootPath, 'package.json');
37
+ let workspaceDirs = [];
38
+ let foundWorkspaces = false;
39
+ // 1. Try to read "workspaces" from package.json
40
+ if (await fs_extra_1.default.pathExists(pkgPath)) {
41
+ const pkg = await fs_extra_1.default.readJSON(pkgPath);
42
+ let globs = [];
43
+ if (pkg.workspaces) {
44
+ if (Array.isArray(pkg.workspaces)) {
45
+ globs = pkg.workspaces;
46
+ }
47
+ else if (pkg.workspaces.packages && Array.isArray(pkg.workspaces.packages)) {
48
+ globs = pkg.workspaces.packages;
49
+ }
50
+ }
51
+ if (globs.length > 0) {
52
+ foundWorkspaces = true;
53
+ const uniqueDirs = new Set();
54
+ for (const pattern of globs) {
55
+ // Pattern examples: "apps/*", "packages/*", "libs/my-lib"
56
+ // We want the top-level folder, e.g. "apps", "packages", "libs"
57
+ const parts = pattern.split('/');
58
+ if (parts.length > 0) {
59
+ const topLevel = parts[0];
60
+ // filter out if the pattern was just "*" (unlikely but possible) or empty
61
+ if (topLevel && topLevel !== '*') {
62
+ uniqueDirs.add(topLevel);
63
+ }
64
+ }
65
+ }
66
+ for (const dirName of uniqueDirs) {
67
+ const fullPath = path_1.default.join(rootPath, dirName);
68
+ if (await fs_extra_1.default.pathExists(fullPath)) {
69
+ workspaceDirs.push({
70
+ label: dirName,
71
+ path: fullPath
72
+ });
73
+ }
74
+ }
75
+ }
76
+ }
77
+ // 2. If no workspaces defined, fallback to scanning root
78
+ if (!foundWorkspaces) {
79
+ const items = await fs_extra_1.default.readdir(rootPath, { withFileTypes: true });
80
+ workspaceDirs = items
81
+ .filter(item => item.isDirectory())
82
+ .filter(item => {
83
+ const name = item.name;
84
+ // Exclude node_modules
85
+ if (name === 'node_modules')
86
+ return false;
87
+ // Exclude hidden fs (start with .)
88
+ if (name.startsWith('.'))
89
+ return false;
90
+ // Exclude folders starting with _
91
+ if (name.startsWith('_'))
92
+ return false;
93
+ return true;
94
+ })
95
+ .map(item => ({
96
+ label: item.name,
97
+ path: path_1.default.join(rootPath, item.name)
98
+ }));
99
+ }
100
+ return res.json(workspaceDirs);
101
+ }
102
+ catch (e) {
103
+ console.error("Error listing workspaces:", e);
104
+ res.status(500).json({ error: e.message });
105
+ }
106
+ });
107
+ exports.default = router;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = require("express");
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const router = (0, express_1.Router)();
10
+ router.post("/", async (req, res) => {
11
+ res.header("Access-Control-Allow-Origin", "*");
12
+ try {
13
+ const reqBody = req.body;
14
+ const targetPath = reqBody.path;
15
+ if (!targetPath) {
16
+ return res.status(400).json({ error: "Path is required" });
17
+ }
18
+ await fs_extra_1.default.ensureDir(targetPath);
19
+ const packageJson = {
20
+ name: reqBody.name || path_1.default.basename(targetPath),
21
+ version: "1.0.0",
22
+ description: reqBody.description || "",
23
+ fontawesomeIcon: reqBody.fontawesomeIcon || "",
24
+ scripts: {
25
+ dev: reqBody.devCommand || "",
26
+ start: reqBody.startCommand || undefined,
27
+ stop: reqBody.stopCommand || undefined,
28
+ build: reqBody.buildCommand || undefined,
29
+ clean: reqBody.cleanCommand || undefined,
30
+ lint: reqBody.lintCommand || undefined,
31
+ test: reqBody.testCommand || undefined
32
+ }
33
+ };
34
+ Object.keys(packageJson.scripts).forEach(key => packageJson.scripts[key] === undefined && delete packageJson.scripts[key]);
35
+ await fs_extra_1.default.writeJSON(path_1.default.join(targetPath, "package.json"), packageJson, { spaces: 2 });
36
+ res.json({ message: "Workspace created successfully", path: targetPath });
37
+ }
38
+ catch (e) {
39
+ console.error("Error creating workspace:", e);
40
+ res.status(500).json({ error: e.message });
41
+ }
42
+ });
43
+ exports.default = router;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ROOT = void 0;
7
+ exports.findMonorepoRoot = findMonorepoRoot;
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const express_1 = require("express");
11
+ const START_DIR = process.cwd();
12
+ function findMonorepoRoot(startDir) {
13
+ let dir = startDir;
14
+ while (dir !== path_1.default.dirname(dir)) {
15
+ const pkgPath = path_1.default.join(dir, "package.json");
16
+ if (fs_extra_1.default.existsSync(pkgPath)) {
17
+ try {
18
+ const pkg = fs_extra_1.default.readJsonSync(pkgPath);
19
+ if (pkg.workspaces) {
20
+ return dir;
21
+ }
22
+ }
23
+ catch (e) {
24
+ // Ignore errors
25
+ }
26
+ }
27
+ dir = path_1.default.dirname(dir);
28
+ }
29
+ return startDir;
30
+ }
31
+ exports.ROOT = findMonorepoRoot(START_DIR);
32
+ const route = (0, express_1.Router)();
33
+ route.get("/", async (req, res) => {
34
+ res.json({ path: exports.ROOT });
35
+ });
36
+ exports.default = route;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.sockets = exports.activeProcesses = void 0;
7
+ exports.default = runCmdDevSocket;
8
+ const child_process_1 = require("child_process");
9
+ const chalk_1 = __importDefault(require("chalk"));
10
+ exports.activeProcesses = new Map();
11
+ exports.sockets = new Map();
12
+ function runCmdDevSocket(io) {
13
+ io.on('connection', (socket) => {
14
+ socket.on('run', (data) => {
15
+ exports.sockets.set(data.workspace.name, socket);
16
+ try {
17
+ handleOnRun(socket, data);
18
+ }
19
+ catch (error) {
20
+ socket.emit('error', {
21
+ message: error
22
+ });
23
+ }
24
+ });
25
+ });
26
+ }
27
+ async function handleOnRun(socket, data) {
28
+ const { workspace, runas } = data;
29
+ if (exports.activeProcesses.has(workspace.name))
30
+ return socket.emit("log", "Attached to already running process...");
31
+ const commandToRun = runas === "dev" ? workspace.devCommand : workspace.startCommand;
32
+ if (!commandToRun)
33
+ throw new Error("No command to run");
34
+ const baseCMD = commandToRun.split(" ")[0];
35
+ const args = commandToRun.split(" ").slice(1);
36
+ socket.emit('log', chalk_1.default.green(`${data.workspace.path}: ${commandToRun}`));
37
+ const child = (0, child_process_1.spawn)(baseCMD, args, {
38
+ cwd: workspace.path,
39
+ env: {
40
+ ...process.env,
41
+ TERM: 'dumb',
42
+ FORCE_COLOR: '1',
43
+ },
44
+ stdio: ['ignore', 'pipe', 'pipe'],
45
+ shell: true,
46
+ detached: process.platform !== 'win32'
47
+ });
48
+ exports.activeProcesses.set(workspace.name, child);
49
+ child.on('error', (error) => {
50
+ socket.emit('error', error.message);
51
+ });
52
+ child.stdout.on('data', (data) => {
53
+ socket.emit('log', data.toString());
54
+ });
55
+ child.stderr.on('data', (data) => {
56
+ socket.emit('error', data.toString());
57
+ });
58
+ child.on('exit', (code) => {
59
+ socket.emit('exit', `Process exited with code ${code}`);
60
+ });
61
+ }
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = require("express");
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const child_process_1 = require("child_process");
10
+ const rootPath_1 = require("./rootPath");
11
+ const router = (0, express_1.Router)();
12
+ router.get("/", async (req, res) => {
13
+ try {
14
+ const packageJsonPath = path_1.default.join(rootPath_1.ROOT, "package.json");
15
+ const turboJsonPath = path_1.default.join(rootPath_1.ROOT, "turbo.json");
16
+ // 1. Read package.json
17
+ if (!fs_extra_1.default.existsSync(packageJsonPath)) {
18
+ res.status(400).json({ error: "package.json not found in root" });
19
+ return; // Stop execution
20
+ }
21
+ const pkg = fs_extra_1.default.readJsonSync(packageJsonPath);
22
+ let pkgChanged = false;
23
+ // 2. Check Workspaces
24
+ if (!pkg.workspaces) {
25
+ pkg.workspaces = ["apps/*", "packages/*"];
26
+ pkgChanged = true;
27
+ }
28
+ // 3. Save package.json if workspaces changed (before install)
29
+ if (pkgChanged) {
30
+ fs_extra_1.default.writeJsonSync(packageJsonPath, pkg, { spaces: 2 });
31
+ }
32
+ // 4. Create directories
33
+ await fs_extra_1.default.ensureDir(path_1.default.join(rootPath_1.ROOT, 'apps'));
34
+ await fs_extra_1.default.ensureDir(path_1.default.join(rootPath_1.ROOT, 'packages'));
35
+ // 4.1 Create monorepotime.json if not exists
36
+ const monorepoTimePath = path_1.default.join(rootPath_1.ROOT, "monorepotime.json");
37
+ if (!fs_extra_1.default.existsSync(monorepoTimePath)) {
38
+ const defaultMonorepoTime = [
39
+ {
40
+ "category": "Internal CRUD Test",
41
+ "devurl": "http://localhost:3200",
42
+ "produrl": "http://superhost:3200",
43
+ "items": [
44
+ {
45
+ "label": "Ping the Tool Server",
46
+ "route": "/pingme",
47
+ "methods": "GET",
48
+ "description": "Ping the tool server to check if it is running.",
49
+ "sampleInput": "{}",
50
+ "suggested": [],
51
+ "expectedOutcome": "# You should see the word \"pong\" as a message \n\n{\n \"message\": \"pong\"\n}",
52
+ "availableFor": "public"
53
+ },
54
+ {
55
+ "label": "Check Post",
56
+ "route": "/pingpost",
57
+ "methods": "POST",
58
+ "description": "Send a POST request to check if it sending correctly",
59
+ "sampleInput": "{\n \"data\": \"test\",\n \"message\": \"test\"\n}",
60
+ "suggested": [
61
+ {
62
+ "name": "Customer Data",
63
+ "urlparams": "",
64
+ "content": "{\n \"name\": \"Demo Customer\",\n \"email\": \"CusRaRa@customer.com\",\n \"phone1\": \"123456789\",\n \"phone2\": \"987654321\",\n \"city\": \"randomw1\",\n \"state\": \"ultra state\",\n \"zip\": \"12345\",\n \"country\": \"mega country\",\n \"icon\": \"test icon\",\n \"gender\": \"female\",\n \"delivery_notes\": \"Make sure that it is packed correctly\"\n}"
65
+ }
66
+ ],
67
+ "expectedOutcome": "# Note \nYou should see the mirror of your inputs",
68
+ "availableFor": "public"
69
+ },
70
+ {
71
+ "label": "Check Stream",
72
+ "route": "/pingstream",
73
+ "methods": "STREAM",
74
+ "description": "Send a stream request to check if it sending correctly",
75
+ "sampleInput": "{ }",
76
+ "suggested": [
77
+ {
78
+ "name": "I Wandered Lonely as a Cloud",
79
+ "urlparams": "?poem=I%20Wandered%20Lonely%20as%20a%20Cloud",
80
+ "content": "{}"
81
+ },
82
+ {
83
+ "name": "The Sun Has Long Been Set",
84
+ "urlparams": "?poem=The%20Sun%20Has%20Long%20Been%20Set",
85
+ "content": "{}"
86
+ }
87
+ ],
88
+ "expectedOutcome": "# Note \nYou should see the stream of words",
89
+ "availableFor": "public"
90
+ }
91
+ ]
92
+ }
93
+ ];
94
+ fs_extra_1.default.writeJsonSync(monorepoTimePath, defaultMonorepoTime, { spaces: 4 });
95
+ }
96
+ // 5. Create turbo.json if not exists
97
+ if (!fs_extra_1.default.existsSync(turboJsonPath) || !pkg.devDependencies?.turbo) {
98
+ if (!fs_extra_1.default.existsSync(turboJsonPath)) {
99
+ const defaultTurbo = {
100
+ "$schema": "https://turbo.build/schema.json",
101
+ "pipeline": {
102
+ "build": {
103
+ "outputs": ["dist/**", ".next/**"]
104
+ },
105
+ "lint": {}
106
+ }
107
+ };
108
+ fs_extra_1.default.writeJsonSync(turboJsonPath, defaultTurbo, { spaces: 2 });
109
+ }
110
+ // 6. Commands
111
+ // Check if turbo is in devDependencies
112
+ const hasTurbo = pkg.devDependencies && pkg.devDependencies.turbo;
113
+ if (!hasTurbo) {
114
+ // installing turbo will install deps
115
+ await runCommand("npm install turbo -D", rootPath_1.ROOT);
116
+ }
117
+ else {
118
+ // just install to ensure workspaces are linked
119
+ await runCommand("npm install", rootPath_1.ROOT);
120
+ }
121
+ }
122
+ else {
123
+ // If everything existed, user requested "then npm install" implies we might still want to ensure state?
124
+ // But the prompt says: "if so [missing turbo.json or turbo dep], then ... then npm install".
125
+ // It also says "if the root package.json has no 'workspaces'... then npm install".
126
+ // To be safe, let's run npm install if we changed workspaces OR if we entered the 'turbo missing' block.
127
+ if (pkgChanged) {
128
+ await runCommand("npm install", rootPath_1.ROOT);
129
+ }
130
+ }
131
+ res.json({ success: true, message: "Scaffolding complete" });
132
+ }
133
+ catch (error) {
134
+ console.error("Scaffolding error:", error);
135
+ res.status(500).json({
136
+ error: "Failed to scaffold",
137
+ details: error instanceof Error ? error.message : String(error)
138
+ });
139
+ }
140
+ });
141
+ function runCommand(cmd, cwd) {
142
+ console.log(`Running: ${cmd} in ${cwd}`);
143
+ return new Promise((resolve, reject) => {
144
+ (0, child_process_1.exec)(cmd, { cwd }, (error, stdout, stderr) => {
145
+ if (error) {
146
+ console.error("Exec error:", stderr);
147
+ reject(error);
148
+ }
149
+ else {
150
+ console.log(stdout); // Log output
151
+ resolve();
152
+ }
153
+ });
154
+ });
155
+ }
156
+ exports.default = router;