@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 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 = true
116
+ required = false
116
117
  startup_timeout_sec = 20
117
118
  tool_timeout_sec = 3600
118
119
  default_tools_approval_mode = "approve"
@@ -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.2";
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.0";
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
- Required env:
96
- LAUNCHCHAIR_AGENT_TOKEN
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("Missing LAUNCHCHAIR_AGENT_TOKEN. LAUNCHCHAIR_API_KEY is also supported as an alias.");
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
  }
@@ -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.0";
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("Missing LAUNCHCHAIR_AGENT_TOKEN for MCP bridge. LAUNCHCHAIR_API_KEY is also supported as an alias.");
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@launchchair/agent",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "LaunchChair Agent CLI, MCP bridge, local bridge, and runners for Codex, Claude Code, ChatGPT, Claude, and Hermes workflows.",
5
5
  "type": "module",
6
6
  "bin": {