@tomagranate/corsa 1.0.0 → 1.0.2

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/README.md CHANGED
@@ -1,12 +1,12 @@
1
- # Corsa
1
+ # corsa
2
2
 
3
3
  A Terminal User Interface (TUI) for managing multiple local development processes. View real-time logs, monitor status, and control all your dev servers from a single dashboard.
4
4
 
5
5
  Built with [OpenTUI](https://github.com/anomalyco/opentui).
6
6
 
7
- ## Why Corsa?
7
+ ## Why corsa?
8
8
 
9
- When working on a full-stack project, you often need to run multiple processes simultaneously—a frontend dev server, a backend API, database containers, workers, etc. Corsa gives you:
9
+ When working on a full-stack project, you often need to run multiple processes simultaneously—a frontend dev server, a backend API, database containers, workers, etc. corsa gives you:
10
10
 
11
11
  - **Single dashboard** for all your processes with tabbed log viewing
12
12
  - **Real-time logs** with search and ANSI color support
@@ -112,7 +112,7 @@ corsa mcp
112
112
 
113
113
  ## Configuration
114
114
 
115
- Corsa is configured via a TOML file. By default, it looks for `corsa.config.toml` in the current directory.
115
+ corsa is configured via a TOML file. By default, it looks for `corsa.config.toml` in the current directory.
116
116
 
117
117
  ### Minimal Example
118
118
 
@@ -170,7 +170,7 @@ For a complete reference of all configuration options, see the [sample config fi
170
170
 
171
171
  ## Themes
172
172
 
173
- Corsa includes several built-in themes. Set in your config:
173
+ corsa includes several built-in themes. Set in your config:
174
174
 
175
175
  ```toml
176
176
  [ui]
@@ -181,7 +181,7 @@ Available themes: `default` (Moss), `mist`, `cappuccino`, `synthwave`, `terminal
181
181
 
182
182
  ## MCP Integration
183
183
 
184
- Corsa can expose an HTTP API for AI agents (Cursor, Claude, etc.) via the Model Context Protocol.
184
+ corsa can expose an HTTP API for AI agents (Cursor, Claude, etc.) via the Model Context Protocol.
185
185
 
186
186
  ### Enable in Config
187
187
 
package/bin/corsa CHANGED
@@ -10,6 +10,111 @@ const binDir = dirname(__filename);
10
10
  const platform = process.platform;
11
11
  const arch = process.arch;
12
12
 
13
+ /**
14
+ * Detect which package manager was used based on lockfiles in the project root.
15
+ * Returns: "bun" | "pnpm" | "yarn" | "npm" | null
16
+ */
17
+ function detectPackageManagerFromLockfile(projectRoot) {
18
+ if (!projectRoot) return null;
19
+
20
+ // Check in order of specificity
21
+ if (
22
+ existsSync(join(projectRoot, "bun.lockb")) ||
23
+ existsSync(join(projectRoot, "bun.lock"))
24
+ ) {
25
+ return "bun";
26
+ }
27
+ if (existsSync(join(projectRoot, "pnpm-lock.yaml"))) {
28
+ return "pnpm";
29
+ }
30
+ if (existsSync(join(projectRoot, "yarn.lock"))) {
31
+ return "yarn";
32
+ }
33
+ if (existsSync(join(projectRoot, "package-lock.json"))) {
34
+ return "npm";
35
+ }
36
+ return null;
37
+ }
38
+
39
+ /**
40
+ * Detect installation method from the wrapper's path.
41
+ * This is passed to the binary via environment variable since
42
+ * Bun-compiled binaries cannot determine their own filesystem path.
43
+ *
44
+ * Returns format: "package-manager-scope" (e.g., "npm-global", "pnpm-local")
45
+ */
46
+ function detectInstallMethod() {
47
+ const wrapperPath = __filename;
48
+
49
+ // Check for bun global install (~/.bun/install/global/...)
50
+ if (
51
+ wrapperPath.includes("/.bun/") &&
52
+ wrapperPath.includes("/install/global/")
53
+ ) {
54
+ return "bun-global";
55
+ }
56
+
57
+ // Check for pnpm global install (has /global/ in pnpm path)
58
+ if (
59
+ (wrapperPath.includes("/pnpm/") || wrapperPath.includes("/.pnpm/")) &&
60
+ wrapperPath.includes("/global/")
61
+ ) {
62
+ return "pnpm-global";
63
+ }
64
+
65
+ // Check for yarn global install
66
+ if (
67
+ (wrapperPath.includes("/yarn/") || wrapperPath.includes("/.yarn/")) &&
68
+ (wrapperPath.includes("/global/") || wrapperPath.includes("/.config/yarn/"))
69
+ ) {
70
+ return "yarn-global";
71
+ }
72
+
73
+ // Check for npm-style global install (version managers, system paths)
74
+ if (wrapperPath.includes("/node_modules/")) {
75
+ const isGlobal =
76
+ wrapperPath.includes("/lib/node_modules/") ||
77
+ wrapperPath.includes("/usr/local/") ||
78
+ wrapperPath.includes("/.nvm/") ||
79
+ wrapperPath.includes("/mise/") ||
80
+ wrapperPath.includes("/volta/") ||
81
+ wrapperPath.includes("/fnm/") ||
82
+ wrapperPath.includes("/asdf/");
83
+
84
+ if (isGlobal) {
85
+ return "npm-global";
86
+ }
87
+
88
+ // Local install - detect package manager from lockfile
89
+ // Find project root by going up from node_modules
90
+ const nodeModulesIndex = wrapperPath.indexOf("/node_modules/");
91
+ if (nodeModulesIndex !== -1) {
92
+ const projectRoot = wrapperPath.substring(0, nodeModulesIndex);
93
+ const pm = detectPackageManagerFromLockfile(projectRoot);
94
+ if (pm) {
95
+ return `${pm}-local`;
96
+ }
97
+ }
98
+
99
+ // Fallback to npm-local if no lockfile found
100
+ return "npm-local";
101
+ }
102
+
103
+ // Fallback - shouldn't normally reach here via wrapper
104
+ return "unknown";
105
+ }
106
+
107
+ const installMethod = detectInstallMethod();
108
+
109
+ // For local installs, find the project root so the binary can run updates there
110
+ let projectRoot = null;
111
+ if (installMethod.endsWith("-local")) {
112
+ const nodeModulesIndex = __filename.indexOf("/node_modules/");
113
+ if (nodeModulesIndex !== -1) {
114
+ projectRoot = __filename.substring(0, nodeModulesIndex);
115
+ }
116
+ }
117
+
13
118
  // Map Node.js platform/arch to our binary names
14
119
  const platformMap = {
15
120
  darwin: "darwin",
@@ -43,9 +148,15 @@ if (!existsSync(binaryPath)) {
43
148
  }
44
149
 
45
150
  // Execute the binary with all arguments passed through
151
+ // Pass install method and project root via env vars since Bun binaries can't detect their own path
46
152
  const child = spawn(binaryPath, process.argv.slice(2), {
47
153
  stdio: "inherit",
48
154
  windowsHide: true,
155
+ env: {
156
+ ...process.env,
157
+ CORSA_INSTALL_METHOD: installMethod,
158
+ ...(projectRoot ? { CORSA_PROJECT_ROOT: projectRoot } : {}),
159
+ },
49
160
  });
50
161
 
51
162
  child.on("error", (err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tomagranate/corsa",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "A Terminal User Interface (TUI) for running multiple local development servers and tools simultaneously",
5
5
  "type": "module",
6
6
  "bin": {
Binary file
package/bin/toolui DELETED
@@ -1,62 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { spawn } from "node:child_process";
4
- import { existsSync } from "node:fs";
5
- import { dirname, join } from "node:path";
6
- import { fileURLToPath } from "node:url";
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const binDir = dirname(__filename);
10
- const platform = process.platform;
11
- const arch = process.arch;
12
-
13
- // Map Node.js platform/arch to our binary names
14
- const platformMap = {
15
- darwin: "darwin",
16
- linux: "linux",
17
- win32: "windows",
18
- };
19
-
20
- const archMap = {
21
- arm64: "arm64",
22
- x64: "x64",
23
- };
24
-
25
- const os = platformMap[platform];
26
- const cpu = archMap[arch];
27
-
28
- if (!os || !cpu) {
29
- console.error(`Unsupported platform: ${platform}-${arch}`);
30
- process.exit(1);
31
- }
32
-
33
- const binaryName = `corsa-${os}-${cpu}${platform === "win32" ? ".exe" : ""}`;
34
- const binaryPath = join(binDir, binaryName);
35
-
36
- if (!existsSync(binaryPath)) {
37
- console.error(`Binary not found: ${binaryPath}`);
38
- console.error(
39
- "This may happen if the postinstall script failed to download the binary.",
40
- );
41
- console.error("Try reinstalling: npm install -g corsa");
42
- process.exit(1);
43
- }
44
-
45
- // Execute the binary with all arguments passed through
46
- const child = spawn(binaryPath, process.argv.slice(2), {
47
- stdio: "inherit",
48
- windowsHide: true,
49
- });
50
-
51
- child.on("error", (err) => {
52
- console.error(`Failed to start corsa: ${err.message}`);
53
- process.exit(1);
54
- });
55
-
56
- child.on("exit", (code, signal) => {
57
- if (signal) {
58
- process.kill(process.pid, signal);
59
- } else {
60
- process.exit(code ?? 0);
61
- }
62
- });