@launchchair/agent 0.4.0 → 0.4.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/AGENTS.md +33 -16
- package/README.md +15 -7
- package/launchchair-cli.mjs +209 -38
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -28,7 +28,7 @@ Fresh LaunchChair projects often do not have a local repo yet. Before Stack Setu
|
|
|
28
28
|
|
|
29
29
|
## Bridge And Runner Files
|
|
30
30
|
|
|
31
|
-
Download these into a stable local folder such as `~/launchchair-agent
|
|
31
|
+
Download these into a stable local folder such as `~/launchchair-agent`:
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
34
|
mkdir -p "$HOME/launchchair-agent"
|
|
@@ -57,28 +57,37 @@ fi
|
|
|
57
57
|
|
|
58
58
|
The final block creates a tiny project-local `AGENTS.md` pointer only when the target folder does not already have one. It helps fresh Codex chats auto-load the LaunchChair instructions without overwriting a real project instruction file.
|
|
59
59
|
|
|
60
|
-
##
|
|
60
|
+
## CLI
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
The npm CLI is the recommended setup path for Codex Desktop and Claude Desktop. It can log in through LaunchChair, save the token locally, print paste-ready MCP config, write Claude Desktop config, and start the local bridge.
|
|
63
63
|
|
|
64
64
|
```bash
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
npm install -g @launchchair/agent
|
|
66
|
+
launchchair login
|
|
67
|
+
launchchair setup codex --cwd /absolute/path/to/repo-or-empty-folder --write-config
|
|
68
|
+
launchchair setup claude --cwd /absolute/path/to/repo-or-empty-folder --write-config
|
|
69
|
+
launchchair projects --query LeafLore
|
|
70
|
+
launchchair create --name SignalLift --one-liner "Distribution workspace for technical founders" --project-type b2b --idempotency-key signallift-v1
|
|
71
|
+
launchchair run-once
|
|
72
|
+
launchchair bridge
|
|
73
|
+
launchchair mcp-config codex --ui-fields
|
|
72
74
|
```
|
|
73
75
|
|
|
74
|
-
|
|
76
|
+
If Codex Desktop is being configured through the custom MCP form instead of `~/.codex/config.toml`, run:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
launchchair setup codex --cwd /absolute/path/to/repo-or-empty-folder --copy-config
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Environment Variables
|
|
75
83
|
|
|
76
84
|
```bash
|
|
77
85
|
LAUNCHCHAIR_BASE_URL="https://www.launchchair.io"
|
|
78
|
-
LAUNCHCHAIR_AGENT_TOKEN="<full lc_at token from LaunchChair Settings API Access>"
|
|
79
86
|
LAUNCHCHAIR_PROJECT_ID="optional project UUID; omit or leave blank if creating or discovering a project"
|
|
80
87
|
```
|
|
81
88
|
|
|
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
|
+
|
|
82
91
|
For Codex Desktop local runs:
|
|
83
92
|
|
|
84
93
|
```bash
|
|
@@ -101,18 +110,26 @@ The build folder can be an empty scratch folder until Stack Setup creates or rec
|
|
|
101
110
|
|
|
102
111
|
```toml
|
|
103
112
|
[mcp_servers.launchchair]
|
|
104
|
-
command = "
|
|
105
|
-
args = ["
|
|
113
|
+
command = "launchchair"
|
|
114
|
+
args = ["mcp-server"]
|
|
115
|
+
required = true
|
|
116
|
+
startup_timeout_sec = 20
|
|
117
|
+
tool_timeout_sec = 3600
|
|
118
|
+
default_tools_approval_mode = "approve"
|
|
106
119
|
|
|
107
120
|
[mcp_servers.launchchair.env]
|
|
108
121
|
LAUNCHCHAIR_BASE_URL = "https://www.launchchair.io"
|
|
109
|
-
LAUNCHCHAIR_AGENT_TOKEN = "<full lc_at token from Settings API Access>"
|
|
110
122
|
LAUNCHCHAIR_PROJECT_ID = ""
|
|
111
123
|
LC_AGENT_ROUTER_GPT_TARGET = "codex"
|
|
112
124
|
LC_AGENT_ROUTER_CODEX_TARGET = "codex"
|
|
113
125
|
LC_AGENT_CODEX_CWD = "/absolute/path/to/the-folder-codex-should-build-into"
|
|
126
|
+
|
|
127
|
+
# Optional fallback if launchchair login was skipped:
|
|
128
|
+
# LAUNCHCHAIR_AGENT_TOKEN = "<full lc_at token from Settings API Access>"
|
|
114
129
|
```
|
|
115
130
|
|
|
131
|
+
If the desktop app cannot find `launchchair`, run `which launchchair` in Terminal and use that absolute path as the MCP command.
|
|
132
|
+
|
|
116
133
|
## What To Do First In A Fresh Chat
|
|
117
134
|
|
|
118
135
|
1. If LaunchChair MCP tools are available, call `launchchair_heartbeat`.
|
|
@@ -229,7 +246,7 @@ Call launchchair_run_once.
|
|
|
229
246
|
Run one queued UI job from CLI:
|
|
230
247
|
|
|
231
248
|
```bash
|
|
232
|
-
|
|
249
|
+
launchchair run-once
|
|
233
250
|
```
|
|
234
251
|
|
|
235
252
|
Select a generated wedge:
|
package/README.md
CHANGED
|
@@ -49,18 +49,24 @@ Tokens are masked in CLI output. Do not paste real tokens into public docs, scre
|
|
|
49
49
|
|
|
50
50
|
## Guided Setup
|
|
51
51
|
|
|
52
|
-
Use `setup` as the easiest path. It saves the build folder, writes a small `AGENTS.md` pointer into that folder, starts browser login when no token is saved yet, prints the MCP config for your desktop agent, and tells you exactly what to do next.
|
|
52
|
+
Use `setup` as the easiest path. It saves the build folder, writes a small `AGENTS.md` pointer into that folder, starts browser login when no token is saved yet, writes or prints the MCP config for your desktop agent, and tells you exactly what to do next.
|
|
53
53
|
|
|
54
54
|
Codex Desktop:
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
|
-
launchchair setup codex --cwd /absolute/path/to/repo-or-empty-folder
|
|
57
|
+
launchchair setup codex --cwd /absolute/path/to/repo-or-empty-folder --write-config
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
If you prefer Codex Desktop's custom MCP form, copy paste-ready fields instead:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
launchchair setup codex --cwd /absolute/path/to/repo-or-empty-folder --copy-config
|
|
58
64
|
```
|
|
59
65
|
|
|
60
66
|
Claude Desktop + Claude Code:
|
|
61
67
|
|
|
62
68
|
```bash
|
|
63
|
-
launchchair setup claude --cwd /absolute/path/to/repo-or-empty-folder
|
|
69
|
+
launchchair setup claude --cwd /absolute/path/to/repo-or-empty-folder --write-config
|
|
64
70
|
```
|
|
65
71
|
|
|
66
72
|
Terminal / CLI agents:
|
|
@@ -83,8 +89,8 @@ Use `setup terminal` when the agent runs inside a normal shell instead of Codex
|
|
|
83
89
|
## Common Commands
|
|
84
90
|
|
|
85
91
|
```bash
|
|
86
|
-
launchchair setup codex --cwd /absolute/path/to/repo-or-empty-folder
|
|
87
|
-
launchchair setup claude --cwd /absolute/path/to/repo-or-empty-folder
|
|
92
|
+
launchchair setup codex --cwd /absolute/path/to/repo-or-empty-folder --write-config
|
|
93
|
+
launchchair setup claude --cwd /absolute/path/to/repo-or-empty-folder --write-config
|
|
88
94
|
launchchair setup terminal --cwd /absolute/path/to/repo-or-empty-folder
|
|
89
95
|
launchchair projects
|
|
90
96
|
launchchair projects --query LeafLore
|
|
@@ -94,6 +100,7 @@ launchchair continue --completion-target "rerun Product Ideation until ICP Pain
|
|
|
94
100
|
launchchair run-once
|
|
95
101
|
launchchair bridge
|
|
96
102
|
launchchair mcp-config codex
|
|
103
|
+
launchchair mcp-config codex --ui-fields --copy-config
|
|
97
104
|
launchchair mcp-config claude
|
|
98
105
|
launchchair install-agent-md --cwd /absolute/path/to/repo-or-empty-folder
|
|
99
106
|
```
|
|
@@ -127,6 +134,7 @@ Print a Codex MCP config example:
|
|
|
127
134
|
|
|
128
135
|
```bash
|
|
129
136
|
launchchair mcp-config codex
|
|
137
|
+
launchchair mcp-config codex --ui-fields
|
|
130
138
|
```
|
|
131
139
|
|
|
132
140
|
Print a Claude Desktop MCP config example:
|
|
@@ -135,9 +143,9 @@ Print a Claude Desktop MCP config example:
|
|
|
135
143
|
launchchair mcp-config claude
|
|
136
144
|
```
|
|
137
145
|
|
|
138
|
-
The
|
|
146
|
+
The recommended config launches `launchchair mcp-server`. That process reads the token saved by `launchchair login`, so Codex and Claude users do not need to paste tokens into MCP config after browser login.
|
|
139
147
|
|
|
140
|
-
|
|
148
|
+
Use `LAUNCHCHAIR_AGENT_TOKEN` only as a manual fallback when you skip `launchchair login`, need a per-client token override, or your desktop app cannot read the saved CLI config. If a desktop app cannot find `launchchair`, run `which launchchair` and use that absolute path as the MCP command.
|
|
141
149
|
|
|
142
150
|
## Local Bridge
|
|
143
151
|
|
package/launchchair-cli.mjs
CHANGED
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
* project discovery/creation, and local bridge control.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { spawn } from "node:child_process";
|
|
12
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
11
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
12
|
+
import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
13
|
import os from "node:os";
|
|
14
14
|
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.2";
|
|
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()
|
|
@@ -163,11 +163,13 @@ Commands:
|
|
|
163
163
|
continue [--project-id ID] Ask LaunchChair to continue the project loop once
|
|
164
164
|
run-once Claim and run one queued LaunchChair job through the local bridge
|
|
165
165
|
bridge Start the long-running local bridge for Run with Agent
|
|
166
|
+
mcp-server Run the stdio MCP server using saved CLI config
|
|
166
167
|
setup codex|claude|terminal [options]
|
|
167
168
|
Guided setup for CLI, CWD, AGENTS.md, MCP config, and bridge
|
|
168
169
|
config Show local CLI config without printing the token
|
|
169
170
|
config set KEY VALUE Save base-url, project-id, codex-cwd, or claude-code-cwd
|
|
170
|
-
mcp-config codex|claude
|
|
171
|
+
mcp-config codex|claude [options]
|
|
172
|
+
Print MCP config or Codex custom MCP form fields
|
|
171
173
|
install-agent-md [--cwd PATH] Create a small AGENTS.md pointer in a fresh repo
|
|
172
174
|
|
|
173
175
|
Create options:
|
|
@@ -207,6 +209,9 @@ Setup options:
|
|
|
207
209
|
--no-open During setup login, print the approval URL instead of opening a browser
|
|
208
210
|
--timeout SECONDS During setup login, approval timeout. Default: 600
|
|
209
211
|
--start-bridge Start the local bridge after setup
|
|
212
|
+
--copy-config Copy generated MCP setup output to clipboard on macOS
|
|
213
|
+
--ui-fields Print Codex custom MCP form fields instead of raw config
|
|
214
|
+
--write-config Write/update Codex or Claude Desktop MCP config when supported
|
|
210
215
|
|
|
211
216
|
Login options:
|
|
212
217
|
--token TOKEN Manual fallback: save an existing lc_at token
|
|
@@ -223,6 +228,10 @@ Env:
|
|
|
223
228
|
LC_AGENT_CODEX_CWD Folder Codex should build into
|
|
224
229
|
LC_AGENT_CLAUDE_CODE_CWD Folder Claude Code should build into
|
|
225
230
|
|
|
231
|
+
MCP config options:
|
|
232
|
+
--ui-fields Print fields for Codex Desktop's custom MCP form
|
|
233
|
+
--copy-config Copy generated output to clipboard on macOS
|
|
234
|
+
|
|
226
235
|
Config:
|
|
227
236
|
${CONFIG_PATH}
|
|
228
237
|
`);
|
|
@@ -731,51 +740,185 @@ function spawnBridge(extraArgs = []) {
|
|
|
731
740
|
});
|
|
732
741
|
}
|
|
733
742
|
|
|
734
|
-
function
|
|
743
|
+
function spawnMcpServer(extraArgs = []) {
|
|
735
744
|
const bridgePath = path.join(SCRIPT_DIR, "mcp-bridge-server.mjs");
|
|
736
|
-
const
|
|
737
|
-
|
|
738
|
-
|
|
745
|
+
const child = spawn(process.execPath, [bridgePath, ...extraArgs], {
|
|
746
|
+
stdio: "inherit",
|
|
747
|
+
env: buildBridgeEnv(),
|
|
748
|
+
});
|
|
749
|
+
child.on("exit", (code) => {
|
|
750
|
+
process.exit(code ?? 0);
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
function normalizedMcpTarget(target) {
|
|
755
|
+
return targetDetails(target || "codex").mcpTarget || "codex";
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
function tomlString(value) {
|
|
759
|
+
return JSON.stringify(String(value ?? ""));
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
function mcpEnvForTarget(target, options = {}) {
|
|
763
|
+
const includeTokenPlaceholder = options.includeTokenPlaceholder !== false;
|
|
764
|
+
const details = targetDetails(target || "codex");
|
|
765
|
+
const projectId = defaultProjectId();
|
|
766
|
+
const cwd = configValue(details.cwdConfigKey, [details.cwdEnvName], "/absolute/path/to/repo-or-empty-folder");
|
|
767
|
+
const envBlock = {
|
|
768
|
+
LAUNCHCHAIR_BASE_URL: baseUrl(),
|
|
769
|
+
...(token() || !includeTokenPlaceholder ? {} : { LAUNCHCHAIR_AGENT_TOKEN: "<optional full lc_at token when launchchair login was not used>" }),
|
|
770
|
+
...(projectId ? { LAUNCHCHAIR_PROJECT_ID: projectId } : {}),
|
|
771
|
+
LC_AGENT_ROUTER_GPT_TARGET: details.routerTarget,
|
|
772
|
+
LC_AGENT_ROUTER_CODEX_TARGET: details.routerTarget,
|
|
773
|
+
[details.cwdEnvName]: cwd,
|
|
774
|
+
};
|
|
775
|
+
return Object.fromEntries(Object.entries(envBlock).filter(([, value]) => String(value ?? "").trim()));
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
function mcpServerConfig(target, options = {}) {
|
|
779
|
+
return {
|
|
780
|
+
command: "launchchair",
|
|
781
|
+
args: ["mcp-server"],
|
|
782
|
+
env: mcpEnvForTarget(target, options),
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
function renderMcpConfig(target, options = {}) {
|
|
787
|
+
const normalized = normalizedMcpTarget(target);
|
|
788
|
+
const server = mcpServerConfig(normalized, options);
|
|
789
|
+
if (normalized === "claude") {
|
|
739
790
|
return JSON.stringify(
|
|
740
791
|
{
|
|
741
792
|
mcpServers: {
|
|
742
|
-
launchchair:
|
|
743
|
-
command: "node",
|
|
744
|
-
args: [bridgePath],
|
|
745
|
-
env: {
|
|
746
|
-
LAUNCHCHAIR_BASE_URL: baseUrl(),
|
|
747
|
-
LAUNCHCHAIR_AGENT_TOKEN: agentTokenPlaceholder,
|
|
748
|
-
LAUNCHCHAIR_PROJECT_ID: projectId,
|
|
749
|
-
LC_AGENT_ROUTER_GPT_TARGET: "claude_code",
|
|
750
|
-
LC_AGENT_ROUTER_CODEX_TARGET: "claude_code",
|
|
751
|
-
LC_AGENT_CLAUDE_CODE_CWD: configValue("claudeCodeCwd", ["LC_AGENT_CLAUDE_CODE_CWD"], "/absolute/path/to/repo-or-empty-folder"),
|
|
752
|
-
},
|
|
753
|
-
},
|
|
793
|
+
launchchair: server,
|
|
754
794
|
},
|
|
755
795
|
},
|
|
756
796
|
null,
|
|
757
797
|
2,
|
|
758
798
|
);
|
|
759
799
|
}
|
|
800
|
+
const envLines = Object.entries(server.env)
|
|
801
|
+
.map(([key, value]) => `${key} = ${tomlString(value)}`)
|
|
802
|
+
.join("\n");
|
|
760
803
|
return `[mcp_servers.launchchair]
|
|
761
|
-
command = "
|
|
762
|
-
args = ["
|
|
763
|
-
required =
|
|
804
|
+
command = "launchchair"
|
|
805
|
+
args = ["mcp-server"]
|
|
806
|
+
required = false
|
|
764
807
|
startup_timeout_sec = 20
|
|
765
808
|
tool_timeout_sec = 3600
|
|
766
809
|
default_tools_approval_mode = "approve"
|
|
767
810
|
|
|
768
811
|
[mcp_servers.launchchair.env]
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
812
|
+
${envLines}`;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
function renderMcpUiFields(target) {
|
|
816
|
+
const normalized = normalizedMcpTarget(target);
|
|
817
|
+
const details = targetDetails(normalized);
|
|
818
|
+
const server = mcpServerConfig(normalized);
|
|
819
|
+
const envLines =
|
|
820
|
+
Object.entries(server.env)
|
|
821
|
+
.map(([key, value]) => ` ${key} = ${value}`)
|
|
822
|
+
.join("\n") || " (none)";
|
|
823
|
+
const workingDir = server.env[details.cwdEnvName] || process.cwd();
|
|
824
|
+
return `Name
|
|
825
|
+
launchchair
|
|
826
|
+
|
|
827
|
+
Type
|
|
828
|
+
STDIO
|
|
829
|
+
|
|
830
|
+
Command to launch
|
|
831
|
+
${server.command}
|
|
832
|
+
|
|
833
|
+
Arguments
|
|
834
|
+
${server.args.join(" ")}
|
|
835
|
+
|
|
836
|
+
Environment variables
|
|
837
|
+
${envLines}
|
|
838
|
+
|
|
839
|
+
Working directory
|
|
840
|
+
${workingDir}`;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
function copyToClipboard(text) {
|
|
844
|
+
if (process.platform !== "darwin") return false;
|
|
845
|
+
const result = spawnSync("pbcopy", { input: text, encoding: "utf8" });
|
|
846
|
+
return result.status === 0;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
function claudeDesktopConfigPath() {
|
|
850
|
+
return path.join(os.homedir() || process.cwd(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
function codexConfigPath() {
|
|
854
|
+
return path.join(os.homedir() || process.cwd(), ".codex", "config.toml");
|
|
775
855
|
}
|
|
776
856
|
|
|
777
|
-
function
|
|
778
|
-
|
|
857
|
+
function removeCodexLaunchChairTables(raw) {
|
|
858
|
+
const lines = String(raw || "").split(/\r?\n/);
|
|
859
|
+
const kept = [];
|
|
860
|
+
let skipping = false;
|
|
861
|
+
|
|
862
|
+
for (const line of lines) {
|
|
863
|
+
const tableName = line.match(/^\s*\[([^\]]+)\]\s*$/)?.[1] ?? "";
|
|
864
|
+
if (tableName) {
|
|
865
|
+
if (tableName === "mcp_servers.launchchair" || tableName === "mcp_servers.launchchair.env") {
|
|
866
|
+
skipping = true;
|
|
867
|
+
continue;
|
|
868
|
+
}
|
|
869
|
+
skipping = false;
|
|
870
|
+
}
|
|
871
|
+
if (!skipping) kept.push(line);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
return kept.join("\n").replace(/\n{3,}$/g, "\n\n").trimEnd();
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
function writeCodexConfig() {
|
|
878
|
+
const configPath = codexConfigPath();
|
|
879
|
+
mkdirSync(path.dirname(configPath), { recursive: true });
|
|
880
|
+
let current = "";
|
|
881
|
+
if (existsSync(configPath)) {
|
|
882
|
+
current = readFileSync(configPath, "utf8");
|
|
883
|
+
const backupPath = `${configPath}.launchchair-backup-${Date.now()}`;
|
|
884
|
+
copyFileSync(configPath, backupPath);
|
|
885
|
+
ok(`Backed up existing Codex config to ${backupPath}`);
|
|
886
|
+
}
|
|
887
|
+
const preserved = removeCodexLaunchChairTables(current);
|
|
888
|
+
const next = `${preserved ? `${preserved}\n\n` : ""}${renderMcpConfig("codex", { includeTokenPlaceholder: false })}\n`;
|
|
889
|
+
writeFileSync(configPath, next);
|
|
890
|
+
return configPath;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
function writeClaudeDesktopConfig() {
|
|
894
|
+
const configPath = claudeDesktopConfigPath();
|
|
895
|
+
mkdirSync(path.dirname(configPath), { recursive: true });
|
|
896
|
+
let current = {};
|
|
897
|
+
if (existsSync(configPath)) {
|
|
898
|
+
const raw = readFileSync(configPath, "utf8");
|
|
899
|
+
current = raw.trim() ? JSON.parse(raw) : {};
|
|
900
|
+
const backupPath = `${configPath}.launchchair-backup-${Date.now()}`;
|
|
901
|
+
copyFileSync(configPath, backupPath);
|
|
902
|
+
ok(`Backed up existing Claude config to ${backupPath}`);
|
|
903
|
+
}
|
|
904
|
+
const next = {
|
|
905
|
+
...current,
|
|
906
|
+
mcpServers: {
|
|
907
|
+
...(current.mcpServers ?? {}),
|
|
908
|
+
launchchair: mcpServerConfig("claude", { includeTokenPlaceholder: false }),
|
|
909
|
+
},
|
|
910
|
+
};
|
|
911
|
+
writeFileSync(configPath, `${JSON.stringify(next, null, 2)}\n`);
|
|
912
|
+
return configPath;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
function printMcpConfig(target, args = {}) {
|
|
916
|
+
const output = args["ui-fields"] === true || args["print-ui-fields"] === true ? renderMcpUiFields(target) : renderMcpConfig(target);
|
|
917
|
+
print(output);
|
|
918
|
+
if (args["copy-config"] === true) {
|
|
919
|
+
if (copyToClipboard(output)) ok("Copied MCP setup output to clipboard.");
|
|
920
|
+
else warn("Could not copy MCP setup output automatically on this platform.");
|
|
921
|
+
}
|
|
779
922
|
}
|
|
780
923
|
|
|
781
924
|
function showConfig() {
|
|
@@ -947,8 +1090,23 @@ async function setup(args) {
|
|
|
947
1090
|
print(` ${paint("launchchair run-once", "cyan")}`);
|
|
948
1091
|
print(` ${paint("launchchair bridge", "cyan")}`);
|
|
949
1092
|
} else {
|
|
950
|
-
|
|
951
|
-
|
|
1093
|
+
if (details.mcpTarget === "codex" && args["write-config"] === true) {
|
|
1094
|
+
const configPath = writeCodexConfig();
|
|
1095
|
+
title("Codex MCP config updated");
|
|
1096
|
+
ok(`Wrote LaunchChair MCP server to ${configPath}`);
|
|
1097
|
+
} else if (details.mcpTarget === "claude" && args["write-config"] === true) {
|
|
1098
|
+
const configPath = writeClaudeDesktopConfig();
|
|
1099
|
+
title("Claude MCP config updated");
|
|
1100
|
+
ok(`Wrote LaunchChair MCP server to ${configPath}`);
|
|
1101
|
+
} else {
|
|
1102
|
+
const output = details.mcpTarget === "codex" || args["ui-fields"] === true ? renderMcpUiFields(details.mcpTarget) : renderMcpConfig(details.mcpTarget);
|
|
1103
|
+
title(details.mcpTarget === "codex" || args["ui-fields"] === true ? "MCP fields to paste" : "MCP config to paste");
|
|
1104
|
+
print(output);
|
|
1105
|
+
if (args["copy-config"] === true) {
|
|
1106
|
+
if (copyToClipboard(output)) ok("Copied MCP setup output to clipboard.");
|
|
1107
|
+
else warn("Could not copy MCP setup output automatically on this platform.");
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
952
1110
|
}
|
|
953
1111
|
|
|
954
1112
|
print("");
|
|
@@ -964,11 +1122,23 @@ async function setup(args) {
|
|
|
964
1122
|
print("3. For product/project work, have it use launchchair projects/create/continue before local code discovery.");
|
|
965
1123
|
print("4. Keep launchchair bridge running only when LaunchChair UI Run with agent jobs should be picked up.");
|
|
966
1124
|
} else {
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
1125
|
+
if (details.mcpTarget === "codex" && args["write-config"] === true) {
|
|
1126
|
+
print("1. Restart or reload Codex Desktop so the MCP server is exposed to fresh chats.");
|
|
1127
|
+
print("2. Keep the generated config file under your user profile; it launches the saved LaunchChair CLI token.");
|
|
1128
|
+
} else if (details.mcpTarget === "codex") {
|
|
1129
|
+
print("1. Fill the Codex custom MCP form with the fields above.");
|
|
1130
|
+
print("2. Restart or reload Codex Desktop so the MCP server is exposed to fresh chats.");
|
|
1131
|
+
} else if (details.mcpTarget === "claude" && args["write-config"] === true) {
|
|
1132
|
+
print("1. Restart or reload Claude Desktop so the MCP server is exposed to fresh chats.");
|
|
1133
|
+
print("2. Keep the generated config file under your user profile; it launches the saved LaunchChair CLI token.");
|
|
1134
|
+
} else {
|
|
1135
|
+
print(`1. Paste the MCP config above into ${details.label}.`);
|
|
1136
|
+
print(`2. Restart or reload ${details.label} so the MCP server is exposed to fresh chats.`);
|
|
1137
|
+
}
|
|
1138
|
+
print("3. If the desktop app cannot find launchchair, run `which launchchair` and use that absolute path as the command.");
|
|
1139
|
+
print("4. Keep this bridge running when you want LaunchChair's Run with agent button to work:");
|
|
970
1140
|
print(` ${paint("launchchair bridge", "cyan")}`);
|
|
971
|
-
print("
|
|
1141
|
+
print("5. Start a fresh agent chat. The agent should discover the LaunchChair skill and MCP server instructions automatically.");
|
|
972
1142
|
}
|
|
973
1143
|
print("");
|
|
974
1144
|
row("Build folder", cwd, "cyan");
|
|
@@ -999,10 +1169,11 @@ async function main() {
|
|
|
999
1169
|
if (command === "continue") return continueProject(args);
|
|
1000
1170
|
if (command === "run-once") return spawnBridge(["--once", "--verbose"]);
|
|
1001
1171
|
if (command === "bridge") return spawnBridge(["--verbose"]);
|
|
1172
|
+
if (command === "mcp-server") return spawnMcpServer();
|
|
1002
1173
|
if (command === "setup") return setup(args);
|
|
1003
1174
|
if (command === "config" && args._[0] === "set") return setConfig({ ...args, _: args._.slice(1) });
|
|
1004
1175
|
if (command === "config") return showConfig();
|
|
1005
|
-
if (command === "mcp-config") return printMcpConfig(args._[0] || "codex");
|
|
1176
|
+
if (command === "mcp-config") return printMcpConfig(args._[0] || "codex", args);
|
|
1006
1177
|
if (command === "install-agent-md") return installAgentMd(args);
|
|
1007
1178
|
throw new Error(`Unknown command: ${command}`);
|
|
1008
1179
|
}
|
package/package.json
CHANGED