@launchchair/agent 0.4.2 → 0.4.3
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/AGENTS.md +2 -1
- package/launchchair-cli.mjs +1 -1
- package/local-bridge.mjs +33 -7
- package/mcp-bridge-server.mjs +32 -7
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -87,6 +87,7 @@ LAUNCHCHAIR_PROJECT_ID="optional project UUID; omit or leave blank if creating o
|
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
`launchchair login` is the recommended token path. It saves the token to `~/.launchchair/config.json`, and `launchchair mcp-server` reads that saved token. Use `LAUNCHCHAIR_AGENT_TOKEN` only as a manual fallback when browser login is skipped or a per-client token override is needed.
|
|
90
|
+
The packaged MCP and local bridges also read the same saved CLI config as a fallback, so a desktop MCP launch should not require pasting a token into Codex or Claude config after browser login.
|
|
90
91
|
|
|
91
92
|
For Codex Desktop local runs:
|
|
92
93
|
|
|
@@ -112,7 +113,7 @@ The build folder can be an empty scratch folder until Stack Setup creates or rec
|
|
|
112
113
|
[mcp_servers.launchchair]
|
|
113
114
|
command = "launchchair"
|
|
114
115
|
args = ["mcp-server"]
|
|
115
|
-
required =
|
|
116
|
+
required = false
|
|
116
117
|
startup_timeout_sec = 20
|
|
117
118
|
tool_timeout_sec = 3600
|
|
118
119
|
default_tools_approval_mode = "approve"
|
package/launchchair-cli.mjs
CHANGED
|
@@ -15,7 +15,7 @@ import path from "node:path";
|
|
|
15
15
|
import process from "node:process";
|
|
16
16
|
import { fileURLToPath } from "node:url";
|
|
17
17
|
|
|
18
|
-
const VERSION = "0.4.
|
|
18
|
+
const VERSION = "0.4.3";
|
|
19
19
|
const SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
20
20
|
const DEFAULT_BASE_URL = "https://www.launchchair.io";
|
|
21
21
|
const CONFIG_DIR = process.env.LAUNCHCHAIR_CONFIG_DIR?.trim()
|
package/local-bridge.mjs
CHANGED
|
@@ -10,14 +10,20 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { spawn } from "node:child_process";
|
|
13
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
14
|
+
import os from "node:os";
|
|
13
15
|
import path from "node:path";
|
|
14
16
|
import process from "node:process";
|
|
15
17
|
import { fileURLToPath } from "node:url";
|
|
16
18
|
import { buildRunnerCommand, parseRunnerCommand } from "./runner-command.mjs";
|
|
17
19
|
|
|
18
|
-
const VERSION = "0.4.
|
|
20
|
+
const VERSION = "0.4.3";
|
|
19
21
|
const CLIENT_TYPES = ["codex", "chatgpt", "claude", "claude_code", "other"];
|
|
20
22
|
const AGENT_SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
23
|
+
const CONFIG_DIR = process.env.LAUNCHCHAIR_CONFIG_DIR?.trim()
|
|
24
|
+
? path.resolve(process.env.LAUNCHCHAIR_CONFIG_DIR.trim())
|
|
25
|
+
: path.join(os.homedir() || process.cwd(), ".launchchair");
|
|
26
|
+
const CONFIG_PATH = path.join(CONFIG_DIR, "config.json");
|
|
21
27
|
|
|
22
28
|
function nodeScriptCommand(scriptName) {
|
|
23
29
|
return `${JSON.stringify(process.execPath)} ${JSON.stringify(path.join(AGENT_SCRIPT_DIR, scriptName))}`;
|
|
@@ -33,6 +39,23 @@ function env(name, fallback = "") {
|
|
|
33
39
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : fallback;
|
|
34
40
|
}
|
|
35
41
|
|
|
42
|
+
function loadSavedConfig() {
|
|
43
|
+
try {
|
|
44
|
+
if (!existsSync(CONFIG_PATH)) return {};
|
|
45
|
+
const parsed = JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
|
|
46
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
47
|
+
} catch {
|
|
48
|
+
return {};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const savedConfig = loadSavedConfig();
|
|
53
|
+
|
|
54
|
+
function savedConfigValue(key, fallback = "") {
|
|
55
|
+
const value = savedConfig[key];
|
|
56
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : fallback;
|
|
57
|
+
}
|
|
58
|
+
|
|
36
59
|
function hasArg(name) {
|
|
37
60
|
return process.argv.includes(name);
|
|
38
61
|
}
|
|
@@ -92,8 +115,9 @@ function printHelp() {
|
|
|
92
115
|
console.log(`
|
|
93
116
|
LaunchChair local bridge v${VERSION}
|
|
94
117
|
|
|
95
|
-
|
|
96
|
-
|
|
118
|
+
Token:
|
|
119
|
+
Recommended: run launchchair login once to save ~/.launchchair/config.json
|
|
120
|
+
Optional env fallback: LAUNCHCHAIR_AGENT_TOKEN or LAUNCHCHAIR_API_KEY
|
|
97
121
|
|
|
98
122
|
Optional env:
|
|
99
123
|
LAUNCHCHAIR_BASE_URL Default: http://localhost:3000
|
|
@@ -153,9 +177,9 @@ Runner placeholders:
|
|
|
153
177
|
}
|
|
154
178
|
|
|
155
179
|
const config = {
|
|
156
|
-
baseUrl: env("LAUNCHCHAIR_BASE_URL", "http://localhost:3000").replace(/\/+$/, ""),
|
|
157
|
-
token: env("LAUNCHCHAIR_AGENT_TOKEN", env("LAUNCHCHAIR_API_KEY")),
|
|
158
|
-
projectId: env("LAUNCHCHAIR_PROJECT_ID") || null,
|
|
180
|
+
baseUrl: env("LAUNCHCHAIR_BASE_URL", savedConfigValue("baseUrl", "http://localhost:3000")).replace(/\/+$/, ""),
|
|
181
|
+
token: env("LAUNCHCHAIR_AGENT_TOKEN", env("LAUNCHCHAIR_API_KEY", savedConfigValue("agentToken"))),
|
|
182
|
+
projectId: env("LAUNCHCHAIR_PROJECT_ID", savedConfigValue("projectId")) || null,
|
|
159
183
|
clientName: env("LC_AGENT_CLIENT_NAME", "Local Bridge"),
|
|
160
184
|
clientType: env("LC_AGENT_CLIENT_TYPE", "auto"),
|
|
161
185
|
clientVersion: env("LC_AGENT_CLIENT_VERSION", VERSION),
|
|
@@ -187,7 +211,9 @@ if (hasArg("--help")) {
|
|
|
187
211
|
|
|
188
212
|
if (!config.token) {
|
|
189
213
|
// eslint-disable-next-line no-console
|
|
190
|
-
console.error(
|
|
214
|
+
console.error(
|
|
215
|
+
`Missing LaunchChair Agent API token. Run "launchchair login" or set LAUNCHCHAIR_AGENT_TOKEN. Checked ${CONFIG_PATH}.`,
|
|
216
|
+
);
|
|
191
217
|
printHelp();
|
|
192
218
|
process.exit(1);
|
|
193
219
|
}
|
package/mcp-bridge-server.mjs
CHANGED
|
@@ -12,14 +12,20 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { spawn } from "node:child_process";
|
|
15
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
16
|
+
import os from "node:os";
|
|
15
17
|
import path from "node:path";
|
|
16
18
|
import process from "node:process";
|
|
17
19
|
import { fileURLToPath } from "node:url";
|
|
18
20
|
import { buildRunnerCommand, parseRunnerCommand } from "./runner-command.mjs";
|
|
19
21
|
|
|
20
|
-
const VERSION = "0.4.
|
|
22
|
+
const VERSION = "0.4.3";
|
|
21
23
|
const SERVER_NAME = "launchchair-agent-mcp";
|
|
22
24
|
const AGENT_SCRIPT_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
25
|
+
const CONFIG_DIR = process.env.LAUNCHCHAIR_CONFIG_DIR?.trim()
|
|
26
|
+
? path.resolve(process.env.LAUNCHCHAIR_CONFIG_DIR.trim())
|
|
27
|
+
: path.join(os.homedir() || process.cwd(), ".launchchair");
|
|
28
|
+
const CONFIG_PATH = path.join(CONFIG_DIR, "config.json");
|
|
23
29
|
const BASE_SERVER_INSTRUCTIONS =
|
|
24
30
|
"Use LaunchChair MCP tools—not web browsing—for LaunchChair project discovery, creation, planning, and loops. Call the most specific available tool. If a requested workflow is unavailable, explain the access or setup issue instead of silently substituting another project type or workflow.";
|
|
25
31
|
|
|
@@ -32,6 +38,23 @@ function env(name, fallback = "") {
|
|
|
32
38
|
return typeof value === "string" && value.trim().length > 0 ? value.trim() : fallback;
|
|
33
39
|
}
|
|
34
40
|
|
|
41
|
+
function loadSavedConfig() {
|
|
42
|
+
try {
|
|
43
|
+
if (!existsSync(CONFIG_PATH)) return {};
|
|
44
|
+
const parsed = JSON.parse(readFileSync(CONFIG_PATH, "utf8"));
|
|
45
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
46
|
+
} catch (_error) {
|
|
47
|
+
return {};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const savedConfig = loadSavedConfig();
|
|
52
|
+
|
|
53
|
+
function savedConfigValue(key, fallback = "") {
|
|
54
|
+
const value = savedConfig[key];
|
|
55
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : fallback;
|
|
56
|
+
}
|
|
57
|
+
|
|
35
58
|
function toInt(value, fallback) {
|
|
36
59
|
const parsed = Number.parseInt(String(value ?? ""), 10);
|
|
37
60
|
return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
|
|
@@ -84,9 +107,9 @@ function builtInRunnerCommand(target) {
|
|
|
84
107
|
}
|
|
85
108
|
|
|
86
109
|
const config = {
|
|
87
|
-
baseUrl: env("LAUNCHCHAIR_BASE_URL", "http://localhost:3000").replace(/\/+$/, ""),
|
|
88
|
-
token: env("LAUNCHCHAIR_AGENT_TOKEN", env("LAUNCHCHAIR_API_KEY")),
|
|
89
|
-
projectId: env("LAUNCHCHAIR_PROJECT_ID") || null,
|
|
110
|
+
baseUrl: env("LAUNCHCHAIR_BASE_URL", savedConfigValue("baseUrl", "http://localhost:3000")).replace(/\/+$/, ""),
|
|
111
|
+
token: env("LAUNCHCHAIR_AGENT_TOKEN", env("LAUNCHCHAIR_API_KEY", savedConfigValue("agentToken"))),
|
|
112
|
+
projectId: env("LAUNCHCHAIR_PROJECT_ID", savedConfigValue("projectId")) || null,
|
|
90
113
|
clientName: env("LC_AGENT_CLIENT_NAME", "MCP Bridge"),
|
|
91
114
|
clientType: env("LC_AGENT_CLIENT_TYPE", "other"),
|
|
92
115
|
clientVersion: env("LC_AGENT_CLIENT_VERSION", VERSION),
|
|
@@ -106,14 +129,16 @@ const config = {
|
|
|
106
129
|
claudeCode: env("LC_AGENT_RUNNER_CMD_CLAUDE_CODE", builtInRunnerCommand("claude_code")),
|
|
107
130
|
},
|
|
108
131
|
localRepoPaths: {
|
|
109
|
-
codex: env("LC_AGENT_CODEX_CWD", process.cwd()),
|
|
110
|
-
claudeCode: env("LC_AGENT_CLAUDE_CODE_CWD", process.cwd()),
|
|
132
|
+
codex: env("LC_AGENT_CODEX_CWD", savedConfigValue("codexCwd", process.cwd())),
|
|
133
|
+
claudeCode: env("LC_AGENT_CLAUDE_CODE_CWD", savedConfigValue("claudeCodeCwd", process.cwd())),
|
|
111
134
|
},
|
|
112
135
|
};
|
|
113
136
|
|
|
114
137
|
if (!config.token) {
|
|
115
138
|
// eslint-disable-next-line no-console
|
|
116
|
-
console.error(
|
|
139
|
+
console.error(
|
|
140
|
+
`Missing LaunchChair Agent API token. Run "launchchair login" or set LAUNCHCHAIR_AGENT_TOKEN. Checked ${CONFIG_PATH}.`,
|
|
141
|
+
);
|
|
117
142
|
process.exit(1);
|
|
118
143
|
}
|
|
119
144
|
|
package/package.json
CHANGED